Merge branch 'master' into legislation-module-stable

This commit is contained in:
Amaia Castro
2016-12-27 16:43:43 +01:00
40 changed files with 779 additions and 22 deletions

View File

@@ -0,0 +1,32 @@
class Admin::SignatureSheetsController < Admin::BaseController
def index
@signature_sheets = SignatureSheet.all
end
def new
@signature_sheet = SignatureSheet.new
end
def create
@signature_sheet = SignatureSheet.new(signature_sheet_params)
@signature_sheet.author = current_user
if @signature_sheet.save
@signature_sheet.delay.verify_signatures
redirect_to [:admin, @signature_sheet], notice: I18n.t('flash.actions.create.signature_sheet')
else
render :new
end
end
def show
@signature_sheet = SignatureSheet.find(params[:id])
end
private
def signature_sheet_params
params.require(:signature_sheet).permit(:signable_type, :signable_id, :document_numbers)
end
end

View File

@@ -0,0 +1,8 @@
module SignatureSheetsHelper
def signable_options
[[t("activerecord.models.proposal", count: 1), Proposal],
[t("activerecord.models.spending_proposal", count: 1), SpendingProposal]]
end
end

View File

@@ -1,5 +1,5 @@
class ApplicationMailer < ActionMailer::Base class ApplicationMailer < ActionMailer::Base
helper :settings helper :settings
default from: "Consul <no-reply@consul.es>" default from: "#{Setting['mailer_from_name']} <#{Setting['mailer_from_address']}>"
layout 'mailer' layout 'mailer'
end end

85
app/models/signature.rb Normal file
View File

@@ -0,0 +1,85 @@
class Signature < ActiveRecord::Base
belongs_to :signature_sheet
belongs_to :user
validates :document_number, presence: true
validates :signature_sheet, presence: true
scope :verified, -> { where(verified: true) }
scope :unverified, -> { where(verified: false) }
delegate :signable, to: :signature_sheet
def verified?
user_exists? || in_census?
end
def verify
if verified?
assign_vote
mark_as_verified
end
end
def assign_vote
if user_exists?
assign_vote_to_user
else
create_user
assign_vote_to_user
end
end
def assign_vote_to_user
set_user
signable.register_vote(user, "yes")
assign_signature_to_vote
end
def assign_signature_to_vote
vote = Vote.where(votable: signable, voter: user).first
vote.update(signature: self)
end
def user_exists?
User.where(document_number: document_number).any?
end
def create_user
user_params = {
document_number: document_number,
created_from_signature: true,
verified_at: Time.now,
erased_at: Time.now,
password: random_password,
terms_of_service: '1',
email: nil
}
User.create!(user_params)
end
def random_password
(0...20).map { ('a'..'z').to_a[rand(26)] }.join
end
def in_census?
response = document_types.detect do |document_type|
CensusApi.new.call(document_type, document_number).valid?
end
response.present?
end
def set_user
user = User.where(document_number: document_number).first
update(user: user)
end
def mark_as_verified
update(verified: true)
end
def document_types
%w(1 2 3 4)
end
end

View File

@@ -0,0 +1,38 @@
class SignatureSheet < ActiveRecord::Base
belongs_to :signable, polymorphic: true
belongs_to :author, class_name: 'User', foreign_key: 'author_id'
VALID_SIGNABLES = %w( Proposal SpendingProposal )
has_many :signatures
validates :author, presence: true
validates :signable_type, inclusion: {in: VALID_SIGNABLES}
validates :document_numbers, presence: true
validates :signable, presence: true
validate :signable_found
def name
"#{signable_name} #{signable_id}"
end
def signable_name
I18n.t("activerecord.models.#{signable_type.underscore}", count: 1)
end
def verify_signatures
parsed_document_numbers.each do |document_number|
signature = signatures.create(document_number: document_number)
signature.verify
end
update(processed: true)
end
def parsed_document_numbers
document_numbers.split(/\W+/)
end
def signable_found
errors.add(:signable_id, :not_found) if errors.messages[:signable].present?
end
end

View File

@@ -35,6 +35,14 @@
</li> </li>
<% end %> <% end %>
<% if feature?(:signature_sheets) %>
<li <%= "class=active" if controller_name == "signature_sheets" %>>
<%= link_to admin_signature_sheets_path do %>
<span class="icon-budget"></span><%= t("admin.menu.signature_sheets") %>
<% end %>
</li>
<% end %>
<% if feature?(:legislation) %> <% if feature?(:legislation) %>
<li <%= "class=active" if controller_name == "processes" %>> <li <%= "class=active" if controller_name == "processes" %>>
<%= link_to admin_legislation_processes_path do %> <%= link_to admin_legislation_processes_path do %>

View File

