Merge pull request #266 from AyuntamientoMadrid/user_verification

User verification
This commit is contained in:
Enrique García
2015-08-28 13:53:19 +02:00
72 changed files with 1819 additions and 25 deletions

View File

@@ -40,6 +40,7 @@ gem 'social-share-button'
gem 'initialjs-rails', '0.2.0'
gem 'unicorn'
gem 'paranoia'
gem 'savon'
gem 'ahoy_matey', '~> 1.2.1'
gem 'groupdate' # group temporary data

View File

@@ -54,6 +54,9 @@ GEM
request_store
user_agent_parser
uuidtools
akami (1.3.1)
gyoku (>= 0.4.0)
nokogiri
arel (6.0.3)
awesome_nested_set (3.0.2)
activerecord (>= 4.0.0, < 5)
@@ -155,10 +158,14 @@ GEM
activesupport (>= 4.1.0)
groupdate (2.4.0)
activesupport (>= 3)
gyoku (1.3.1)
builder (>= 2.1.2)
hashie (3.4.2)
highline (1.7.3)
http-cookie (1.0.2)
domain_name (~> 0.5)
httpi (2.4.1)
rack
i18n (0.7.0)
i18n-tasks (0.8.7)
activesupport (>= 2.3.18)
@@ -204,6 +211,7 @@ GEM
netrc (0.10.3)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
nori (2.6.0)
oauth (0.4.7)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
@@ -305,6 +313,14 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (~> 1.1)
savon (2.11.1)
akami (~> 1.2)
builder (>= 2.1.2)
gyoku (~> 1.2)
httpi (~> 2.3)
nokogiri (>= 1.4.0)
nori (~> 2.4)
wasabi (~> 3.4)
simple_captcha2 (0.3.4)
rails (>= 4.1)
simplecov (0.10.0)
@@ -353,6 +369,9 @@ GEM
uuidtools (2.1.5)
warden (1.2.3)
rack (>= 1.0)
wasabi (3.5.0)
httpi (~> 2.0)
nokogiri (>= 1.4.2)
web-console (2.2.1)
activemodel (>= 4.0)
binding_of_caller (>= 0.7.2)
@@ -409,6 +428,7 @@ DEPENDENCIES
responders
rspec-rails (~> 3.0)
sass-rails (~> 5.0)
savon
simple_captcha2
social-share-button
spring

View File

@@ -51,4 +51,10 @@ class ApplicationController < ActionController::Base
redirect_to finish_signup_path
end
end
def verify_resident!
unless current_user.residence_verified?
redirect_to new_residence_path, alert: t('verification.residence.alert.unconfirmed_residency')
end
end
end

View File

@@ -0,0 +1,31 @@
class Verification::EmailController < ApplicationController
before_action :authenticate_user!
before_action :set_verified_user
skip_authorization_check
def show
if Email.find(current_user, params[:email_verification_token])
current_user.update(verified_at: Time.now)
redirect_to account_path, notice: t('verification.email.show.flash.success')
else
redirect_to verified_user_path, alert: t('verification.email.show.alert.failure')
end
end
def create
@email = Email.new(@verified_user)
if @email.save
current_user.reload
Mailer.email_verification(current_user, @email.recipient, @email.encrypted_token).deliver_now
redirect_to account_path, notice: t('verification.email.create.flash.success', email: @verified_user.email)
else
redirect_to verified_user_path, alert: t('verification.email.create.alert.failure')
end
end
private
def set_verified_user
@verified_user = VerifiedUser.by_user(current_user).by_email(params[:recipient]).first
end
end

View File

@@ -0,0 +1,32 @@
class Verification::LetterController < ApplicationController
before_action :authenticate_user!
before_action :verify_resident!
before_action :verify_phone_or_email!
skip_authorization_check
def new
@letter = Letter.new(user: current_user)
end
def create
@letter = Letter.new(user: current_user)
if @letter.save
redirect_to account_path, notice: t('verification.letter.create.flash.success')
else
flash.now.alert = t('verification.letter.create.alert.failure')
render :new
end
end
private
def letter_params
params.require(:letter).permit()
end
def verify_phone_or_email!
unless current_user.confirmed_phone?
redirect_to verified_user_path, alert: t('verification.letter.alert.unconfirmed_personal_data')
end
end
end

View File

@@ -0,0 +1,31 @@
class Verification::ResidenceController < ApplicationController
before_action :authenticate_user!
before_action :verify_attemps_left!, only: [:new, :create]
skip_authorization_check
def new
@residence = Residence.new
end
def create
@residence = Residence.new(residence_params.merge(user: current_user))
if @residence.save
redirect_to verified_user_path, notice: t('verification.residence.create.flash.success')
else
current_user.update(residence_verification_tries: current_user.residence_verification_tries += 1)
render :new
end
end
private
def residence_params
params.require(:residence).permit(:document_number, :document_type, :date_of_birth, :postal_code)
end
def verify_attemps_left!
if current_user.residence_verification_tries >= 5
redirect_to account_path, alert: t('verification.residence.alert.verify_attemps_left')
end
end
end

View File

@@ -0,0 +1,62 @@
class Verification::SmsController < ApplicationController
before_action :authenticate_user!
before_action :verify_resident!
before_action :verify_attemps_left!, only: [:new, :create]
skip_authorization_check
def new
@sms = Sms.new(phone: params[:phone])
end
def create
@sms = Sms.new(sms_params.merge(user: current_user))
if @sms.save
redirect_to edit_sms_path, notice: t('verification.sms.create.flash.success')
else
render :new
end
end
def edit
@sms = Sms.new
end
def update
@sms = Sms.new(sms_params.merge(user: current_user))
if @sms.verify?
current_user.update(confirmed_phone: current_user.unconfirmed_phone)
if VerifiedUser.phone?(current_user)
current_user.update(verified_at: Time.now)
end
redirect_to_next_path
else
@error = t('verification.sms.update.error')
render :edit
end
end
private
def sms_params
params.require(:sms).permit(:phone, :confirmation_code)
end
def redirect_to_next_path
current_user.reload
if current_user.level_three_verified?
redirect_to account_path, notice: t('verification.sms.update.flash.level_three.success')
else
redirect_to new_letter_path, notice: t('verification.sms.update.flash.level_two.success')
end
end
def verify_attemps_left!
if current_user.sms_confirmation_tries >= 3
redirect_to account_path, notice: t('verification.sms.alert.verify_attemps_left')
end
end
end

View File

@@ -0,0 +1,9 @@
class Verification::VerifiedUserController < ApplicationController
before_action :authenticate_user!
skip_authorization_check
def show
@verified_users = VerifiedUser.by_user(current_user)
redirect_to new_sms_path if @verified_users.blank?
end
end

View File

@@ -0,0 +1,9 @@
module VerificationHelper
def document_types
[[t('verification.residence.new.document_type.spanish_id'), 1],
[t('verification.residence.new.document_type.passport'), 2],
[t('verification.residence.new.document_type.residence_card'), 3]]
end
end

View File

