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_by_type, 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

#previously_published?, #published?

Class Method Details

.log_presenter_class_for(_log) ⇒ Object



163
164
165
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 163

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

.ransack(params = {}, options = {}) ⇒ Object



473
474
475
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 473

def self.ransack(params = {}, options = {})
  Initiatives::InitiativeSearch.new(self, params, options)
end

.ransackable_scopes(_auth_object = nil) ⇒ Object



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

def self.ransackable_scopes(_auth_object = nil)
  [:with_any_state, :with_any_type, :with_any_scope, :with_any_area]
end

Instance Method Details

#accepts_offline_votes?Boolean

Returns:

  • (Boolean)


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

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

#accepts_online_unvotes?Boolean

Returns:

  • (Boolean)


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

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

#accepts_online_votes?Boolean

Returns:

  • (Boolean)


424
425
426
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 424

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

#allow_resource_permissions?Boolean

Public: Overrides the ‘allow_resource_permissions?` Resourceable concern method.

Returns:

  • (Boolean)


465
466
467
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 465

def allow_resource_permissions?
  true
end

#answered?Boolean

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

Returns a Boolean.

Returns:

  • (Boolean)


236
237
238
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 236

def answered?
  answered_at.present?
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.

Returns a string



216
217
218
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 216

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

#author_usersObject



416
417
418
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 416

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

Public: Overrides participatory space’s banner image with the banner image defined for the initiative type.

Returns Decidim::BannerImageUploader



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

def banner_image
  type.attached_uploader(:banner_image)
end

#closed?Boolean

Public: Checks if 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 a Boolean

Returns:

  • (Boolean)


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

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

#commentable?Boolean

Public: Whether the object’s comments are visible or not.

Returns:

  • (Boolean)


180
181
182
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 180

def commentable?
  type.comments_enabled?
end

#comments_have_alignment?Boolean

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

Returns:

  • (Boolean)


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

def comments_have_alignment?
  true
end

#comments_have_votes?Boolean

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

Returns:

  • (Boolean)


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

def comments_have_votes?
  true
end

#componentObject



444
445
446
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 444

def component
  nil
end

#created_by_individual?Boolean

Public: Check if an initiative has been created by an individual person. If it is false, then it has been created by an authorized organization.

Returns a Boolean

Returns:

  • (Boolean)


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

def created_by_individual?
  decidim_user_group_id.nil?
end

#enough_committee_members?Boolean

Returns:

  • (Boolean)


436
437
438
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 436

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)


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

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)


278
279
280
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 278

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

#hashtagObject

Public: Returns the hashtag for the initiative.



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

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

#minimum_committee_membersObject



432
433
434
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 432

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

#missing_committee_membersObject



440
441
442
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 440

def missing_committee_members
  minimum_committee_members - committee_members.approved.count
end

#offline_votes_countObject



332
333
334
335
336
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 332

def offline_votes_count
  return 0 if online_signature_type?

  offline_votes["total"].to_i
end

#offline_votes_count_for(scope) ⇒ Object



346
347
348
349
350
351
352
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 346

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.



326
327
328
329
330
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 326

def online_votes_count
  return 0 if offline_signature_type?

  online_votes["total"].to_i
end

#online_votes_count_for(scope) ⇒ Object



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

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: check if an initiative is open

Returns a Boolean

Returns:

  • (Boolean)


195
196
197
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 195

def open?
  !closed?
end

#percentageObject

Public: Returns the percentage of required supports reached



309
310
311
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 309

def percentage
  [supports_count * 100 / supports_required, 100].min
end

#publish!Object

Public: Publishes this initiative

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



257
258
259
260
261
262
263
264
265
266
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 257

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 will not be directly managed by the user and it will be enabled by default.



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

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 will not be directly managed by the user and it will be enabled by default.

Returns:

  • (Boolean)


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

def scopes_enabled?
  true
end

#set_offline_votes_totalObject



366
367
368
369
370
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 366

def set_offline_votes_total
  return if offline_votes.blank?

  offline_votes["total"] = offline_votes[scope&.id.to_s] || offline_votes["global"]
end

#slugObject

Public: Overrides slug attribute from participatory processes.



387
388
389
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 387

def slug
  slug_from_id(id)
end

#supports_countObject

Public: Calculates the number of total current supports.

Returns an Integer.



290
291
292
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 290

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.



297
298
299
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 297

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)


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

def supports_goal_reached?
  votable_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)


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

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.



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

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

#to_paramObject



391
392
393
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 391

def to_param
  slug
end

#unpublish!Object

Public: Unpublishes this initiative

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



271
272
273
274
275
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 271

def unpublish!
  return false unless published?

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

#update_online_votes_countersObject



354
355
356
357
358
359
360
361
362
363
364
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 354

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_allowed_to_comment?(user) ⇒ Boolean

Returns:

  • (Boolean)


469
470
471
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 469

def user_allowed_to_comment?(user)
  ActionAuthorizer.new(user, "comment", self, nil).authorize.ok?
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.



460
461
462
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 460

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 does not have the sms authorization available

Returns a Boolean

Returns:

  • (Boolean)


453
454
455
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 453

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.



378
379
380
381
382
383
384
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 378

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)


229
230
231
# File 'decidim-initiatives/app/models/decidim/initiative.rb', line 229

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

#votes_enabled?Boolean

Returns:

  • (Boolean)


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

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