@@ -0,0 +1,31 @@
<h2 class="inline-block"><%= t("admin.signature_sheets.index.title") %></h2>
<%= link_to t("admin.signature_sheets.index.new"), new_admin_signature_sheet_path,
class: "button success float-right" %>
<% if @signature_sheets.any? %>
<table>
<tr>
<th><%= t("admin.signature_sheets.name") %></th>
<th><%= t("admin.signature_sheets.author") %></th>
<th><%= t("admin.signature_sheets.created_at") %></th>
</tr>
<% @signature_sheets.each do |signature_sheet| %>
<tr id="<%= dom_id(signature_sheet) %>" class="signature_sheet">
<td>
<%= link_to signature_sheet.name, [:admin, signature_sheet] %>
</td>
<td>
<%= signature_sheet.author.name %>
</td>
<td>
<%= l(signature_sheet.created_at, format: :short) %>
</td>
</tr>
<% end %>
</table>
<% else %>
<div class="callout primary margin-top">
<%= t("admin.signature_sheets.no_signature_sheets") %>
</div>
<% end %>

View File

@@ -0,0 +1,22 @@
<%= render 'shared/back_link' %>
<h2><%= t("admin.signature_sheets.new.title") %></h2>
<%= form_for [:admin, @signature_sheet] do |f| %>
<%= render 'shared/errors',
resource: @signature_sheet %>
<div class="small-12 medium-6 large-4">
<%= f.select :signable_type, signable_options %>
</div>
<div class="small-12 medium-6 large-4">
<%= f.text_field :signable_id %>
</div>
<%= f.label :document_numbers %>
<p class="note"><%= t("admin.signature_sheets.new.document_numbers_note") %></p>
<%= f.text_area :document_numbers, rows: "6", label: false %>
<%= f.submit(class: "button", value: t("admin.signature_sheets.new.submit")) %>
<% end %>

View File

@@ -0,0 +1,39 @@
<h2 class="inline-block"><%= @signature_sheet.name %></h2>
<div class="callout secondary float-right">
<%= t("admin.signature_sheets.show.created_at") %>
<strong><%= l(@signature_sheet.created_at, format: :short) %></strong>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<%= t("admin.signature_sheets.show.author") %>
<strong><%= @signature_sheet.author.name %></strong>
</div>
<div class="callout margin-top">
<p><strong><%= t("admin.signature_sheets.show.documents") %></strong></p>
<%= simple_format @signature_sheet.document_numbers %>
</div>
<div id="verified_signatures" class="callout success">
<strong>
<%= t("admin.signature_sheets.show.verified",
count: @signature_sheet.signatures.verified.count ) %>
</strong>
</div>
<div id="unverified_signatures" class="callout alert">
<p>
<strong>
<%= t("admin.signature_sheets.show.unverified",
count: @signature_sheet.signatures.unverified.count ) %>
<%= t("admin.signature_sheets.show.unverified_error") %>
</strong>
</p>
<%= @signature_sheet.signatures.unverified.map(&:document_number).join(", ") %>
</div>
<% unless @signature_sheet.processed? %>
<div class="callout primary margin-top">
<%= t("admin.signature_sheets.show.loading") %>
</div>
<% end %>

View File

@@ -1,6 +1,5 @@
<%= form_for(@debate) do |f| %> <%= form_for(@debate) do |f| %>
<%= render 'shared/errors', resource: @debate %> <%= render 'shared/errors', resource: @debate %>
<div class="row"> <div class="row">

View File

@@ -95,6 +95,8 @@ search:
# - '{devise,simple_form}.*' # - '{devise,simple_form}.*'
ignore_missing: ignore_missing:
- 'unauthorized.*' - 'unauthorized.*'
- 'activerecord.models.proposal'
- 'activerecord.models.spending_proposal'
- 'activerecord.errors.models.proposal_notification.*' - 'activerecord.errors.models.proposal_notification.*'
- 'activerecord.errors.models.direct_message.*' - 'activerecord.errors.models.direct_message.*'
- 'errors.messages.blank' - 'errors.messages.blank'

View File

@@ -12,7 +12,11 @@ Devise.setup do |config|
# Configure the e-mail address which will be shown in Devise::Mailer, # Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class # note that it will be overwritten if you use your own mailer class
# with default "from" parameter. # with default "from" parameter.
config.mailer_sender = 'noreply@consul.es' if Rails.env.test?
config.mailer_sender = "noreply@example.org"
else
config.mailer_sender = "#{Setting['mailer_from_name']} <#{Setting['mailer_from_address']}>"
end
# Configure the class responsible to send e-mails. # Configure the class responsible to send e-mails.
config.mailer = 'DeviseMailer' config.mailer = 'DeviseMailer'

View File

@@ -1,4 +1,6 @@
ActsAsVotable::Vote.class_eval do ActsAsVotable::Vote.class_eval do
belongs_to :signature
def self.for_debates(debates) def self.for_debates(debates)
where(votable_type: 'Debate', votable_id: debates) where(votable_type: 'Debate', votable_id: debates)
end end
@@ -14,4 +16,5 @@ ActsAsVotable::Vote.class_eval do
def value def value
vote_flag vote_flag
end end
end end

