Class: OpenProject::Token

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Validations
Defined in:
lib/open_project/token.rb,
lib/open_project/token/armor.rb,
lib/open_project/token/plans.rb,
lib/open_project/token/version.rb,
lib/open_project/token/extractor.rb

Defined Under Namespace

Modules: Armor Classes: Error, Extractor, ImportError, ParseError, ValidationError

Constant Summary collapse

LEGACY_ENTERPRISE_PLAN_FEATURES =
%i[
  baseline_comparison
  board_view
  conditional_highlighting
  custom_actions
  custom_field_hierarchies
  date_alerts
  define_custom_style
  edit_attribute_groups
  gantt_pdf_export
  ldap_groups
  one_drive_sharepoint_file_storage
  placeholder_users
  project_list_sharing
  readonly_work_packages
  sso_auth_providers
  team_planner_view
  virus_scanning
  work_package_query_relation_columns
  work_package_sharing
].freeze
BASIC_PLAN_FEATURES =
%i[
  baseline_comparison
  board_view
  conditional_highlighting
  custom_actions
  custom_field_hierarchies
  date_alerts
  define_custom_style
  edit_attribute_groups
  gantt_pdf_export
  placeholder_users
  readonly_work_packages
  team_planner_view
  work_package_query_relation_columns
].freeze
PROFESSIONAL_PLAN_FEATURES =
%i[
  internal_comments
  one_drive_sharepoint_file_storage
  sso_auth_providers
  time_entry_time_restrictions
  work_package_sharing
  work_package_subject_generation
].freeze
PREMIUM_PLAN_FEATURES =
%i[
  calculated_values
  customize_life_cycle
  ldap_groups
  project_list_sharing
].freeze
CORPORATE_PLAN_FEATURES =
%i[
  nextcloud_sso
  scim_api
  virus_scanning
].freeze
FEATURES_PER_PLAN =
{
  # old plan that is used for all plans that do not have a plan set
  legacy_enterprise: LEGACY_ENTERPRISE_PLAN_FEATURES,

  # old plan that receives new features from the given new plan name
  legacy_enterprise_professional: (LEGACY_ENTERPRISE_PLAN_FEATURES + PROFESSIONAL_PLAN_FEATURES).uniq,
  legacy_enterprise_premium: (LEGACY_ENTERPRISE_PLAN_FEATURES + PREMIUM_PLAN_FEATURES + PROFESSIONAL_PLAN_FEATURES).uniq,

  # new plans
  basic: BASIC_PLAN_FEATURES,
  professional: PROFESSIONAL_PLAN_FEATURES + BASIC_PLAN_FEATURES,
  premium: PREMIUM_PLAN_FEATURES + PROFESSIONAL_PLAN_FEATURES + BASIC_PLAN_FEATURES,
  corporate: CORPORATE_PLAN_FEATURES + PREMIUM_PLAN_FEATURES + PROFESSIONAL_PLAN_FEATURES + BASIC_PLAN_FEATURES
}.freeze
ACTIVE_PLAN_NAMES =

Current plan names, sorted by inheritance

%i[basic professional premium corporate].freeze
LEGACY_PLAN_NAMES =
%i[legacy_enterprise legacy_enterprise_professional
legacy_enterprise_premium legacy_enterprise_corporate].freeze
AVAILABLE_PLAN_NAMES =

All available plan names

LEGACY_PLAN_NAMES + ACTIVE_PLAN_NAMES
DEFAULT_PLAN =

default plan that is assigned to a token if no plan is given (especially legacy tokens)

:legacy_enterprise
VERSION =
"7.4.0"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}) ⇒ Token

Returns a new instance of Token.



85
86
87
# File 'lib/open_project/token.rb', line 85

def initialize(attributes = {})
  load_attributes(attributes)
end

Class Attribute Details

.extractorObject (readonly)

Returns the value of attribute extractor.



23
24
25
# File 'lib/open_project/token.rb', line 23

def extractor
  @extractor
end

.keyObject

Returns the value of attribute key.



23
24
25
# File 'lib/open_project/token.rb', line 23

def key
  @key
end

Instance Attribute Details

#block_changes_atObject

Returns the value of attribute block_changes_at.



61
62
63
# File 'lib/open_project/token.rb', line 61

def block_changes_at
  @block_changes_at
end

#companyObject

Returns the value of attribute company.



61
62
63
# File 'lib/open_project/token.rb', line 61

def company
  @company
end

#domainObject

Returns the value of attribute domain.



61
62
63
# File 'lib/open_project/token.rb', line 61

def domain
  @domain
end

#expires_atObject

Returns the value of attribute expires_at.



