Class: Decidim::Initiatives::SignatureHandler

Inherits:
Form
  • Object
show all
Includes:
ValidatableAuthorizations
Defined in:
app/services/decidim/initiatives/signature_handler.rb

Overview

This is the base class for signature handlers, all implementations should inherit from it. Each SignatureHandler is a form that will be used to check if the signature is valid or not. When it is valid the initiatives votes defined by the initiative type will be created for the user.

Feel free to use validations to assert fields against a remote API, local database, or whatever.

It also sets two default attributes, ‘user` and `initiative`.

Direct Known Subclasses

LegacySignatureHandler

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.requires_extra_attributes?Boolean

Returns:

  • (Boolean)


172
173
174
# File 'app/services/decidim/initiatives/signature_handler.rb', line 172

def self.requires_extra_attributes?
  new.form_attributes.present?
end

Instance Method Details

#already_voted?Boolean

Returns:

  • (Boolean)


176
177
178
# File 'app/services/decidim/initiatives/signature_handler.rb', line 176

def already_voted?
  Decidim::InitiativesVote.exists?(author: user, initiative:)
end

#authorization_handlerObject



128
129
130
131
132
# File 'app/services/decidim/initiatives/signature_handler.rb', line 128

def authorization_handler
  return if authorization_handler_form_class.blank?

  @authorization_handler ||= authorization_handler_form_class.from_params(authorization_handler_params)
end

#authorization_handler_paramsObject

Params to be sent to the authorization handler. By default consists on the metadata hash including the signer user



116
117
118
119
120
# File 'app/services/decidim/initiatives/signature_handler.rb', line 116

def authorization_handler_params
  params = .merge(user:)
  params = params.merge(tos_agreement:) if ephemeral_tos_pending?
  params
end

#authorized_scopesObject

Public: Builds the list of scopes where the user is authorized to vote in. This is used when the initiative allows also voting on child scopes, not only the main scope.

Instead of just listing the children of the main scope, we just want to select the ones that have been added to the InitiativeType with its voting settings.



59
60
61
62
63
64
65
# File 'app/services/decidim/initiatives/signature_handler.rb', line 59

def authorized_scopes
  initiative.votable_initiative_type_scopes.select do |initiative_type_scope|
    initiative_type_scope.global_scope? ||
      initiative_type_scope.scope == user_signature_scope ||
      initiative_type_scope.scope.ancestor_of?(user_signature_scope)
  end.flat_map(&:scope)
end

#encrypted_metadataObject



47
48
49
50
51
# File 'app/services/decidim/initiatives/signature_handler.rb', line 47

def 
  return if .blank?

  @encrypted_metadata ||= encryptor.encrypt()
end

#form_attributesObject

The attributes of the handler that should be exposed as form input when rendering the handler in a form.

Returns an Array of Strings.



154
155
156
# File 'app/services/decidim/initiatives/signature_handler.rb', line 154

def form_attributes
  attributes.except("id", "user", "initiative", "tos_agreement", "transfer_status").keys
end

#hash_idObject



138
139
140
141
142
143
144
145
146
147
148
# File 'app/services/decidim/initiatives/signature_handler.rb', line 138

def hash_id
  return unless initiative && (unique_id || user)

  @hash_id ||= Digest::SHA256.hexdigest(
    [
      initiative.id,
      unique_id || user.id,
      Rails.application.secret_key_base
    ].compact.join("-")
  )
end

#metadataObject

Any data that the developer would like to inject to the ‘metadata` field of a vote when it is created. Can be useful if some of the params the user sent with the signature form want to be persisted for future use.

Returns a Hash.



110
111
112
# File 'app/services/decidim/initiatives/signature_handler.rb', line 110

def 
  {}
end

#signature_scope_candidatesObject

Public: Builds a list of Decidim::Scopes where the user could have a valid authorization.

If the initiative is set with a global scope (meaning the scope is nil), all the scopes in the organization are valid.

Returns an array of Decidim::Scopes.



95
96
97
98
99
100
101
102
103
# File 'app/services/decidim/initiatives/signature_handler.rb', line 95

def signature_scope_candidates
  signature_scope_candidates = [initiative.scope]
  signature_scope_candidates += if initiative.scope.present?
                                  initiative.scope.descendants
                                else
                                  initiative.organization.scopes
                                end
  signature_scope_candidates.uniq
end

#signature_scope_idObject

The signature_scope_id can be defined in the signature workflow to be used by the author scope feature



124
125
126
# File 'app/services/decidim/initiatives/signature_handler.rb', line 124

def signature_scope_id
  scope.id
end

#signature_workflow_nameObject



134
135
136
# File 'app/services/decidim/initiatives/signature_handler.rb', line 134

def signature_workflow_name
  @signature_workflow_name ||= initiative&.type&.document_number_authorization_handler
end

#to_partial_pathObject

The String partial path so Rails can render the handler as a form. This is useful if you want to have a custom view to render the form instead of the default view.

Example:

A handler named Decidim::CensusHandler would look for its partial in:
decidim/census/form

Returns a String.



168
169
170
# File 'app/services/decidim/initiatives/signature_handler.rb', line 168

def to_partial_path
  "decidim/initiatives/initiative_signatures/#{signature_workflow_name.sub(/_handler$/, "")}/form"
end

#unique_idObject

A unique ID to be implemented by the signature handler that ensures no duplicates are created.



43
44
45
# File 'app/services/decidim/initiatives/signature_handler.rb', line 43

def unique_id
  nil
end

#user_signature_scopeObject

Public: Finds the scope the user has an authorization for, this way the user can vote on that scope and its parents.

This is can be used to allow users that are authorized with a children scope to sign an initiative with a parent scope.

As an example: A city (global scope) has many districts (scopes with parent nil), and each district has different neighbourhoods (with its parent as a district). If we setup the authorization handler to match a neighbourhood, the same authorization can be used to participate in district, neighbourhoods or city initiatives.

Returns a Decidim::Scope.



80
81
82
83
84
85
86
# File 'app/services/decidim/initiatives/signature_handler.rb', line 80

def user_signature_scope
  return if signature_scope_id.blank?

  @user_signature_scope ||= signature_scope_candidates.find do |scope_candidate|
    scope_candidate&.id == signature_scope_id
  end
end