View File

@@ -75,6 +75,10 @@ en:
external_url: "Link to additional documentation" external_url: "Link to additional documentation"
geozone_id: "Scope of operation" geozone_id: "Scope of operation"
title: "Title" title: "Title"
signature_sheet:
signable_type: "Signable type"
signable_id: "Signable ID"
document_numbers: "Documents numbers"
legislation/process: legislation/process:
title: Process Title title: Process Title
description: Description description: Description
@@ -117,3 +121,8 @@ en:
attributes: attributes:
minimum_interval: minimum_interval:
invalid: "You have to wait a minium of %{interval} days between notifications" invalid: "You have to wait a minium of %{interval} days between notifications"
signature:
attributes:
document_number:
not_in_census: 'Not verified by Census'
already_voted: 'Already voted this proposal'

View File

@@ -75,6 +75,10 @@ es:
external_url: "Enlace a documentación adicional" external_url: "Enlace a documentación adicional"
geozone_id: "Ámbito de actuación" geozone_id: "Ámbito de actuación"
title: "Título" title: "Título"
signature_sheet:
signable_type: "Tipo de hoja de firmas"
signable_id: "ID Propuesta ciudadana/Propuesta inversión"
document_numbers: "Números de documentos"
legislation/process: legislation/process:
title: Título del proceso title: Título del proceso
description: En qué consiste description: En qué consiste
@@ -117,3 +121,8 @@ es:
attributes: attributes:
minimum_interval: minimum_interval:
invalid: "Debes esperar un mínimo de %{interval} días entre notificaciones" invalid: "Debes esperar un mínimo de %{interval} días entre notificaciones"
signature:
attributes:
document_number:
not_in_census: 'No verificado por Padrón'
already_voted: 'Ya ha votado esta propuesta'

View File

@@ -187,6 +187,7 @@ en:
settings: Configuration settings settings: Configuration settings
spending_proposals: Spending proposals spending_proposals: Spending proposals
stats: Statistics stats: Statistics
signature_sheets: Signature Sheets
legislation: Collaborative Legislation legislation: Collaborative Legislation
moderators: moderators:
index: index:
@@ -372,6 +373,30 @@ en:
delete: delete:
success: Geozone successfully deleted success: Geozone successfully deleted
error: This geozone can't be deleted since there are elements attached to it error: This geozone can't be deleted since there are elements attached to it
signature_sheets:
author: Author
created_at: Creation date
name: Name
no_signature_sheets: "There are not signature_sheets"
index:
title: Signature sheets
new: New signature sheets
new:
title: New signature sheets
document_numbers_note: "Write the numbers separated by commas (,)"
submit: Create signature sheet
show:
created_at: Created
author: Author
documents: Documents
verified:
one: "There is %{count} valid signature"
other: "There are %{count} valid signatures"
unverified:
one: "There is %{count} invalid signature"
other: "There are %{count} invalid signatures"
unverified_error: (Not verified by Census)
loading: "There are still signatures that are being verified by the Census, please refresh the page in a few moments"
stats: stats:
show: show:
stats_title: Stats stats_title: Stats

View File

@@ -185,6 +185,7 @@ es:
settings: Configuración global settings: Configuración global
spending_proposals: Propuestas de inversión spending_proposals: Propuestas de inversión
stats: Estadísticas stats: Estadísticas
signature_sheets: Hojas de firmas
legislation: Legislación colaborativa legislation: Legislación colaborativa
moderators: moderators:
index: index:
@@ -370,6 +371,30 @@ es:
delete: delete:
success: Distrito borrado correctamente success: Distrito borrado correctamente
error: No se puede borrar el distrito porque ya tiene elementos asociados error: No se puede borrar el distrito porque ya tiene elementos asociados
signature_sheets:
author: Autor
created_at: Fecha de creación
name: Nombre
no_signature_sheets: "No existen hojas de firmas"
index:
title: Hojas de firmas
new: Nueva hoja de firmas
new:
title: Nueva hoja de firmas
document_numbers_note: "Introduce los números separados por comas (,)"
submit: Crear hoja de firmas
show:
created_at: Creado
author: Autor
documents: Documentos
verified:
one: "Hay %{count} firma válida"
other: "Hay %{count} firmas válidas"
unverified:
one: "Hay %{count} firma inválida"
other: "Hay %{count} firmas inválidas"
unverified_error: (No verificadas por el Padrón)
loading: "Aún hay firmas que se están verificando por el Padrón, por favor refresca la página en unos instantes"
stats: stats:
show: show:
stats_title: Estadísticas stats_title: Estadísticas

View File

@@ -154,6 +154,7 @@ en:
spending_proposal: Spending proposal spending_proposal: Spending proposal
user: Account user: Account
verification/sms: phone verification/sms: phone
signature_sheet: Signature sheet
geozones: geozones:
none: All city none: All city
all: All scopes all: All scopes

View File

@@ -154,6 +154,7 @@ es:
spending_proposal: la propuesta de gasto spending_proposal: la propuesta de gasto
user: la cuenta user: la cuenta
verification/sms: el teléfono verification/sms: el teléfono
signature_sheet: la hoja de firmas
geozones: geozones:
none: Toda la ciudad none: Toda la ciudad
all: Todos los ámbitos all: Todos los ámbitos

View File

@@ -9,7 +9,7 @@ en:
proposal: "Proposal created successfully." proposal: "Proposal created successfully."
proposal_notification: "Your message has been sent correctly." proposal_notification: "Your message has been sent correctly."
spending_proposal: "Spending proposal created successfully. You can access it from %{activity}" spending_proposal: "Spending proposal created successfully. You can access it from %{activity}"
signature_sheet: "Signature sheet created successfully"
save_changes: save_changes:
notice: Changes saved notice: Changes saved
update: update:

View File

@@ -9,6 +9,7 @@ es:
proposal: "Propuesta creada correctamente." proposal: "Propuesta creada correctamente."
proposal_notification: "Tu message ha sido enviado correctamente." proposal_notification: "Tu message ha sido enviado correctamente."
spending_proposal: "Propuesta de inversión creada correctamente. Puedes acceder a ella desde %{activity}" spending_proposal: "Propuesta de inversión creada correctamente. Puedes acceder a ella desde %{activity}"
signature_sheet: "Hoja de firmas creada correctamente"
save_changes: save_changes:
notice: Cambios guardados notice: Cambios guardados
update: update:

View File

@@ -27,7 +27,10 @@ en:
facebook_login: Facebook login facebook_login: Facebook login
google_login: Google login google_login: Google login
debates: Debates debates: Debates
signature_sheets: Signature sheets
spending_proposals: Investment projects spending_proposals: Investment projects
spending_proposal_features: spending_proposal_features:
voting_allowed: Voting on investment projects voting_allowed: Voting on investment projects
legislation: Legislation legislation: Legislation
mailer_from_name: Origin email name
mailer_from_address: Origin email address

View File

@@ -27,7 +27,10 @@ es:
facebook_login: Registro con Facebook facebook_login: Registro con Facebook
google_login: Registro con Google google_login: Registro con Google
debates: Debates debates: Debates
signature_sheets: Hojas de firmas
spending_proposals: Propuestas de inversión spending_proposals: Propuestas de inversión
spending_proposal_features: spending_proposal_features:
voting_allowed: Votaciones sobre propuestas de inversión. voting_allowed: Votaciones sobre propuestas de inversión.
legislation: Legislación legislation: Legislación
mailer_from_name: Nombre email remitente
mailer_from_address: Dirección email remitente

View File

@@ -169,6 +169,8 @@ Rails.application.routes.draw do
get :summary, on: :collection get :summary, on: :collection
end end
resources :signature_sheets, only: [:index, :new, :create, :show]
resources :banners, only: [:index, :new, :create, :edit, :update, :destroy] do resources :banners, only: [:index, :new, :create, :edit, :update, :destroy] do
collection { get :search} collection { get :search}
end end

View File