61
62
63
# File 'lib/open_project/token.rb', line 61

def expires_at
  @expires_at
end

#featuresObject

Returns the value of attribute features.



61
62
63
# File 'lib/open_project/token.rb', line 61

def features
  @features
end

#issued_atObject

Returns the value of attribute issued_at.



61
62
63
# File 'lib/open_project/token.rb', line 61

def issued_at
  @issued_at
end

#mailObject

Returns the value of attribute mail.



61
62
63
# File 'lib/open_project/token.rb', line 61

def mail
  @mail
end

#notify_admins_atObject

Returns the value of attribute notify_admins_at.



61
62
63
# File 'lib/open_project/token.rb', line 61

def notify_admins_at
  @notify_admins_at
end

#notify_users_atObject

Returns the value of attribute notify_users_at.



61
62
63
# File 'lib/open_project/token.rb', line 61

def notify_users_at
  @notify_users_at
end

#planObject

Returns the value of attribute plan.



60
61
62
# File 'lib/open_project/token.rb', line 60

def plan
  @plan
end

#reprieve_daysObject

Returns the value of attribute reprieve_days.



61
62
63
# File 'lib/open_project/token.rb', line 61

def reprieve_days
  @reprieve_days
end

#restrictionsObject

Returns the value of attribute restrictions.



61
62
63
# File 'lib/open_project/token.rb', line 61

def restrictions
  @restrictions
end

#starts_atObject

Returns the value of attribute starts_at.



61
62
63
# File 'lib/open_project/token.rb', line 61

def starts_at
  @starts_at
end

#subscriberObject

Returns the value of attribute subscriber.



61
62
63
# File 'lib/open_project/token.rb', line 61

def subscriber
  @subscriber
end

#trialObject

Returns the value of attribute trial.



61
62
63
# File 'lib/open_project/token.rb', line 61

def trial
  @trial
end

#validate_domainObject

Returns the value of attribute validate_domain.



61
62
63
# File 'lib/open_project/token.rb', line 61

def validate_domain
  @validate_domain
end

#versionObject (readonly)

Returns the value of attribute version.



60
61
62
# File 'lib/open_project/token.rb', line 60

def version
  @version
end

Class Method Details

.import(data) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/open_project/token.rb', line 34

def import(data)
  raise ImportError, "Missing key." if key.nil?
  raise ImportError, "No token data." if data.nil?

  data = Armor.decode(data)
  json = extractor.read(data)
  attributes = JSON.parse(json)

  new(attributes)
rescue Extractor::Error
  raise ImportError, "Token value could not be read."
rescue JSON::ParserError
  raise ImportError, "Token value is invalid JSON."
rescue Armor::ParseError
  raise ImportError, "Token value could not be parsed."
end

.lowest_plan_for(feature) ⇒ Object



51
52
53
54
55
# File 'lib/open_project/token.rb', line 51

def lowest_plan_for(feature)
  OpenProject::Token::ACTIVE_PLAN_NAMES.detect do |plan|
    OpenProject::Token::FEATURES_PER_PLAN[plan].include?(feature)
  end
end

Instance Method Details

#active?(reprieve: true) ⇒ Boolean

Indicates whether the token is active

Parameters:

  • reprieve (Boolean) (defaults to: true)

    Allow for reprieve (default true)

Returns:

  • (Boolean)

    Returns whether the token is active



157
158
159
# File 'lib/open_project/token.rb', line 157

def active?(reprieve: true)
  started? && !expired?(reprieve: reprieve)
end

#attributesObject

rubocop:disable Metrics/AbcSize



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/open_project/token.rb', line 208

def attributes # rubocop:disable Metrics/AbcSize
  hash = {
    "version" => version,
    "subscriber" => subscriber,
    "mail" => mail,
    "company" => company,
    "domain" => domain,
    "validate_domain" => validate_domain,
    "plan" => plan,
    "issued_at" => issued_at,
    "starts_at" => starts_at,
    "trial" => trial,
    "features" => features
  }

  if will_expire?
    hash["expires_at"]       = expires_at
    hash["reprieve_days"]    = reprieve_days
  end

  hash["notify_admins_at"] = notify_admins_at if will_notify_admins?
  hash["notify_users_at"]  = notify_users_at  if will_notify_users?
  hash["block_changes_at"] = block_changes_at if will_block_changes?

  hash["restrictions"]     = restrictions     if restricted?

  hash
end

#available_featuresObject



117
118
119
120
121
122
123
124
# File 'lib/open_project/token.rb', line 117

def available_features
  return @available_features if defined?(@available_features)

  relevant_features = OpenProject::Token::FEATURES_PER_PLAN[plan] || []
  additional_features = features || []

  @available_features = (relevant_features + additional_features).uniq
