Class: Decidim::Proposals::Proposal
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Decidim::Proposals::Proposal
- Includes:
- Amendable, Coauthorable, DownloadYourData, Endorsable, FilterableResource, Fingerprintable, Followable, HasAttachments, HasCategory, HasComponent, HasReference, Loggable, NewsletterParticipant, CommentableProposal, ParticipatoryTextSection, Valuatable, Randomable, Reportable, Resourceable, ScopableResource, Searchable, Traceable, TranslatableAttributes, TranslatableResource
- Defined in:
- app/models/decidim/proposals/proposal.rb
Overview
The data store for a Proposal in the Decidim::Proposals component.
Constant Summary
Constants included from ParticipatoryTextSection
Decidim::Proposals::ParticipatoryTextSection::LEVELS
Class Method Summary collapse
- .download_your_data_images(user) ⇒ Object
- .export_serializer ⇒ Object
- .log_presenter_class_for(_log) ⇒ Object
- .newsletter_participant_ids(component) ⇒ Object
- .ransack(params = {}, options = {}) ⇒ Object
- .ransackable_scopes(auth_object = nil) ⇒ Object
- .retrieve_proposals_for(component) ⇒ Object
- .sort_by_translated_title_asc ⇒ Object
- .sort_by_translated_title_desc ⇒ Object
-
.user_collection(author) ⇒ Object
Returns a collection scoped by an author.
-
.valuator_role_ids_has(value) ⇒ Object
method to filter by assigned valuator role ID.
- .with_valuation_assigned_to(user, space) ⇒ Object
Instance Method Summary collapse
-
#accepted? ⇒ Boolean
Public: Checks if the organization has accepted a proposal.
-
#allow_resource_permissions? ⇒ Boolean
Public: Overrides the ‘allow_resource_permissions?` Resourceable concern method.
-
#answered? ⇒ Boolean
Public: Checks if the organization has given an answer for the proposal.
- #assign_state(token) ⇒ Object
-
#can_accumulate_votes_beyond_threshold ⇒ Object
Public: Can accumulate more votes than maximum for this proposal.
-
#draft? ⇒ Boolean
Public: Whether the proposal is a draft or not.
-
#editable_by?(user) ⇒ Boolean
Checks whether the user can edit the given proposal.
-
#evaluating? ⇒ Boolean
Public: Checks if the organization has marked the proposal as evaluating it.
-
#internal_state ⇒ Object
Public: Returns the internal state of the proposal.
-
#maximum_votes ⇒ Object
Public: The maximum amount of votes allowed for this proposal.
-
#maximum_votes_reached? ⇒ Boolean
Public: The maximum amount of votes allowed for this proposal.
-
#official? ⇒ Boolean
Public: Whether the proposal is official or not.
-
#official_meeting? ⇒ Boolean
Public: Whether the proposal is created in a meeting or not.
-
#presenter ⇒ Object
Returns the presenter for this author, to be used in the views.
- #process_amendment_state_change! ⇒ Object
-
#published? ⇒ Boolean
Public: Checks if the proposal has been published or not.
-
#published_state? ⇒ Boolean
Public: Checks if the organization has published the state for the proposal.
-
#rejected? ⇒ Boolean
Public: Checks if the organization has rejected a proposal.
-
#reported_attributes ⇒ Object
Public: Overrides the ‘reported_attributes` Reportable concern method.
-
#reported_content_url ⇒ Object
Public: Overrides the ‘reported_content_url` Reportable concern method.
-
#reported_searchable_content_extras ⇒ Object
Public: Overrides the ‘reported_searchable_content_extras` Reportable concern method.
-
#state ⇒ Object
Public: Returns the published state of the proposal.
-
#update_votes_count ⇒ Object
Public: Updates the vote count of this proposal.
-
#voted_by?(user) ⇒ Boolean
Public: Check if the user has voted the proposal.
- #withdraw! ⇒ Object
-
#withdrawable_by?(user) ⇒ Boolean
Checks whether the user can withdraw the given proposal.
-
#withdrawn? ⇒ Boolean
Public: Checks if the author has withdrawn the proposal.
-
#within_edit_time_limit? ⇒ Boolean
Checks whether the proposal is inside the time window to be editable or not once published.
Class Method Details
.download_your_data_images(user) ⇒ Object
465 466 467 |
# File 'app/models/decidim/proposals/proposal.rb', line 465 def self.download_your_data_images(user) user_collection(user).map { |p| p..collect(&:file) } end |
.export_serializer ⇒ Object
461 462 463 |
# File 'app/models/decidim/proposals/proposal.rb', line 461 def self.export_serializer Decidim::Proposals::ProposalSerializer end |
.log_presenter_class_for(_log) ⇒ Object
178 179 180 |
# File 'app/models/decidim/proposals/proposal.rb', line 178 def self.log_presenter_class_for(_log) Decidim::Proposals::AdminLog::ProposalPresenter end |
.newsletter_participant_ids(component) ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'app/models/decidim/proposals/proposal.rb', line 201 def self.(component) proposals = retrieve_proposals_for(component).uniq = proposals.map { |p| p.notifiable_identities.pluck(:id) }.flatten.compact.uniq participants_has_voted_ids = Decidim::Proposals::ProposalVote.joins(:proposal).where(proposal: proposals).joins(:author).map(&:decidim_author_id).flatten.compact.uniq endorsements_participants_ids = Decidim::Endorsement.where(resource: proposals) .where(decidim_author_type: "Decidim::UserBaseEntity") .pluck(:decidim_author_id).to_a.compact.uniq commentators_ids = Decidim::Comments::Comment.user_commentators_ids_in(proposals) (endorsements_participants_ids + participants_has_voted_ids + + commentators_ids).flatten.compact.uniq end |
.ransack(params = {}, options = {}) ⇒ Object
388 389 390 |
# File 'app/models/decidim/proposals/proposal.rb', line 388 def self.ransack(params = {}, = {}) ProposalSearch.new(self, params, ) end |
.ransackable_scopes(auth_object = nil) ⇒ Object
405 406 407 408 409 410 411 |
# File 'app/models/decidim/proposals/proposal.rb', line 405 def self.ransackable_scopes(auth_object = nil) base = [:with_any_origin, :with_any_state, :state_eq, :voted_by, :coauthored_by, :related_to, :with_any_scope, :with_any_category] return base unless auth_object&.admin? # Add extra scopes for admins for the admin panel searches base + [:valuator_role_ids_has] end |
.retrieve_proposals_for(component) ⇒ Object
192 193 194 195 196 197 198 199 |
# File 'app/models/decidim/proposals/proposal.rb', line 192 def self.retrieve_proposals_for(component) Decidim::Proposals::Proposal.where(component:).joins(:coauthorships) .includes(:votes, :endorsements) .where(decidim_coauthorships: { decidim_author_type: "Decidim::UserBaseEntity" }) .not_hidden .published .not_withdrawn end |
.sort_by_translated_title_asc ⇒ Object
430 431 432 433 |
# File 'app/models/decidim/proposals/proposal.rb', line 430 def self.sort_by_translated_title_asc field = Arel::Nodes::InfixOperation.new("->>", arel_table[:title], Arel::Nodes.build_quoted(I18n.locale)) order(Arel::Nodes::InfixOperation.new("", field, Arel.sql("ASC"))) end |
.sort_by_translated_title_desc ⇒ Object
435 436 437 438 |
# File 'app/models/decidim/proposals/proposal.rb', line 435 def self.sort_by_translated_title_desc field = Arel::Nodes::InfixOperation.new("->>", arel_table[:title], Arel::Nodes.build_quoted(I18n.locale)) order(Arel::Nodes::InfixOperation.new("", field, Arel.sql("DESC"))) end |
.user_collection(author) ⇒ Object
Returns a collection scoped by an author. Overrides this method in DownloadYourData to support Coauthorable.
184 185 186 187 188 189 190 |
# File 'app/models/decidim/proposals/proposal.rb', line 184 def self.user_collection() return unless .is_a?(Decidim::User) joins(:coauthorships) .where(decidim_coauthorships: { coauthorable_type: name }) .where("decidim_coauthorships.decidim_author_id = ? AND decidim_coauthorships.decidim_author_type = ? ", .id, .class.base_class.name) end |
.valuator_role_ids_has(value) ⇒ Object
method to filter by assigned valuator role ID
393 394 395 396 397 398 399 400 401 402 403 |
# File 'app/models/decidim/proposals/proposal.rb', line 393 def self.valuator_role_ids_has(value) query = <<-SQL.squish :value = any( (SELECT decidim_proposals_valuation_assignments.valuator_role_id FROM decidim_proposals_valuation_assignments WHERE decidim_proposals_valuation_assignments.decidim_proposal_id = decidim_proposals_proposals.id ) ) SQL where(query, value:) end |
.with_valuation_assigned_to(user, space) ⇒ Object
159 160 161 162 163 164 |
# File 'app/models/decidim/proposals/proposal.rb', line 159 def self.with_valuation_assigned_to(user, space) valuator_roles = space.user_roles(:valuator).where(user:) includes(:valuation_assignments) .where(decidim_proposals_valuation_assignments: { valuator_role_id: valuator_roles }) end |
Instance Method Details
#accepted? ⇒ Boolean
Public: Checks if the organization has accepted a proposal.
Returns Boolean.
286 287 288 |
# File 'app/models/decidim/proposals/proposal.rb', line 286 def accepted? state == "accepted" end |
#allow_resource_permissions? ⇒ Boolean
Public: Overrides the ‘allow_resource_permissions?` Resourceable concern method.
470 471 472 |
# File 'app/models/decidim/proposals/proposal.rb', line 470 def component.settings. end |
#answered? ⇒ Boolean
Public: Checks if the organization has given an answer for the proposal.
Returns Boolean.
272 273 274 |
# File 'app/models/decidim/proposals/proposal.rb', line 272 def answered? answered_at.present? end |
#assign_state(token) ⇒ Object
32 33 34 35 36 |
# File 'app/models/decidim/proposals/proposal.rb', line 32 def assign_state(token) proposal_state = Decidim::Proposals::ProposalState.where(component:, token:).first self.proposal_state = proposal_state end |
#can_accumulate_votes_beyond_threshold ⇒ Object
Public: Can accumulate more votes than maximum for this proposal.
Returns true if can accumulate, false otherwise
358 359 360 |
# File 'app/models/decidim/proposals/proposal.rb', line 358 def can_accumulate_votes_beyond_threshold component.settings.can_accumulate_votes_beyond_threshold end |
#draft? ⇒ Boolean
Public: Whether the proposal is a draft or not.
384 385 386 |
# File 'app/models/decidim/proposals/proposal.rb', line 384 def draft? published_at.nil? end |
#editable_by?(user) ⇒ Boolean
Checks whether the user can edit the given proposal.
user - the user to check for authorship
365 366 367 368 369 |
# File 'app/models/decidim/proposals/proposal.rb', line 365 def editable_by?(user) return true if draft? && created_by?(user) !published_state? && within_edit_time_limit? && !copied_from_other_component? && created_by?(user) end |
#evaluating? ⇒ Boolean
Public: Checks if the organization has marked the proposal as evaluating it.
Returns Boolean.
300 301 302 |
# File 'app/models/decidim/proposals/proposal.rb', line 300 def evaluating? state == "evaluating" end |
#internal_state ⇒ Object
Public: Returns the internal state of the proposal.
Returns Boolean.
256 257 258 259 260 |
# File 'app/models/decidim/proposals/proposal.rb', line 256 def internal_state return amendment.state if emendation? proposal_state&.token || "not_answered" end |
#maximum_votes ⇒ Object
Public: The maximum amount of votes allowed for this proposal.
Returns an Integer with the maximum amount of votes, nil otherwise.
339 340 341 342 343 344 |
# File 'app/models/decidim/proposals/proposal.rb', line 339 def maximum_votes maximum_votes = component.settings.threshold_per_proposal return nil if maximum_votes.zero? maximum_votes end |
#maximum_votes_reached? ⇒ Boolean
Public: The maximum amount of votes allowed for this proposal. 0 means infinite.
Returns true if reached, false otherwise.
349 350 351 352 353 |
# File 'app/models/decidim/proposals/proposal.rb', line 349 def maximum_votes_reached? return false unless maximum_votes votes.count >= maximum_votes end |
#official? ⇒ Boolean
Public: Whether the proposal is official or not.
327 328 329 |
# File 'app/models/decidim/proposals/proposal.rb', line 327 def official? .first.is_a?(Decidim::Organization) end |
#official_meeting? ⇒ Boolean
Public: Whether the proposal is created in a meeting or not.
332 333 334 |
# File 'app/models/decidim/proposals/proposal.rb', line 332 def official_meeting? .first.instance_of?(Decidim::Meetings::Meeting) end |
#presenter ⇒ Object
Returns the presenter for this author, to be used in the views. Required by ResourceRenderer.
311 312 313 |
# File 'app/models/decidim/proposals/proposal.rb', line 311 def presenter Decidim::Proposals::ProposalPresenter.new(self) end |
#process_amendment_state_change! ⇒ Object
483 484 485 486 487 488 489 490 491 |
# File 'app/models/decidim/proposals/proposal.rb', line 483 def process_amendment_state_change! return withdraw! if amendment.withdrawn? return unless %w(accepted rejected evaluating).member?(amendment.state) PaperTrail.request(enabled: false) do assign_state(amendment.state) update!(state_published_at: Time.current) end end |
#published? ⇒ Boolean
Public: Checks if the proposal has been published or not.
Returns Boolean.
236 237 238 |
# File 'app/models/decidim/proposals/proposal.rb', line 236 def published? published_at.present? end |
#published_state? ⇒ Boolean
Public: Checks if the organization has published the state for the proposal.
Returns Boolean.
265 266 267 |
# File 'app/models/decidim/proposals/proposal.rb', line 265 def published_state? emendation? || state_published_at.present? end |
#rejected? ⇒ Boolean
Public: Checks if the organization has rejected a proposal.
Returns Boolean.
293 294 295 |
# File 'app/models/decidim/proposals/proposal.rb', line 293 def rejected? state == "rejected" end |
#reported_attributes ⇒ Object
Public: Overrides the ‘reported_attributes` Reportable concern method.
316 317 318 |
# File 'app/models/decidim/proposals/proposal.rb', line 316 def reported_attributes [:title, :body] end |
#reported_content_url ⇒ Object
Public: Overrides the ‘reported_content_url` Reportable concern method.
305 306 307 |
# File 'app/models/decidim/proposals/proposal.rb', line 305 def reported_content_url ResourceLocatorPresenter.new(self).url end |
#reported_searchable_content_extras ⇒ Object
Public: Overrides the ‘reported_searchable_content_extras` Reportable concern method. Returns authors name or title in case it is a meeting
322 323 324 |
# File 'app/models/decidim/proposals/proposal.rb', line 322 def reported_searchable_content_extras [.map { |p| p.respond_to?(:name) ? p.name : p.title }.join("\n")] end |
#state ⇒ Object
Public: Returns the published state of the proposal.
Returns Boolean.
243 244 245 246 247 248 |
# File 'app/models/decidim/proposals/proposal.rb', line 243 def state return amendment.state if emendation? return nil unless published_state? || withdrawn? proposal_state&.token || "not_answered" end |
#update_votes_count ⇒ Object
Public: Updates the vote count of this proposal.
Returns nothing. rubocop:disable Rails/SkipsModelValidations
221 222 223 |
# File 'app/models/decidim/proposals/proposal.rb', line 221 def update_votes_count update_columns(proposal_votes_count: votes.count) end |
#voted_by?(user) ⇒ Boolean
Public: Check if the user has voted the proposal.
Returns Boolean.
229 230 231 |
# File 'app/models/decidim/proposals/proposal.rb', line 229 def voted_by?(user) ProposalVote.where(proposal: self, author: user).any? end |
#withdraw! ⇒ Object
378 379 380 381 |
# File 'app/models/decidim/proposals/proposal.rb', line 378 def withdraw! self.withdrawn_at = Time.zone.now save end |
#withdrawable_by?(user) ⇒ Boolean
Checks whether the user can withdraw the given proposal.
user - the user to check for withdrawability.
374 375 376 |
# File 'app/models/decidim/proposals/proposal.rb', line 374 def withdrawable_by?(user) user && !withdrawn? && (user) && !copied_from_other_component? end |
#withdrawn? ⇒ Boolean
Public: Checks if the author has withdrawn the proposal.
Returns Boolean.
279 280 281 |
# File 'app/models/decidim/proposals/proposal.rb', line 279 def withdrawn? withdrawn_at.present? end |
#within_edit_time_limit? ⇒ Boolean
Checks whether the proposal is inside the time window to be editable or not once published.
475 476 477 478 479 480 481 |
# File 'app/models/decidim/proposals/proposal.rb', line 475 def within_edit_time_limit? return true if draft? return true if component.settings.proposal_edit_time == "infinite" limit = updated_at + component.settings.proposal_edit_before_minutes.minutes Time.current < limit end |