@@ -30,9 +30,13 @@ Setting.create(key: 'feature.spending_proposal_features.voting_allowed', value:
Setting.create(key: 'feature.twitter_login', value: "true") Setting.create(key: 'feature.twitter_login', value: "true")
Setting.create(key: 'feature.facebook_login', value: "true") Setting.create(key: 'feature.facebook_login', value: "true")
Setting.create(key: 'feature.google_login', value: "true") Setting.create(key: 'feature.google_login', value: "true")
Setting.create(key: 'feature.signature_sheets', value: "true")
Setting.create(key: 'feature.legislation', value: "true") Setting.create(key: 'feature.legislation', value: "true")
Setting.create(key: 'per_page_code', value: "") Setting.create(key: 'per_page_code', value: "")
Setting.create(key: 'comments_body_max_length', value: '1000') Setting.create(key: 'comments_body_max_length', value: '1000')
Setting.create(key: 'mailer_from_name', value: 'Consul')
Setting.create(key: 'mailer_from_address', value: 'noreply@consul.dev')
puts "Creating Geozones" puts "Creating Geozones"
('A'..'Z').each { |i| Geozone.create(name: "District #{i}", external_code: i.ord, census_code: i.ord) } ('A'..'Z').each { |i| Geozone.create(name: "District #{i}", external_code: i.ord, census_code: i.ord) }

View File

@@ -0,0 +1,11 @@
class CreateSignatureSheets < ActiveRecord::Migration
def change
create_table :signature_sheets do |t|
t.references :signable, polymorphic: true
t.text :document_numbers
t.boolean :processed, default: false
t.references :author
t.timestamps
end
end
end

View File

@@ -0,0 +1,11 @@
class CreateSignatures < ActiveRecord::Migration
def change
create_table :signatures do |t|
t.references :signature_sheet
t.references :user
t.string :document_number
t.boolean :verified, default: false
t.timestamps
end
end
end

View File

@@ -0,0 +1,5 @@
class AddSigntureIdToVotes < ActiveRecord::Migration
def change
add_reference :votes, :signature, index: true
end
end

View File

@@ -0,0 +1,5 @@
class AddCreatedFromSignatureToUsers < ActiveRecord::Migration
def change
add_column :users, :created_from_signature, :boolean, default: false
end
end

View File

@@ -123,10 +123,10 @@ ActiveRecord::Schema.define(version: 20161222180927) do
t.string "visit_id" t.string "visit_id"
t.datetime "hidden_at" t.datetime "hidden_at"
t.integer "flags_count", default: 0 t.integer "flags_count", default: 0
t.datetime "ignored_flag_at"
t.integer "cached_votes_total", default: 0 t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0 t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0 t.integer "cached_votes_down", default: 0
t.datetime "ignored_flag_at"
t.integer "comments_count", default: 0 t.integer "comments_count", default: 0
t.datetime "confirmed_hide_at" t.datetime "confirmed_hide_at"
t.integer "cached_anonymous_votes_total", default: 0 t.integer "cached_anonymous_votes_total", default: 0
@@ -145,7 +145,6 @@ ActiveRecord::Schema.define(version: 20161222180927) do
add_index "debates", ["cached_votes_total"], name: "index_debates_on_cached_votes_total", using: :btree add_index "debates", ["cached_votes_total"], name: "index_debates_on_cached_votes_total", using: :btree
add_index "debates", ["cached_votes_up"], name: "index_debates_on_cached_votes_up", using: :btree add_index "debates", ["cached_votes_up"], name: "index_debates_on_cached_votes_up", using: :btree
add_index "debates", ["confidence_score"], name: "index_debates_on_confidence_score", using: :btree add_index "debates", ["confidence_score"], name: "index_debates_on_confidence_score", using: :btree
add_index "debates", ["description"], name: "index_debates_on_description", using: :btree
add_index "debates", ["geozone_id"], name: "index_debates_on_geozone_id", using: :btree add_index "debates", ["geozone_id"], name: "index_debates_on_geozone_id", using: :btree
add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree
add_index "debates", ["hot_score"], name: "index_debates_on_hot_score", using: :btree add_index "debates", ["hot_score"], name: "index_debates_on_hot_score", using: :btree
@@ -382,7 +381,6 @@ ActiveRecord::Schema.define(version: 20161222180927) do
add_index "proposals", ["author_id"], name: "index_proposals_on_author_id", using: :btree add_index "proposals", ["author_id"], name: "index_proposals_on_author_id", using: :btree
add_index "proposals", ["cached_votes_up"], name: "index_proposals_on_cached_votes_up", using: :btree add_index "proposals", ["cached_votes_up"], name: "index_proposals_on_cached_votes_up", using: :btree
add_index "proposals", ["confidence_score"], name: "index_proposals_on_confidence_score", using: :btree add_index "proposals", ["confidence_score"], name: "index_proposals_on_confidence_score", using: :btree
add_index "proposals", ["description"], name: "index_proposals_on_description", using: :btree
add_index "proposals", ["geozone_id"], name: "index_proposals_on_geozone_id", using: :btree add_index "proposals", ["geozone_id"], name: "index_proposals_on_geozone_id", using: :btree
add_index "proposals", ["hidden_at"], name: "index_proposals_on_hidden_at", using: :btree add_index "proposals", ["hidden_at"], name: "index_proposals_on_hidden_at", using: :btree
add_index "proposals", ["hot_score"], name: "index_proposals_on_hot_score", using: :btree add_index "proposals", ["hot_score"], name: "index_proposals_on_hot_score", using: :btree
@@ -398,6 +396,25 @@ ActiveRecord::Schema.define(version: 20161222180927) do
add_index "settings", ["key"], name: "index_settings_on_key", using: :btree add_index "settings", ["key"], name: "index_settings_on_key", using: :btree
create_table "signature_sheets", force: :cascade do |t|
t.integer "signable_id"
t.string "signable_type"
t.text "document_numbers"
t.boolean "processed", default: false
t.integer "author_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "signatures", force: :cascade do |t|
t.integer "signature_sheet_id"
t.integer "user_id"
t.string "document_number"
t.boolean "verified", default: false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "spending_proposals", force: :cascade do |t| create_table "spending_proposals", force: :cascade do |t|
t.string "title" t.string "title"
t.text "description" t.text "description"
@@ -536,7 +553,8 @@ ActiveRecord::Schema.define(version: 20161222180927) do
t.boolean "email_digest", default: true t.boolean "email_digest", default: true
t.boolean "email_on_direct_message", default: true t.boolean "email_on_direct_message", default: true
t.boolean "official_position_badge", default: false t.boolean "official_position_badge", default: false
t.datetime "password_changed_at", default: '2016-11-02 13:51:14', null: false t.datetime "password_changed_at", default: '2016-12-21 17:55:08', null: false
t.boolean "created_from_signature", default: false
end end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
@@ -616,8 +634,10 @@ ActiveRecord::Schema.define(version: 20161222180927) do
t.integer "vote_weight" t.integer "vote_weight"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.integer "signature_id"
end end
add_index "votes", ["signature_id"], name: "index_votes_on_signature_id", using: :btree
add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope", using: :btree add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope", using: :btree
add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope", using: :btree add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope", using: :btree

View File

@@ -64,6 +64,7 @@ Setting['feature.twitter_login'] = true
Setting['feature.facebook_login'] = true Setting['feature.facebook_login'] = true
Setting['feature.google_login'] = true Setting['feature.google_login'] = true
Setting['feature.public_stats'] = true Setting['feature.public_stats'] = true
Setting['feature.signature_sheets'] = true
Setting['feature.legislation'] = true Setting['feature.legislation'] = true
# Spending proposals feature flags # Spending proposals feature flags
@@ -82,3 +83,7 @@ Setting['banner-img.banner-img-three'] = "Banner image 3"
# Proposal notifications # Proposal notifications
Setting['proposal_notification_minimum_interval_in_days'] = 3 Setting['proposal_notification_minimum_interval_in_days'] = 3
Setting['direct_message_max_per_day'] = 3 Setting['direct_message_max_per_day'] = 3
# Email settings
Setting['mailer_from_name'] = 'Consul'
Setting['mailer_from_address'] = 'noreply@consul.dev'

View File

@@ -74,7 +74,7 @@ class CensusApi
if end_point_available? if end_point_available?
client.call(:get_habita_datos, message: request(document_type, document_number)).body client.call(:get_habita_datos, message: request(document_type, document_number)).body
else else
stubbed_response_body stubbed_response(document_type, document_number)
end end
end end
@@ -97,8 +97,20 @@ class CensusApi
Rails.env.staging? || Rails.env.preproduction? || Rails.env.production? Rails.env.staging? || Rails.env.preproduction? || Rails.env.production?
end end
def stubbed_response_body def stubbed_response(document_type, document_number)
{get_habita_datos_response: {get_habita_datos_return: {hay_errores: false, datos_habitante: { item: {fecha_nacimiento_string: "31-12-1980", identificador_documento: "12345678Z", descripcion_sexo: "Varón" }}, datos_vivienda: {item: {codigo_postal: "28013", codigo_distrito: "01"}}}}} if document_number == "12345678Z" && document_type == "1"
stubbed_valid_response
else
stubbed_invalid_response
end
end
def stubbed_valid_response
{get_habita_datos_response: {get_habita_datos_return: {datos_habitante: { item: {fecha_nacimiento_string: "31-12-1980", identificador_documento: "12345678Z", descripcion_sexo: "Varón", nombre: "José", apellido1: "García" }}, datos_vivienda: {item: {codigo_postal: "28013", codigo_distrito: "01"}}}}}
end
def stubbed_invalid_response
{get_habita_datos_response: {get_habita_datos_return: {datos_habitante: {}, datos_vivienda: {}}}}
end end
def is_dni?(document_type) def is_dni?(document_type)

View File

@@ -344,6 +344,17 @@ FactoryGirl.define do
association :receiver, factory: :user association :receiver, factory: :user
end end
factory :signature_sheet do
association :signable, factory: :proposal
association :author, factory: :user
document_numbers "123A, 456B, 789C"
end
factory :signature do
signature_sheet
sequence(:document_number) { |n| "#{n}A" }
end
factory :legislation_process, class: 'Legislation::Process' do factory :legislation_process, class: 'Legislation::Process' do
title "A collaborative legislation process" title "A collaborative legislation process"
description "Description of the process" description "Description of the process"

View File

@@ -0,0 +1,71 @@
require 'rails_helper'
feature 'Signature sheets' do
background do
admin = create(:administrator)
login_as(admin.user)
end
scenario "Index" do
3.times { create(:signature_sheet) }
visit admin_signature_sheets_path
expect(page).to have_css(".signature_sheet", count: 3)
SignatureSheet.all.each do |signature_sheet|
expect(page).to have_content signature_sheet.name
end
end
scenario 'Create' do
proposal = create(:proposal)
visit new_admin_signature_sheet_path
select "Citizen proposal", from: "signature_sheet_signable_type"
fill_in "signature_sheet_signable_id", with: proposal.id
fill_in "signature_sheet_document_numbers", with: "12345678Z, 99999999Z"
click_button "Create signature sheet"
expect(page).to have_content "Signature sheet created successfully"
visit proposal_path(proposal)
expect(page).to have_content "1 support"
end
scenario 'Errors on create' do
visit new_admin_signature_sheet_path
click_button "Create signature sheet"
expect(page).to have_content error_message
end
scenario 'Show' do
proposal = create(:proposal)
user = Administrator.first.user
signature_sheet = create(:signature_sheet,
signable: proposal,
document_numbers: "12345678Z, 123A, 123B",
author: user)
signature_sheet.verify_signatures
visit admin_signature_sheet_path(signature_sheet)
expect(page).to have_content "Citizen proposal #{proposal.id}"
expect(page).to have_content "12345678Z, 123A, 123B"
expect(page).to have_content signature_sheet.created_at.strftime("%d %b %H:%M")
expect(page).to have_content user.name
within("#verified_signatures") do
expect(page).to have_content 1
end
within("#unverified_signatures") do
expect(page).to have_content 2
end
end
end

View File

@@ -47,7 +47,7 @@ feature 'DocumentVerifications' do
scenario 'Verifying a user which does exists in the census but not in the db redirects allows sending an email' do scenario 'Verifying a user which does exists in the census but not in the db redirects allows sending an email' do
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '1234' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
expect(page).to have_content "Please introduce the email used on the account" expect(page).to have_content "Please introduce the email used on the account"
@@ -66,7 +66,7 @@ feature 'DocumentVerifications' do
expect_any_instance_of(Verification::Management::Document).to receive(:under_sixteen?).and_return(true) expect_any_instance_of(Verification::Management::Document).to receive(:under_sixteen?).and_return(true)
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '1234' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
expect(page).to have_content "You must be over 16 to verify your account." expect(page).to have_content "You must be over 16 to verify your account."

View File

@@ -8,7 +8,7 @@ feature 'EmailVerifications' do
user = create(:user) user = create(:user)
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '1234' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
expect(page).to have_content "Please introduce the email used on the account" expect(page).to have_content "Please introduce the email used on the account"
@@ -30,7 +30,7 @@ feature 'EmailVerifications' do
expect(page).to_not have_link "Verify my account" expect(page).to_not have_link "Verify my account"
expect(page).to have_content "Account verified" expect(page).to have_content "Account verified"
expect(user.reload.document_number).to eq('1234') expect(user.reload.document_number).to eq('12345678Z')
expect(user).to be_level_three_verified expect(user).to be_level_three_verified
end end

View File

@@ -57,7 +57,7 @@ feature 'Managed User' do
user = create(:user) user = create(:user)
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '1234' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
within(".account-info") do within(".account-info") do
@@ -66,7 +66,7 @@ feature 'Managed User' do
expect(page).not_to have_content "Email" expect(page).not_to have_content "Email"
expect(page).to have_content "Document type" expect(page).to have_content "Document type"
expect(page).to have_content "Document number" expect(page).to have_content "Document number"
expect(page).to have_content "1234" expect(page).to have_content "12345678Z"
end end
expect(page).to have_content "Please introduce the email used on the account" expect(page).to have_content "Please introduce the email used on the account"
@@ -88,7 +88,7 @@ feature 'Managed User' do
login_as_manager login_as_manager
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '1234' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
expect(page).to have_content "Please introduce the email used on the account" expect(page).to have_content "Please introduce the email used on the account"

View File

@@ -9,7 +9,7 @@ feature 'Users' do
scenario 'Create a level 3 user from scratch' do scenario 'Create a level 3 user from scratch' do
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '1234' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
expect(page).to have_content "Please introduce the email used on the account" expect(page).to have_content "Please introduce the email used on the account"
@@ -45,10 +45,10 @@ feature 'Users' do
end end
scenario 'Delete a level 2 user account from document verification page', :js do scenario 'Delete a level 2 user account from document verification page', :js do
level_2_user = create(:user, :level_two, document_number: 13579) level_2_user = create(:user, :level_two, document_number: "12345678Z")
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '13579' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
expect(page).to_not have_content "This user account is already verified." expect(page).to_not have_content "This user account is already verified."
@@ -62,7 +62,7 @@ feature 'Users' do
expect(level_2_user.reload.erase_reason).to eq "Deleted by manager: manager_user_#{Manager.last.user_id}" expect(level_2_user.reload.erase_reason).to eq "Deleted by manager: manager_user_#{Manager.last.user_id}"
visit management_document_verifications_path visit management_document_verifications_path
fill_in 'document_verification_document_number', with: '13579' fill_in 'document_verification_document_number', with: '12345678Z'
click_button 'Check' click_button 'Check'
expect(page).to have_content "no user account associated to it" expect(page).to have_content "no user account associated to it"

View File

@@ -0,0 +1,81 @@
require 'rails_helper'
describe SignatureSheet do
let(:signature_sheet) { build(:signature_sheet) }
describe "validations" do
it "should be valid" do
expect(signature_sheet).to be_valid
end
it "should be valid with a valid signable" do
signature_sheet.signable = create(:proposal)
expect(signature_sheet).to be_valid
signature_sheet.signable = create(:spending_proposal)
expect(signature_sheet).to be_valid
end
it "should not be valid without signable" do
signature_sheet.signable = nil
expect(signature_sheet).to_not be_valid
end
it "should not be valid without a valid signable" do
signature_sheet.signable = create(:comment)
expect(signature_sheet).to_not be_valid
end
it "should not be valid without document numbers" do
signature_sheet.document_numbers = nil
expect(signature_sheet).to_not be_valid
end
it "should not be valid without an author" do
signature_sheet.author = nil
expect(signature_sheet).to_not be_valid
end
end
describe "#name" do
it "returns name for proposal signature sheets" do
proposal = create(:proposal)
signature_sheet.signable = proposal
expect(signature_sheet.name).to eq("Citizen proposal #{proposal.id}")
end
it "returns name for spending proposal signature sheets" do
spending_proposal = create(:spending_proposal)
signature_sheet.signable = spending_proposal
expect(signature_sheet.name).to eq("Spending proposal #{spending_proposal.id}")
end
end
describe "#verify_signatures" do
it "creates signatures for each document number" do
signature_sheet = create(:signature_sheet, document_numbers: "123A, 456B")
signature_sheet.verify_signatures
expect(Signature.count).to eq(2)
end
it "marks signature sheet as processed" do
signature_sheet = create(:signature_sheet)
signature_sheet.verify_signatures
expect(signature_sheet.processed).to eq(true)
end
end
describe "#parsed_document_numbers" do
it "returns an array after spliting document numbers by newlines or commas" do
signature_sheet.document_numbers = "123A\r\n456B\n789C,123B"
expect(signature_sheet.parsed_document_numbers).to eq(['123A', '456B', '789C', '123B'])
end
end
end

View File

@@ -0,0 +1,171 @@
require 'rails_helper'
describe Signature do
let(:signature) { build(:signature) }
describe "validations" do
it "should be valid" do
expect(signature).to be_valid
end
it "should not be valid without a document number" do
signature.document_number = nil
expect(signature).to_not be_valid
end
it "should not be valid without an associated signature sheet" do
signature.signature_sheet = nil
expect(signature).to_not be_valid
end
end
describe "#verified?" do
it "returns true if user exists" do
user = create(:user, :level_two, document_number: "123A")
signature = create(:signature, document_number: user.document_number)
expect(signature.verified?).to eq(true)
end
it "returns true if document number in census" do
signature = create(:signature, document_number: "12345678Z")
expect(signature.verified?).to eq(true)
end
it "returns false if user does not exist and not in census" do
signature = create(:signature, document_number: "123A")
expect(signature.verified?).to eq(false)
end
end
describe "#assign_vote" do
describe "existing user" do
it "assigns vote to user" do
user = create(:user, :level_two, document_number: "123A")
signature = create(:signature, document_number: user.document_number)
proposal = signature.signable
signature.assign_vote
expect(user.voted_for?(proposal)).to be
end
it "does not assign vote to user multiple times" do
user = create(:user, :level_two, document_number: "123A")
signature = create(:signature, document_number: user.document_number)
signature.assign_vote
signature.assign_vote
expect(Vote.count).to eq(1)
end
it "does not assign vote to user if already voted" do
proposal = create(:proposal)
user = create(:user, :level_two, document_number: "123A")
vote = create(:vote, votable: proposal, voter: user)
signature_sheet = create(:signature_sheet, signable: proposal)
signature = create(:signature, signature_sheet: signature_sheet, document_number: user.document_number)
signature.assign_vote
expect(Vote.count).to eq(1)
end
it "marks the vote as coming from a signature" do
signature = create(:signature, document_number: "12345678Z")
signature.assign_vote
expect(Vote.last.signature).to eq(signature)
end
end
describe "inexistent user" do
it "creates a user with that document number" do
signature = create(:signature, document_number: "12345678Z")
proposal = signature.signable
signature.assign_vote
user = User.last
expect(user.document_number).to eq("12345678Z")
expect(user.created_from_signature).to eq(true)
expect(user.verified_at).to be
expect(user.erased_at).to be
end
it "assign the vote to newly created user" do
signature = create(:signature, document_number: "12345678Z")
proposal = signature.signable
signature.assign_vote
user = signature.user
expect(user.voted_for?(proposal)).to be
end
it "assigns signature to vote" do
signature = create(:signature, document_number: "12345678Z")
signature.assign_vote
expect(Vote.last.signature).to eq(signature)
end
end
end
describe "#verify" do
describe "document in census" do
it "calls assign_vote" do
signature = create(:signature, document_number: "12345678Z")
expect(signature).to receive(:assign_vote)
signature.verify
end
it "sets signature as verified" do
user = create(:user, :level_two, document_number: "123A")
signature = create(:signature, document_number: user.document_number)
signature.verify
expect(signature).to be_verified
end
end
describe "document not in census" do
it "does not call assign_vote" do
signature = create(:signature, document_number: "123A")
expect(signature).to_not receive(:assign_vote)
signature.verify
end
it "maintains signature as not verified" do
signature = create(:signature, document_number: "123A")
signature.verify
expect(signature).to_not be_verified
end
end
end
end