end

#block_changes?Boolean

Returns:

  • (Boolean)


179
180
181
# File 'lib/open_project/token.rb', line 179

def block_changes?
  will_block_changes? && Date.today >= block_changes_at
end

#expired?(reprieve: true) ⇒ Boolean

Indicates whether or not the token has expired.

This does include a reprieve (grace period) if configured. I.e. this will return false even if ‘expires_at` has passed if `reprieve_days` is configured, as long as the current date is still within those days after the actual expiration.

Parameters:

  • reprieve (Boolean) (defaults to: true)

    Allow for reprieve (default true)

Returns:

  • (Boolean)


135
136
137
138
139
# File 'lib/open_project/token.rb', line 135

def expired?(reprieve: true)
  offset = reprieve ? reprieve_days.to_i : 0

  will_expire? && Date.today > expires_at.next_day(offset)
end

#from_json(json) ⇒ Object



241
242
243
244
245
# File 'lib/open_project/token.rb', line 241

def from_json(json)
  load_attributes(JSON.parse(json))
rescue StandardError => e
  raise ParseError, "Failed to load from json: #{e}"
end

#has_feature?(name) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/open_project/token.rb', line 109

def has_feature?(name)
  available_features.include?(name.to_sym)
end

#notify_admins?Boolean

Returns:

  • (Boolean)


171
172
173
# File 'lib/open_project/token.rb', line 171

def notify_admins?
  will_notify_admins? && Date.today >= notify_admins_at
end

#notify_users?Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/open_project/token.rb', line 175

def notify_users?
  will_notify_users? && Date.today >= notify_users_at
end

#parsed_domainObject



247
248
249
250
251
# File 'lib/open_project/token.rb', line 247

def parsed_domain
  @parsed_domain = read_domain!(domain) unless defined?(@parsed_domain)

  @parsed_domain
end

#reprieve_days_leftObject

Returns the number of days of reprieve left after the token has expired.

Returns:

  • Returns ‘nil` if the token hasn’t expired yet or if no reprieve was given.



165
166
167
168
169
# File 'lib/open_project/token.rb', line 165

def reprieve_days_left
  return nil unless reprieve_days.to_i > 0 && expired?(reprieve: false)

  (expires_at.next_day(reprieve_days.to_i) - Date.today).to_i
end

#restricted?(key = nil) ⇒ Boolean

Returns:

  • (Boolean)


200
201
202
203
204
205
206
# File 'lib/open_project/token.rb', line 200

def restricted?(key = nil)
  if key
    restricted? && restrictions.has_key?(key)
  else
    restrictions && restrictions.length >= 1
  end
end

#started?Boolean

Indicates whether or not the token’s validity has even started

Returns:

  • (Boolean)

    Returns whether the token’s validity has started



145
146
147
148
149
# File 'lib/open_project/token.rb', line 145

def started?
  return true if starts_at.nil?

  Date.today >= starts_at
end

#to_json(*_args) ⇒ Object



237
238
239
# File 'lib/open_project/token.rb', line 237

def to_json(*_args)
  JSON.dump(attributes)
end

#trial?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/open_project/token.rb', line 105

def trial?
  trial
end

#valid_domain?(input) ⇒ Boolean

Returns:

  • (Boolean)


190
191
192
193
194
195
196
197
198
# File 'lib/open_project/token.rb', line 190

def valid_domain?(input)
  return true if domain.nil?

  if parsed_domain.is_a?(Regexp)
    parsed_domain.match?(input)
  else
    domain.casecmp(input).zero?
  end
end

#validate_domain?Boolean

tokens with no version or a version lower than 2.0 don’t have the attributes company or domain

Returns:

  • (Boolean)


184
185
186
187
188
# File 'lib/open_project/token.rb', line 184

def validate_domain?
  return validate_domain unless validate_domain.nil?

  version && Gem::Version.new(version) >= domain_required_from_version
end

#will_block_changes?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/open_project/token.rb', line 101

def will_block_changes?
  block_changes_at
end

#will_expire?Boolean

Returns:

  • (Boolean)


89
90
91
# File 'lib/open_project/token.rb', line 89

def will_expire?
  expires_at
end

#will_notify_admins?Boolean

Returns:

  • (Boolean)


93
94
95
# File 'lib/open_project/token.rb', line 93

def will_notify_admins?
  notify_admins_at
end

#will_notify_users?Boolean

Returns:

  • (Boolean)


97
98
99
# File 'lib/open_project/token.rb', line 97

def will_notify_users?
  notify_users_at
end