Skip to content

Commit

Permalink
[Zipcode] Validation à la création d'un User ou d'un Partner (#597)
Browse files Browse the repository at this point in the history
* Validates address zipcode on create context only for User and Partner

* UI for admin campaigns

* campaigns admin fill rates

* Validates address zipcode on create context only for User and Partner

* Fix rebase conflict

Co-authored-by: Mathieu Ripert <[email protected]>
  • Loading branch information
navidemad and mathieuripert authored Apr 30, 2021
1 parent 44463c3 commit 8b7581e
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 22 deletions.
3 changes: 3 additions & 0 deletions app/assets/stylesheets/components/fields/_text.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.is-invalid.ap-input#user_address ~ .ap-input-icon {
right: 34px !important;
}
11 changes: 5 additions & 6 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,17 @@ def update

def create
@user = User.new(user_params)
@user.address = params[:user][:address]
@user.ensure_lat_lon(params[:user][:address]) # fallback in case lat/lon are not returning from client
@user.ensure_lat_lon # fallback in case lat/lon are not returning from client
@user.statement_accepted_at = Time.zone.now if @user.statement
@user.toc_accepted_at = Time.zone.now if @user.toc
authorize @user
@user.save
set_counters
prepare_phone_number
render action: :new
rescue ActiveRecord::RecordNotUnique
render action: :new, status: :ok
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
flash.now[:error] = "Une erreur s’est produite."
render action: :new
render action: :new, status: :unprocessable_entity
end

def delete
Expand All @@ -78,7 +77,7 @@ def prepare_phone_number
end

def user_params
params.require(:user).permit(:email, :phone_number, :toc, :lat, :lon, :birthdate, :password, :statement)
params.require(:user).permit(:email, :phone_number, :toc, :address, :lat, :lon, :birthdate, :password, :statement)
end

def sign_out_if_anonymized!
Expand Down
3 changes: 2 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class User < ApplicationRecord

blind_index :email

validates :address, presence: true, postal_address: {with_zipcode: true}, on: :create
validates :lat, presence: true, unless: proc { |u| u.persisted? }
validates :lon, presence: true, unless: proc { |u| u.persisted? }
validates :birthdate, presence: true
Expand Down Expand Up @@ -60,7 +61,7 @@ def extract_email_domain
end
end

def ensure_lat_lon(address)
def ensure_lat_lon
return unless lat.nil? || lon.nil?
return if address.blank?
results = GeocodingService.new(address).call
Expand Down
1 change: 1 addition & 0 deletions app/models/vaccination_center.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module Kinds
validates :name, :address, :phone_number, presence: true
validates :lat, :lon, presence: true, on: :validation_by_admin
validates :kind, inclusion: {in: VaccinationCenter::Kinds::ALL}
validates :address, postal_address: {with_zipcode: true}, on: :create

has_many :partner_vaccination_centers
has_many :partners, through: :partner_vaccination_centers
Expand Down
26 changes: 26 additions & 0 deletions app/validators/postal_address_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class PostalAddressValidator < ActiveModel::EachValidator
REGEX_ZIPCODE = %r{
\d{2}[ ]?\d{3} # France
|
973\d{2} # Guyane
|
9[78][01]\d{2} # Guadeloupe
|
9[78]4\d{2} # La Réunion
|
9[78]2\d{2} # Martinique
|
976\d{2} # Mayotte
}x

def initialize(options)
@with_zipcode = !options[:with_zipcode].nil? ? options[:with_zipcode] : true
super
end

def validate_each(record, attribute, value)
unless @with_zipcode.nil? || value.match?(REGEX_ZIPCODE)
record.errors.add(attribute, (options[:message] || I18n.t("errors.messages.missing_zipcode")))
end
end
end
9 changes: 4 additions & 5 deletions app/views/users/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@
input_html: {autocomplete: "email", autofocus: "true"} %>

<%= f.input :address,
label: false,
error: "Adresse invalide",
placeholder: "Adresse",
required: true,
input_html: {class: "pr-5"} %>
label: "Adresse",
error: "Adresse complète requise",
placeholder: "5 rue Larue, 13600 Marseille",
required: true %>
<%= f.input_field :lat, as: :hidden %>
<%= f.input_field :lon, as: :hidden %>

Expand Down
1 change: 1 addition & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ fr:
errors:
format: "%{attribute} %{message}"
messages:
missing_zipcode: doit comporter un code postal
accepted: doit être accepté(e)
blank: doit être rempli(e)
confirmation: ne concorde pas avec %{attribute}
Expand Down
2 changes: 1 addition & 1 deletion spec/factories/sequence_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
sequence(:company_name) { Faker::Company.name }
sequence(:description) { Faker::Lorem.paragraph(sentence_count: 2) }
sequence(:firstname) { Faker::Name.first_name }
sequence(:french_address) { Faker::Address.country_by_code(code: "FR") }
sequence(:french_address) { "#{Faker::Address.full_address} #{Faker::Address.country_by_code(code: "FR")}" }
sequence(:lastname) { Faker::Name.last_name }
sequence(:lat) { Faker::Address.latitude }
sequence(:lon) { Faker::Address.longitude }
Expand Down
4 changes: 2 additions & 2 deletions spec/factories/user_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
toc { true }

