Class: Decidim::Initiative

Overview

The data store for a Initiative in the Decidim::Initiatives component.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Searchable

searchable_resources, searchable_resources_of_type_comment, searchable_resources_of_type_component, searchable_resources_of_type_participant, searchable_resources_of_type_participatory_space

Methods included from Decidim::Initiatives::InitiativeSlug

#id_from_slug, #slug_from_id

Methods included from HasAttachments

#attachment_context

Methods included from Followable

#followers

Methods included from Publicable

#published?

Class Method Details

.log_presenter_class_for(_log) ⇒ Object


123
124
125
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 123

def self.log_presenter_class_for(_log)
  Decidim::Initiatives::AdminLog::InitiativePresenter
end

Instance Method Details

#accepts_offline_votes?Boolean

Returns:

  • (Boolean)

393
394
395
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 393

def accepts_offline_votes?
  published? && (offline_signature_type? || any_signature_type?)
end

#accepts_online_unvotes?Boolean

Returns:

  • (Boolean)

401
402
403
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 401

def accepts_online_unvotes?
  accepts_online_votes? && type.undo_online_signatures_enabled?
end

#accepts_online_votes?Boolean

Returns:

  • (Boolean)

397
398
399
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 397

def accepts_online_votes?
  votes_enabled? && (online_signature_type? || any_signature_type?)
end

#answered?Boolean

Public: Checks if the organization has given an answer for the initiative.

Returns Boolean.

Returns:

  • (Boolean)

207
208
209
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 207

def answered?
  answered_at.present?
end

#author_avatar_urlObject

PUBLIC author_avatar_url

Returns the author's avatar URL. In case it is not defined the method falls back to images/default-avatar.svg

RETURNS STRING


186
187
188
189
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 186

def author_avatar_url
  author.avatar&.url ||
    ActionController::Base.helpers.asset_pack_path("media/images/default-avatar.svg")
end

#author_nameObject

PUBLIC

Returns the author name. If it has been created by an organization it will return the organization's name. Otherwise it will return author's name.

RETURN string


176
177
178
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 176

def author_name
  user_group&.name || author.name
end

#author_usersObject


389
390
391
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 389

def author_users
  [author].concat(committee_members.excluding_author.map(&:user))
end

#closed?Boolean

PUBLIC

Returns when an initiative is closed. An initiative is closed when at least one of the following conditions is true:

  • It has been discarded.

  • It has been rejected.

  • It has been accepted.

  • Signature collection period has finished.

RETURNS BOOLEAN

Returns:

  • (Boolean)

166
167
168
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 166

def closed?
  discarded? || rejected? || accepted? || !votes_enabled?
end

#comments_have_alignment?Boolean

Public: Overrides the `comments_have_alignment?` Commentable concern method.

Returns:

  • (Boolean)

370
371
372
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 370

def comments_have_alignment?
  true
end

#comments_have_votes?Boolean

Public: Overrides the `comments_have_votes?` Commentable concern method.

Returns:

  • (Boolean)

375
376
377
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 375

def comments_have_votes?
  true
end

#created_by_individual?Boolean

PUBLIC

Returns true when an initiative has been created by an individual person. False in case it has been created by an authorized organization.

RETURN boolean

Returns:

  • (Boolean)

143
144
145
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 143

def created_by_individual?
  decidim_user_group_id.nil?
end

#enough_committee_members?Boolean

Returns:

  • (Boolean)

409
410
411
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 409

def enough_committee_members?
  committee_members.approved.count >= minimum_committee_members
end

#has_authorship?(user) ⇒ Boolean

Public: Checks if user is the author or is part of the promotal committee of the initiative.

Returns a Boolean.

Returns:

  • (Boolean)

383
384
385
386
387
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 383

def has_authorship?(user)
  return true if author.id == user.id

  committee_members.approved.where(decidim_users_id: user.id).any?
end

#has_signature_interval_defined?Boolean

Public: Returns wether the signature interval is already defined or not.

Returns:

  • (Boolean)

249
250
251
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 249

def has_signature_interval_defined?
  signature_end_date.present? && signature_start_date.present?
end

#hashtagObject

Public: Returns the hashtag for the initiative.


254
255
256
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 254

def hashtag
  attributes["hashtag"].to_s.delete("#")
end

#minimum_committee_membersObject


405
406
407
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 405

def minimum_committee_members
  type.minimum_committee_members || Decidim::Initiatives.minimum_committee_members
end

#offline_votes_countObject


305
306
307
308
309
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 305

def offline_votes_count
  return 0 if online_signature_type?

  offline_votes["total"].to_i
end

#offline_votes_count_for(scope) ⇒ Object


319
320
321
322
323
324
325
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 319

def offline_votes_count_for(scope)
  return 0 if online_signature_type?

  scope_key = (scope&.id || "global").to_s

  (offline_votes || {}).fetch(scope_key, 0).to_i
end

#online_votes_countObject

Public: Calculates all the votes across all the scopes.

Returns an Integer.


299
300
301
302
303
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 299

def online_votes_count
  return 0 if offline_signature_type?

  online_votes["total"].to_i
end

#online_votes_count_for(scope) ⇒ Object


311
312
313
314
315
316
317
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 311

def online_votes_count_for(scope)
  return 0 if offline_signature_type?

  scope_key = (scope&.id || "global").to_s

  (online_votes || {}).fetch(scope_key, 0).to_i
end

#open?Boolean

PUBLIC

RETURN boolean TRUE when the initiative is open, false in case its not closed.

