Merge branch 'dev'
This commit is contained in:
commit
c24c542cb0
19 changed files with 167 additions and 133 deletions
|
@ -74,11 +74,13 @@ jobs:
|
|||
DATABASE_URL: "postgres://tps_test@localhost:5432/tps_test"
|
||||
name: Run Tests, Splitted by Timings
|
||||
command: |
|
||||
bundle exec rspec --profile 10 \
|
||||
COMMAND="bundle exec rspec --profile 10 \
|
||||
--format RspecJunitFormatter \
|
||||
--out ~/test_results/rspec.xml \
|
||||
--format progress \
|
||||
$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
|
||||
$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
|
||||
echo $COMMAND
|
||||
eval $COMMAND
|
||||
- store_test_results:
|
||||
path: ~/test_results/rspec.xml
|
||||
lint:
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
.close-icon {
|
||||
vertical-align: top;
|
||||
margin-top: 12px;
|
||||
margin-left: 6px;
|
||||
margin-right: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
class InvitesController < ApplicationController
|
||||
before_action :ensure_user_signed_in
|
||||
SESSION_USER_RETURN_LOCATION = 'user_return_to'
|
||||
|
||||
before_action :authenticate_user!, only: [:create]
|
||||
before_action :store_user_location!, only: [:show]
|
||||
|
||||
def create
|
||||
email = params[:invite_email].downcase
|
||||
|
@ -30,11 +33,35 @@ class InvitesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def show
|
||||
if user_signed_in?
|
||||
erase_user_location!
|
||||
|
||||
dossier = Dossier.joins(:invites)
|
||||
.find_by!(invites: { email: current_user.email, id: params[:id] })
|
||||
|
||||
if dossier.brouillon?
|
||||
redirect_to brouillon_dossier_path(dossier)
|
||||
else
|
||||
redirect_to dossier_path(dossier)
|
||||
end
|
||||
elsif params[:email].present? && !User.find_by(email: params[:email])
|
||||
redirect_to new_user_registration_path(user: { email: params[:email] })
|
||||
else
|
||||
authenticate_user!
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
flash.alert = t('errors.messages.dossier_not_found')
|
||||
redirect_to dossiers_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_user_signed_in
|
||||
if !user_signed_in?
|
||||
return redirect_to root_path
|
||||
end
|
||||
def store_user_location!
|
||||
store_location_for(:user, request.fullpath)
|
||||
end
|
||||
|
||||
def erase_user_location!
|
||||
session.delete(SESSION_USER_RETURN_LOCATION)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
class Users::Dossiers::InvitesController < UsersController
|
||||
def authenticate_user!
|
||||
session["user_return_to"] = request.fullpath
|
||||
email = params[:email]
|
||||
|
||||
if email.present? && User.find_by(email: email).nil?
|
||||
redirect_to new_user_registration_path(user: { email: email })
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
invite = Invite.where(email: current_user.email, id: params[:id].to_i).first!
|
||||
dossier = invite.dossier
|
||||
|
||||
if dossier.brouillon?
|
||||
redirect_to brouillon_dossier_path(dossier)
|
||||
else
|
||||
redirect_to dossier_path(dossier)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
flash.alert = t('errors.messages.dossier_not_found')
|
||||
redirect_to url_for dossiers_path
|
||||
end
|
||||
end
|
|
@ -426,6 +426,7 @@ class Procedure < ApplicationRecord
|
|||
def percentile_time(start_attribute, end_attribute, p)
|
||||
times = dossiers
|
||||
.state_termine
|
||||
.where(end_attribute => 1.month.ago..DateTime.current)
|
||||
.pluck(start_attribute, end_attribute)
|
||||
.map { |(start_date, end_date)| end_date - start_date }
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
end
|
||||
|
||||
%table#features
|
||||
- Flipflop.feature_set.features.each do |feature|
|
||||
- if !feature.group || feature.group.key != :production
|
||||
%tr
|
||||
%td= feature.title
|
||||
%td
|
||||
= check_box_tag "enable-feature", "enable", field.data[feature.name], data: { url: url, key: feature.key }
|
||||
- admin_features = Flipflop.feature_set.features.reject{ |f| f.group.try(:key) == :production }
|
||||
- admin_features.each do |feature|
|
||||
%tr
|
||||
%td= feature.title
|
||||
%td
|
||||
= check_box_tag "enable-feature", "enable", field.data[feature.name], data: { url: url, key: feature.key }
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
Afin de répondre à cette invitation, merci de vous inscrire avec l'adresse email
|
||||
= @invite.email
|
||||
sur
|
||||
= users_dossiers_invite_url(@invite.id, params: { email: @invite.email })
|
||||
= invite_url(@invite, params: { email: @invite.email })
|
||||
|
||||
%p
|
||||
Bonne journée,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
%p
|
||||
Pour le consulter, merci de suivre ce lien :
|
||||
= users_dossiers_invite_url(@invite.id)
|
||||
= invite_url(@invite)
|
||||
|
||||
%p
|
||||
Bonne journée,
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
%p Vous pouvez inviter quelqu’un à remplir ce dossier avec vous.
|
||||
%p Cette personne aura le droit de modifier votre dossier.
|
||||
|
||||
= form_tag invites_dossier_path(dossier_id: dossier.id), remote: true, method: :post, class: 'form' do
|
||||
= form_tag dossier_invites_path(dossier), remote: true, method: :post, class: 'form' do
|
||||
= email_field_tag :invite_email, '', class: 'small', placeholder: 'adresse email', required: true
|
||||
= submit_tag 'Envoyer une invitation', class: 'button accepted'
|
||||
|
|
|
@ -59,10 +59,9 @@
|
|||
|
||||
- @current_filters.each do |filter|
|
||||
%span.filter
|
||||
= "#{filter['label']} : #{filter['value']}"
|
||||
= link_to remove_filter_gestionnaire_procedure_path(@procedure, statut: @statut, table: filter['table'], column: filter['column']) do
|
||||
%img.close-icon{ src: image_url("close.svg") }
|
||||
|
||||
= "#{filter['label'].truncate(50)} : #{filter['value']}"
|
||||
%table.table.dossiers-table.hoverable
|
||||
%thead
|
||||
%tr
|
||||
|
|
|
@ -27,8 +27,7 @@ Flipflop.configure do
|
|||
default: ENV['FOG_ENABLED'] == 'enabled'
|
||||
feature :weekly_overview,
|
||||
default: ENV['APP_NAME'] == 'tps'
|
||||
feature :pre_maintenance_mode
|
||||
feature :maintenance_mode
|
||||
end
|
||||
|
||||
feature :pre_maintenance_mode
|
||||
feature :maintenance_mode
|
||||
end
|
||||
|
|
6
config/locales/models/gestionnaire/fr.yml
Normal file
6
config/locales/models/gestionnaire/fr.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
fr:
|
||||
activerecord:
|
||||
models:
|
||||
gestionnaire:
|
||||
one: Instructeur
|
||||
other: Instructeurs
|
|
@ -1,5 +1,9 @@
|
|||
fr:
|
||||
activerecord:
|
||||
models:
|
||||
procedure:
|
||||
one: Démarche
|
||||
other: Démarches
|
||||
attributes:
|
||||
procedure:
|
||||
path: Lien public
|
||||
|
|
|
@ -144,10 +144,6 @@ Rails.application.routes.draw do
|
|||
#
|
||||
|
||||
namespace :users do
|
||||
namespace :dossiers do
|
||||
resources :invites, only: [:index, :show]
|
||||
end
|
||||
|
||||
resources :dossiers, only: [] do
|
||||
post '/carte/zones' => 'carte#zones'
|
||||
get '/carte' => 'carte#show'
|
||||
|
@ -159,6 +155,7 @@ Rails.application.routes.draw do
|
|||
# Redirection of legacy "/users/dossiers" route to "/dossiers"
|
||||
get 'dossiers', to: redirect('/dossiers')
|
||||
get 'dossiers/:id/recapitulatif', to: redirect('/dossiers/%{id}')
|
||||
get 'dossiers/invites/:id', to: redirect(path: '/invites/%{id}')
|
||||
end
|
||||
|
||||
namespace :gestionnaire do
|
||||
|
@ -241,8 +238,10 @@ Rails.application.routes.draw do
|
|||
get 'address/suggestions' => 'address#suggestions'
|
||||
get 'address/geocode' => 'address#geocode'
|
||||
|
||||
namespace :invites do
|
||||
post 'dossier/:dossier_id' => '/invites#create', as: 'dossier'
|
||||
resources :invites, only: [:show] do
|
||||
collection do
|
||||
post 'dossier/:dossier_id', to: 'invites#create', as: :dossier
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -158,4 +158,81 @@ describe InvitesController, type: :controller do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#GET show' do
|
||||
let(:user) { create :user }
|
||||
|
||||
context "when invite without email exists" do
|
||||
let(:invite) { create(:invite, dossier: dossier) }
|
||||
|
||||
subject { get :show, params: { id: invite.id, email: email } }
|
||||
|
||||
context 'when email is not set' do
|
||||
let(:email) { nil }
|
||||
|
||||
context 'and user is not connected' do
|
||||
it { is_expected.to redirect_to new_user_session_path }
|
||||
end
|
||||
|
||||
context 'and user is connected' do
|
||||
let(:invite) { create :invite, dossier: dossier, user: user }
|
||||
|
||||
before { sign_in user }
|
||||
|
||||
it { is_expected.to redirect_to(dossier_path(dossier)) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when email is blank' do
|
||||
let(:email) { '' }
|
||||
|
||||
it { is_expected.to redirect_to new_user_session_path }
|
||||
end
|
||||
|
||||
context 'when email is not blank' do
|
||||
context 'when email is affected at an user' do
|
||||
let(:email) { user.email }
|
||||
|
||||
it { is_expected.to redirect_to new_user_session_path }
|
||||
end
|
||||
|
||||
context 'when email is not affected at an user' do
|
||||
let(:email) { 'new_user@octo.com' }
|
||||
|
||||
it { is_expected.to redirect_to new_user_registration_path(user: { email: email }) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when invite with email exists" do
|
||||
let(:invite) { create :invite, email: email, dossier: dossier }
|
||||
|
||||
before do
|
||||
sign_in user
|
||||
end
|
||||
|
||||
subject! { get :show, params: { id: invite.id } }
|
||||
|
||||
context 'when invitation ID is attached at the user email account' do
|
||||
let(:email) { user.email }
|
||||
|
||||
context 'and dossier is a brouillon' do
|
||||
let(:dossier) { create :dossier, state: Dossier.states.fetch(:brouillon) }
|
||||
it { is_expected.to redirect_to brouillon_dossier_path(dossier) }
|
||||
end
|
||||
|
||||
context 'and dossier is not a brouillon' do
|
||||
let(:dossier) { create :dossier, :en_construction }
|
||||
it { is_expected.to redirect_to(dossier_path(dossier)) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when invitation ID is not attached at the user email account' do
|
||||
let(:email) { 'fake@email.com' }
|
||||
|
||||
it { is_expected.to redirect_to dossiers_path }
|
||||
it { expect(flash[:alert]).to be_present }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
describe Users::Dossiers::InvitesController, type: :controller do
|
||||
describe '#authenticate_user!' do
|
||||
let(:user) { create :user }
|
||||
let(:dossier) { create(:dossier, :en_construction) }
|
||||
let(:invite) { create(:invite, dossier: dossier) }
|
||||
|
||||
subject { get :show, params: { id: invite.id, email: email } }
|
||||
|
||||
context 'when email is not set' do
|
||||
let(:email) { nil }
|
||||
|
||||
context 'and user is not connected' do
|
||||
it { is_expected.to redirect_to new_user_session_path }
|
||||
end
|
||||
|
||||
context 'and user is connected' do
|
||||
let(:invite) { create :invite, dossier: dossier, user: user }
|
||||
before { sign_in invite.user }
|
||||
it { is_expected.to redirect_to(dossier_path(dossier)) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when email is blank' do
|
||||
let(:email) { '' }
|
||||
it { is_expected.to redirect_to new_user_session_path }
|
||||
end
|
||||
|
||||
context 'when email is not blank' do
|
||||
context 'when email is affected at an user' do
|
||||
let(:email) { user.email }
|
||||
it { is_expected.to redirect_to new_user_session_path }
|
||||
end
|
||||
|
||||
context 'when email is not affected at an user' do
|
||||
let(:email) { 'new_user@octo.com' }
|
||||
it { is_expected.to redirect_to new_user_registration_path(user: { email: email }) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#GET show' do
|
||||
let(:user) { create :user }
|
||||
let(:dossier) { create :dossier }
|
||||
let(:invite) { create :invite, email: email, dossier: dossier }
|
||||
|
||||
before do
|
||||
sign_in user
|
||||
end
|
||||
|
||||
subject! { get :show, params: { id: invite.id } }
|
||||
|
||||
context 'when invitation ID is attached at the user email account' do
|
||||
let(:email) { user.email }
|
||||
|
||||
context 'and dossier is a brouillon' do
|
||||
let(:dossier) { create :dossier, state: Dossier.states.fetch(:brouillon) }
|
||||
it { is_expected.to redirect_to brouillon_dossier_path(dossier) }
|
||||
end
|
||||
|
||||
context 'and dossier is not a brouillon' do
|
||||
let(:dossier) { create :dossier, :en_construction }
|
||||
it { is_expected.to redirect_to(dossier_path(dossier)) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when invitation ID is not attached at the user email account' do
|
||||
let(:email) { 'fake@email.com' }
|
||||
it { is_expected.to redirect_to dossiers_path }
|
||||
it { expect(flash[:alert]).to be_present }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -31,7 +31,7 @@ feature 'Invitations' do
|
|||
|
||||
scenario 'an invited user can register using the registration link sent in the invitation email' do
|
||||
# Click the invitation link
|
||||
visit users_dossiers_invite_path(invite.id, params: { email: invite.email })
|
||||
visit invite_path(invite, params: { email: invite.email })
|
||||
expect(page).to have_current_path(new_user_registration_path, ignore_query: true)
|
||||
expect(page).to have_field('user_email', with: invite.email)
|
||||
|
||||
|
@ -115,7 +115,7 @@ feature 'Invitations' do
|
|||
end
|
||||
|
||||
def navigate_to_invited_dossier(invite)
|
||||
visit users_dossiers_invite_path(invite)
|
||||
visit invite_path(invite)
|
||||
expect(page).to have_current_path(new_user_session_path)
|
||||
sign_in_with(invited_user.email, invited_user.password)
|
||||
end
|
||||
|
|
|
@ -626,6 +626,7 @@ describe Procedure do
|
|||
|
||||
describe "#export_filename" do
|
||||
before { Timecop.freeze(Time.zone.local(2018, 1, 2, 23, 11, 14)) }
|
||||
after { Timecop.return }
|
||||
|
||||
subject { procedure.export_filename }
|
||||
|
||||
|
@ -708,12 +709,14 @@ describe Procedure do
|
|||
describe '#usual_instruction_time' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
|
||||
def create_dossier(instruction_date:, processed_date:)
|
||||
dossier = create(:dossier, :accepte, procedure: procedure)
|
||||
dossier.update!(en_instruction_at: instruction_date, processed_at: processed_date)
|
||||
end
|
||||
|
||||
before do
|
||||
processed_delays.each do |delay|
|
||||
dossier = create :dossier, :accepte, procedure: procedure
|
||||
instruction_date = 1.month.ago
|
||||
processed_date = instruction_date + delay
|
||||
dossier.update!(en_instruction_at: instruction_date, processed_at: processed_date)
|
||||
create_dossier(instruction_date: 1.week.ago - delay, processed_date: 1.week.ago)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -725,9 +728,18 @@ describe Procedure do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when there are very old dossiers' do
|
||||
let(:processed_delays) { [2.days, 2.days] }
|
||||
let!(:old_dossier) { create_dossier(instruction_date: 3.months.ago, processed_date: 2.months.ago) }
|
||||
|
||||
it 'ignores dossiers older than 1 month' do
|
||||
expect(procedure.usual_instruction_time).to be_within(10.seconds).of(2.days)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is only one processed dossier' do
|
||||
let(:processed_delays) { [1.day] }
|
||||
it { expect(procedure.usual_instruction_time).to eq(1.day) }
|
||||
it { expect(procedure.usual_instruction_time).to be_within(10.seconds).of(1.day) }
|
||||
end
|
||||
|
||||
context 'where there is no processed dossier' do
|
||||
|
|
|
@ -81,6 +81,7 @@ end
|
|||
DatabaseCleaner.strategy = :transaction
|
||||
|
||||
TPS::Application.load_tasks
|
||||
Rake.application.options.trace = false
|
||||
|
||||
include Warden::Test::Helpers
|
||||
|
||||
|
@ -103,6 +104,11 @@ RSpec.configure do |config|
|
|||
config.infer_spec_type_from_file_location!
|
||||
config.tty = true
|
||||
|
||||
# Since rspec 3.8.0, bisect uses fork to improve bisection speed.
|
||||
# This however fails as soon as we're running feature tests (which uses many processes).
|
||||
# Default to the :shell bisect runner, so that bisecting over feature tests works.
|
||||
config.bisect_runner = :shell
|
||||
|
||||
config.include Shoulda::Matchers::ActiveRecord, type: :model
|
||||
config.include Shoulda::Matchers::ActiveModel, type: :model
|
||||
config.include Shoulda::Matchers::Independent, type: :model
|
||||
|
|
Loading…
Reference in a new issue