trait :from_lyon do
address { "21 Rue Bergère 75009 Paris" }
address { "21 Rue Bergère 75009 Paris France" }
lat { "48.87242501471677" }
lon { "2.344941896580627" }
end

trait :from_paris do
address { "7 Rue Auguste Comte 69002 Lyon" }
address { "7 Rue Auguste Comte 69002 Lyon France" }
lat { "45.75620064462772" }
lon { "4.8319385046869945" }
end
Expand Down
32 changes: 30 additions & 2 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
expect(user).to be_valid
end

it "is invalid without a first_name" do
it "is valid without a first_name" do
user.firstname = nil
expect(user).to be_valid
end

it "is invalid without a last_name" do
it "is valid without a last_name" do
user.lastname = nil
expect(user).to be_valid
end
Expand All @@ -32,6 +32,34 @@
user.email = nil
expect(user).to_not be_valid
end

context "when the user has incomplete address without zipcode" do
context "on persistent context" do
it "is always valid" do
persistent_user = create(:user)
persistent_user.address = "21 Rue Bergère"
expect(persistent_user).to be_valid
persistent_user.address = "21 Rue Bergère 75009 Paris"
expect(persistent_user).to be_valid
end
end
context "on new context" do
it "is valid" do
user.address = generate(:french_address)
expect(user).to be_valid
user.address = "21 Rue Bergère 75009 Paris"
expect(user).to be_valid
end
it "is invalid" do
user.address = "21 Rue Bergère Paris"
expect(user).not_to be_valid
expect(user.errors[:address]).to include(I18n.t("errors.messages.missing_zipcode"))
user.address = "21 Rue Bergère Paris France"
expect(user).not_to be_valid
expect(user.errors[:address]).to include(I18n.t("errors.messages.missing_zipcode"))
end
end
end
end

describe "latitude/lontidude" do
Expand Down
41 changes: 36 additions & 5 deletions spec/models/vaccination_center_spec.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
require "rails_helper"

RSpec.describe VaccinationCenter, type: :model do
let(:vaccination_center) { create(:vaccination_center, lat: 42, lon: 2) }
let(:vaccination_center) { build(:vaccination_center, :from_paris) }

describe "validations" do
context "when vaccination center has no lat neither lon" do
subject { build(:vaccination_center, lat: nil, lon: nil) }

context "on default context" do
it "is valid" do
expect(subject.valid?).to be true
vaccination_center.lat = nil
vaccination_center.lon = nil
expect(vaccination_center).to be_valid
end
end
context "on validation_by_admin context" do
it "is invalid" do
expect(subject.invalid?(:validation_by_admin)).to be true
vaccination_center.lat = nil
vaccination_center.lon = nil
expect(vaccination_center.invalid?(:validation_by_admin)).to be true
end
end
end

context "when the user has incomplete address without zipcode" do
context "on persistent context" do
it "is always valid" do
persistent_vaccination_center = create(:vaccination_center)
persistent_vaccination_center.address = "21 Rue Bergère"
expect(persistent_vaccination_center).to be_valid
persistent_vaccination_center.address = "21 Rue Bergère 75009 Paris"
expect(persistent_vaccination_center).to be_valid
end
end
context "on new context" do
it "is valid" do
vaccination_center.address = generate(:french_address)
expect(vaccination_center).to be_valid
vaccination_center.address = "21 Rue Bergère 75009 Paris"
expect(vaccination_center).to be_valid
end
it "is invalid" do
vaccination_center.address = "21 Rue Bergère Paris"
expect(vaccination_center).not_to be_valid
expect(vaccination_center.errors[:address]).to include(I18n.t("errors.messages.missing_zipcode"))
vaccination_center.address = "21 Rue Bergère Paris France"
expect(vaccination_center).not_to be_valid
expect(vaccination_center.errors[:address]).to include(I18n.t("errors.messages.missing_zipcode"))
end
end
end
Expand Down
13 changes: 13 additions & 0 deletions spec/system/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ def signup_submit
end.to change { User.count }.by(1)
end

it "rejects sign up if address has no zipcode valid" do
user.save!

expect do
visit "/"
fill_valid_user
fill_in :user_address, with: "5 rue Larue, Marseille" # no zipcode
signup_submit
end.not_to change { User.count }

expect(page).to have_text("doit comporter un code postal")
end

it "rejects sign up if email is not unique" do
user.save!

Expand Down
35 changes: 35 additions & 0 deletions spec/validators/postal_address_validator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require "rails_helper"

RSpec.describe PostalAddressValidator do
subject do
Class.new do
include ActiveModel::Validations
attr_accessor :address
validates :address, postal_address: {with_zipcode: true, message: "invalid_message"}
end.new
end

context "when the postal address is valid" do
let(:address) { generate(:french_address) }

it "allows the input" do
subject.address = address
expect(subject).to be_valid
end
end

context "when the postal address is invalid" do
let(:invalid_message) { "invalid_message" }

it "invalidates the input" do
subject.address = "21 Rue Bergère"
expect(subject).not_to be_valid
end

it "alerts the consumer" do
subject.address = "address"
subject.valid?
expect(subject.errors[:address]).to include(invalid_message)
end
end
end

0 comments on commit 8b7581e

Please sign in to comment.