@@ -14,4 +14,11 @@ class Mailer < ApplicationMailer
mail(to: @recipient.email, subject: t('mailer.reply.subject'))
end
def email_verification(user, recipient, token)
@user = user
@recipient = recipient
@token = token
mail(to: @recipient, subject: "Verifica tu email")
end
end

3
app/models/address.rb Normal file
View File

@@ -0,0 +1,3 @@
class Address < ActiveRecord::Base
belongs_to :user
end

34
app/models/email.rb Normal file
View File

@@ -0,0 +1,34 @@
class Email
include ActiveModel::Model
attr_accessor :verified_user, :recipient, :plain_token, :encrypted_token
validates :verified_user, presence: true
validates :recipient, presence: true
def initialize(verified_user)
@verified_user = verified_user
@recipient = @verified_user.try(:email)
end
def save
return false unless valid?
generate_token
user = User.where(document_number: verified_user.document_number).first
user.update(email_verification_token: @plain_token)
end
def generate_token
@plain_token, @encrypted_token = Devise.token_generator.generate(User, :email_verification_token)
end
def self.find(user, token)
self.valid_token?(user, token)
end
def self.valid_token?(user, token)
Devise.token_generator.digest(User, :email_verification_token, user.email_verification_token) == token
end
end

53
app/models/letter.rb Normal file
View File

@@ -0,0 +1,53 @@
class Letter
include ActiveModel::Model
attr_accessor :user, :address
validates :user, presence: true
validates :address, presence: true
validate :correct_address
def initialize(attrs={})
@user = attrs[:user]
end
def save
valid? &&
letter_requested! &&
update_user_address
end
def address
@address ||= UserApi.new(user).address
end
def letter_requested!
user.update(letter_requested_at: Time.now)
end
def update_user_address
user.address = Address.new(parsed_address)
user.save
end
def correct_address
errors.add(:address, "Address not found") unless address.present?
end
def parsed_address
{ postal_code: address[:codigo_postal],
street: address[:nombre_via],
street_type: address[:sigla_via],
number: address[:numero_via],
number_type: address[:nominal_via],
letter: address[:letra_via],
portal: address[:portal],
stairway: address[:escalera],
floor: address[:planta],
door: address[:puerta],
km: address[:km],
neighbourhood: address[:nombre_barrio],
district: address[:nombre_distrito] }
end
end

View File

@@ -6,9 +6,9 @@ class Organization < ActiveRecord::Base
delegate :email, :phone_number, to: :user
scope :pending, -> { where(verified_at: nil, rejected_at: nil) }
scope :verified, -> { where("verified_at is not null and (rejected_at is null or rejected_at < verified_at)") }
scope :rejected, -> { where("rejected_at is not null and (verified_at is null or verified_at < rejected_at)") }
scope :pending, -> { where('organizations.verified_at is null and rejected_at is null') }
scope :verified, -> { where("organizations.verified_at is not null and (rejected_at is null or rejected_at < organizations.verified_at)") }
scope :rejected, -> { where("rejected_at is not null and (organizations.verified_at is null or organizations.verified_at < rejected_at)") }
def verify
update(verified_at: Time.now)

45
app/models/residence.rb Normal file
View File

@@ -0,0 +1,45 @@
class Residence
include ActiveModel::Model
include ActiveModel::Dates
attr_accessor :user, :document_number, :document_type, :date_of_birth, :postal_code
validates_presence_of :document_number
validates_presence_of :document_type
validates_presence_of :date_of_birth
validates_presence_of :postal_code
validates :postal_code, length: { is: 5 }
validate :residence_in_madrid
validate :document_number_uniqueness
def initialize(attrs={})
self.date_of_birth = parse_date('date_of_birth', attrs)
attrs = remove_date('date_of_birth', attrs)
super
end
def save
return false unless valid?
user.update(document_number: document_number,
document_type: document_type,
residence_verified_at: Time.now)
end
def document_number_uniqueness
errors.add(:document_number, "Already in use") if User.where(document_number: document_number).any?
end
def residence_in_madrid
return if errors.any?
self.date_of_birth = date_to_string(date_of_birth)
residency = UserApi.new(self)
errors.add(:residence_in_madrid, false) unless residency.valid?
self.date_of_birth = string_to_date(date_of_birth)
end
end

47
app/models/sms.rb Normal file
View File

@@ -0,0 +1,47 @@
class Sms
include ActiveModel::Model
attr_accessor :user, :phone, :confirmation_code
validates_presence_of :phone
validates :phone, length: { is: 9 }
validate :spanish_phone
validate :uniqness_phone
def spanish_phone
errors.add(:phone, :invalid) unless phone.start_with?('6', '7')
end
def uniqness_phone
errors.add(:phone, :taken) if User.where(confirmed_phone: phone).any?
end
def save
return false unless self.valid?
update_user_phone_information
send_sms
increase_sms_tries
end
def update_user_phone_information
user.update(unconfirmed_phone: phone, sms_confirmation_code: four_digit_code)
end
def send_sms
SMSApi.new.sms_deliver(user.unconfirmed_phone, user.sms_confirmation_code)
end
def increase_sms_tries
user.update(sms_confirmation_tries: user.sms_confirmation_tries += 1)
end
def verify?
user.sms_confirmation_code == confirmation_code
end
private
def four_digit_code
rand.to_s[2..5]
end
end

View File

@@ -1,4 +1,5 @@
class User < ActiveRecord::Base
include Verification
OMNIAUTH_EMAIL_PREFIX = 'omniauth@participacion'
OMNIAUTH_EMAIL_REGEX = /\A#{OMNIAUTH_EMAIL_PREFIX}/
@@ -11,6 +12,7 @@ class User < ActiveRecord::Base
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
has_one :address
has_one :administrator
has_one :moderator
has_one :organization

View File

@@ -0,0 +1,12 @@
# make sure document_type is being stored and queried in the correct format (Is it DNI? a number, a string?)
class VerifiedUser < ActiveRecord::Base
scope :by_user, -> (user) { where(document_number: user.document_number,
document_type: user.document_type) }
scope :by_email, -> (email) { where(email: email) }
scope :by_phone, -> (phone) { where(phone: phone) }
def self.phone?(user)
by_user(user).by_phone(user.unconfirmed_phone).first.present?
end
end

View File

@@ -2,6 +2,16 @@
<div class="small-12 column">
<%= link_to t("account.show.change_credentials_link"), edit_user_registration_path, class: 'button radius small secondary right' %>
<span class="right" style="padding-right: 30px">
<% if current_user.level_three_verified? %>
<%= t("account.show.level_three_user") %>
<% elsif current_user.level_two_verified? %>
<%= t("account.show.level_two_user") %>
<% else %>
<%= link_to t("account.show.verify_my_account"), new_residence_path, class: 'button radius small secondary right' %>
<% end %>
</span>
<h1 class="inline-block"><%= t("account.show.title") %></h1>
<%= form_for @account, as: :account, url: account_path do |f| %>

View File

@@ -32,7 +32,7 @@
<%= link_to t("layouts.header.welcome"), root_path %>
</div>
<div class="small-12 medium-2 column end">
<%= link_to t("layouts.header.debates"), debates_path, class: ("active" if current_page?(controller: "debates")) %>
<%= link_to t("layouts.header.debates"), debates_path, class: ("active" if current_page?(controller: "/debates")) %>
</div>
<div class="small-12 medium-2 column end">
<%= link_to t("layouts.header.initiatives"), "#" %>

View File

@@ -0,0 +1,15 @@
<td style="padding-bottom: 20px; padding-left: 10px;">
<h1 style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;">
<%= t("mailers.email_verification.title") %>
</h1>
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px;">
<%= t("mailers.email_verification.instructions_html",
verification_link: link_to(
t('mailers.email_verification.click_here_to_verify'),
email_url(email_verification_token: @token))) %>
</p>
</td>

View File

@@ -3,7 +3,13 @@
<p>
<strong>
<%= pluralize resource.errors.count, t("form.error"), t("form.errors") %>
<%= t("form.not_saved", resource: t("form.#{resource.class.to_s.downcase}")) %>
<% if local_assigns[:message].present? %>
<%= message %>
<% else %>
<%= t("form.not_saved", resource: t("form.#{resource.class.to_s.downcase}")) %>
<% end %>
</strong>
</p>
</div>

View File

@@ -0,0 +1,4 @@
<%= form_for Email.new(verified_user), url: email_path, method: :post do |f| %>
<%= hidden_field_tag :recipient, verified_user.email %>
<%= f.submit t('verification.email.form.submit_button') %>
<% end %>

View File

@@ -0,0 +1,15 @@
<div class="row account">
<div class="small-12 column">
<h1 class="inline-block"><%= t('verification.letter.new.title') %></h1>
<div>
<%= t('verification.letter.new.explanation') %>
</div>
<%= form_for @letter, url: letter_path do |f| %>
<%= render 'shared/errors', resource: @letter %>
<%= f.submit t('verification.letter.new.submit_button') %>
<% end %>
</div>
</div>

View File

@@ -0,0 +1,12 @@
<% if @residence.errors[:residence_in_madrid].present? %>
<div id="error_explanation" class="alert-box alert radius">
<%= t('verification.residence.new.error_verifying_census') %>
<%= mail_to "tec.gobiernoabierto@madrid.es" %>
</div>
<% else %>
<%= render 'shared/errors',
resource: @residence,
message: t('verification.residence.new.form_errors') %>
<% end %>

View File

@@ -0,0 +1,19 @@
<div class="row account">
<div class="small-12 column">
<h1 class="inline-block"><%= t('verification.residence.new.title') %></h1>
<%= form_for @residence, url: residence_path do |f| %>
<%= render 'errors' %>
<%= f.select :document_type, document_types, prompt: "" %>
<%= f.text_field :document_number %>
<%= f.date_select :date_of_birth,
prompt: true,
start_year: 1900, end_year: 16.years.ago.year %>
<%= f.text_field :postal_code %>
<%= f.submit "Verify" %>
<% end %>
</div>
</div>

View File

@@ -0,0 +1,5 @@
<%= form_for sms, url: sms_path do |f| %>
<%= render 'shared/errors', resource: sms %>
<%= f.hidden_field :phone %>
<%= f.submit t('verification.sms.form.submit_button') %>
<% end %>

View File

@@ -0,0 +1,16 @@
<div class="row account">
<div class="small-12 column">
<h1 class="inline-block"><%= t('verification.sms.edit.title') %></h1>
<%= form_for @sms, url: sms_path, method: :put do |f| %>
<p><%= @error %></p>
<%= f.text_field :confirmation_code %>
<%= f.submit t('verification.sms.edit.submit_button') %>
<% end %>
<%= t('verification.sms.edit.resend_sms_text') %>
<%= link_to t('verification.sms.edit.resend_sms_link'), verified_user_path %>
</div>
</div>

View File

@@ -0,0 +1,14 @@
<div class="row account">
<div class="small-12 column">
<h1 class="inline-block"><%= t('verification.sms.new.title') %></h1>
<%= form_for @sms, url: sms_path do |f| %>
<%= render 'shared/errors', resource: @sms %>
<%= f.text_field :phone %>
<%= f.submit t('verification.sms.new.submit_button') %>
<% end %>
</div>
</div>

View File

@@ -0,0 +1,49 @@
<div class="row account">
<div class="small-12 column">
<h1 class="inline-block"><%= t('verification.verified_user.show.title') %></h1>
<% if @verified_users.map(&:email).any? %>
<div><strong><%= t('verification.verified_user.show.email_title') %></strong></div>
<ul>
<% @verified_users.each do |verified_user| %>
<% if verified_user.email.present? %>
<li id="<%= dom_id(verified_user) %>_email" style="float:left">
<span style="float:left">
<%= verified_user.email %>
</span>
<span style="float:left;padding-left:30px">
<%= render '/verification/email/form', verified_user: verified_user %>
</span>
</li>
<br/><br/><br/>
<% end %>
<% end %>
</ul>
<% end %>
<% if @verified_users.map(&:phone).any? %>
<div><strong><%= t('verification.verified_user.show.phone_title') %></strong></div>
<ul style="padding-top:40px">
<% @verified_users.each do |verified_user| %>
<% if verified_user.phone.present? %>
<li id="<%= dom_id(verified_user) %>_phone" style="float:left">
<span style="float:left">
<%= verified_user.phone %>
</span>
<span style="float:left;padding-left:30px">
<%= render '/verification/sms/form', sms: Sms.new(phone: verified_user.phone) %>
</span>
</li>
<br/><br/><br/>
<% end %>
<% end %>
</ul>
<% end %>
<div style="margin-top: 30px">
<%= link_to t('verification.verified_user.show.use_another_phone'), new_sms_path %>
</div>
</div>
</div>

View File

@@ -24,6 +24,7 @@ data:
- config/locales/%{locale}.yml
- config/locales/admin.%{locale}.yml
- config/locales/moderation.%{locale}.yml
- config/locales/verification.%{locale}.yml
- config/locales/mailers.%{locale}.yml
- config/locales/devise_views.%{locale}.yml
- config/locales/responders.%{locale}.yml

View File

@@ -0,0 +1,16 @@
en:
activemodel:
models:
residence: Residence
sms: SMS
attributes:
residence:
document_type: Document type
document_number: Document number(including letter)
date_of_birth: Date of birth
postal_code: Postal code
sms:
phone: 'Phone'
confirmation_code: 'Confirmation code'
email:
recipient: 'Email'

View File

@@ -0,0 +1,16 @@
es:
activemodel:
models:
residence: Residencia
sms: SMS
attributes:
residence:
document_type: Tipo documento
document_number: Numero de documento (incluida letra)
date_of_birth: Fecha de nacimiento
postal_code: 'Código postal'
sms:
phone: 'Teléfono'
confirmation_code: 'Código de confirmación'
email:
recipient: 'Email'

View File

@@ -7,6 +7,7 @@ en:
user: User
vote: Vote
organization: Organization
residence: Residencia
attributes:
comment:
body: Comment

