commit
3563aa10ab
26 changed files with 344 additions and 133 deletions
|
@ -13,7 +13,10 @@ defaults: &defaults
|
||||||
bundle_restore_cache: &bundle_restore_cache
|
bundle_restore_cache: &bundle_restore_cache
|
||||||
restore_cache:
|
restore_cache:
|
||||||
name: Restore Bundler Package 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
|
bundle_save_cache: &bundle_save_cache
|
||||||
save_cache:
|
save_cache:
|
||||||
|
@ -30,19 +33,45 @@ bundle_install: &bundle_install
|
||||||
yarn_restore_cache: &yarn_restore_cache
|
yarn_restore_cache: &yarn_restore_cache
|
||||||
restore_cache:
|
restore_cache:
|
||||||
name: Restore Yarn Package 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
|
yarn_save_cache: &yarn_save_cache
|
||||||
save_cache:
|
save_cache:
|
||||||
name: Save Yarn Package Cache
|
name: Save Yarn Package Cache
|
||||||
key: yarn-install-v1-{{ arch }}-{{ checksum "yarn.lock" }}
|
key: yarn-install-v3-{{ arch }}-{{ checksum "yarn.lock" }}
|
||||||
paths:
|
paths:
|
||||||
- ~/.cache/yarn
|
- ~/.cache/yarn
|
||||||
|
|
||||||
yarn_install: &yarn_install
|
yarn_install: &yarn_install
|
||||||
run:
|
run:
|
||||||
name: Install JS Dependencies
|
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:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -53,8 +82,8 @@ jobs:
|
||||||
- *bundle_install
|
- *bundle_install
|
||||||
- *bundle_save_cache
|
- *bundle_save_cache
|
||||||
- *yarn_restore_cache
|
- *yarn_restore_cache
|
||||||
- *yarn_save_cache
|
|
||||||
- *yarn_install
|
- *yarn_install
|
||||||
|
- *yarn_save_cache
|
||||||
test:
|
test:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
parallelism: 3
|
parallelism: 3
|
||||||
|
@ -64,16 +93,15 @@ jobs:
|
||||||
- *bundle_install
|
- *bundle_install
|
||||||
- *yarn_restore_cache
|
- *yarn_restore_cache
|
||||||
- *yarn_install
|
- *yarn_install
|
||||||
|
- *webpacker_restore_cache
|
||||||
|
- *webpacker_precompile
|
||||||
|
- *webpacker_save_cache
|
||||||
- run:
|
- run:
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: "postgres://tps_test@localhost:5432/tps_test"
|
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
|
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:
|
- run:
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: "postgres://tps_test@localhost:5432/tps_test"
|
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:
|
on:
|
||||||
issue_comment:
|
issue_comment:
|
||||||
types: [created]
|
types: [created]
|
||||||
name: Rebase automatique
|
name: Automatic Rebase
|
||||||
jobs:
|
jobs:
|
||||||
rebase:
|
rebase:
|
||||||
name: Rebase
|
name: Rebase
|
||||||
|
@ -9,13 +9,15 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
- name: Automatic Rebase
|
- name: Automatic Rebase
|
||||||
uses: cirrus-actions/rebase@master
|
uses: cirrus-actions/rebase@1.2
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
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
|
# https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250
|
||||||
always_job:
|
always_job:
|
||||||
name: Aways run job
|
name: Always run job
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Always run
|
- name: Always run
|
||||||
|
|
58
Gemfile.lock
58
Gemfile.lock
|
@ -117,7 +117,7 @@ GEM
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
brakeman (4.3.1)
|
brakeman (4.3.1)
|
||||||
browser (2.5.3)
|
browser (2.5.3)
|
||||||
builder (3.2.3)
|
builder (3.2.4)
|
||||||
byebug (10.0.2)
|
byebug (10.0.2)
|
||||||
capybara (3.29.0)
|
capybara (3.29.0)
|
||||||
addressable
|
addressable
|
||||||
|
@ -155,7 +155,7 @@ GEM
|
||||||
connection_pool (2.2.2)
|
connection_pool (2.2.2)
|
||||||
crack (0.4.3)
|
crack (0.4.3)
|
||||||
safe_yaml (~> 1.0.0)
|
safe_yaml (~> 1.0.0)
|
||||||
crass (1.0.5)
|
crass (1.0.6)
|
||||||
css_parser (1.6.0)
|
css_parser (1.6.0)
|
||||||
addressable
|
addressable
|
||||||
curb (0.9.10)
|
curb (0.9.10)
|
||||||
|
@ -242,7 +242,7 @@ GEM
|
||||||
graphiql-rails (1.7.0)
|
graphiql-rails (1.7.0)
|
||||||
railties
|
railties
|
||||||
sprockets-rails
|
sprockets-rails
|
||||||
graphql (1.9.15)
|
graphql (1.9.16)
|
||||||
graphql-batch (0.4.1)
|
graphql-batch (0.4.1)
|
||||||
graphql (>= 1.3, < 2)
|
graphql (>= 1.3, < 2)
|
||||||
promise.rb (~> 0.7.2)
|
promise.rb (~> 0.7.2)
|
||||||
|
@ -305,7 +305,7 @@ GEM
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
http_parser.rb (0.6.0)
|
http_parser.rb (0.6.0)
|
||||||
httpclient (2.8.3)
|
httpclient (2.8.3)
|
||||||
i18n (1.7.0)
|
i18n (1.8.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
ipaddress (0.8.3)
|
ipaddress (0.8.3)
|
||||||
jaro_winkler (1.5.2)
|
jaro_winkler (1.5.2)
|
||||||
|
@ -350,7 +350,7 @@ GEM
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
logstash-event (1.2.02)
|
logstash-event (1.2.02)
|
||||||
loofah (2.3.1)
|
loofah (2.4.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
lumberjack (1.0.13)
|
lumberjack (1.0.13)
|
||||||
|
@ -369,7 +369,7 @@ GEM
|
||||||
mimemagic (0.3.3)
|
mimemagic (0.3.3)
|
||||||
mini_mime (1.0.2)
|
mini_mime (1.0.2)
|
||||||
mini_portile2 (2.4.0)
|
mini_portile2 (2.4.0)
|
||||||
minitest (5.13.0)
|
minitest (5.14.0)
|
||||||
momentjs-rails (2.20.1)
|
momentjs-rails (2.20.1)
|
||||||
railties (>= 3.1)
|
railties (>= 3.1)
|
||||||
multi_json (1.14.1)
|
multi_json (1.14.1)
|
||||||
|
@ -379,7 +379,7 @@ GEM
|
||||||
nenv (0.3.0)
|
nenv (0.3.0)
|
||||||
netrc (0.11.0)
|
netrc (0.11.0)
|
||||||
nio4r (2.5.2)
|
nio4r (2.5.2)
|
||||||
nokogiri (1.10.5)
|
nokogiri (1.10.7)
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
notiffany (0.1.1)
|
notiffany (0.1.1)
|
||||||
nenv (~> 0.1)
|
nenv (~> 0.1)
|
||||||
|
@ -450,7 +450,7 @@ GEM
|
||||||
puma (3.12.2)
|
puma (3.12.2)
|
||||||
pundit (2.0.1)
|
pundit (2.0.1)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
rack (2.0.8)
|
rack (2.1.2)
|
||||||
rack-attack (6.0.0)
|
rack-attack (6.0.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rack-mini-profiler (1.0.1)
|
rack-mini-profiler (1.0.1)
|
||||||
|
@ -528,27 +528,27 @@ GEM
|
||||||
builder (>= 3.0)
|
builder (>= 3.0)
|
||||||
rubyzip (>= 1.0)
|
rubyzip (>= 1.0)
|
||||||
rouge (3.9.0)
|
rouge (3.9.0)
|
||||||
rspec (3.8.0)
|
rspec (3.9.0)
|
||||||
rspec-core (~> 3.8.0)
|
rspec-core (~> 3.9.0)
|
||||||
rspec-expectations (~> 3.8.0)
|
rspec-expectations (~> 3.9.0)
|
||||||
rspec-mocks (~> 3.8.0)
|
rspec-mocks (~> 3.9.0)
|
||||||
rspec-core (3.8.0)
|
rspec-core (3.9.1)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.9.1)
|
||||||
rspec-expectations (3.8.2)
|
rspec-expectations (3.9.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.9.0)
|
||||||
rspec-mocks (3.8.0)
|
rspec-mocks (3.9.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.9.0)
|
||||||
rspec-rails (3.8.1)
|
rspec-rails (3.9.0)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
rspec-core (~> 3.8.0)
|
rspec-core (~> 3.9.0)
|
||||||
rspec-expectations (~> 3.8.0)
|
rspec-expectations (~> 3.9.0)
|
||||||
rspec-mocks (~> 3.8.0)
|
rspec-mocks (~> 3.9.0)
|
||||||
rspec-support (~> 3.8.0)
|
rspec-support (~> 3.9.0)
|
||||||
rspec-support (3.8.0)
|
rspec-support (3.9.2)
|
||||||
rspec_junit_formatter (0.4.1)
|
rspec_junit_formatter (0.4.1)
|
||||||
rspec-core (>= 2, < 4, != 2.12.0)
|
rspec-core (>= 2, < 4, != 2.12.0)
|
||||||
rubocop (0.62.0)
|
rubocop (0.62.0)
|
||||||
|
@ -614,9 +614,9 @@ GEM
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
rack-protection (= 2.0.5)
|
rack-protection (= 2.0.5)
|
||||||
tilt (~> 2.0)
|
tilt (~> 2.0)
|
||||||
skylight (3.1.2)
|
skylight (4.2.1)
|
||||||
skylight-core (= 3.1.2)
|
skylight-core (= 4.2.1)
|
||||||
skylight-core (3.1.2)
|
skylight-core (4.2.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
smart_listing (1.2.2)
|
smart_listing (1.2.2)
|
||||||
coffee-rails
|
coffee-rails
|
||||||
|
@ -644,7 +644,7 @@ GEM
|
||||||
httpclient (>= 2.4)
|
httpclient (>= 2.4)
|
||||||
sysexits (1.2.0)
|
sysexits (1.2.0)
|
||||||
temple (0.8.0)
|
temple (0.8.0)
|
||||||
thor (0.20.3)
|
thor (1.0.1)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tilt (2.0.9)
|
tilt (2.0.9)
|
||||||
timecop (0.9.1)
|
timecop (0.9.1)
|
||||||
|
@ -654,7 +654,7 @@ GEM
|
||||||
turbolinks-source (5.2.0)
|
turbolinks-source (5.2.0)
|
||||||
typhoeus (1.3.1)
|
typhoeus (1.3.1)
|
||||||
ethon (>= 0.9.0)
|
ethon (>= 0.9.0)
|
||||||
tzinfo (1.2.5)
|
tzinfo (1.2.6)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
@import "colors";
|
@import "colors";
|
||||||
@import "constants";
|
@import "constants";
|
||||||
|
|
||||||
|
$dossier-actions-bar-border-width: 1px;
|
||||||
|
|
||||||
.dossier-header {
|
.dossier-header {
|
||||||
.container {
|
.container {
|
||||||
padding-bottom: $default-padding;
|
padding-bottom: $default-padding;
|
||||||
|
@ -46,29 +48,40 @@
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.send-dossier-actions-bar {
|
.dossier-edit-sticky-footer {
|
||||||
// scss-lint:disable VendorPrefix
|
// 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)
|
position: -webkit-sticky; // This is needed on Safari (tested on 12.1)
|
||||||
// scss-lint:enable VendorPrefix
|
|
||||||
position: sticky;
|
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;
|
bottom: 0;
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: $default-padding;
|
margin-top: $default-padding;
|
||||||
margin-left: -$default-padding;
|
margin-left: -$default-padding;
|
||||||
margin-right: -$default-padding;
|
margin-right: -$default-padding;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: $default-spacer;
|
padding-right: $default-padding - $dossier-actions-bar-border-width;
|
||||||
padding-right: $default-padding;
|
padding-left: $default-padding - $dossier-actions-bar-border-width;
|
||||||
padding-left: $default-padding;
|
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
border: 1px solid #CCCCCC;
|
|
||||||
|
border: $dossier-actions-bar-border-width solid #CCCCCC;
|
||||||
border-top-left-radius: 5px;
|
border-top-left-radius: 5px;
|
||||||
border-top-right-radius: 5px;
|
border-top-right-radius: 5px;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-dossier-actions-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.button:not(:small) {
|
.button:not(:small) {
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
|
@ -81,13 +94,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal layout
|
// Normal layout
|
||||||
@media (min-width: 500px) {
|
@media (min-width: 620px) {
|
||||||
padding-top: $default-spacer * 2;
|
padding-top: $default-spacer * 2;
|
||||||
padding-bottom: $default-spacer * 2;
|
padding-bottom: $default-spacer * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compact layout
|
// Compact layout
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 620px) {
|
||||||
padding-top: $default-spacer;
|
padding-top: $default-spacer;
|
||||||
padding-bottom: $default-spacer;
|
padding-bottom: $default-spacer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
module Manager
|
module Manager
|
||||||
class UsersController < Manager::ApplicationController
|
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
|
def resend_confirmation_instructions
|
||||||
user = User.find(params[:id])
|
user = User.find(params[:id])
|
||||||
user.resend_confirmation_instructions
|
user.resend_confirmation_instructions
|
||||||
|
|
|
@ -41,7 +41,9 @@ class UserDashboard < Administrate::BaseDashboard
|
||||||
# FORM_ATTRIBUTES
|
# FORM_ATTRIBUTES
|
||||||
# an array of attributes that will be displayed
|
# an array of attributes that will be displayed
|
||||||
# on the model's form (`new` and `edit`) pages.
|
# 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
|
# Overwrite this method to customize how users are displayed
|
||||||
# across all pages of the admin dashboard.
|
# 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 })
|
raise GraphQL::ExecutionError.new("An object of type #{error.type.graphql_name} was hidden due to permissions", extensions: { code: :unauthorized })
|
||||||
end
|
end
|
||||||
|
|
||||||
middleware(GraphQL::Schema::TimeoutMiddleware.new(max_seconds: 5) do |_, query|
|
use GraphQL::Execution::Interpreter
|
||||||
Rails.logger.info("GraphQL Timeout: #{query.query_string}")
|
use GraphQL::Analysis::AST
|
||||||
end)
|
use GraphQL::Schema::Timeout, max_seconds: 5
|
||||||
|
use GraphQL::Batch
|
||||||
|
use GraphQL::Backtrace
|
||||||
|
|
||||||
if Rails.env.development?
|
if Rails.env.development?
|
||||||
query_analyzer(GraphQL::Analysis::QueryComplexity.new do |_, complexity|
|
class LogQueryDepth < GraphQL::Analysis::AST::QueryDepth
|
||||||
Rails.logger.info("[GraphQL Query Complexity] #{complexity}")
|
def result
|
||||||
end)
|
Rails.logger.info("[GraphQL Query Depth] #{super}")
|
||||||
query_analyzer(GraphQL::Analysis::QueryDepth.new do |_, depth|
|
end
|
||||||
Rails.logger.info("[GraphQL Query Depth] #{depth}")
|
end
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
use GraphQL::Batch
|
class LogQueryComplexity < GraphQL::Analysis::AST::QueryComplexity
|
||||||
use GraphQL::Tracing::SkylightTracing
|
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
|
end
|
||||||
|
|
|
@ -43,7 +43,9 @@ class Avis < ApplicationRecord
|
||||||
['Question / Introduction', :introduction],
|
['Question / Introduction', :introduction],
|
||||||
['Réponse', :answer],
|
['Réponse', :answer],
|
||||||
['Créé le', :created_at],
|
['Créé le', :created_at],
|
||||||
['Répondu le', :updated_at]
|
['Répondu le', :updated_at],
|
||||||
|
['Instructeur', claimant&.email],
|
||||||
|
['Expert', instructeur&.email]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,9 @@ class Champs::LinkedDropDownListChamp < Champ
|
||||||
value.present? ? { primary: primary_value, secondary: secondary_value } : nil
|
value.present? ? { primary: primary_value, secondary: secondary_value } : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def mandatory_and_blank?
|
def blank?
|
||||||
mandatory? && (primary_value.blank? || secondary_value.blank?)
|
primary_value.blank? ||
|
||||||
|
(has_secondary_options_for_primary? && secondary_value.blank?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def search_terms
|
def search_terms
|
||||||
|
@ -58,4 +59,8 @@ class Champs::LinkedDropDownListChamp < Champ
|
||||||
def pack_value(primary, secondary)
|
def pack_value(primary, secondary)
|
||||||
self.value = JSON.generate([primary, secondary])
|
self.value = JSON.generate([primary, secondary])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_secondary_options_for_primary?
|
||||||
|
primary_value.present? && secondary_options[primary_value]&.any?(&:present?)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -216,6 +216,7 @@ class Dossier < ApplicationRecord
|
||||||
|
|
||||||
validates :user, presence: true
|
validates :user, presence: true
|
||||||
validates :individual, presence: true, if: -> { procedure.for_individual? }
|
validates :individual, presence: true, if: -> { procedure.for_individual? }
|
||||||
|
validates :groupe_instructeur, presence: true
|
||||||
|
|
||||||
def update_search_terms
|
def update_search_terms
|
||||||
self.search_terms = [
|
self.search_terms = [
|
||||||
|
|
|
@ -16,6 +16,7 @@ class Procedure < ApplicationRecord
|
||||||
has_one :attestation_template, dependent: :destroy
|
has_one :attestation_template, dependent: :destroy
|
||||||
|
|
||||||
belongs_to :parent_procedure, class_name: 'Procedure'
|
belongs_to :parent_procedure, class_name: 'Procedure'
|
||||||
|
belongs_to :canonical_procedure, class_name: 'Procedure'
|
||||||
belongs_to :service
|
belongs_to :service
|
||||||
|
|
||||||
has_many :administrateurs_procedures
|
has_many :administrateurs_procedures
|
||||||
|
@ -129,9 +130,10 @@ class Procedure < ApplicationRecord
|
||||||
other_procedure = other_procedure_with_path(path)
|
other_procedure = other_procedure_with_path(path)
|
||||||
if other_procedure.present? && administrateur.owns?(other_procedure)
|
if other_procedure.present? && administrateur.owns?(other_procedure)
|
||||||
other_procedure.unpublish!
|
other_procedure.unpublish!
|
||||||
|
publish!(other_procedure.canonical_procedure || other_procedure)
|
||||||
|
else
|
||||||
|
publish!
|
||||||
end
|
end
|
||||||
|
|
||||||
publish!
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -615,8 +617,8 @@ class Procedure < ApplicationRecord
|
||||||
update!(closed_at: nil, unpublished_at: nil)
|
update!(closed_at: nil, unpublished_at: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_publish
|
def after_publish(canonical_procedure = nil)
|
||||||
update!(published_at: Time.zone.now)
|
update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure)
|
||||||
end
|
end
|
||||||
|
|
||||||
def after_close
|
def after_close
|
||||||
|
|
|
@ -24,9 +24,11 @@ as well as a link to its edit page.
|
||||||
<%= content_for(:title) %>
|
<%= content_for(:title) %>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= button_to "modifier", edit_manager_user_path(page.resource), method: :get, class: "button" %>
|
||||||
|
</div>
|
||||||
<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é" %>
|
<%= 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>
|
||||||
<div>
|
<div>
|
||||||
<% if !user.confirmed? %>
|
<% if !user.confirmed? %>
|
||||||
|
|
|
@ -30,11 +30,22 @@
|
||||||
%hr
|
%hr
|
||||||
|
|
||||||
- if dossier.procedure.routee?
|
- 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,
|
= f.select :groupe_instructeur_id,
|
||||||
dossier.procedure.groupe_instructeurs.order(:label).map { |gi| [gi.label, gi.id] },
|
dossier.procedure.groupe_instructeurs.order(:label).map { |gi| [gi.label, gi.id] },
|
||||||
{},
|
{ include_blank: false }
|
||||||
required: true
|
|
||||||
|
|
||||||
= f.fields_for :champs, dossier.champs do |champ_form|
|
= f.fields_for :champs, dossier.champs do |champ_form|
|
||||||
- champ = champ_form.object
|
- champ = champ_form.object
|
||||||
|
@ -42,31 +53,32 @@
|
||||||
locals: { champ: champ, form: champ_form }
|
locals: { champ: champ, form: champ_form }
|
||||||
|
|
||||||
- if !apercu
|
- if !apercu
|
||||||
.send-dossier-actions-bar
|
.dossier-edit-sticky-footer
|
||||||
- if dossier.brouillon?
|
.send-dossier-actions-bar
|
||||||
- if autosave_available?(dossier)
|
- if dossier.brouillon?
|
||||||
= render partial: 'users/dossiers/autosave'
|
- if autosave_available?(dossier)
|
||||||
|
= render partial: 'users/dossiers/autosave'
|
||||||
|
- else
|
||||||
|
= f.button 'Enregistrer le brouillon',
|
||||||
|
formnovalidate: true,
|
||||||
|
class: 'button send secondary',
|
||||||
|
data: { 'disable-with': "Envoi en cours…" }
|
||||||
|
|
||||||
|
- if dossier.can_transition_to_en_construction?
|
||||||
|
= f.button 'Déposer le dossier',
|
||||||
|
name: :submit_draft,
|
||||||
|
value: true,
|
||||||
|
class: 'button send primary',
|
||||||
|
disabled: !current_user.owns?(dossier),
|
||||||
|
data: { 'disable-with': "Envoi en cours…" }
|
||||||
|
|
||||||
- else
|
- else
|
||||||
= f.button 'Enregistrer le brouillon',
|
= f.button 'Enregistrer les modifications du dossier',
|
||||||
formnovalidate: true,
|
|
||||||
class: 'button send secondary',
|
|
||||||
data: { 'disable-with': "Envoi en cours…" }
|
|
||||||
|
|
||||||
- if dossier.can_transition_to_en_construction?
|
|
||||||
= f.button 'Déposer le dossier',
|
|
||||||
name: :submit_draft,
|
|
||||||
value: true,
|
|
||||||
class: 'button send primary',
|
class: 'button send primary',
|
||||||
disabled: !current_user.owns?(dossier),
|
|
||||||
data: { 'disable-with': "Envoi en cours…" }
|
data: { 'disable-with': "Envoi en cours…" }
|
||||||
|
|
||||||
- else
|
- if dossier.brouillon? && !current_user.owns?(dossier)
|
||||||
= f.button 'Enregistrer les modifications du dossier',
|
.send-notice.invite-cannot-submit
|
||||||
class: 'button send primary',
|
En tant qu’invité, vous pouvez remplir ce formulaire – mais le titulaire du dossier doit le déposer lui-même.
|
||||||
data: { 'disable-with': "Envoi en cours…" }
|
|
||||||
|
|
||||||
- if dossier.brouillon? && !current_user.owns?(dossier)
|
= render partial: "shared/dossiers/submit_is_over", locals: { dossier: dossier }
|
||||||
.send-notice.invite-cannot-submit
|
|
||||||
En tant qu’invité, vous pouvez remplir ce formulaire – mais le titulaire du dossier doit le déposer lui-même.
|
|
||||||
|
|
||||||
= render partial: "shared/dossiers/submit_is_over", locals: { dossier: dossier }
|
|
||||||
|
|
|
@ -49,5 +49,7 @@ module TPS
|
||||||
debounce_delay: 3000,
|
debounce_delay: 3000,
|
||||||
status_visible_duration: 6000
|
status_visible_duration: 6000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.skylight.probes += [:graphql]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
Browser.modern_rules.clear
|
Browser.modern_rules.clear
|
||||||
Browser.modern_rules << -> b { b.chrome? && b.version.to_i >= 50 && !b.platform.ios? }
|
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.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.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.opera? && b.version.to_i >= 40 }
|
||||||
Browser.modern_rules << -> b { b.safari? && b.version.to_i >= 8 }
|
Browser.modern_rules << -> b { b.safari? && b.version.to_i >= 8 }
|
||||||
|
|
|
@ -24,7 +24,7 @@ Rails.application.routes.draw do
|
||||||
delete 'delete', on: :member
|
delete 'delete', on: :member
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :users, only: [:index, :show] do
|
resources :users, only: [:index, :show, :edit, :update] do
|
||||||
delete 'delete', on: :member
|
delete 'delete', on: :member
|
||||||
post 'resend_confirmation_instructions', on: :member
|
post 'resend_confirmation_instructions', on: :member
|
||||||
put 'enable_feature', 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.
|
# 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
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -502,6 +502,7 @@ ActiveRecord::Schema.define(version: 2019_12_18_103727) do
|
||||||
t.boolean "ods_export_queued"
|
t.boolean "ods_export_queued"
|
||||||
t.datetime "closed_at"
|
t.datetime "closed_at"
|
||||||
t.datetime "unpublished_at"
|
t.datetime "unpublished_at"
|
||||||
|
t.bigint "canonical_procedure_id"
|
||||||
t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state"
|
t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state"
|
||||||
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"
|
t.index ["hidden_at"], name: "index_procedures_on_hidden_at"
|
||||||
t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id"
|
t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id"
|
||||||
|
|
|
@ -21,6 +21,7 @@ describe ApplicationController, type: :controller do
|
||||||
let(:payload) { {} }
|
let(:payload) { {} }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
allow(@controller).to receive(:content_type).and_return('')
|
||||||
allow(@controller).to receive(:current_user).and_return(current_user)
|
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_instructeur).and_return(current_instructeur)
|
||||||
expect(@controller).to receive(:current_administrateur).and_return(current_administrateur)
|
expect(@controller).to receive(:current_administrateur).and_return(current_administrateur)
|
||||||
|
@ -42,6 +43,8 @@ describe ApplicationController, type: :controller do
|
||||||
payload.delete(key)
|
payload.delete(key)
|
||||||
end
|
end
|
||||||
expect(payload).to eq({
|
expect(payload).to eq({
|
||||||
|
sk_rendered_format: nil,
|
||||||
|
sk_variant: [],
|
||||||
user_agent: 'Rails Testing',
|
user_agent: 'Rails Testing',
|
||||||
user_roles: 'Guest'
|
user_roles: 'Guest'
|
||||||
})
|
})
|
||||||
|
@ -61,6 +64,8 @@ describe ApplicationController, type: :controller do
|
||||||
payload.delete(key)
|
payload.delete(key)
|
||||||
end
|
end
|
||||||
expect(payload).to eq({
|
expect(payload).to eq({
|
||||||
|
sk_rendered_format: nil,
|
||||||
|
sk_variant: [],
|
||||||
user_agent: 'Rails Testing',
|
user_agent: 'Rails Testing',
|
||||||
user_id: current_user.id,
|
user_id: current_user.id,
|
||||||
user_email: current_user.email,
|
user_email: current_user.email,
|
||||||
|
@ -85,6 +90,8 @@ describe ApplicationController, type: :controller do
|
||||||
payload.delete(key)
|
payload.delete(key)
|
||||||
end
|
end
|
||||||
expect(payload).to eq({
|
expect(payload).to eq({
|
||||||
|
sk_rendered_format: nil,
|
||||||
|
sk_variant: [],
|
||||||
user_agent: 'Rails Testing',
|
user_agent: 'Rails Testing',
|
||||||
user_id: current_user.id,
|
user_id: current_user.id,
|
||||||
user_email: current_user.email,
|
user_email: current_user.email,
|
||||||
|
|
|
@ -4,6 +4,7 @@ describe Manager::ApplicationController, type: :controller do
|
||||||
let(:payload) { {} }
|
let(:payload) { {} }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
allow(@controller).to receive(:content_type).and_return('')
|
||||||
allow(@controller).to receive(:current_user).and_return(current_user)
|
allow(@controller).to receive(:current_user).and_return(current_user)
|
||||||
@controller.send(:append_info_to_payload, payload)
|
@controller.send(:append_info_to_payload, payload)
|
||||||
end
|
end
|
||||||
|
@ -13,6 +14,8 @@ describe Manager::ApplicationController, type: :controller do
|
||||||
payload.delete(key)
|
payload.delete(key)
|
||||||
end
|
end
|
||||||
expect(payload).to eq({
|
expect(payload).to eq({
|
||||||
|
sk_rendered_format: nil,
|
||||||
|
sk_variant: [],
|
||||||
user_agent: 'Rails Testing',
|
user_agent: 'Rails Testing',
|
||||||
user_id: current_user.id,
|
user_id: current_user.id,
|
||||||
user_email: current_user.email
|
user_email: current_user.email
|
||||||
|
|
|
@ -1,6 +1,36 @@
|
||||||
describe Manager::UsersController, type: :controller do
|
describe Manager::UsersController, type: :controller do
|
||||||
let(:administration) { create(:administration) }
|
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
|
describe '#delete' do
|
||||||
let!(:user) { create(:user) }
|
let!(:user) { create(:user) }
|
||||||
|
|
||||||
|
|
|
@ -3,29 +3,29 @@ require 'spec_helper'
|
||||||
feature 'Outdated browsers support:' do
|
feature 'Outdated browsers support:' do
|
||||||
context 'when the user browser is outdated' do
|
context 'when the user browser is outdated' do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
ie_10_user_agent = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)'
|
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_10_user_agent)
|
Capybara.page.driver.header('user-agent', ie_11_user_agent)
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'a banner is displayed' do
|
scenario 'a banner is displayed' do
|
||||||
visit new_user_session_path
|
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
|
end
|
||||||
|
|
||||||
scenario 'the banner can be dismissed' do
|
scenario 'the banner can be dismissed' do
|
||||||
visit new_user_session_path
|
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
|
# The banner is hidden immediately
|
||||||
within '#outdated-browser-banner' do
|
within '#outdated-browser-banner' do
|
||||||
click_on 'Ignorer'
|
click_on 'Ignorer'
|
||||||
end
|
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)
|
expect(page).to have_current_path(new_user_session_path)
|
||||||
|
|
||||||
# The banner is hidden after a refresh
|
# The banner is hidden after a refresh
|
||||||
page.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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -91,7 +91,14 @@ describe Champs::LinkedDropDownListChamp do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when there is a secondary value' do
|
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 }
|
it { is_expected.not_to be_mandatory_and_blank }
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Exercice do
|
describe Exercice do
|
||||||
|
describe 'validations' do
|
||||||
|
it { is_expected.to validate_presence_of(:ca) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -534,41 +534,101 @@ describe Procedure do
|
||||||
let(:procedure) { create(:procedure, path: 'example-path') }
|
let(:procedure) { create(:procedure, path: 'example-path') }
|
||||||
let(:now) { Time.zone.now.beginning_of_minute }
|
let(:now) { Time.zone.now.beginning_of_minute }
|
||||||
|
|
||||||
after { Timecop.return }
|
context 'when publishing a new procedure' do
|
||||||
|
|
||||||
context "without parent procedure" do
|
|
||||||
before do
|
before do
|
||||||
Timecop.freeze(now)
|
Timecop.freeze(now) do
|
||||||
procedure.publish!
|
procedure.publish!
|
||||||
|
end
|
||||||
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.closed_at).to be_nil
|
||||||
expect(procedure.published_at).to eq(now)
|
expect(procedure.published_at).to eq(now)
|
||||||
expect(Procedure.find_by(path: "example-path")).to eq(procedure)
|
expect(Procedure.find_by(path: "example-path")).to eq(procedure)
|
||||||
expect(Procedure.find_by(path: "example-path").administrateurs).to eq(procedure.administrateurs)
|
expect(Procedure.find_by(path: "example-path").administrateurs).to eq(procedure.administrateurs)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
describe "#publish_or_reopen!" do
|
describe "#publish_or_reopen!" do
|
||||||
let(:published_procedure) { create(:procedure, :published) }
|
let(:canonical_procedure) { create(:procedure, :published) }
|
||||||
let(:administrateur) { published_procedure.administrateurs.first }
|
let(:administrateur) { canonical_procedure.administrateurs.first }
|
||||||
|
|
||||||
let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
|
let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
|
||||||
let(:now) { Time.zone.now.beginning_of_minute }
|
let(:now) { Time.zone.now.beginning_of_minute }
|
||||||
|
|
||||||
context "without parent procedure" do
|
context 'when publishing over a previous canonical procedure' do
|
||||||
before do
|
before do
|
||||||
Timecop.freeze(now)
|
procedure.path = canonical_procedure.path
|
||||||
procedure.path = published_procedure.path
|
Timecop.freeze(now) do
|
||||||
procedure.publish_or_reopen!(administrateur)
|
procedure.publish_or_reopen!(administrateur)
|
||||||
|
end
|
||||||
|
canonical_procedure.reload
|
||||||
end
|
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.closed_at).to be_nil
|
||||||
expect(procedure.published_at).to eq(now)
|
expect(procedure.published_at).to eq(now)
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -577,10 +637,10 @@ describe Procedure do
|
||||||
let(:now) { Time.zone.now.beginning_of_minute }
|
let(:now) { Time.zone.now.beginning_of_minute }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Timecop.freeze(now)
|
Timecop.freeze(now) do
|
||||||
procedure.unpublish!
|
procedure.unpublish!
|
||||||
|
end
|
||||||
end
|
end
|
||||||
after { Timecop.return }
|
|
||||||
|
|
||||||
it {
|
it {
|
||||||
expect(procedure.closed_at).to eq(nil)
|
expect(procedure.closed_at).to eq(nil)
|
||||||
|
@ -653,11 +713,11 @@ describe Procedure do
|
||||||
let(:procedure) { create(:procedure, :published) }
|
let(:procedure) { create(:procedure, :published) }
|
||||||
let(:now) { Time.zone.now.beginning_of_minute }
|
let(:now) { Time.zone.now.beginning_of_minute }
|
||||||
before do
|
before do
|
||||||
Timecop.freeze(now)
|
Timecop.freeze(now) do
|
||||||
procedure.close!
|
procedure.close!
|
||||||
|
end
|
||||||
procedure.reload
|
procedure.reload
|
||||||
end
|
end
|
||||||
after { Timecop.return }
|
|
||||||
|
|
||||||
it { expect(procedure.close?).to be_truthy }
|
it { expect(procedure.close?).to be_truthy }
|
||||||
it { expect(procedure.closed_at).to eq(now) }
|
it { expect(procedure.closed_at).to eq(now) }
|
||||||
|
|
|
@ -295,7 +295,9 @@ describe ProcedureExportService do
|
||||||
"Question / Introduction",
|
"Question / Introduction",
|
||||||
"Réponse",
|
"Réponse",
|
||||||
"Créé le",
|
"Créé le",
|
||||||
"Répondu le"
|
"Répondu le",
|
||||||
|
"Instructeur",
|
||||||
|
"Expert"
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue