Class: Decidim::Initiative

Inherits:
ApplicationRecord
  • Object
show all
Includes:
ActiveModel::Dirty, Authorable, Comments::Commentable, DownloadYourData, FilterableResource, Followable, HasArea, HasAttachmentCollections, HasAttachments, HasReference, HasResourcePermission, Decidim::Initiatives::HasArea, Decidim::Initiatives::InitiativeSlug, Loggable, Participable, Publicable, Randomable, Reportable, Resourceable, ScopableParticipatorySpace, Searchable, ShareableWithToken, 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

.export_serializerObject



159
160
161
# File 'app/models/decidim/initiative.rb', line 159

def self.export_serializer
  Decidim::Initiatives::DownloadYourDataInitiativeSerializer
end

.log_presenter_class_for(_log) ⇒ Object



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

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

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



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

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

.ransackable_associations(_auth_object = nil) ⇒ Object



179
180
181
# File 'app/models/decidim/initiative.rb', line 179

def self.ransackable_associations(_auth_object = nil)
  %w(area scope taxonomies)
end

.ransackable_attributes(auth_object = nil) ⇒ Object



171
172
173
174
175
176
177
# File 'app/models/decidim/initiative.rb', line 171

def self.ransackable_attributes(auth_object = nil)
  base = %w(search_text title description id id_string supports_count author_name author_nickname)

  return base unless auth_object&.admin?

  base + %w(published_at created_at state decidim_area_id type_id)
end

.ransackable_scopes(_auth_object = nil) ⇒ Object



183
184
185
# File 'app/models/decidim/initiative.rb', line 183

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)


392
393
394
# File 'app/models/decidim/initiative.rb', line 392

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

#accepts_online_unvotes?Boolean

Returns:

  • (Boolean)


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

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

#accepts_online_votes?Boolean

Returns:

  • (Boolean)


396
397
398
# File 'app/models/decidim/initiative.rb', line 396

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)


443
444
445
# File 'app/models/decidim/initiative.rb', line 443

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)


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

def answered?
  answered_at.present?
end

#author_usersObject



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

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

#commentable?Boolean

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

Returns:

  • (Boolean)


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

def commentable?
  type.comments_enabled?
end

#comments_have_alignment?Boolean

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

Returns:

  • (Boolean)


369
370
371
# File 'app/models/decidim/initiative.rb', line 369

def comments_have_alignment?
  true
end

#comments_have_votes?Boolean

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

Returns:

  • (Boolean)


374
375
376
# File 'app/models/decidim/initiative.rb', line 374

def comments_have_votes?
  true
end

#componentObject



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

def component
  nil
end

#enough_committee_members?Boolean

Returns:

  • (Boolean)


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

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)


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

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 whether the signature interval is already defined or not.

Returns:

  • (Boolean)


255
256
257
# File 'app/models/decidim/initiative.rb', line 255

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

#minimum_committee_membersObject



404
405
406
# File 'app/models/decidim/initiative.rb', line 404

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

#missing_committee_membersObject



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

def missing_committee_members
  minimum_committee_members - committee_members.approved.count
end

#offline_votes_countObject



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

def offline_votes_count
  return 0 if online_signature_type?

  offline_votes["total"].to_i
end

#offline_votes_count_for(scope) ⇒ Object



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

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.



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

def online_votes_count
  return 0 if offline_signature_type?

  online_votes["total"].to_i
end

#online_votes_count_for(scope) ⇒ Object



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

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

#percentageObject

Public: Returns the percentage of required supports reached



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

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

#presenterObject



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

def presenter
  Decidim::InitiativePresenter.new(self)
end

#publish!Object

Public: Publishes this initiative

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



234
235
236
237
238
239
240
241
242
243
# File 'app/models/decidim/initiative.rb', line 234

def publish!
  return false if published?

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

#reported_attributesObject

Public: Overrides the ‘reported_attributes` Reportable concern method.



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

def reported_attributes
  [:title, :description]
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.



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

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)


220
221
222
# File 'app/models/decidim/initiative.rb', line 220

def scopes_enabled?
  true
end

#set_offline_votes_totalObject



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

def set_offline_votes_total
  return if offline_votes.blank?

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

#shareable_url(share_token) ⇒ Object



455
456
457
# File 'app/models/decidim/initiative.rb', line 455

def shareable_url(share_token)
  EngineRouter.main_proxy(self).initiative_url(self, share_token: share_token.token)
end

#slugObject

Public: Overrides slug attribute from participatory processes.



359
360
361
# File 'app/models/decidim/initiative.rb', line 359

def slug
  slug_from_id(id)
end

#supports_countObject

Public: Calculates the number of total current supports.

Returns an Integer.



262
263
264
# File 'app/models/decidim/initiative.rb', line 262

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.



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

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)


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

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)


291
292
293
# File 'app/models/decidim/initiative.rb', line 291

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.



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

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

#to_paramObject



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

def to_param
  slug
end

#unpublish!Object

Public: Unpublishes this initiative

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



248
249
250
251
252
# File 'app/models/decidim/initiative.rb', line 248

def unpublish!
  return false unless published?

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

#update_online_votes_countersObject



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

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)


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

def user_allowed_to_comment?(user)
  ActionAuthorizer.new(user, "comment", self, nil).authorize.ok?
end

#user_allowed_to_vote_comment?(user) ⇒ Boolean

Returns:

  • (Boolean)


451
452
453
# File 'app/models/decidim/initiative.rb', line 451

def user_allowed_to_vote_comment?(user)
  ActionAuthorizer.new(user, "vote_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.



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

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

#user_roles(_role_name = nil) ⇒ Object

Public: Initiatives do not have user roles like other participatory spaces. Returns an empty relation.



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

def user_roles(_role_name = nil)
  self.class.none
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)


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

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.



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

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)


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

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

#votes_enabled?Boolean

Returns:

  • (Boolean)


197
198
199
200
201
# File 'app/models/decidim/initiative.rb', line 197

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