View File

@@ -52,6 +52,7 @@ en:
accept_terms: I accept the privacy policy and the legal terms
user: account
debate: debate
sms: phone
debates:
index:
create_debate: Create a debate
@@ -149,6 +150,9 @@ en:
phone_number_label: "Phone number"
organization_name_label: "Organization name"
notifications: Notifications
level_two_user: You are a level 2 user
level_three_user: You are a level 3 user
verify_my_account: Verify my account
simple_captcha:
placeholder: "Enter the image value"
label: "Enter the code in the box"

View File

@@ -52,6 +52,7 @@ es:
accept_terms: Acepto la política de privacidad y el aviso legal
user: la cuenta
debate: el debate
sms: el teléfono
debates:
index:
create_debate: Crea un debate
@@ -149,6 +150,9 @@ es:
phone_number_label: "Teléfono"
organization_name_label: "Nombre de la organización"
notifications: Notificaciones
level_two_user: Eres un usuario verificado de nivel 2
level_three_user: Eres un usuario verificado de nivel 3
verify_my_account: Verificar mi cuenta
simple_captcha:
placeholder: "Introduce el texto de la imagen"
label: "Introduce el texto en la caja"

View File

@@ -3,8 +3,13 @@ en:
comment:
hi: Hello
title: New comment on your debate
new_comment_by_html: "There'is a new comment by <b<%{commenter}</b> on"
new_comment_by_html: "There is a new comment by <b>%{commenter}</b> on"
reply:
hi: Hello
title: New reply on your comment
new_reply_by_html: "There'is a new reply by <b>%{commenter}</b> to your comment on"
email_verification:
title: Please verify yourself
instructions_html: "We need to verify you using this email, which we got from the Census. %{verification_link}"
click_here_to_verify: "Please click here to verify yourself"

View File

@@ -8,3 +8,7 @@ es:
hi: Hola
title: Nueva respuesta a tu comentario
new_reply_by_html: "Hay una nueva respuesta de <b>%{commenter}</b> a tu comentario en"
email_verification:
title: Por favor verifícate
instructions_html: "Vamos a proceder a verificar tu cuenta en la aplicación de participación ciudadana utilizando esta cuenta de correo que sacamos del padrón. %{verification_link}."
click_here_to_verify: "Por favor pulsa este enlace para verificarte"

View File

@@ -125,6 +125,7 @@ es:
too_short: es demasiado corto (%{count} caracteres mínimo)
wrong_length: no tiene la longitud correcta (%{count} caracteres exactos)
other_than: debe ser distinto de %{count}
invalid_date: "no es una fecha valida"
template:
body: 'Se encontraron problemas con los siguientes campos:'
header:

View File

@@ -0,0 +1,72 @@
en:
verification:
residence:
new:
title: 'Verify residence'
document_type:
spanish_id: 'Spanish ID'
passport: 'Passport'
residence_card: 'Residence card'
form_errors: 'prevented your residence verification'
error_verifying_census: 'The census of the city of Madrid could not verify your information. Pero revise de information and try again or get in touch with us.'
create:
flash:
success: 'Residence verified'
alert:
verify_attemps_left: 'You have reached the maximum number of Census verification tries'
unconfirmed_residency: 'You have not yet confirmed your residence'
sms:
new:
title: Phone verification
submit_button: Send
create:
flash:
success: 'Enter the confirmation code we have sent your phone'
edit:
title: Security code confirmation
resend_sms_text: You have not received the confirmation code in your phone?
resend_sms_link: Click here to send the confirmation code again
submit_button: Send
update:
error: 'Incorrect confirmation code'
flash:
level_three:
success: 'Correct code. You are now a verified user'
level_two:
success: 'Correct code'
form:
submit_button: Send
alert:
verify_attemps_left: 'You have reached the maximum number of sms verification tries'
email:
show:
flash:
success: 'You are now a verified user'
alert:
failure: 'Incorrect verification code'
create:
flash:
success: "We have send you a confirmation email to your email account: %{email}"
alert:
failure: "There was a problem sending you an email to your account"
form:
submit_button: Send
letter:
new:
title: Final Verification
explanation: 'To completely verify your account we need to go to one of these offices or send you a letter with a special code to your home address'
submit_button: 'Send me a letter'
create:
flash:
success: "You will receive a letter to your home address in the next couple of days"
alert:
failure: "We could not verify your address with the Census please try again later"
alert:
unconfirmed_personal_data: 'You have not yet confirmed your personal data'
verified_user:
show:
title: Available information
email_title: Emails
phone_title: Phones
use_another_phone: Use another phone

View File

@@ -0,0 +1,71 @@
es:
verification:
residence:
new:
title: 'Verificar residencia'
document_type:
spanish_id: 'DNI'
passport: 'Pasaporte'
residence_card: 'Tarjeta de residencia'
form_errors: 'evitaron verificar tu residencia'
error_verifying_census: 'El Padrón de Madrid no pudo verificar tu información. Revisa la información ó ponte en contacto con nosotros.'
create:
flash:
success: 'Residencia verificada'
alert:
verify_attemps_left: 'Has llegado al máximo número de intentos de verificar tu residencia.'
unconfirmed_residency: 'Aún no has verificado tu residencia'
sms:
new:
title: Verificación de teléfono móvil
submit_button: Enviar
create:
flash:
success: 'Introduce el código de confirmación que te hemos enviado por mensaje de texto'
edit:
title: 'Confirmación de código de seguridad'
resend_sms_text: '¿No has recibido un mensaje de texto con tu código de confirmación?'
resend_sms_link: 'Haz click aquí para volver a enviártelo'
submit_button: Enviar
update:
error: 'Código de confirmación incorrecto'
flash:
level_three:
success: 'Código correcto. Ya eres un usuario verificado'
level_two:
success: 'Código incorrecto'
form:
submit_button: Enviar
alert:
verify_attemps_left: 'Has llegado al máximo número de intentos de verificar tu teléfono.'
email:
show:
flash:
success: 'Eres un usuario verificado'
alert:
failure: 'Código de verificación incorrecto'
create:
flash:
success: "Te hemos enviado un email de confirmación a tu cuenta: %{email}"
alert:
failure: "Hubo un problema enviándote un email a tu cuenta"
form:
submit_button: Enviar
letter:
new:
title: Final Verification
explanation: 'To completely verify your account we need to go to one of these offices or send you a letter with a special code to your home address'
submit_button: 'Send me a letter'
create:
flash:
success: "You will receive a letter to your home address in the next couple of days"
alert:
failure: "We could not verify your address with the Census please try again later"
alert:
unconfirmed_personal_data: 'You have not yet confirmed your personal data'
verified_user:
show:
title: Información disponible
email_title: Emails
phone_title: Teléfonos
use_another_phone: Utilizar otro teléfono

View File

@@ -42,10 +42,13 @@ Rails.application.routes.draw do
end
resource :account, controller: "account", only: [:show, :update]
resource :stats, only: [:show]
namespace :api do
resource :stats, only: [:show]
scope module: :verification do
resource :residence, controller: "residence", only: [:new, :create]
resource :sms, controller: "sms", only: [:new, :create, :edit, :update]
resource :verified_user, controller: "verified_user", only: [:show]
resource :email, controller: "email", only: [:new, :show, :create]
resource :letter, controller: "letter", only: [:new, :create]
end
namespace :admin do
@@ -110,6 +113,12 @@ Rails.application.routes.draw do
end
end
resource :stats, only: [:show]
namespace :api do
resource :stats, only: [:show]
end
# Example of regular route:
# get 'products/:id' => 'catalog#view'

View File

@@ -0,0 +1,6 @@
class AddSmsVerificationCodeToUsers < ActiveRecord::Migration
def change
add_column :users, :sms_verification_code, :string
add_column :users, :sms_verified_at, :datetime
end
end

View File

@@ -0,0 +1,5 @@
class AddPhoneToUsers < ActiveRecord::Migration
def change
add_column :users, :phone, :string
end
end

View File

@@ -0,0 +1,14 @@
class CreateVerifiedUsers < ActiveRecord::Migration
def change
unless ActiveRecord::Base.connection.table_exists? 'verified_users'
create_table :verified_users do |t|
t.string :document_number
t.string :document_type
t.string :phone
t.string :email
t.timestamps null: false
end
end
end
end

View File

@@ -0,0 +1,6 @@
class AddDocumentToUsers < ActiveRecord::Migration
def change
add_column :users, :document_number, :string
add_column :users, :document_type, :string
end
end

View File

@@ -0,0 +1,5 @@
class AddResidenceVerifiedAtToUsers < ActiveRecord::Migration
def change
add_column :users, :residence_verified_at, :datetime
end
end

View File

@@ -0,0 +1,6 @@
class AddLetterToUsers < ActiveRecord::Migration
def change
add_column :users, :letter_requested, :boolean, default: false
add_column :users, :letter_sent_at, :datetime
end
end

View File

@@ -0,0 +1,5 @@
class AddEmailVerifiedAtToUsers < ActiveRecord::Migration
def change
add_column :users, :email_verified_at, :datetime
end
end

View File

@@ -0,0 +1,6 @@
class AddEmailVerificationToUsers < ActiveRecord::Migration
def change
add_column :users, :email_verification_token, :string
add_column :users, :email_for_verification, :string
end
end

View File

@@ -0,0 +1,5 @@
class AddVerifiedUserSmsVerifiedAtToUsers < ActiveRecord::Migration
def change
add_column :users, :verified_user_sms_verified_at, :datetime
end
end

View File

@@ -0,0 +1,5 @@
class AddSmsTriedToUsers < ActiveRecord::Migration
def change
add_column :users, :sms_tries, :integer, default: 0
end
end

View File

@@ -0,0 +1,5 @@
class AddResidenceVerificationTriesToUsers < ActiveRecord::Migration
def change
add_column :users, :residence_verification_tries, :integer, default: 0
end
end

View File

@@ -0,0 +1,23 @@
class CreateAddresses < ActiveRecord::Migration
def change
create_table :addresses do |t|
t.integer :user_id
t.string :street
t.string :street_type
t.string :number
t.string :number_type
t.string :letter
t.string :portal
t.string :stairway
t.string :floor
t.string :door
t.string :km
t.string :neighbourhood
t.string :district
t.string :postal_code
t.string :toponymy
t.timestamps null: false
end
end
end

View File

@@ -0,0 +1,20 @@
class RefactorVerificationColumns < ActiveRecord::Migration
def change
rename_column :users, :sms_verification_code, :sms_confirmation_code
remove_column :users, :sms_verified_at
remove_column :users, :email_verified_at
remove_column :users, :email_for_verification
remove_column :users, :verified_user_sms_verified_at
add_column :users, :verified_at, :datetime
remove_column :users, :phone
add_column :users, :unconfirmed_phone, :string
add_column :users, :confirmed_phone, :string
remove_column :users, :letter_requested
add_column :users, :letter_requested_at, :datetime
rename_column :users, :sms_tries, :sms_confirmation_tries
end
end

View File

@@ -16,6 +16,26 @@ ActiveRecord::Schema.define(version: 20150828085718) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "addresses", force: :cascade do |t|
t.integer "user_id"
t.string "street"
t.string "street_type"
t.string "number"
t.string "number_type"
t.string "letter"
t.string "portal"
t.string "stairway"
t.string "floor"
t.string "door"
t.string "km"
t.string "neighbourhood"
t.string "district"
t.string "postal_code"
t.string "toponymy"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "administrators", force: :cascade do |t|
t.integer "user_id"
end
@@ -47,8 +67,8 @@ ActiveRecord::Schema.define(version: 20150828085718) do
t.integer "rgt"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "children_count", default: 0
t.datetime "hidden_at"
t.integer "children_count", default: 0
t.integer "flags_count", default: 0
t.datetime "ignored_flag_at"
t.integer "moderator_id"
@@ -70,14 +90,14 @@ ActiveRecord::Schema.define(version: 20150828085718) do
t.string "title", limit: 80
t.text "description"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "hidden_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "visit_id"
t.datetime "hidden_at"
t.integer "flags_count", default: 0
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.datetime "ignored_flag_at"
t.integer "comments_count", default: 0
t.datetime "confirmed_hide_at"
@@ -161,29 +181,41 @@ ActiveRecord::Schema.define(version: 20150828085718) do
add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.boolean "email_on_debate_comment", default: false
t.boolean "email_on_comment_reply", default: false
t.boolean "email_on_debate_comment", default: false
t.boolean "email_on_comment_reply", default: false
t.string "phone_number", limit: 30
t.string "official_position"
t.integer "official_level", default: 0
t.integer "official_level", default: 0
t.datetime "hidden_at"
t.string "phone_number", limit: 30
t.string "sms_confirmation_code"
t.string "username"
t.string "document_number"
t.string "document_type"
t.datetime "residence_verified_at"
t.datetime "letter_sent_at"
t.string "email_verification_token"
t.integer "sms_confirmation_tries", default: 0
t.integer "residence_verification_tries", default: 0
t.datetime "verified_at"
t.string "unconfirmed_phone"
t.string "confirmed_phone"
t.datetime "letter_requested_at"
t.datetime "confirmed_hide_at"
end
@@ -192,6 +224,15 @@ ActiveRecord::Schema.define(version: 20150828085718) do
add_index "users", ["hidden_at"], name: "index_users_on_hidden_at", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "verified_users", force: :cascade do |t|
t.string "document_number"
t.string "document_type"
t.string "phone"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "visits", id: :uuid, default: nil, force: :cascade do |t|
t.uuid "visitor_id"
t.string "ip"

25
lib/active_model/dates.rb Normal file
View File

@@ -0,0 +1,25 @@
module ActiveModel::Dates
def parse_date(field, attrs)
day, month, year = attrs["#{field}(1i)"],
attrs["#{field}(2i)"],
attrs["#{field}(3i)"]
return nil unless day.present? && month.present? && year.present?
Date.new(day.to_i, month.to_i, year.to_i)
end
def remove_date(field, attrs)
attrs.except("#{field}(1i)", "#{field}(2i)", "#{field}(3i)")
end
def date_to_string(date)
date.strftime("%d-%m-%Y")
end
def string_to_date(value)
day, month, year = value.split("-")
Date.new(year.to_i, month.to_i, day.to_i)
end
end

44
lib/sms_api.rb Normal file
View File

@@ -0,0 +1,44 @@
require 'open-uri'
class SMSApi
attr_accessor :client
def initialize
@client = Savon.client(wsdl: url)
end
def url
return "" unless end_point_available?
open(Rails.application.secrets.sms_end_point).base_uri.to_s
end
def authorization
Base64.encode64("#{Rails.application.secrets.sms_username}:#{Rails.application.secrets.sms_password}")
end
def sms_deliver(phone, code)
return stubbed_response unless end_point_available?
response = client.call(:enviar_sms_simples, message: request(phone, code))
success?(response)
end
def request(phone, code)
{ autorizacion: authorization,
destinatarios: { destinatario: phone },
texto_mensaje: "Código de verificación: #{code}",
solicita_notificacion: "All" }
end
def success?(response)
response.body[:respuesta_sms][:respuesta_servicio_externo][:texto_respuesta] == "Success"
end
def end_point_available?
Rails.env.staging? || Rails.env.production?
end
def stubbed_response
{:respuesta_sms=>{:identificador_mensaje=>"1234567", :fecha_respuesta=>"Thu, 20 Aug 2015 16:28:05 +0200", :respuesta_pasarela=>{:codigo_pasarela=>"0000", :descripcion_pasarela=>"Operación ejecutada correctamente."}, :respuesta_servicio_externo=>{:codigo_respuesta=>"1000", :texto_respuesta=>"Success"}}}
end
end

56
lib/user_api.rb Normal file
View File

@@ -0,0 +1,56 @@
class UserApi
attr_accessor :client, :citizen, :response
def initialize(citizen)
@citizen = citizen
end
def client
@client = Savon.client(wsdl: Rails.application.secrets.padron_end_point)
end
def response
return stubbed_response unless end_point_available?
client.call(:get_habita_datos, message: request).body
end
def request
{ request:
{ codigo_institucion: Rails.application.secrets.institution_code,
codigo_portal: Rails.application.secrets.portal_name,
codigo_usuario: Rails.application.secrets.user_code,
documento: citizen.document_number,
tipo_documento: citizen.document_type,
codigo_idioma: 102,
nivel: 3 }}
end
def data
response[:get_habita_datos_response][:get_habita_datos_return]
end
def date_of_birth
data[:datos_habitante][:item][:fecha_nacimiento_string]
end
def postal_code
data[:datos_vivienda][:item][:codigo_postal]
end
def address
response[:get_habita_datos_response][:get_habita_datos_return][:datos_vivienda][:item]
end
def valid?
citizen.date_of_birth == date_of_birth &&
citizen.postal_code == postal_code
end
def end_point_available?
Rails.env.staging? || Rails.env.production?
end
def stubbed_response
{:get_habita_datos_response=>{:get_habita_datos_return=>{:hay_errores=>false, :datos_habitante=>{:item=>{:fecha_nacimiento_string=>"31-12-1980", :identificador_documento=>"12345678Z", }}, :datos_vivienda=>{:item=>{:codigo_postal=>"28013", :escalera=>"4", :km=>"0", :letra_via=>"B", :nombre_barrio=>"JUSTICIA", :nombre_distrito=>"CENTRO", :nombre_via=>"ALCALÁ", :nominal_via=>"NUM", :numero_via=>"1", :planta=>"PB", :portal=>"1", :puerta=>"DR", :sigla_via=>"CALLE"}}}}}
end
end

20
lib/verification.rb Normal file
View File

@@ -0,0 +1,20 @@
module Verification
def residence_verified?
residence_verified_at.present?
end
def sms_verified?
confirmed_phone.present?
end
def level_two_verified?
residence_verified? && sms_verified?
end
def level_three_verified?
verified_at.present?
end
end

View File

@@ -20,6 +20,33 @@ FactoryGirl.define do
uid "MyString"
end
factory :residence do
document_number '12345678Z'
document_type 1
date_of_birth Date.new(1980, 12, 31)
postal_code "28013"
end
factory :sms do
phone "699999999"
end
factory :letter do
user
address
end
factory :address do
street_type "Calle"
street "Alcalá"
number "1"
end
factory :verified_user do
document_number '12345678Z'
document_type 'dni'
end
factory :debate do
sequence(:title) { |n| "Debate #{n} title" }
description 'Debate description'

View File

@@ -0,0 +1,65 @@
require 'rails_helper'
feature 'Verify email' do
scenario 'Verify' do
user = create(:user,
residence_verified_at: Time.now,
document_number: '12345678Z',
document_type: 'dni')
verified_user = create(:verified_user,
document_number: '12345678Z',
document_type: 'dni',
email: 'rock@example.com')
login_as(user)
visit verified_user_path
within("#verified_user_#{verified_user.id}_email") do
expect(page).to have_content 'rock@example.com'
click_button "Send"
end
expect(page).to have_content 'We have send you a confirmation email to your email account: rock@example.com'
sent_token = /.*email_verification_token=(.*)".*/.match(ActionMailer::Base.deliveries.last.body.to_s)[1]
visit email_path(email_verification_token: sent_token)
expect(page).to have_content "You are now a verified user"
expect(page).to_not have_link "Verify my account"
expect(page).to have_content "You are a level 3 user"
end
scenario "Errors on token verification" do
user = create(:user, residence_verified_at: Time.now)
login_as(user)
visit email_path(email_verification_token: "1234")
expect(page).to have_content "Incorrect verification code"
end
scenario "Errors on sending confirmation email" do
user = create(:user,
residence_verified_at: Time.now,
document_number: '12345678Z',
document_type: 'dni')
verified_user = create(:verified_user,
document_number: '12345678Z',
document_type: 'dni',
email: 'rock@example.com')
login_as(user)
visit verified_user_path
verified_user.destroy
click_button "Send"
expect(page).to have_content "There was a problem sending you an email to your account"
end
end

View File

@@ -0,0 +1,60 @@
require 'rails_helper'
feature 'Verify Letter' do
scenario 'Send letter level 2 verified with phone' do
user = create(:user, residence_verified_at: Time.now, confirmed_phone: "611111111")
login_as(user)
visit new_letter_path
click_button "Send me a letter"
expect(page).to have_content "You will receive a letter to your home address"
end
scenario "Error accessing address from UserApi" do
user = create(:user, residence_verified_at: Time.now, confirmed_phone: "611111111")
login_as(user)
visit new_letter_path
allow_any_instance_of(UserApi).to receive(:address).and_return(nil)
click_button "Send me a letter"
expect(page).to have_content "We could not verify your address with the Census please try again later"
end
scenario 'Send letter level 2 user verified with email' do
user = create(:user, residence_verified_at: Time.now, confirmed_phone: "611111111")
login_as(user)
visit new_letter_path
click_button "Send me a letter"
expect(page).to have_content "You will receive a letter to your home address"
end
scenario "Deny access unless verified residence" do
user = create(:user)
login_as(user)
visit new_letter_path
expect(page).to have_content 'You have not yet confirmed your residence'
expect(URI.parse(current_url).path).to eq(new_residence_path)
end
scenario "Deny access unless verified phone/email" do
user = create(:user, residence_verified_at: Time.now)
login_as(user)
visit new_letter_path
expect(page).to have_content 'You have not yet confirmed your personal data'
expect(URI.parse(current_url).path).to eq(new_sms_path)
end
end

View File

@@ -0,0 +1,113 @@
require 'rails_helper'
feature 'Level three verification' do
scenario 'Verification with residency and verified sms' do
user = create(:user)
verified_user = create(:verified_user,
document_number: '12345678Z',
document_type: '1',
phone: '611111111')
login_as(user)
visit account_path
click_link 'Verify my account'
select 'Spanish ID', from: 'residence_document_type'
fill_in 'residence_document_number', with: "12345678Z"
select_date '31-December-1980', from: 'residence_date_of_birth'
fill_in 'residence_postal_code', with: '28013'
click_button 'Verify'
expect(page).to have_content 'Residence verified'
within("#verified_user_#{verified_user.id}_phone") do
click_button "Send"
end
expect(page).to have_content 'Security code confirmation'
user = user.reload
fill_in 'sms_confirmation_code', with: user.sms_confirmation_code
click_button 'Send'
expect(page).to have_content 'Correct code'
expect(page).to have_content "You are now a verified user"
expect(page).to_not have_link "Verify my account"
expect(page).to have_content "You are a level 3 user"
end
scenario 'Verification with residency and verified email' do
user = create(:user)
verified_user = create(:verified_user,
document_number: '12345678Z',
document_type: '1',
email: 'rock@example.com')
login_as(user)
visit account_path
click_link 'Verify my account'
select 'Spanish ID', from: 'residence_document_type'
fill_in 'residence_document_number', with: "12345678Z"
select_date '31-December-1980', from: 'residence_date_of_birth'
fill_in 'residence_postal_code', with: '28013'
click_button 'Verify'
expect(page).to have_content 'Residence verified'
within("#verified_user_#{verified_user.id}_email") do
click_button "Send"
end
expect(page).to have_content 'We have send you a confirmation email to your email account: rock@example.com'
sent_token = /.*email_verification_token=(.*)".*/.match(ActionMailer::Base.deliveries.last.body.to_s)[1]
visit email_path(email_verification_token: sent_token)
expect(page).to have_content "You are now a verified user"
expect(page).to_not have_link "Verify my account"
expect(page).to have_content "You are a level 3 user"
end
scenario 'Verification with residency and sms and letter' do
user = create(:user)
login_as(user)
visit account_path
click_link 'Verify my account'
select 'Spanish ID', from: 'residence_document_type'
fill_in 'residence_document_number', with: "12345678Z"
select_date '31-December-1980', from: 'residence_date_of_birth'
fill_in 'residence_postal_code', with: '28013'
click_button 'Verify'
expect(page).to have_content 'Residence verified'
fill_in 'sms_phone', with: "611111111"
click_button 'Send'
expect(page).to have_content 'Security code confirmation'
user = user.reload
fill_in 'sms_confirmation_code', with: user.sms_confirmation_code
click_button 'Send'
expect(page).to have_content 'Correct code'
click_button "Send me a letter"
expect(page).to have_content "You will receive a letter to your home address"
end
end

View File

@@ -0,0 +1,33 @@
require 'rails_helper'
feature 'Level two verification' do
scenario 'Verification with residency and sms' do
user = create(:user)
login_as(user)
visit account_path
click_link 'Verify my account'
select 'Spanish ID', from: 'residence_document_type'
fill_in 'residence_document_number', with: "12345678Z"
select_date '31-December-1980', from: 'residence_date_of_birth'
fill_in 'residence_postal_code', with: '28013'
click_button 'Verify'
expect(page).to have_content 'Residence verified'
fill_in 'sms_phone', with: "611111111"
click_button 'Send'
expect(page).to have_content 'Security code confirmation'
user = user.reload
fill_in 'sms_confirmation_code', with: user.sms_confirmation_code
click_button 'Send'
expect(page).to have_content 'Correct code'
end
end

View File

@@ -0,0 +1,80 @@
require 'rails_helper'
feature 'Residence' do
scenario 'Verify resident in Madrid' do
user = create(:user)
login_as(user)
visit account_path
click_link 'Verify my account'
fill_in 'residence_document_number', with: "12345678Z"
select 'Spanish ID', from: 'residence_document_type'
select_date '31-December-1980', from: 'residence_date_of_birth'
fill_in 'residence_postal_code', with: '28013'
click_button 'Verify'
expect(page).to have_content 'Residence verified'
end
scenario 'Error on verify' do
user = create(:user)
login_as(user)
visit account_path
click_link 'Verify my account'
click_button 'Verify'
expect(page).to have_content /\d errors? prevented your residence verification/
end
scenario 'Error on Madrid census' do
user = create(:user)
login_as(user)
visit account_path
click_link 'Verify my account'
fill_in 'residence_document_number', with: "12345678Z"
select 'Spanish ID', from: 'residence_document_type'
select '1997', from: 'residence_date_of_birth_1i'
select 'January', from: 'residence_date_of_birth_2i'
select '1', from: 'residence_date_of_birth_3i'
fill_in 'residence_postal_code', with: '28013'
click_button 'Verify'
expect(page).to have_content 'The census of the city of Madrid could not verify your information'
end
scenario '5 tries allowed' do
user = create(:user)
login_as(user)
visit account_path
click_link 'Verify my account'
5.times do
fill_in 'residence_document_number', with: "12345678Z"
select 'Spanish ID', from: 'residence_document_type'
select '1997', from: 'residence_date_of_birth_1i'
select 'January', from: 'residence_date_of_birth_2i'
select '1', from: 'residence_date_of_birth_3i'
fill_in 'residence_postal_code', with: '28013'
click_button 'Verify'
expect(page).to have_content 'The census of the city of Madrid could not verify your information'
end
click_button 'Verify'
expect(page).to have_content 'You have reached the maximum number of Census verification tries'
expect(URI.parse(current_url).path).to eq(account_path)
visit new_residence_path
expect(page).to have_content 'You have reached the maximum number of Census verification tries'
expect(URI.parse(current_url).path).to eq(account_path)
end
end

View File

@@ -0,0 +1,80 @@
require 'rails_helper'
feature 'SMS Verification' do
scenario 'Verify' do
user = create(:user, residence_verified_at: Time.now)
login_as(user)
visit new_sms_path
fill_in 'sms_phone', with: "611111111"
click_button 'Send'
expect(page).to have_content 'Security code confirmation'
user = user.reload
fill_in 'sms_confirmation_code', with: user.sms_confirmation_code
click_button 'Send'
expect(page).to have_content 'Correct code'
end
scenario 'Errors on phone number' do
user = create(:user, residence_verified_at: Time.now)
login_as(user)
visit new_sms_path
click_button 'Send'
expect(page).to have_content error_message
end
scenario 'Errors on verification code' do
user = create(:user, residence_verified_at: Time.now)
login_as(user)
visit new_sms_path
fill_in 'sms_phone', with: "611111111"
click_button 'Send'
expect(page).to have_content 'Security code confirmation'
click_button 'Send'
expect(page).to have_content 'Incorrect confirmation code'
end
scenario 'Deny access unless residency verified' do
user = create(:user)
login_as(user)
visit new_sms_path
expect(page).to have_content 'You have not yet confirmed your residence'
expect(URI.parse(current_url).path).to eq(new_residence_path)
end
scenario '3 tries allowed' do
user = create(:user, residence_verified_at: Time.now)
login_as(user)
visit new_sms_path
3.times do
fill_in 'sms_phone', with: "611111111"
click_button 'Send'
click_link 'Click here to send the confirmation code again'
end
expect(page).to have_content 'You have reached the maximum number of sms verification tries'
expect(URI.parse(current_url).path).to eq(account_path)
visit new_sms_path
expect(page).to have_content 'You have reached the maximum number of sms verification tries'
expect(URI.parse(current_url).path).to eq(account_path)
end
end

View File

@@ -0,0 +1,132 @@
require 'rails_helper'
feature 'Verified users' do
scenario "Verified emails" do
user = create(:user,
residence_verified_at: Time.now,
document_number: '12345678Z',
document_type: '2')
create(:verified_user,
document_number: '12345678Z',
document_type: '2',
email: 'rock@example.com')
create(:verified_user,
document_number: '12345678Z',
document_type: '2',
email: 'roll@example.com')
create(:verified_user,
document_number: '99999999R',
document_type: '2',
email: 'another@example.com')
login_as(user)
visit verified_user_path
expect(page).to have_content 'rock@example.com'
expect(page).to have_content 'roll@example.com'
end
scenario "Verified phones" do
user = create(:user,
residence_verified_at: Time.now,
document_number: '12345678Z',
document_type: '2')
create(:verified_user,
document_number: '12345678Z',
document_type: '2',
phone: '611111111')
create(:verified_user,
document_number: '12345678Z',
document_type: '2',
email: '622222222')
create(:verified_user,
document_number: '99999999R',
document_type: '2',
email: '633333333')
login_as(user)
visit verified_user_path
expect(page).to have_content '611111111'
expect(page).to have_content '622222222'
end
scenario "Select a verified email" do
user = create(:user,
residence_verified_at: Time.now,
document_number: '12345678Z',
document_type: '2')
verified_user = create(:verified_user,
document_number: '12345678Z',
document_type: '2',
email: 'rock@example.com')
login_as(user)
visit verified_user_path
within("#verified_user_#{verified_user.id}_email") do
click_button "Send"
end
expect(page).to have_content 'We have send you a confirmation email to your email account: rock@example.com'
expect(URI.parse(current_url).path).to eq(account_path)
end
scenario "Select a verified phone" do
user = create(:user,
residence_verified_at: Time.now,
document_number: '12345678Z',
document_type: '2')
verified_user = create(:verified_user,
document_number: '12345678Z',
document_type: '2',
phone: '611111111')
login_as(user)
visit verified_user_path
within("#verified_user_#{verified_user.id}_phone") do
click_button "Send"
end
expect(page).to have_content 'Enter the confirmation code'
end
scenario "Continue without selecting any verified information" do
user = create(:user,
residence_verified_at: Time.now,
document_number: '12345678Z',
document_type: '2')
create(:verified_user,
document_number: '12345678Z',
document_type: '2',
phone: '611111111')
login_as(user)
visit verified_user_path
click_link "Use another phone"
expect(URI.parse(current_url).path).to eq(new_sms_path)
end
scenario "No verified information" do
user = create(:user, residence_verified_at: Time.now)
login_as(user)
visit verified_user_path
expect(URI.parse(current_url).path).to eq(new_sms_path)
end
end

View File

@@ -0,0 +1,59 @@
require 'rails_helper'
describe 'Letter' do
let(:user) { create(:user) }
describe "validations" do
let(:letter) { build(:letter) }
it "should be valid" do
expect(letter).to be_valid
end
it "should not be valid without a user" do
letter.user = nil
expect(letter).to_not be_valid
end
it "should not be valid without an address" do
letter.address = {}
expect(letter).to_not be_valid
end
end
describe "save" do
before(:each) do
letter = Letter.new(user: user)
letter.save
user.reload
end
it "should update letter_requested" do
expect(user.letter_requested_at).to be
end
it "should update address" do
expect(user.address).to have_attributes({
postal_code: "28013",
street: "ALCALÁ",
street_type: "CALLE",
number: "1",
number_type: "NUM",
letter: "B",
portal: "1",
stairway: "4",
floor: "PB",
door: "DR",
km: "0",
neighbourhood: "JUSTICIA",
district: "CENTRO"
})
end
end
end

View File

@@ -0,0 +1,52 @@
require 'rails_helper'
describe Residence do
let(:residence) { build(:residence) }
describe "validations" do
it "should be valid" do
expect(residence).to be_valid
end
describe "dates" do
it "should be valid with a valid date of birth" do
residence = Residence.new({"date_of_birth(3i)"=>"1", "date_of_birth(2i)"=>"1", "date_of_birth(1i)"=>"1980"})
expect(residence.errors[:date_of_birth].size).to eq(0)
end
it "should not be valid without a date of birth" do
residence = Residence.new({"date_of_birth(3i)"=>"", "date_of_birth(2i)"=>"", "date_of_birth(1i)"=>""})
residence.valid?
expect(residence.errors[:date_of_birth]).to include("can't be blank")
end
end
it "should validate uniquness of document_number" do
user = create(:user)
residence.user = user
residence.save
residence2 = build(:residence)
residence.valid?
expect(residence.errors[:document_number]).to include("Already in use")
end
end
describe "save" do
it "should store document number and type" do
user = create(:user)
residence.user = user
residence.save
user.reload
expect(user.document_number).to eq('12345678Z')
expect(user.document_type).to eq("1")
end
end
end

15
spec/models/sms_spec.rb Normal file
View File

@@ -0,0 +1,15 @@
require 'rails_helper'
describe Sms do
it "should be valid" do
sms = build(:sms)
expect(sms).to be_valid
end
it "should validate uniqness of phone" do
user = create(:user, confirmed_phone: "699999999")
sms = Sms.new(phone: "699999999")
expect(sms).to_not be_valid
end
end

View File

@@ -80,4 +80,12 @@ module CommonActions
def expect_to_be_signed_in
expect(find('.top-bar')).to have_content 'My account'
end
def select_date(values, selector)
selector = selector[:from]
day, month, year = values.split("-")
select day, from: "#{selector}_3i"
select month, from: "#{selector}_2i"
select year, from: "#{selector}_1i"
end
end