Class: Decidim::Initiative

Inherits:
ApplicationRecord
  • Object
show all
Includes:
ActiveModel::Dirty, Authorable, Comments::Commentable, FilterableResource, Followable, HasArea, HasAttachmentCollections, HasAttachments, HasReference, HasResourcePermission, Decidim::Initiatives::HasArea, Decidim::Initiatives::InitiativeSlug, Loggable, Participable, Publicable, Randomable, Resourceable, ScopableParticipatorySpace, Searchable, Traceable, TranslatableResource
Defined in:
app/models/decidim/initiative.rb

Overview

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

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Decidim::Initiatives::InitiativeSlug

#id_from_slug, #slug_from_id

Class Method Details

.log_presenter_class_for(_log) ⇒ Object



157
158
159
# File 'app/models/decidim/initiative.rb', line 157

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

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



466
467
468
# File 'app/models/decidim/initiative.rb', line 466

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

.ransackable_scopes(_auth_object = nil) ⇒ Object



161
162
163
# File 'app/models/decidim/initiative.rb', line 161

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)


417
418
419
# File 'app/models/decidim/initiative.rb', line 417

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

#accepts_online_unvotes?Boolean

Returns:

  • (Boolean)


425
426
427
# File 'app/models/decidim/initiative.rb', line 425

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

#accepts_online_votes?Boolean

Returns:

  • (Boolean)


421
422
423
# File 'app/models/decidim/initiative.rb', line 421

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)


458
459
460
# File 'app/models/decidim/initiative.rb', line 458

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)


233
234
235
# File 'app/models/decidim/initiative.rb', line 233

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



213
214
215
# File 'app/models/decidim/initiative.rb', line 213

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

#author_usersObject



413
414
415
# File 'app/models/decidim/initiative.rb', line 413

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



172
173
174
# File 'app/models/decidim/initiative.rb', line 172

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)


205
206
207
# File 'app/models/decidim/initiative.rb', line 205

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

#commentable?Boolean

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

Returns:

  • (Boolean)


177
178
179
# File 'app/models/decidim/initiative.rb', line 177

def commentable?
  type.comments_enabled?
end

#comments_have_alignment?Boolean

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

Returns:

  • (Boolean)


394
395
396
# File 'app/models/decidim/initiative.rb', line 394

def comments_have_alignment?
  true
end

#comments_have_votes?Boolean

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

Returns:

  • (Boolean)


399
400
401
# File 'app/models/decidim/initiative.rb', line 399

def comments_have_votes?
  true
end

#componentObject



437
438
439
# File 'app/models/decidim/initiative.rb', line 437

def component
  nil
end

#created_by_individual?Boolean

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

Returns a Boolean

Returns:

  • (Boolean)


185
186
187
# File 'app/models/decidim/initiative.rb', line 185

def created_by_individual?
  decidim_user_group_id.nil?
end

#enough_committee_members?Boolean

Returns:

  • (Boolean)


433
434
435
# File 'app/models/decidim/initiative.rb', line 433

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)


407
408
409
410
411
# File 'app/models/decidim/initiative.rb', line 407

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)


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

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

#hashtagObject

Public: Returns the hashtag for the initiative.



280
281
282
# File 'app/models/decidim/initiative.rb', line 280

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

#minimum_committee_membersObject



429
430
431
# File 'app/models/decidim/initiative.rb', line 429

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

#offline_votes_countObject



329
330
331
332
333
# File 'app/models/decidim/initiative.rb', line 329

def offline_votes_count
  return 0 if online_signature_type?

  offline_votes["total"].to_i
end

#offline_votes_count_for(scope) ⇒ Object



343
344
345
346
347
348
349
# File 'app/models/decidim/initiative.rb', line 343

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.



323
324
325
326
327
# File 'app/models/decidim/initiative.rb', line 323

def online_votes_count
  return 0 if offline_signature_type?

  online_votes["total"].to_i
end

#online_votes_count_for(scope) ⇒ Object



335
336
337
338
339
340
341
# File 'app/models/decidim/initiative.rb', line 335

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)


192
193
194
# File 'app/models/decidim/initiative.rb', line 192

def open?
  !closed?
end

#percentageObject

Public: Returns the percentage of required supports reached



306
307
308
# File 'app/models/decidim/initiative.rb', line 306

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.



254
255
256
257
258
259
260
261
262
263
# File 'app/models/decidim/initiative.rb', line 254

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.



247
248
249
# File 'app/models/decidim/initiative.rb', line 247

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)


240
241
242
# File 'app/models/decidim/initiative.rb', line 240

def scopes_enabled?
  true
end

#set_offline_votes_totalObject



363
364
365
366
367
# File 'app/models/decidim/initiative.rb', line 363

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.



384
385
386
# File 'app/models/decidim/initiative.rb', line 384

def slug
  slug_from_id(id)
end

#supports_countObject

Public: Calculates the number of total current supports.

Returns an Integer.



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

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.



294
295
296
# File 'app/models/decidim/initiative.rb', line 294

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)


311
312
313
# File 'app/models/decidim/initiative.rb', line 311

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)


316
317
318
# File 'app/models/decidim/initiative.rb', line 316

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.



301
302
303
# File 'app/models/decidim/initiative.rb', line 301

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

#to_paramObject



388
389
390
# File 'app/models/decidim/initiative.rb', line 388

def to_param
  slug
end

#unpublish!Object

Public: Unpublishes this initiative

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



268
269
270
271
272
# File 'app/models/decidim/initiative.rb', line 268

def unpublish!
  return false unless published?

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

#update_online_votes_countersObject



351
352
353
354
355
356
357
358
359
360
361
# File 'app/models/decidim/initiative.rb', line 351

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)


462
463
464
# File 'app/models/decidim/initiative.rb', line 462

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.



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

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 a Boolean

Returns:

  • (Boolean)


446
447
448
# File 'app/models/decidim/initiative.rb', line 446

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.



375
376
377
378
379
380
381
# File 'app/models/decidim/initiative.rb', line 375

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)


226
227
228
# File 'app/models/decidim/initiative.rb', line 226

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

#votes_enabled?Boolean

Returns:

  • (Boolean)


217
218
219
220
221
# File 'app/models/decidim/initiative.rb', line 217

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