Returns:

  • (Boolean)

151
152
153
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 151

def open?
  !closed?
end

#percentageObject

Public: Returns the percentage of required supports reached


280
281
282
283
284
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 280

def percentage
  return 100 if supports_goal_reached?

  supports_count * 100 / supports_required
end

#publish!Object

Public: Publishes this initiative

Returns true if the record was properly saved, false otherwise.


228
229
230
231
232
233
234
235
236
237
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 228

def publish!
  return false if published?

  update(
    published_at: Time.current,
    state: "published",
    signature_start_date: Date.current,
    signature_end_date: signature_end_date || Date.current + Decidim::Initiatives.default_signature_time_period_length
  )
end

#scopes_enabledObject

Public: Overrides scopes enabled attribute value. For initiatives it won't be directly managed by the user and it will be enabled by default.


221
222
223
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 221

def scopes_enabled
  true
end

#scopes_enabled?Boolean

Public: Overrides scopes enabled flag available in other models like participatory space or assemblies. For initiatives it won't be directly managed by the user and it will be enabled by default.

Returns:

  • (Boolean)

214
215
216
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 214

def scopes_enabled?
  true
end

#set_offline_votes_totalObject


339
340
341
342
343
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 339

def set_offline_votes_total
  return if offline_votes.blank? || scope.nil?

  offline_votes["total"] = offline_votes[scope.id.to_s]
end

#slugObject

Public: Overrides slug attribute from participatory processes.


360
361
362
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 360

def slug
  slug_from_id(id)
end

#supports_countObject

Public: Calculates the number of total current supports.

Returns an Integer.


261
262
263
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 261

def supports_count
  online_votes_count + offline_votes_count
end

#supports_count_for(scope) ⇒ Object

Public: Calculates the number of current supports for a scope.

Returns an Integer.


268
269
270
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 268

def supports_count_for(scope)
  online_votes_count_for(scope) + offline_votes_count_for(scope)
end

#supports_goal_reached?Boolean

Public: Whether the supports required objective has been reached

Returns:

  • (Boolean)

287
288
289
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 287

def supports_goal_reached?
  initiative_type_scopes.map(&:scope).all? { |scope| supports_goal_reached_for?(scope) }
end

#supports_goal_reached_for?(scope) ⇒ Boolean

Public: Whether the supports required objective has been reached for a scope

Returns:

  • (Boolean)

292
293
294
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 292

def supports_goal_reached_for?(scope)
  supports_count_for(scope) >= supports_required_for(scope)
end

#supports_required_for(scope) ⇒ Object

Public: Calculates the number of supports required to accept the initiative for a scope.

Returns an Integer.


275
276
277
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 275

def supports_required_for(scope)
  initiative_type_scopes.find_by(decidim_scopes_id: scope&.id).supports_required
end

#to_paramObject


364
365
366
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 364

def to_param
  slug
end

#unpublish!Object

Public: Unpublishes this initiative

Returns true if the record was properly saved, false otherwise.


242
243
244
245
246
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 242

def unpublish!
  return false unless published?

  update(published_at: nil, state: "discarded")
end

#update_online_votes_countersObject


327
328
329
330
331
332
333
334
335
336
337
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 327

def update_online_votes_counters
  online_votes = votes.group(:scope).count.each_with_object({}) do |(scope, count), counters|
    counters[scope&.id || "global"] = count
    counters["total"] ||= 0
    counters["total"] += count
  end

  # rubocop:disable Rails/SkipsModelValidations
  update_column("online_votes", online_votes)
  # rubocop:enable Rails/SkipsModelValidations
end

#user_role_config_for(_user, _role_name) ⇒ Object

Public: Returns an empty object. This method should be implemented by `ParticipatorySpaceResourceable`, but for some reason this model does not implement this interface.


427
428
429
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 427

def user_role_config_for(_user, _role_name)
  Decidim::ParticipatorySpaceRoleConfig::Base.new(:empty_role_name)
end

#validate_sms_code_on_votes?Boolean

PUBLIC

Checks if the type the initiative belongs to enables SMS code verification step. Tis configuration is ignored if the organization doesn't have the sms authorization available

RETURNS boolean

Returns:

  • (Boolean)

420
421
422
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 420

def validate_sms_code_on_votes?
  organization.available_authorizations.include?("sms") && type.validate_sms_code_on_votes?
end

#votable_initiative_type_scopesObject

Public: Finds all the InitiativeTypeScopes that are eligible to be voted by a user. Usually this is only the `scoped_type` but voting on children of the scoped type is enabled we have to filter all the available scopes in the initiative type to select the ones that are a descendant of the initiative type.

Returns an Array of Decidim::InitiativesScopeType.


351
352
353
354
355
356
357
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 351

def votable_initiative_type_scopes
  return Array(scoped_type) unless type.child_scope_threshold_enabled?

  initiative_type_scopes.select do |initiative_type_scope|
    initiative_type_scope.scope.present? && (scoped_type.global_scope? || scoped_type.scope.ancestor_of?(initiative_type_scope.scope))
  end.prepend(scoped_type).uniq
end

#voted_by?(user) ⇒ Boolean

Public: Check if the user has voted the question.

Returns Boolean.

Returns:

  • (Boolean)

200
201
202
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 200

def voted_by?(user)
  votes.where(author: user).any?
end

#votes_enabled?Boolean

Returns:

  • (Boolean)

191
192
193
194
195
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 191

def votes_enabled?
  published? &&
    signature_start_date <= Date.current &&
    signature_end_date >= Date.current
end