commit
3563aa10ab
26 changed files with 344 additions and 133 deletions
|
@ -13,7 +13,10 @@ defaults: &defaults
|
|||
bundle_restore_cache: &bundle_restore_cache
|
||||
restore_cache:
|
||||
name: Restore Bundler Package Cache
|
||||
key: bundle-install-v9-{{ arch }}-{{ checksum "Gemfile.lock" }}
|
||||
keys:
|
||||
- bundle-install-v9-{{ arch }}-{{ checksum "Gemfile.lock" }}
|
||||
- bundle-install-v9-{{ arch }}
|
||||
- bundle-install-v9
|
||||
|
||||
bundle_save_cache: &bundle_save_cache
|
||||
save_cache:
|
||||
|
@ -30,19 +33,45 @@ bundle_install: &bundle_install
|
|||
yarn_restore_cache: &yarn_restore_cache
|
||||
restore_cache:
|
||||
name: Restore Yarn Package Cache
|
||||
key: yarn-install-v1-{{ arch }}-{{ checksum "yarn.lock" }}
|
||||
keys:
|
||||
- yarn-install-v3-{{ arch }}-{{ checksum "yarn.lock" }}
|
||||
- yarn-install-v3-{{ arch }}
|
||||
- yarn-install-v3
|
||||
|
||||
yarn_save_cache: &yarn_save_cache
|
||||
save_cache:
|
||||
name: Save Yarn Package Cache
|
||||
key: yarn-install-v1-{{ arch }}-{{ checksum "yarn.lock" }}
|
||||
key: yarn-install-v3-{{ arch }}-{{ checksum "yarn.lock" }}
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
|
||||
yarn_install: &yarn_install
|
||||
run:
|
||||
name: Install JS Dependencies
|
||||
command: yarn install --non-interactive || yarn install --non-interactive
|
||||
command: yarn install --frozen-lockfile --non-interactive || yarn install --frozen-lockfile --non-interactive
|
||||
|
||||
webpacker_restore_cache: &webpacker_restore_cache
|
||||
restore_cache:
|
||||
name: Restore Webpacker Cache
|
||||
keys:
|
||||
- webpacker-v1-{{ .Branch }}-{{ .Revision }}
|
||||
- webpacker-v1-{{ .Branch }}
|
||||
- webpacker-v1
|
||||
|
||||
webpacker_save_cache: &webpacker_save_cache
|
||||
save_cache:
|
||||
name: Save Webpacker Cache
|
||||
key: webpacker-v1-{{ .Branch }}-{{ .Revision }}
|
||||
paths:
|
||||
- public/packs-test
|
||||
- tmp/cache/webpacker
|
||||
|
||||
webpacker_precompile: &webpacker_precompile
|
||||
run:
|
||||
environment:
|
||||
RAILS_ENV: test
|
||||
name: Precompile Webpack assets
|
||||
command: bin/webpack
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -53,8 +82,8 @@ jobs:
|
|||
- *bundle_install
|
||||
- *bundle_save_cache
|
||||
- *yarn_restore_cache
|
||||
- *yarn_save_cache
|
||||
- *yarn_install
|
||||
- *yarn_save_cache
|
||||
test:
|
||||
<<: *defaults
|
||||
parallelism: 3
|
||||
|
@ -64,16 +93,15 @@ jobs:
|
|||
- *bundle_install
|
||||
- *yarn_restore_cache
|
||||
- *yarn_install
|
||||
- *webpacker_restore_cache
|
||||
- *webpacker_precompile
|
||||
- *webpacker_save_cache
|
||||
- run:
|
||||
environment:
|
||||
DATABASE_URL: "postgres://tps_test@localhost:5432/tps_test"
|
||||
name: Create DB
|
||||
name: Create Database
|
||||
command: bundle exec rake db:create db:schema:load db:migrate RAILS_ENV=test
|
||||
- run:
|
||||
environment:
|
||||
RAILS_ENV: test
|
||||
name: Precompile Webpack assets
|
||||
command: bin/webpack
|
||||
|
||||
- run:
|
||||
environment:
|
||||
DATABASE_URL: "postgres://tps_test@localhost:5432/tps_test"
|
||||
|
|
8
.github/workflows/rebase.yml
vendored
8
.github/workflows/rebase.yml
vendored
|
@ -1,7 +1,7 @@
|
|||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
name: Rebase automatique
|
||||
name: Automatic Rebase
|
||||
jobs:
|
||||
rebase:
|
||||
name: Rebase
|
||||
|
@ -9,13 +9,15 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Automatic Rebase
|
||||
uses: cirrus-actions/rebase@master
|
||||
uses: cirrus-actions/rebase@1.2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250
|
||||
always_job:
|
||||
name: Aways run job
|
||||
name: Always run job
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Always run
|
||||
|
|
58
Gemfile.lock
58
Gemfile.lock
|
@ -117,7 +117,7 @@ GEM
|
|||
railties (>= 3.0)
|
||||
brakeman (4.3.1)
|
||||
browser (2.5.3)
|
||||
builder (3.2.3)
|
||||
builder (3.2.4)
|
||||
byebug (10.0.2)
|
||||
capybara (3.29.0)
|
||||
addressable
|
||||
|
@ -155,7 +155,7 @@ GEM
|
|||
connection_pool (2.2.2)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
crass (1.0.5)
|
||||
crass (1.0.6)
|
||||
css_parser (1.6.0)
|
||||
addressable
|
||||
curb (0.9.10)
|
||||
|
@ -242,7 +242,7 @@ GEM
|
|||
graphiql-rails (1.7.0)
|
||||
railties
|
||||
sprockets-rails
|
||||
graphql (1.9.15)
|
||||
graphql (1.9.16)
|
||||
graphql-batch (0.4.1)
|
||||
graphql (>= 1.3, < 2)
|
||||
promise.rb (~> 0.7.2)
|
||||
|
@ -305,7 +305,7 @@ GEM
|
|||
domain_name (~> 0.5)
|
||||
http_parser.rb (0.6.0)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.7.0)
|
||||
i18n (1.8.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
ipaddress (0.8.3)
|
||||
jaro_winkler (1.5.2)
|
||||
|
@ -350,7 +350,7 @@ GEM
|
|||
railties (>= 4)
|
||||
request_store (~> 1.0)
|
||||
logstash-event (1.2.02)
|
||||
loofah (2.3.1)
|
||||
loofah (2.4.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lumberjack (1.0.13)
|
||||
|
@ -369,7 +369,7 @@ GEM
|
|||
mimemagic (0.3.3)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.13.0)
|
||||
minitest (5.14.0)
|
||||
momentjs-rails (2.20.1)
|
||||
railties (>= 3.1)
|
||||
multi_json (1.14.1)
|
||||
|
@ -379,7 +379,7 @@ GEM
|
|||
nenv (0.3.0)
|
||||
netrc (0.11.0)
|
||||
nio4r (2.5.2)
|
||||
nokogiri (1.10.5)
|
||||
nokogiri (1.10.7)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
notiffany (0.1.1)
|
||||
nenv (~> 0.1)
|
||||
|
@ -450,7 +450,7 @@ GEM
|
|||
puma (3.12.2)
|
||||
pundit (2.0.1)
|
||||
activesupport (>= 3.0.0)
|
||||
rack (2.0.8)
|
||||
rack (2.1.2)
|
||||
rack-attack (6.0.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-mini-profiler (1.0.1)
|
||||
|
@ -528,27 +528,27 @@ GEM
|
|||
builder (>= 3.0)
|
||||
rubyzip (>= 1.0)
|
||||
rouge (3.9.0)
|
||||
rspec (3.8.0)
|
||||
rspec-core (~> 3.8.0)
|
||||
rspec-expectations (~> 3.8.0)
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-core (3.8.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-expectations (3.8.2)
|
||||
rspec (3.9.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-core (3.9.1)
|
||||
rspec-support (~> 3.9.1)
|
||||
rspec-expectations (3.9.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-mocks (3.8.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-mocks (3.9.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-rails (3.8.1)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rails (3.9.0)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.8.0)
|
||||
rspec-expectations (~> 3.8.0)
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-support (3.8.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-support (3.9.2)
|
||||
rspec_junit_formatter (0.4.1)
|
||||
rspec-core (>= 2, < 4, != 2.12.0)
|
||||
rubocop (0.62.0)
|
||||
|
@ -614,9 +614,9 @@ GEM
|
|||
rack (~> 2.0)
|
||||
rack-protection (= 2.0.5)
|
||||
tilt (~> 2.0)
|
||||
skylight (3.1.2)
|
||||
skylight-core (= 3.1.2)
|
||||
skylight-core (3.1.2)
|
||||
skylight (4.2.1)
|
||||
skylight-core (= 4.2.1)
|
||||
skylight-core (4.2.1)
|
||||
activesupport (>= 4.2.0)
|
||||
smart_listing (1.2.2)
|
||||
coffee-rails
|
||||
|
@ -644,7 +644,7 @@ GEM
|
|||
httpclient (>= 2.4)
|
||||
sysexits (1.2.0)
|
||||
temple (0.8.0)
|
||||
thor (0.20.3)
|
||||
thor (1.0.1)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.9)
|
||||
timecop (0.9.1)
|
||||
|
@ -654,7 +654,7 @@ GEM
|
|||
turbolinks-source (5.2.0)
|
||||
typhoeus (1.3.1)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (1.2.5)
|
||||
tzinfo (1.2.6)
|
||||
thread_safe (~> 0.1)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
@import "colors";
|
||||
@import "constants";
|
||||
|
||||
$dossier-actions-bar-border-width: 1px;
|
||||
|
||||
.dossier-header {
|
||||
.container {
|
||||
padding-bottom: $default-padding;
|
||||
|
@ -46,29 +48,40 @@
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.send-dossier-actions-bar {
|
||||
// scss-lint:disable VendorPrefix
|
||||
.dossier-edit-sticky-footer {
|
||||
// scss-lint:disable VendorPrefix DuplicateProperty
|
||||
position: fixed; // Fallback for IE 11, and other browser that don't support sticky
|
||||
position: -webkit-sticky; // This is needed on Safari (tested on 12.1)
|
||||
// scss-lint:enable VendorPrefix
|
||||
position: sticky;
|
||||
// scss-lint:enable VendorPrefix DuplicateProperty
|
||||
|
||||
// IE 11 uses `position:fixed` – and thus needs an explicit width, content-box for better layout, etc.
|
||||
width: 100%;
|
||||
max-width: $page-width + 2 * $default-padding;
|
||||
box-sizing: content-box;
|
||||
|
||||
bottom: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-top: $default-padding;
|
||||
margin-left: -$default-padding;
|
||||
margin-right: -$default-padding;
|
||||
margin-bottom: 0;
|
||||
padding-top: 0;
|
||||
padding-bottom: $default-spacer;
|
||||
padding-right: $default-padding;
|
||||
padding-left: $default-padding;
|
||||
|
||||
padding-right: $default-padding - $dossier-actions-bar-border-width;
|
||||
padding-left: $default-padding - $dossier-actions-bar-border-width;
|
||||
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #CCCCCC;
|
||||
|
||||
border: $dossier-actions-bar-border-width solid #CCCCCC;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.send-dossier-actions-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.button:not(:small) {
|
||||
min-height: 38px;
|
||||
|
@ -81,13 +94,13 @@
|
|||
}
|
||||
|
||||
// Normal layout
|
||||
@media (min-width: 500px) {
|
||||
@media (min-width: 620px) {
|
||||
padding-top: $default-spacer * 2;
|
||||
padding-bottom: $default-spacer * 2;
|
||||
}
|
||||
|
||||
// Compact layout
|
||||
@media (max-width: 500px) {
|
||||
@media (max-width: 620px) {
|
||||
padding-top: $default-spacer;
|
||||
padding-bottom: $default-spacer;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
module Manager
|
||||
class UsersController < Manager::ApplicationController
|
||||
def update
|
||||
user = User.find(params[:id])
|
||||
new_email = params[:user][:email]
|
||||
user.skip_reconfirmation!
|
||||
user.update(email: new_email)
|
||||
if (user.valid?)
|
||||
flash[:notice] = "L'email a été modifié en « #{new_email} » sans notification ni validation par email."
|
||||
else
|
||||
flash[:error] = "« #{new_email} » n'est pas une adresse valide."
|
||||
end
|
||||
redirect_to edit_manager_user_path(user)
|
||||
end
|
||||
|
||||
def resend_confirmation_instructions
|
||||
user = User.find(params[:id])
|
||||
user.resend_confirmation_instructions
|
||||
|
|
|
@ -41,7 +41,9 @@ class UserDashboard < Administrate::BaseDashboard
|
|||
# FORM_ATTRIBUTES
|
||||
# an array of attributes that will be displayed
|
||||
# on the model's form (`new` and `edit`) pages.
|
||||
FORM_ATTRIBUTES = [].freeze
|
||||
FORM_ATTRIBUTES = [
|
||||
:email
|
||||
].freeze
|
||||
|
||||
# Overwrite this method to customize how users are displayed
|
||||
# across all pages of the admin dashboard.
|
||||
|
|
|
@ -59,19 +59,29 @@ class Api::V2::Schema < GraphQL::Schema
|
|||
raise GraphQL::ExecutionError.new("An object of type #{error.type.graphql_name} was hidden due to permissions", extensions: { code: :unauthorized })
|
||||
end
|
||||
|
||||
middleware(GraphQL::Schema::TimeoutMiddleware.new(max_seconds: 5) do |_, query|
|
||||
Rails.logger.info("GraphQL Timeout: #{query.query_string}")
|
||||
end)
|
||||
use GraphQL::Execution::Interpreter
|
||||
use GraphQL::Analysis::AST
|
||||
use GraphQL::Schema::Timeout, max_seconds: 5
|
||||
use GraphQL::Batch
|
||||
use GraphQL::Backtrace
|
||||
|
||||
if Rails.env.development?
|
||||
query_analyzer(GraphQL::Analysis::QueryComplexity.new do |_, complexity|
|
||||
Rails.logger.info("[GraphQL Query Complexity] #{complexity}")
|
||||
end)
|
||||
query_analyzer(GraphQL::Analysis::QueryDepth.new do |_, depth|
|
||||
Rails.logger.info("[GraphQL Query Depth] #{depth}")
|
||||
end)
|
||||
class LogQueryDepth < GraphQL::Analysis::AST::QueryDepth
|
||||
def result
|
||||
Rails.logger.info("[GraphQL Query Depth] #{super}")
|
||||
end
|
||||
end
|
||||
|
||||
use GraphQL::Batch
|
||||
use GraphQL::Tracing::SkylightTracing
|
||||
class LogQueryComplexity < GraphQL::Analysis::AST::QueryComplexity
|
||||
def result
|
||||
Rails.logger.info("[GraphQL Query Complexity] #{super}")
|
||||
end
|
||||
end
|
||||
|
||||
query_analyzer(LogQueryComplexity)
|
||||
query_analyzer(LogQueryDepth)
|
||||
else
|
||||
query_analyzer(GraphQL::Analysis::AST::MaxQueryComplexity)
|
||||
query_analyzer(GraphQL::Analysis::AST::MaxQueryDepth)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,7 +43,9 @@ class Avis < ApplicationRecord
|
|||
['Question / Introduction', :introduction],
|
||||
['Réponse', :answer],
|
||||
['Créé le', :created_at],
|
||||
['Répondu le', :updated_at]
|
||||
['Répondu le', :updated_at],
|
||||
['Instructeur', claimant&.email],
|
||||
['Expert', instructeur&.email]
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -45,8 +45,9 @@ class Champs::LinkedDropDownListChamp < Champ
|
|||
value.present? ? { primary: primary_value, secondary: secondary_value } : nil
|
||||
end
|
||||
|
||||
def mandatory_and_blank?
|
||||
mandatory? && (primary_value.blank? || secondary_value.blank?)
|
||||
def blank?
|
||||
primary_value.blank? ||
|
||||
(has_secondary_options_for_primary? && secondary_value.blank?)
|
||||
end
|
||||
|
||||
def search_terms
|
||||
|
@ -58,4 +59,8 @@ class Champs::LinkedDropDownListChamp < Champ
|
|||
def pack_value(primary, secondary)
|
||||
self.value = JSON.generate([primary, secondary])
|
||||
end
|
||||
|
||||
def has_secondary_options_for_primary?
|
||||
primary_value.present? && secondary_options[primary_value]&.any?(&:present?)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -216,6 +216,7 @@ class Dossier < ApplicationRecord
|
|||
|
||||
validates :user, presence: true
|
||||
validates :individual, presence: true, if: -> { procedure.for_individual? }
|
||||
validates :groupe_instructeur, presence: true
|
||||
|
||||
def update_search_terms
|
||||
self.search_terms = [
|
||||
|
|
|
@ -16,6 +16,7 @@ class Procedure < ApplicationRecord
|
|||
has_one :attestation_template, dependent: :destroy
|
||||
|
||||
belongs_to :parent_procedure, class_name: 'Procedure'
|
||||
belongs_to :canonical_procedure, class_name: 'Procedure'
|
||||
belongs_to :service
|
||||
|
||||
has_many :administrateurs_procedures
|
||||
|
@ -129,11 +130,12 @@ class Procedure < ApplicationRecord
|
|||
other_procedure = other_procedure_with_path(path)
|
||||
if other_procedure.present? && administrateur.owns?(other_procedure)
|
||||
other_procedure.unpublish!
|
||||
end
|
||||
|
||||
publish!(other_procedure.canonical_procedure || other_procedure)
|
||||
else
|
||||
publish!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def csv_export_stale?
|
||||
!csv_export_file.attached? || csv_export_file.created_at < MAX_DUREE_CONSERVATION_EXPORT.ago
|
||||
|
@ -615,8 +617,8 @@ class Procedure < ApplicationRecord
|
|||
update!(closed_at: nil, unpublished_at: nil)
|
||||
end
|
||||
|
||||
def after_publish
|
||||
update!(published_at: Time.zone.now)
|
||||
def after_publish(canonical_procedure = nil)
|
||||
update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure)
|
||||
end
|
||||
|
||||
def after_close
|
||||
|
|
|
@ -24,9 +24,11 @@ as well as a link to its edit page.
|
|||
<%= content_for(:title) %>
|
||||
</h1>
|
||||
|
||||
<div>
|
||||
<%= button_to "modifier", edit_manager_user_path(page.resource), method: :get, class: "button" %>
|
||||
</div>
|
||||
<div>
|
||||
<%= button_to "supprimer", delete_manager_user_path(page.resource), method: :delete, disabled: !page.resource.can_be_deleted?, class: "button", data: { confirm: "Confirmez-vous la suppression de l'utilisateur ?" }, title: page.resource.can_be_deleted? ? "Supprimer" : "Cet utilisateur a des dossiers dont l'instruction a commencé et ne peut être supprimé" %>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<% if !user.confirmed? %>
|
||||
|
|
|
@ -30,11 +30,22 @@
|
|||
%hr
|
||||
|
||||
- if dossier.procedure.routee?
|
||||
= f.label :groupe_instructeur_id, dossier.procedure.routing_criteria_name
|
||||
= f.label :groupe_instructeur_id do
|
||||
= dossier.procedure.routing_criteria_name
|
||||
%span.mandatory *
|
||||
-# The routing dropdown has 'include_blank: false', because otherwise a blank
|
||||
-# value may nullify the groupe_instructeur – and thus the link between the dossier
|
||||
-# and its procedure.
|
||||
-#
|
||||
-# If, one day, we need to make clearer to the user that they must actually choose an
|
||||
-# option, THINK TWICE before adding a blank option, and what would happen if the form is
|
||||
-# saved when the blank option is selected.
|
||||
-# Instead please consider other possibilities; like using CSS to gray out the default option,
|
||||
-# or adding some "(please select an option)" wording aside the label of the default group.
|
||||
-# CSS
|
||||
= f.select :groupe_instructeur_id,
|
||||
dossier.procedure.groupe_instructeurs.order(:label).map { |gi| [gi.label, gi.id] },
|
||||
{},
|
||||
required: true
|
||||
{ include_blank: false }
|
||||
|
||||
= f.fields_for :champs, dossier.champs do |champ_form|
|
||||
- champ = champ_form.object
|
||||
|
@ -42,6 +53,7 @@
|
|||
locals: { champ: champ, form: champ_form }
|
||||
|
||||
- if !apercu
|
||||
.dossier-edit-sticky-footer
|
||||
.send-dossier-actions-bar
|
||||
- if dossier.brouillon?
|
||||
- if autosave_available?(dossier)
|
||||
|
|
|
@ -49,5 +49,7 @@ module TPS
|
|||
debounce_delay: 3000,
|
||||
status_visible_duration: 6000
|
||||
}
|
||||
|
||||
config.skylight.probes += [:graphql]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
Browser.modern_rules.clear
|
||||
Browser.modern_rules << -> b { b.chrome? && b.version.to_i >= 50 && !b.platform.ios? }
|
||||
Browser.modern_rules << -> b { b.edge? && b.version.to_i >= 14 && !b.compatibility_view? }
|
||||
Browser.modern_rules << -> b { b.ie? && b.version.to_i >= 11 && !b.compatibility_view? }
|
||||
Browser.modern_rules << -> b { b.firefox? && b.version.to_i >= 50 && !b.platform.ios? }
|
||||
Browser.modern_rules << -> b { b.opera? && b.version.to_i >= 40 }
|
||||
Browser.modern_rules << -> b { b.safari? && b.version.to_i >= 8 }
|
||||
|
|
|
@ -24,7 +24,7 @@ Rails.application.routes.draw do
|
|||
delete 'delete', on: :member
|
||||
end
|
||||
|
||||
resources :users, only: [:index, :show] do
|
||||
resources :users, only: [:index, :show, :edit, :update] do
|
||||
delete 'delete', on: :member
|
||||
post 'resend_confirmation_instructions', on: :member
|
||||
put 'enable_feature', on: :member
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddCanonicalProcedureIdToProcedures < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :procedures, :canonical_procedure_id, :bigint
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2019_12_18_103727) do
|
||||
ActiveRecord::Schema.define(version: 2020_01_14_113700) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -502,6 +502,7 @@ ActiveRecord::Schema.define(version: 2019_12_18_103727) do
|
|||
t.boolean "ods_export_queued"
|
||||
t.datetime "closed_at"
|
||||
t.datetime "unpublished_at"
|
||||
t.bigint "canonical_procedure_id"
|
||||
t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state"
|
||||
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"
|
||||
t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id"
|
||||
|
|
|
@ -21,6 +21,7 @@ describe ApplicationController, type: :controller do
|
|||
let(:payload) { {} }
|
||||
|
||||
before do
|
||||
allow(@controller).to receive(:content_type).and_return('')
|
||||
allow(@controller).to receive(:current_user).and_return(current_user)
|
||||
expect(@controller).to receive(:current_instructeur).and_return(current_instructeur)
|
||||
expect(@controller).to receive(:current_administrateur).and_return(current_administrateur)
|
||||
|
@ -42,6 +43,8 @@ describe ApplicationController, type: :controller do
|
|||
payload.delete(key)
|
||||
end
|
||||
expect(payload).to eq({
|
||||
sk_rendered_format: nil,
|
||||
sk_variant: [],
|
||||
user_agent: 'Rails Testing',
|
||||
user_roles: 'Guest'
|
||||
})
|
||||
|
@ -61,6 +64,8 @@ describe ApplicationController, type: :controller do
|
|||
payload.delete(key)
|
||||
end
|
||||
expect(payload).to eq({
|
||||
sk_rendered_format: nil,
|
||||
sk_variant: [],
|
||||
user_agent: 'Rails Testing',
|
||||
user_id: current_user.id,
|
||||
user_email: current_user.email,
|
||||
|
@ -85,6 +90,8 @@ describe ApplicationController, type: :controller do
|
|||
payload.delete(key)
|
||||
end
|
||||
expect(payload).to eq({
|
||||
sk_rendered_format: nil,
|
||||
sk_variant: [],
|
||||
user_agent: 'Rails Testing',
|
||||
user_id: current_user.id,
|
||||
user_email: current_user.email,
|
||||
|
|
|
@ -4,6 +4,7 @@ describe Manager::ApplicationController, type: :controller do
|
|||
let(:payload) { {} }
|
||||
|
||||
before do
|
||||
allow(@controller).to receive(:content_type).and_return('')
|
||||
allow(@controller).to receive(:current_user).and_return(current_user)
|
||||
@controller.send(:append_info_to_payload, payload)
|
||||
end
|
||||
|
@ -13,6 +14,8 @@ describe Manager::ApplicationController, type: :controller do
|
|||
payload.delete(key)
|
||||
end
|
||||
expect(payload).to eq({
|
||||
sk_rendered_format: nil,
|
||||
sk_variant: [],
|
||||
user_agent: 'Rails Testing',
|
||||
user_id: current_user.id,
|
||||
user_email: current_user.email
|
||||
|
|
|
@ -1,6 +1,36 @@
|
|||
describe Manager::UsersController, type: :controller do
|
||||
let(:administration) { create(:administration) }
|
||||
|
||||
describe '#update' do
|
||||
let!(:user) { create(:user, email: 'ancien.email@domaine.fr') }
|
||||
|
||||
before {
|
||||
sign_in administration
|
||||
}
|
||||
subject { patch :update, params: { id: user.id, user: { email: nouvel_email } } }
|
||||
|
||||
describe 'with a valid email' do
|
||||
let(:nouvel_email) { 'nouvel.email@domaine.fr' }
|
||||
|
||||
it 'updates the user email' do
|
||||
subject
|
||||
|
||||
expect(User.find_by(id: user.id).email).to eq(nouvel_email)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with an invalid email' do
|
||||
let(:nouvel_email) { 'plop' }
|
||||
|
||||
it 'does not update the user email' do
|
||||
subject
|
||||
|
||||
expect(User.find_by(id: user.id).email).not_to eq(nouvel_email)
|
||||
expect(flash[:error]).to match("« #{nouvel_email} » n'est pas une adresse valide.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete' do
|
||||
let!(:user) { create(:user) }
|
||||
|
||||
|
|
|
@ -3,29 +3,29 @@ require 'spec_helper'
|
|||
feature 'Outdated browsers support:' do
|
||||
context 'when the user browser is outdated' do
|
||||
before(:each) do
|
||||
ie_10_user_agent = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)'
|
||||
Capybara.page.driver.header('user-agent', ie_10_user_agent)
|
||||
ie_11_user_agent = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko'
|
||||
Capybara.page.driver.header('user-agent', ie_11_user_agent)
|
||||
end
|
||||
|
||||
scenario 'a banner is displayed' do
|
||||
visit new_user_session_path
|
||||
expect(page).to have_content('Internet Explorer 10 est trop ancien')
|
||||
expect(page).to have_content('Internet Explorer 11 est trop ancien')
|
||||
end
|
||||
|
||||
scenario 'the banner can be dismissed' do
|
||||
visit new_user_session_path
|
||||
expect(page).to have_content('Internet Explorer 10 est trop ancien')
|
||||
expect(page).to have_content('Internet Explorer 11 est trop ancien')
|
||||
|
||||
# The banner is hidden immediately
|
||||
within '#outdated-browser-banner' do
|
||||
click_on 'Ignorer'
|
||||
end
|
||||
expect(page).not_to have_content('Internet Explorer 10 est trop ancien')
|
||||
expect(page).not_to have_content('Internet Explorer 11 est trop ancien')
|
||||
expect(page).to have_current_path(new_user_session_path)
|
||||
|
||||
# The banner is hidden after a refresh
|
||||
page.refresh
|
||||
expect(page).not_to have_content('Internet Explorer 10 est trop ancien')
|
||||
expect(page).not_to have_content('Internet Explorer 11 est trop ancien')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -91,7 +91,14 @@ describe Champs::LinkedDropDownListChamp do
|
|||
end
|
||||
|
||||
context 'when there is a secondary value' do
|
||||
before { subject.secondary_value = 'Primary' }
|
||||
before { subject.secondary_value = 'Secondary' }
|
||||
|
||||
it { is_expected.not_to be_mandatory_and_blank }
|
||||
end
|
||||
|
||||
context 'when there is nothing to select for the secondary value' do
|
||||
let(:drop_down_list) { build(:drop_down_list, value: "--A--\nAbbott\nAbelard\n--B--\n--C--\nCynthia") }
|
||||
before { subject.primary_value = 'B' }
|
||||
|
||||
it { is_expected.not_to be_mandatory_and_blank }
|
||||
end
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Exercice do
|
||||
describe 'validations' do
|
||||
it { is_expected.to validate_presence_of(:ca) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -534,41 +534,101 @@ describe Procedure do
|
|||
let(:procedure) { create(:procedure, path: 'example-path') }
|
||||
let(:now) { Time.zone.now.beginning_of_minute }
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
context "without parent procedure" do
|
||||
context 'when publishing a new procedure' do
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
Timecop.freeze(now) do
|
||||
procedure.publish!
|
||||
end
|
||||
end
|
||||
|
||||
it do
|
||||
it 'no reference to the canonical procedure on the published procedure' do
|
||||
expect(procedure.canonical_procedure).to be_nil
|
||||
end
|
||||
|
||||
it 'changes the procedure state to published' do
|
||||
expect(procedure.closed_at).to be_nil
|
||||
expect(procedure.published_at).to eq(now)
|
||||
expect(Procedure.find_by(path: "example-path")).to eq(procedure)
|
||||
expect(Procedure.find_by(path: "example-path").administrateurs).to eq(procedure.administrateurs)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when publishing over a previous canonical procedure' do
|
||||
let(:canonical_procedure) { create(:procedure, :published) }
|
||||
|
||||
before do
|
||||
Timecop.freeze(now) do
|
||||
procedure.publish!(canonical_procedure)
|
||||
end
|
||||
end
|
||||
|
||||
it 'references the canonical procedure on the published procedure' do
|
||||
expect(procedure.canonical_procedure).to eq(canonical_procedure)
|
||||
end
|
||||
|
||||
it 'changes the procedure state to published' do
|
||||
expect(procedure.closed_at).to be_nil
|
||||
expect(procedure.published_at).to eq(now)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#publish_or_reopen!" do
|
||||
let(:published_procedure) { create(:procedure, :published) }
|
||||
let(:administrateur) { published_procedure.administrateurs.first }
|
||||
let(:canonical_procedure) { create(:procedure, :published) }
|
||||
let(:administrateur) { canonical_procedure.administrateurs.first }
|
||||
|
||||
let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
|
||||
let(:now) { Time.zone.now.beginning_of_minute }
|
||||
|
||||
context "without parent procedure" do
|
||||
context 'when publishing over a previous canonical procedure' do
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
procedure.path = published_procedure.path
|
||||
procedure.path = canonical_procedure.path
|
||||
Timecop.freeze(now) do
|
||||
procedure.publish_or_reopen!(administrateur)
|
||||
end
|
||||
canonical_procedure.reload
|
||||
end
|
||||
|
||||
it do
|
||||
it 'references the canonical procedure on the published procedure' do
|
||||
expect(procedure.canonical_procedure).to eq(canonical_procedure)
|
||||
end
|
||||
|
||||
it 'changes the procedure state to published' do
|
||||
expect(procedure.closed_at).to be_nil
|
||||
expect(procedure.published_at).to eq(now)
|
||||
end
|
||||
|
||||
it 'unpublishes the canonical procedure' do
|
||||
expect(canonical_procedure.unpublished_at).to eq(now)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when publishing over a previous procedure with canonical procedure' do
|
||||
let(:canonical_procedure) { create(:procedure, :closed) }
|
||||
let(:parent_procedure) { create(:procedure, :published, administrateurs: [administrateur]) }
|
||||
|
||||
before do
|
||||
parent_procedure.update!(path: canonical_procedure.path, canonical_procedure: canonical_procedure)
|
||||
procedure.path = canonical_procedure.path
|
||||
Timecop.freeze(now) do
|
||||
procedure.publish_or_reopen!(administrateur)
|
||||
end
|
||||
parent_procedure.reload
|
||||
end
|
||||
|
||||
it 'references the canonical procedure on the published procedure' do
|
||||
expect(procedure.canonical_procedure).to eq(canonical_procedure)
|
||||
end
|
||||
|
||||
it 'changes the procedure state to published' do
|
||||
expect(procedure.canonical_procedure).to eq(canonical_procedure)
|
||||
expect(procedure.closed_at).to be_nil
|
||||
expect(procedure.published_at).to eq(now)
|
||||
end
|
||||
|
||||
it 'unpublishes parent procedure' do
|
||||
expect(parent_procedure.unpublished_at).to eq(now)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -577,10 +637,10 @@ describe Procedure do
|
|||
let(:now) { Time.zone.now.beginning_of_minute }
|
||||
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
Timecop.freeze(now) do
|
||||
procedure.unpublish!
|
||||
end
|
||||
after { Timecop.return }
|
||||
end
|
||||
|
||||
it {
|
||||
expect(procedure.closed_at).to eq(nil)
|
||||
|
@ -653,11 +713,11 @@ describe Procedure do
|
|||
let(:procedure) { create(:procedure, :published) }
|
||||
let(:now) { Time.zone.now.beginning_of_minute }
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
Timecop.freeze(now) do
|
||||
procedure.close!
|
||||
end
|
||||
procedure.reload
|
||||
end
|
||||
after { Timecop.return }
|
||||
|
||||
it { expect(procedure.close?).to be_truthy }
|
||||
it { expect(procedure.closed_at).to eq(now) }
|
||||
|
|
|
@ -295,7 +295,9 @@ describe ProcedureExportService do
|
|||
"Question / Introduction",
|
||||
"Réponse",
|
||||
"Créé le",
|
||||
"Répondu le"
|
||||
"Répondu le",
|
||||
"Instructeur",
|
||||
"Expert"
|
||||
])
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue