diff --git a/.gitignore b/.gitignore index d7587c6c6..8d761de27 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,6 @@ bin/* config/initializers/token.rb config/initializers/super_admin.rb doc/*.svg -rubocop.html config/france_connect.yml config/initializers/mailjet.rb config/fog_credentials.yml @@ -35,3 +34,4 @@ uploads/* coverage/**/* .DS_Store .byebug_history +.env diff --git a/.rubocop.yml b/.rubocop.yml deleted file mode 100644 index 341d26106..000000000 --- a/.rubocop.yml +++ /dev/null @@ -1,7 +0,0 @@ -require: rubocop-rspec -AllCops: - Exclude: - - db/**/* - RunRailsCops: true -Metrics/LineLength: - Enabled: false diff --git a/Gemfile b/Gemfile index a389a030a..aea82425d 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,5 @@ source 'https://rubygems.org' -# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '5.0.0.1' gem 'actioncable', '5.0.0.1' @@ -18,30 +17,22 @@ gem 'therubyracer', platforms: :ruby gem 'jquery-rails' # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks gem 'turbolinks', '~> 2.5' -# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.0' # bundle exec rake doc:rails generates the API under doc/api. gem 'sdoc', '~> 0.4.0', group: :doc # Enable deep clone of active record models gem 'deep_cloneable', '~> 2.2.1' -# Use ActiveModel has_secure_password -# gem 'bcrypt', '~> 3.1.7' - # Use Unicorn as the app server gem 'unicorn' -# Use Capistrano for deployment -# gem 'capistrano-rails', group: :development - # serializer gem 'active_model_serializers' -#haml +# haml gem 'haml-rails' -#bootstrap saas +# bootstrap saas gem 'bootstrap-sass', '~> 3.3.5' # Pagination @@ -49,9 +40,10 @@ gem 'will_paginate-bootstrap' # Decorators gem 'draper', '~> 3.0.0.pre1' + gem 'unicode_utils' -#Gestion des comptes utilisateurs +# Gestion des comptes utilisateurs gem 'devise' gem 'openid_connect' @@ -76,13 +68,13 @@ gem 'chartkick' gem 'logstasher' -gem "font-awesome-rails" +gem 'font-awesome-rails' gem 'hashie' gem 'mailjet' -gem "smart_listing" +gem 'smart_listing' gem 'bootstrap-wysihtml5-rails', '~> 0.3.3.8' @@ -90,7 +82,8 @@ gem 'as_csv' gem 'spreadsheet_architect' gem 'apipie-rails' -gem "maruku" # for Markdown support in apipie +# For Markdown support in apipie +gem 'maruku' gem 'openstack' @@ -98,15 +91,22 @@ gem 'browser' gem 'simple_form' +gem 'newrelic_rpm' + +# Sidekiq +gem 'sidekiq' +gem 'sidekiq-cron', '~> 0.4.4' +gem 'sinatra', git: 'https://github.com/sinatra/sinatra.git', require: false + +gem 'select2-rails' + group :test do gem 'capybara' gem 'launchy' gem 'factory_girl' gem 'database_cleaner' - gem 'selenium-webdriver' gem 'webmock' gem 'shoulda-matchers', require: false - gem 'simplecov', require: false gem 'poltergeist' gem 'timecop' gem 'guard' @@ -122,13 +122,9 @@ group :development do gem 'web-console' gem 'rack-handlers' gem 'xray-rails' - gem 'scenic' end group :development, :test do - # gem 'terminal-notifier' - # gem 'terminal-notifier-guard' - # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' gem 'pry-byebug' @@ -138,21 +134,17 @@ group :development, :test do gem 'spring-commands-rspec' gem 'rspec-rails', '~> 3.0' - gem 'railroady' - - gem 'rubocop', require: false - gem 'rubocop-checkstyle_formatter', require: false - gem 'rubocop-rspec', require: false - - gem 'parallel_tests', '~> 2.10' - - gem 'brakeman', require: false - # Deploy gem 'mina', ref: '343a7', git: 'https://github.com/mina-deploy/mina.git' + + # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' + gem 'dotenv-rails' end group :production, :staging do - gem 'scenic' gem 'sentry-raven' end + +group :production, :staging, :development do + gem 'scenic' +end diff --git a/Gemfile.lock b/Gemfile.lock index aa235f499..3eb20b63b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,6 +7,18 @@ GIT open4 (~> 1.3.4) rake +GIT + remote: https://github.com/sinatra/sinatra.git + revision: d0c4053fd459be9f2c207cfeec5c0606461c014b + specs: + rack-protection (2.0.0.rc1) + rack + sinatra (2.0.0.rc1) + mustermann (= 1.0.0) + rack (~> 2.0) + rack-protection (= 2.0.0.rc1) + tilt (~> 2.0) + GEM remote: https://rubygems.org/ specs: @@ -66,7 +78,6 @@ GEM actionpack (>= 3.0) activemodel (>= 3.0) responders - ast (2.3.0) attr_required (1.0.1) autoprefixer-rails (6.5.4) execjs @@ -83,7 +94,6 @@ GEM sass (>= 3.3.4) bootstrap-wysihtml5-rails (0.3.3.8) railties (>= 3.0) - brakeman (3.4.1) browser (2.3.0) builder (3.2.2) byebug (9.0.6) @@ -101,8 +111,6 @@ GEM mime-types (>= 1.16) mimemagic (>= 0.3.0) chartkick (2.2.1) - childprocess (0.5.9) - ffi (~> 1.0, >= 1.0.11) clamav-client (3.1.0) cliver (0.3.2) coderay (1.1.1) @@ -114,6 +122,7 @@ GEM execjs coffee-script-source (1.11.1) concurrent-ruby (1.0.2) + connection_pool (2.2.1) crack (0.4.3) safe_yaml (~> 1.0.0) database_cleaner (1.5.3) @@ -127,9 +136,12 @@ GEM responders warden (~> 1.2.3) diff-lcs (1.2.5) - docile (1.1.5) domain_name (0.5.20161129) unf (>= 0.0.5, < 1.0.0) + dotenv (2.2.0) + dotenv-rails (2.2.0) + dotenv (= 2.2.0) + railties (>= 3.2, < 5.1) draper (3.0.0.pre1) actionpack (~> 5.0) activemodel (~> 5.0) @@ -322,14 +334,11 @@ GEM i18n (0.7.0) inflecto (0.0.2) ipaddress (0.8.3) - jbuilder (2.6.1) - activesupport (>= 3.0.0, < 5.1) - multi_json (~> 1.2) jquery-rails (4.2.1) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.3) + json (1.8.6) json-jwt (1.7.0) activesupport bindata @@ -378,8 +387,10 @@ GEM minitest (5.10.1) multi_json (1.12.1) multipart-post (2.0.0) + mustermann (1.0.0) nenv (0.3.0) netrc (0.11.0) + newrelic_rpm (3.18.1.330) nio4r (1.2.1) nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) @@ -401,17 +412,11 @@ GEM openstack (3.3.7) json orm_adapter (0.5.0) - parallel (1.10.0) - parallel_tests (2.10.0) - parallel - parser (2.3.3.1) - ast (~> 2.2) pg (0.19.0) poltergeist (1.12.0) capybara (~> 2.1) cliver (~> 0.3.1) websocket-driver (>= 0.2.0) - powerpack (0.1.1) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -431,7 +436,6 @@ GEM rack (>= 1.1) rack-test (0.6.3) rack (>= 1.0) - railroady (1.5.2) rails (5.0.0.1) actioncable (= 5.0.0.1) actionmailer (= 5.0.0.1) @@ -459,7 +463,6 @@ GEM method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.1.0) raindrops (0.17.0) rake (12.0.0) rb-fsevent (0.9.8) @@ -471,7 +474,9 @@ GEM nokogiri (~> 1.5) trollop (~> 2.1) rdoc (4.3.0) - redis (3.3.0) + redis (3.3.3) + redis-namespace (1.5.3) + redis (~> 3.0, >= 3.0.4) ref (2.0.0) request_store (1.3.1) responders (2.3.0) @@ -508,21 +513,12 @@ GEM rspec-mocks (~> 3.5.0) rspec-support (~> 3.5.0) rspec-support (3.5.0) - rubocop (0.46.0) - parser (>= 2.3.1.1, < 3.0) - powerpack (~> 0.1) - rainbow (>= 1.99.1, < 3.0) - ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.0, >= 1.0.1) - rubocop-checkstyle_formatter (0.3.0) - rubocop (>= 0.30.1) - rubocop-rspec (1.8.0) - rubocop (>= 0.42.0) - ruby-progressbar (1.8.1) ruby_dep (1.5.0) ruby_parser (3.8.3) sexp_processor (~> 4.1) rubyzip (1.0.0) + rufus-scheduler (3.3.4) + tzinfo safe_yaml (1.0.4) sass (3.4.22) sass-rails (5.0.6) @@ -538,24 +534,26 @@ GEM json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) securecompare (1.0.0) - selenium-webdriver (3.0.3) - childprocess (~> 0.5) - rubyzip (~> 1.0) - websocket (~> 1.0) + select2-rails (4.0.3) + thor (~> 0.14) sentry-raven (2.2.0) faraday (>= 0.7.6, < 1.0) sexp_processor (4.7.0) shellany (0.0.1) shoulda-matchers (3.1.1) activesupport (>= 4.0.0) + sidekiq (4.2.9) + concurrent-ruby (~> 1.0) + connection_pool (~> 2.2, >= 2.2.0) + rack-protection (>= 1.5.0) + redis (~> 3.2, >= 3.2.1) + sidekiq-cron (0.4.5) + redis-namespace (>= 1.5.2) + rufus-scheduler (>= 2.0.24) + sidekiq (>= 4.2.1) simple_form (3.4.0) actionpack (> 4, < 5.1) activemodel (> 4, < 5.1) - simplecov (0.12.0) - docile (~> 1.1.0) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.0) slop (3.6.0) smart_listing (1.2.0) coffee-rails @@ -600,7 +598,6 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.2) - unicode-display_width (1.1.2) unicode_utils (1.4.0) unicorn (5.2.0) kgio (~> 2.6) @@ -628,7 +625,6 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff - websocket (1.2.3) websocket-driver (0.6.4) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -652,7 +648,6 @@ DEPENDENCIES bootstrap-datepicker-rails bootstrap-sass (~> 3.3.5) bootstrap-wysihtml5-rails (~> 0.3.3.8) - brakeman browser byebug capybara @@ -662,6 +657,7 @@ DEPENDENCIES database_cleaner deep_cloneable (~> 2.2.1) devise + dotenv-rails draper (~> 3.0.0.pre1) factory_girl fog @@ -672,7 +668,6 @@ DEPENDENCIES guard-rspec haml-rails hashie - jbuilder (~> 2.0) jquery-rails launchy leaflet-draw-rails @@ -682,31 +677,29 @@ DEPENDENCIES mailjet maruku mina! + newrelic_rpm openid_connect openstack - parallel_tests (~> 2.10) pg poltergeist pry-byebug rack-handlers - railroady rails (= 5.0.0.1) rails-controller-testing redis rest-client rgeo-geojson rspec-rails (~> 3.0) - rubocop - rubocop-checkstyle_formatter - rubocop-rspec sass-rails (~> 5.0) scenic sdoc (~> 0.4.0) - selenium-webdriver + select2-rails sentry-raven shoulda-matchers + sidekiq + sidekiq-cron (~> 0.4.4) simple_form - simplecov + sinatra! smart_listing spreadsheet_architect spring @@ -725,4 +718,4 @@ DEPENDENCIES xray-rails BUNDLED WITH - 1.14.4 + 1.14.6 diff --git a/LICENSE.agpl-3.0.txt b/LICENSE.agpl-3.0.txt new file mode 100644 index 000000000..923414255 --- /dev/null +++ b/LICENSE.agpl-3.0.txt @@ -0,0 +1,661 @@ +GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + + Preamble + +The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + +A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + +The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + +An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + +The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + +0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +1. Source Code. + +The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + +The Corresponding Source for a work in source code form is that +same work. + +2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + +4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + +a) The work must carry prominent notices stating that you modified +it, and giving a relevant date. + +b) The work must carry prominent notices stating that it is +released under this License and any conditions added under section +7. This requirement modifies the requirement in section 4 to +"keep intact all notices". + +c) You must license the entire work, as a whole, under this +License to anyone who comes into possession of a copy. This +License will therefore apply, along with any applicable section 7 +additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no +permission to license the work in any other way, but it does not +invalidate such permission if you have separately received it. + +d) If the work has interactive user interfaces, each must display +Appropriate Legal Notices; however, if the Program has interactive +interfaces that do not display Appropriate Legal Notices, your +work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + +a) Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by the +Corresponding Source fixed on a durable physical medium +customarily used for software interchange. + +b) Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by a +written offer, valid for at least three years and valid for as +long as you offer spare parts or customer support for that product +model, to give anyone who possesses the object code either (1) a +copy of the Corresponding Source for all the software in the +product that is covered by this License, on a durable physical +medium customarily used for software interchange, for a price no +more than your reasonable cost of physically performing this +conveying of source, or (2) access to copy the +Corresponding Source from a network server at no charge. + +c) Convey individual copies of the object code with a copy of the +written offer to provide the Corresponding Source. This +alternative is allowed only occasionally and noncommercially, and +only if you received the object code with such an offer, in accord +with subsection 6b. + +d) Convey the object code by offering access from a designated +place (gratis or for a charge), and offer equivalent access to the +Corresponding Source in the same way through the same place at no +further charge. You need not require recipients to copy the +Corresponding Source along with the object code. If the place to +copy the object code is a network server, the Corresponding Source +may be on a different server (operated by you or a third party) +that supports equivalent copying facilities, provided you maintain +clear directions next to the object code saying where to find the +Corresponding Source. Regardless of what server hosts the +Corresponding Source, you remain obligated to ensure that it is +available for as long as needed to satisfy these requirements. + +e) Convey the object code using peer-to-peer transmission, provided +you inform other peers where the object code and Corresponding +Source of the work are being offered to the general public at no +charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + +a) Disclaiming warranty or limiting liability differently from the +terms of sections 15 and 16 of this License; or + +b) Requiring preservation of specified reasonable legal notices or +author attributions in that material or in the Appropriate Legal +Notices displayed by works containing it; or + +c) Prohibiting misrepresentation of the origin of that material, or +requiring that modified versions of such material be marked in +reasonable ways as different from the original version; or + +d) Limiting the use for publicity purposes of names of licensors or +authors of the material; or + +e) Declining to grant rights under trademark law for use of some +trade names, trademarks, or service marks; or + +f) Requiring indemnification of licensors and authors of that +material by anyone who conveys the material (or modified versions of +it) with contractual assumptions of liability to the recipient, for +any liability that these contractual assumptions directly impose on +those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + +8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + +13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + +14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + +Copyright (C) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + +You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/app/assets/images/drapeau_europe.png b/app/assets/images/drapeau_europe.png index 67289bccc..21cb9ab13 100644 Binary files a/app/assets/images/drapeau_europe.png and b/app/assets/images/drapeau_europe.png differ diff --git a/app/assets/images/edit.png b/app/assets/images/edit.png index 3f82d738b..bd2a9c31d 100644 Binary files a/app/assets/images/edit.png and b/app/assets/images/edit.png differ diff --git a/app/assets/images/etapes/complet_2.png b/app/assets/images/etapes/complet_2.png index 90c8241f4..148292409 100644 Binary files a/app/assets/images/etapes/complet_2.png and b/app/assets/images/etapes/complet_2.png differ diff --git a/app/assets/images/etapes/create_1.png b/app/assets/images/etapes/create_1.png index 1a37f8c11..cbc61e88e 100644 Binary files a/app/assets/images/etapes/create_1.png and b/app/assets/images/etapes/create_1.png differ diff --git a/app/assets/images/etapes/message_3.png b/app/assets/images/etapes/message_3.png index facf08a69..fa0cdbeb1 100644 Binary files a/app/assets/images/etapes/message_3.png and b/app/assets/images/etapes/message_3.png differ diff --git a/app/assets/images/etapes/shared_4.png b/app/assets/images/etapes/shared_4.png index 90ce51dd3..6fcdee938 100644 Binary files a/app/assets/images/etapes/shared_4.png and b/app/assets/images/etapes/shared_4.png differ diff --git a/app/assets/images/franceconnect_logo.png b/app/assets/images/franceconnect_logo.png index 393bfc221..c1a8ce071 100644 Binary files a/app/assets/images/franceconnect_logo.png and b/app/assets/images/franceconnect_logo.png differ diff --git a/app/assets/images/landing_background.png b/app/assets/images/landing_background.png index a043859f7..5e4169f67 100644 Binary files a/app/assets/images/landing_background.png and b/app/assets/images/landing_background.png differ diff --git a/app/assets/images/landing_background_old.png b/app/assets/images/landing_background_old.png index 1d67e71a1..77e4b9b0e 100644 Binary files a/app/assets/images/landing_background_old.png and b/app/assets/images/landing_background_old.png differ diff --git a/app/assets/images/logo_FC_02.png b/app/assets/images/logo_FC_02.png index f69cbb86b..d3d246d48 100644 Binary files a/app/assets/images/logo_FC_02.png and b/app/assets/images/logo_FC_02.png differ diff --git a/app/assets/images/logo_FC_02_small.png b/app/assets/images/logo_FC_02_small.png index 24ac2810b..944de73ce 100644 Binary files a/app/assets/images/logo_FC_02_small.png and b/app/assets/images/logo_FC_02_small.png differ diff --git a/app/assets/images/logo_mini_FC.png b/app/assets/images/logo_mini_FC.png index f2c46cf0b..f52981879 100644 Binary files a/app/assets/images/logo_mini_FC.png and b/app/assets/images/logo_mini_FC.png differ diff --git a/app/assets/images/logos-02V.png b/app/assets/images/logos-02V.png index b74ebfdb3..3712d2d8b 100644 Binary files a/app/assets/images/logos-02V.png and b/app/assets/images/logos-02V.png differ diff --git a/app/assets/images/logos/logo-opensimplif.jpg b/app/assets/images/logos/logo-opensimplif.jpg index d87c8b015..a4e3bc9f9 100644 Binary files a/app/assets/images/logos/logo-opensimplif.jpg and b/app/assets/images/logos/logo-opensimplif.jpg differ diff --git a/app/assets/images/logos/logo-tps.png b/app/assets/images/logos/logo-tps.png index b667980eb..a6d614857 100644 Binary files a/app/assets/images/logos/logo-tps.png and b/app/assets/images/logos/logo-tps.png differ diff --git a/app/assets/images/logos/logo-tps_old.png b/app/assets/images/logos/logo-tps_old.png index af81e35a9..7d785b1f2 100644 Binary files a/app/assets/images/logos/logo-tps_old.png and b/app/assets/images/logos/logo-tps_old.png differ diff --git a/app/assets/images/marianne_small.png b/app/assets/images/marianne_small.png index 886b05bf7..cc77557a6 100644 Binary files a/app/assets/images/marianne_small.png and b/app/assets/images/marianne_small.png differ diff --git a/app/assets/images/marker-icon.png b/app/assets/images/marker-icon.png index de1f1568d..10c179077 100644 Binary files a/app/assets/images/marker-icon.png and b/app/assets/images/marker-icon.png differ diff --git a/app/assets/images/pencil.png b/app/assets/images/pencil.png index c8ccf045b..d0b269009 100644 Binary files a/app/assets/images/pencil.png and b/app/assets/images/pencil.png differ diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index 6c2e63536..967633a7b 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -23,22 +23,25 @@ function destroy_action(){ } function on_change_type_de_champ_select (){ - $("select.form-control.type_champ").on('change', function(e){ parent = $(this).parent().parent(); parent.removeClass('header_section'); parent.children(".drop_down_list").removeClass('show_inline'); + $('.mandatory', parent).show(); switch(this.value){ case 'header_section': parent.addClass('header_section'); break; case 'drop_down_list': + case 'multiple_drop_down_list': parent.children(".drop_down_list").addClass('show_inline'); break; - + case 'explication': + $('.mandatory', parent).hide(); + break; } - }) + }); } diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 567658f93..a7827dfc8 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -31,6 +31,7 @@ //= require bootstrap-wysihtml5/locales/fr-FR //= require handlebars //= require typeahead.bundle +//= require select2 $(document).on('page:load', application_init); $(document).ready(application_init); diff --git a/app/assets/javascripts/user/description.js b/app/assets/javascripts/user/description.js new file mode 100644 index 000000000..cdae9a4c1 --- /dev/null +++ b/app/assets/javascripts/user/description.js @@ -0,0 +1,6 @@ +$(document).on('page:load', activeSelect2); +$(document).ready(activeSelect2); + +function activeSelect2() { + $('select.select2').select2({ theme: "bootstrap", width: '100%' }); +} diff --git a/app/assets/stylesheets/admin_type_de_champ.scss b/app/assets/stylesheets/admin_type_de_champ.scss index e4a9b92e9..bc2613075 100644 --- a/app/assets/stylesheets/admin_type_de_champ.scss +++ b/app/assets/stylesheets/admin_type_de_champ.scss @@ -23,6 +23,10 @@ } #liste_champ{ + .form-inline { + margin-bottom: 30px; + } + .show_inline { display: inline-block !important; } @@ -30,4 +34,16 @@ .form-group.drop_down_list{ display: none; } -} \ No newline at end of file + + .form-group { + vertical-align: top; + margin-right: 15px; + } + + .description { + padding: 0; + textarea { + padding: 6px 12px; + } + } +} diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 5e30ef194..6d4168935 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -19,6 +19,8 @@ *= require font-awesome *= require franceconnect *= require bootstrap-wysihtml5 + *= require select2 + *= require select2-bootstrap */ @import "variables"; @import "bootstrap-sprockets"; diff --git a/app/controllers/admin/procedures_controller.rb b/app/controllers/admin/procedures_controller.rb index fa04bb72d..639c79242 100644 --- a/app/controllers/admin/procedures_controller.rb +++ b/app/controllers/admin/procedures_controller.rb @@ -193,10 +193,11 @@ class Admin::ProceduresController < AdminController private def procedure_params + editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :lien_notice, :euro_flag, :logo, :auto_archive_on] if @procedure.try(:locked?) - params.require(:procedure).permit(:libelle, :description, :organisation, :direction, :lien_site_web, :lien_notice, :euro_flag, :logo) + params.require(:procedure).permit(*editable_params) else - params.require(:procedure).permit(:libelle, :description, :organisation, :direction, :lien_site_web, :lien_notice, :euro_flag, :logo, :lien_demarche, :cerfa_flag, :for_individual, :individual_with_siret, module_api_carto_attributes: [:id, :use_api_carto, :quartiers_prioritaires, :cadastre]).merge(administrateur_id: current_administrateur.id) + params.require(:procedure).permit(*editable_params, :lien_demarche, :cerfa_flag, :for_individual, :individual_with_siret, module_api_carto_attributes: [:id, :use_api_carto, :quartiers_prioritaires, :cadastre]).merge(administrateur_id: current_administrateur.id) end end diff --git a/app/controllers/demo_controller.rb b/app/controllers/demo_controller.rb index 89f1da027..5933c5735 100644 --- a/app/controllers/demo_controller.rb +++ b/app/controllers/demo_controller.rb @@ -6,7 +6,7 @@ class DemoController < ApplicationController return redirect_to root_path if Rails.env.production? smart_listing_create :procedures, - Procedure.where(archived: false, published: true), + Procedure.where(archived: false, published: true).order("id DESC"), partial: "demo/list", array: true end diff --git a/app/decorators/champ_decorator.rb b/app/decorators/champ_decorator.rb index 42c9639e4..8c95b8183 100644 --- a/app/decorators/champ_decorator.rb +++ b/app/decorators/champ_decorator.rb @@ -2,9 +2,8 @@ class ChampDecorator < Draper::Decorator delegate_all def value - if type_champ == 'checkbox' - return object.value == 'on' ? 'Oui' : 'Non' - end + return object.value == 'on' ? 'Oui' : 'Non' if type_champ == 'checkbox' + return JSON.parse(object.value).join(', ') if type_champ == 'multiple_drop_down_list' && object.value.present? object.value end diff --git a/app/decorators/france_connect_information_decorator.rb b/app/decorators/france_connect_information_decorator.rb index 27e69987d..503caee5b 100644 --- a/app/decorators/france_connect_information_decorator.rb +++ b/app/decorators/france_connect_information_decorator.rb @@ -2,6 +2,6 @@ class FranceConnectInformationDecorator < Draper::Decorator delegate_all def gender_fr - gender == 'female' ? 'Mme' : 'Mr' + gender == 'female' ? 'Mme' : 'M.' end end diff --git a/app/decorators/type_de_champ_decorator.rb b/app/decorators/type_de_champ_decorator.rb index ffe824855..d54293195 100644 --- a/app/decorators/type_de_champ_decorator.rb +++ b/app/decorators/type_de_champ_decorator.rb @@ -3,11 +3,19 @@ class TypeDeChampDecorator < Draper::Decorator delegate_all def button_up params - h.link_to '', params[:url], class: up_classes, id: "btn_up_#{params[:index]}", remote: true, method: :post if display_up_button?(params[:index], params[:private]) + h.link_to '', params[:url], class: up_classes, + id: "btn_up_#{params[:index]}", + remote: true, + method: :post, + style: display_up_button?(params[:index], params[:private]) ? '' : 'visibility: hidden;' end def button_down params - h.link_to '', params[:url], class: down_classes, id: "btn_down_#{params[:index]}", remote: true, method: :post if display_down_button?(params[:index], params[:private]) + h.link_to '', params[:url], class: down_classes, + id: "btn_down_#{params[:index]}", + remote: true, + method: :post, + style: display_down_button?(params[:index], params[:private]) ? '' : 'visibility: hidden;' end private diff --git a/app/decorators/user_decorator.rb b/app/decorators/user_decorator.rb index 97430e215..d870ccd0a 100644 --- a/app/decorators/user_decorator.rb +++ b/app/decorators/user_decorator.rb @@ -2,7 +2,7 @@ class UserDecorator < Draper::Decorator delegate_all def gender_fr - return 'Mr' if gender == 'male' + return 'M.' if gender == 'male' return 'Mme' if gender == 'female' end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 00afd691e..7002b2ab9 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -181,9 +181,7 @@ class Dossier < ActiveRecord::Base where(state: WAITING_FOR_USER, archived: false).order("updated_at #{order}") end - def self.en_construction order = 'ASC' - where(state: EN_CONSTRUCTION, archived: false).order("updated_at #{order}") - end + scope :en_construction, -> { where(state: EN_CONSTRUCTION, archived: false).order(updated_at: :asc) } def self.ouvert order = 'ASC' where(state: OUVERT, archived: false).order("updated_at #{order}") diff --git a/app/models/drop_down_list.rb b/app/models/drop_down_list.rb index d6e2d3d02..979112f4c 100644 --- a/app/models/drop_down_list.rb +++ b/app/models/drop_down_list.rb @@ -2,6 +2,19 @@ class DropDownList < ActiveRecord::Base belongs_to :type_de_champ def options - value.split(/[\r\n]|[\r]|[\n]|[\n\r]/).reject(&:empty?) + result = value.split(/[\r\n]|[\r]|[\n]|[\n\r]/).reject(&:empty?) + result.blank? ? [] : [''] + result + end + + def disabled_options + options.select{ |v| !(v =~ /^--.*--$/).nil? } + end + + def selected_options(champ) + champ.object.value.blank? ? [] : multiple ? JSON.parse(champ.object.value) : [champ.object.value] + end + + def multiple + type_de_champ.type_champ == 'multiple_drop_down_list' end end diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 947499b30..1d791e9d8 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -39,13 +39,15 @@ class Procedure < ActiveRecord::Base MAIL_TEMPLATE_TYPES = %w(InitiatedMail ReceivedMail ClosedMail RefusedMail WithoutContinuationMail) MAIL_TEMPLATE_TYPES.each do |name| - has_one "#{name.underscore}".to_sym, class_name: "Mails::#{name}" + has_one "#{name.underscore}".to_sym, class_name: "Mails::#{name}", dependent: :destroy define_method("#{name.underscore}_with_override") do self.send("#{name.underscore}_without_override") || Object.const_get("Mails::#{name}").default end alias_method_chain "#{name.underscore.to_sym}".to_s, :override end + scope :not_archived, -> { where(archived: false) } + def path procedure_path.path unless procedure_path.nil? end @@ -66,10 +68,6 @@ class Procedure < ActiveRecord::Base types_de_piece_justificative.order(:order_place) end - def self.not_archived id - Procedure.where(archived: false).find(id) - end - def self.active id Procedure.where(archived: false, published: true).find(id) end diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 9d1b2e693..2dbfb2d90 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -12,11 +12,13 @@ class TypeDeChamp < ActiveRecord::Base address: 'address', yes_no: 'yes_no', drop_down_list: 'drop_down_list', + multiple_drop_down_list: 'multiple_drop_down_list', pays: 'pays', regions: 'regions', departements: 'departements', engagement: 'engagement', - header_section: 'header_section' + header_section: 'header_section', + explication: 'explication' } belongs_to :procedure @@ -29,7 +31,7 @@ class TypeDeChamp < ActiveRecord::Base validates :libelle, presence: true, allow_blank: false, allow_nil: false validates :type_champ, presence: true, allow_blank: false, allow_nil: false - before_validation :change_header_section_mandatory + before_validation :check_mandatory def self.type_de_champs_list_fr type_champs.map { |champ| [I18n.t("activerecord.attributes.type_de_champ.type_champs.#{champ.last}"), champ.first] } @@ -39,8 +41,8 @@ class TypeDeChamp < ActiveRecord::Base !(type_champ == 'textarea' || type_champ == 'header_section') end - def change_header_section_mandatory - self.mandatory = false if self.type_champ == 'header_section' + def check_mandatory + self.mandatory = false if %w(header_section explication).include?(self.type_champ) true end end diff --git a/app/services/types_de_champ_service.rb b/app/services/types_de_champ_service.rb index b8397d3a4..eba9a549a 100644 --- a/app/services/types_de_champ_service.rb +++ b/app/services/types_de_champ_service.rb @@ -12,8 +12,18 @@ class TypesDeChampService if param_second[:libelle].empty? parameters[attributes].delete(param_first.to_s) end + + if param_second['drop_down_list_attributes'] && param_second['drop_down_list_attributes']['value'] + param_second['drop_down_list_attributes']['value'] = self.clean_value (param_second['drop_down_list_attributes']['value']) + end end parameters end -end \ No newline at end of file + + private + + def self.clean_value value + value.split("\r\n").map{ |v| v.strip }.join("\r\n") + end +end diff --git a/app/views/admin/procedures/_informations.html.haml b/app/views/admin/procedures/_informations.html.haml index 833f5fee3..c379ac924 100644 --- a/app/views/admin/procedures/_informations.html.haml +++ b/app/views/admin/procedures/_informations.html.haml @@ -80,3 +80,16 @@ %label = f.check_box :individual_with_siret Donner la possibilité de renseigner un SIRET au cours de la construction du dossier. +.row + .col-md-6 + %h4 Options avancées + + %label{ for: :auto_archive_on} Archivage automatique le + = f.text_field :auto_archive_on, id: 'auto_archive_on', value: @procedure.auto_archive_on.try{ |d| d.strftime("%d-%m-%Y") }, data: { provide: 'datepicker', 'date-format' => 'dd/mm/yyyy' } + (à 00h00) + %p.help-block + %i.fa.fa-info-circle + L'archivage automatique de la procédure entrainera le passage en instruction de tous les dossiers en construction. + + + diff --git a/app/views/admin/procedures/show.html.haml b/app/views/admin/procedures/show.html.haml index e0c945cff..7249a0ed6 100644 --- a/app/views/admin/procedures/show.html.haml +++ b/app/views/admin/procedures/show.html.haml @@ -82,7 +82,7 @@ .pieces_justificatives.col-xs-6.col-md-3 %h4.text-info - Pièces justificatives + Pièces jointes .badge.progress-bar-info = @facade.procedure.types_de_piece_justificative.size - @facade.procedure.types_de_piece_justificative.each do |piece_justificative| diff --git a/app/views/admin/profile/show.html.haml b/app/views/admin/profile/show.html.haml index 5349fd071..615d5331e 100644 --- a/app/views/admin/profile/show.html.haml +++ b/app/views/admin/profile/show.html.haml @@ -1,5 +1,5 @@ #profile_page -%h2 Profile +%h2 Profil %hr %p API TOKEN : diff --git a/app/views/admin/types_de_champ/_fields.html.haml b/app/views/admin/types_de_champ/_fields.html.haml index 649be960e..01c60cdd9 100644 --- a/app/views/admin/types_de_champ/_fields.html.haml +++ b/app/views/admin/types_de_champ/_fields.html.haml @@ -1,27 +1,31 @@ = f.fields_for @types_de_champ_facade.fields_for_var, types_de_champ, remote: true do |ff| - .form-inline{class:"#{ff.object.object.type_champ == 'header_section' ? 'header_section' : ''}"} + - type_champ = ff.object.object.type_champ + + .form-inline{ class: (type_champ == 'header_section' ? 'header_section' : nil) } .form-group.libelle %h4 Libellé = ff.text_field :libelle, class: 'form-control libelle', placeholder: 'Libellé' .form-group.type %h4 Type - = ff.select :type_champ, TypeDeChamp.type_de_champs_list_fr, {}, {class: 'form-control type_champ'} + = ff.select :type_champ, TypeDeChamp.type_de_champs_list_fr, {}, { class: 'form-control type_champ' } .form-group.description %h4 Description - = ff.text_area :description, class: 'form-control description', placeholder: 'Description', rows: 2 + = ff.text_area :description, class: 'form-control description', placeholder: 'Description', rows: 3 - .form-group.drop_down_list{class:"#{ff.object.object.type_champ == 'drop_down_list' ? 'show_inline' : ''}",style:'margin-right: 5px'} + .form-group.drop_down_list{ class: (%w(drop_down_list multiple_drop_down_list).include?(type_champ) ? 'show_inline' : nil), style: 'margin-right: 5px' } %h4 Liste déroulante = ff.fields_for :drop_down_list_attributes, ff.object.object.drop_down_list do |fff| - = fff.text_area :value, class: 'form-control drop_down_list', placeholder: "Ecrire une valeur par ligne.\nEcrire --valeur-- pour un séparateur.", rows: 3, cols: 30 + ~ fff.text_area :value, class: 'form-control drop_down_list', placeholder: "Ecrire une valeur par ligne et --valeur-- pour un séparateur.", rows: 3, cols: 30 = fff.hidden_field :id - - unless ff.object.object.class == TypeDeChampPrivate - .form-group.mandatory - %h4 Obligatoire ? - .center - = ff.check_box :mandatory, placeholder: 'Obligatoire ?' + + + - hide_mandatory = (ff.object.object.class == TypeDeChampPrivate || type_champ == 'explication') + .form-group.mandatory{ style: hide_mandatory ? 'visibility: hidden;' : nil } + %h4 Obligatoire ? + .center + = ff.check_box :mandatory, placeholder: 'Obligatoire ?' .form-group = ff.hidden_field :order_place, value: ff.index @@ -41,4 +45,6 @@ - else = link_to("", @types_de_champ_facade.delete_url(ff), method: :delete, remote: true, id: "delete_type_de_champ_#{ff.object.id}", class: %w(form-control btn btn-danger fa fa-trash-o) ) + %div{ style: 'background-color: rgb(204, 204, 204); height: 1px; margin: 30px auto;' } + diff --git a/app/views/administrations/_list.html.haml b/app/views/administrations/_list.html.haml index 10d515c57..3af742c9c 100644 --- a/app/views/administrations/_list.html.haml +++ b/app/views/administrations/_list.html.haml @@ -1,30 +1,31 @@ -- unless smart_listing.empty? - %table.table - %thead - %th.col-xs-4= smart_listing.sortable 'Email', :email - %th.col-xs-4= smart_listing.sortable 'Date de dernière connexion', :last_sign_in_at - %th.col-xs-2 Procédure active - %th.col-xs-2 Dossier en cours +.card + - unless smart_listing.empty? + %table.table + %thead + %th.col-xs-4= smart_listing.sortable 'Email', :email + %th.col-xs-4= smart_listing.sortable 'Date de dernière connexion', :last_sign_in_at + %th.col-xs-2 Procédure active + %th.col-xs-2 Dossier en cours - - @admins.each do |admin| - %tr - %td - = admin.email - %td - - unless admin.last_sign_in_at.nil? - = time_ago_in_words(l(admin.last_sign_in_at, format: "%d/%m/%Y %H:%M UTC +02:00")) - ( - = admin.last_sign_in_at.to_date.strftime('%d/%m/%Y') - ) - %td - = admin.procedures.where(published: true).count - %td - - total_dossier = 0 - - admin.procedures.each do |procedure| total_dossier += procedure.dossiers.where.not(state: :draft).count end - = total_dossier - = smart_listing.paginate - = smart_listing.pagination_per_page_links + - @admins.each do |admin| + %tr + %td + = admin.email + %td + - unless admin.last_sign_in_at.nil? + = time_ago_in_words(l(admin.last_sign_in_at, format: "%d/%m/%Y %H:%M UTC +02:00")) + ( + = admin.last_sign_in_at.to_date.strftime('%d/%m/%Y') + ) + %td + = admin.procedures.where(published: true).count + %td + - total_dossier = 0 + - admin.procedures.each do |procedure| total_dossier += procedure.dossiers.where.not(state: :draft).count end + = total_dossier + = smart_listing.paginate + = smart_listing.pagination_per_page_links -- else - %h4.center - Aucun administrateur créé + - else + %h4.center + Aucun administrateur créé diff --git a/app/views/administrations/index.html.haml b/app/views/administrations/index.html.haml index bf4e66d9a..07351a196 100644 --- a/app/views/administrations/index.html.haml +++ b/app/views/administrations/index.html.haml @@ -1,22 +1,19 @@ -%br -%br +.container + .mt-1 + = form_for @admin, url: {controller: 'administrations', action: :create} do |f| + .form-group.form-inline.text-center + = f.text_field :email, placeholder: :email, class: 'form-control' + = f.text_field :password, placeholder: :password, class: 'form-control' -= form_for @admin, url: {controller: 'administrations', action: :create} do |f| - .form-group.form-inline.center - = f.text_field :email, placeholder: :email, class: 'form-control' - = f.text_field :password, placeholder: :password, class: 'form-control' + = f.submit 'Créer un administrateur', class: 'btn btn-success', id: 'submit_new_administrateur' - = f.submit 'Valider', class: 'btn btn-success', id: 'submit_new_administrateur' + .text-center + =link_to 'Stats', administrations_stats_path, style: 'margin-bottom: 50px; display: block', 'data-no-turbolink': true -%br + = smart_listing_render :admins -.center - =link_to 'Stats', administrations_stats_path, style: 'margin-bottom: 50px; display: block', 'data-no-turbolink': true + %br + %br -= smart_listing_render :admins - -%br -%br - -.center - =link_to 'Deconnexion', '/administrations/sign_out', method: :delete \ No newline at end of file + .text-center + =link_to 'Deconnexion', '/administrations/sign_out', method: :delete \ No newline at end of file diff --git a/app/views/administrations/stats/index.html.haml b/app/views/administrations/stats/index.html.haml index 7c9a3f696..e24ecb500 100644 --- a/app/views/administrations/stats/index.html.haml +++ b/app/views/administrations/stats/index.html.haml @@ -3,7 +3,7 @@ .container .stats .stat-card - %h1 Procédures crées + %h1 Procédures créées = line_chart @procedures .stat-card diff --git a/app/views/dossiers/_infos_dossier.html.haml b/app/views/dossiers/_infos_dossier.html.haml index afe71a442..91d85a427 100644 --- a/app/views/dossiers/_infos_dossier.html.haml +++ b/app/views/dossiers/_infos_dossier.html.haml @@ -1,5 +1,5 @@ %div.row - .col-lg-12.col-md-12.col-sm-12.col-xs-12 + .col-xs-12 - if @facade.procedure.for_individual? .row.title-row %div.col-xs-4.split-hr @@ -7,24 +7,25 @@ %div.col-xs-4.split-hr .row %div.col-xs-6.depositaire-label Civilité - %div.col-md-1.col-lg-1.col-sm-1.col-xs-1.comments-off= "-" + %div.col-xs-1.comments-off= "-" %div.col-xs-5.depositaire-info= @facade.individual.gender .row %div.col-xs-6.depositaire-label Nom - %div.col-md-1.col-lg-1.col-sm-1.col-xs-1.comments-off= "-" + %div.col-xs-1.comments-off= "-" %div.col-xs-5.depositaire-info= @facade.individual.nom .row %div.col-xs-6.depositaire-label Prénom - %div.col-md-1.col-lg-1.col-sm-1.col-xs-1.comments-off= "-" + %div.col-xs-1.comments-off= "-" %div.col-xs-5.despositaire-info= @facade.individual.prenom .row %div.col-xs-6.depositaire-label Date de naissance - %div.col-md-1.col-lg-1.col-sm-1.col-xs-1.comments-off= "-" + %div.col-xs-1.comments-off= "-" %div.col-xs-5.depositaire-info= @facade.individual.birthdate .row.margin-top-20 - unless @facade.champs.nil? - @facade.champs.each do |champ| + - next if champ.type_champ == 'explication' - if champ.type_champ == 'header_section' .row.title-row.margin-top-40 %div.col-xs-3.split-hr @@ -48,19 +49,19 @@ =")" %div.row - if @facade.procedure.cerfa_flag? || @facade.dossier.types_de_piece_justificative.count > 0 - .col-lg-12.col-md-12.col-sm-12.col-xs-12 + .col-xs-12 .row.title-row %div.col-xs-4.split-hr %div.col-xs-4.dossier-title= t('utils.pieces').upcase %div.col-xs-4.split-hr - .col-lg-12.col-md-12.col-sm-12.col-xs-12#pieces_justificatives.margin-bot-40 + .col-xs-12#pieces_justificatives.margin-bot-40 .row - if @facade.procedure.cerfa_flag? .col-xs-12#piece_justificative_0 .row.piece-row .col-xs-6.depositaire-label= 'Formulaire' - .col-md-1.col-lg-1.col-sm-1.col-xs-1.comments-off= "-" + .col-xs-1.comments-off= "-" .col-xs-5.despositaire-info - if @facade.dossier.cerfa_available? %a{ href: "#{@facade.dossier.cerfa.last.content_url}", target: '_blank' } Consulter @@ -77,7 +78,7 @@ .col-xs-12{ id: "piece_justificative_#{type_de_piece_justificative.id}" } .row %div.col-xs-6.depositaire-label= type_de_piece_justificative.libelle - %div.col-md-1.col-lg-1.col-sm-1.col-xs-1.comments-off= "-" + %div.col-xs-1.comments-off= "-" %div.col-xs-5.despositaire-info - if type_de_piece_justificative.api_entreprise %span.text-success Nous l'avons récupéré pour vous. @@ -95,13 +96,13 @@ - if user_signed_in? && (@facade.dossier.owner?(current_user.email) || @facade.dossier.invite_by_user?(current_user.email)) - if @facade.procedure.cerfa_flag? || @facade.dossier.types_de_piece_justificative.size > 0 .row - .col-lg-4.col-md-4.col-sm-4.col-xs-4 + .col-xs-4 %a#maj_pj.action{"data-target" => "#UploadPJmodal", "data-toggle" => "modal", :type => "button"} - .col-lg-4.col-md-4.col-sm-4.col-xs-4.action + .col-xs-4.action Modifier les documents %br = render partial: 'users/recapitulatif/modal_upload_pj' - .col-lg-4.col-md-4.col-sm-4.col-xs-4 + .col-xs-4 - if gestionnaire_signed_in? #PJmodal.modal.fade{"aria-labelledby" => "myModalLabel", :role => "dialog", :tabindex => "-1"} diff --git a/app/views/dossiers/_invites.html.haml b/app/views/dossiers/_invites.html.haml index 345760df0..a84af7849 100644 --- a/app/views/dossiers/_invites.html.haml +++ b/app/views/dossiers/_invites.html.haml @@ -14,5 +14,5 @@ .col-xs-3 = form_tag invites_dossier_path(dossier_id: @facade.dossier.id), method: :post, class: 'form-inline' do = text_field_tag :email, '', class: 'form-control', placeholder: 'Envoyer une invitation' - = submit_tag 'Ajouter', class: 'btn btn-success', id: 'send-invitation' + = submit_tag 'Ajouter', class: 'btn btn-success', id: 'send-invitation', data: {confirm: "Envoyer l'invitation ?"} diff --git a/app/views/dossiers/etapes/etape_2/_individual.html.haml b/app/views/dossiers/etapes/etape_2/_individual.html.haml index ae1d3a56e..8e8a457e3 100644 --- a/app/views/dossiers/etapes/etape_2/_individual.html.haml +++ b/app/views/dossiers/etapes/etape_2/_individual.html.haml @@ -16,7 +16,7 @@ %label %h4 Civilité - = ff.select :gender, ['Mr', 'Mme'] + = ff.select :gender, ['M.', 'Mme'] .form-group %label %h4 diff --git a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml index a78879adc..8a05145b8 100644 --- a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml +++ b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml @@ -31,7 +31,7 @@ - unless @procedure.locked? %a{:href => "#{url_for admin_procedure_pieces_justificatives_path(@procedure)}", id: 'onglet-pieces'} %div.procedure_list_element{class: ('active' if active == 'Pieces')} - Pièces justificatives + Pièces jointes - unless @procedure.locked? %a{:href => "#{url_for admin_procedure_types_de_champ_private_path(@procedure)}", id: 'onglet-private-champs'} diff --git a/app/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show.html.haml b/app/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show.html.haml index 5868e5ae8..12f7b4e7c 100644 --- a/app/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show.html.haml +++ b/app/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show.html.haml @@ -5,19 +5,21 @@ #action-block - if gestionnaire_signed_in? - if !@facade.dossier.read_only? || @facade.dossier.initiated? - = link_to 'Passer en instruction', backoffice_dossier_receive_path(@facade.dossier), method: :post, class: 'btn btn-danger btn-block' + = link_to 'Passer en instruction', backoffice_dossier_receive_path(@facade.dossier), method: :post, class: 'btn btn-danger btn-block', data: { confirm: "Confirmer vous le passage en instruction de ce dossier ?" } - elsif @facade.dossier.received? - = form_tag(url_for({controller: 'backoffice/dossiers', action: :close, dossier_id: @facade.dossier.id}), class: 'form-inline action_button', method: 'POST', style: 'display:inline', 'data-toggle' => :tooltip, title: 'Accepter') do - %button.action.close-dossier - %i.fa.fa-check - = form_tag(url_for({controller: 'backoffice/dossiers', action: :without_continuation, dossier_id: @facade.dossier.id}), class: 'form-inline action_button', method: 'POST', style: 'display:inline', 'data-toggle' => :tooltip, title: 'Classer sans suite') do - %button.action.forget-dossier - %i.fa.fa-circle-o - = form_tag(url_for({controller: 'backoffice/dossiers', action: :refuse, dossier_id: @facade.dossier.id}), class: 'form-inline action_button', method: 'POST', style: 'display:inline', 'data-toggle' => :tooltip, title: 'Refuser') do - %button.action.refuse-dossier - %i.fa.fa-times - = link_to 'Reouvrir', backoffice_dossier_reopen_path(@facade.dossier), method: :post, class: 'btn btn-default btn-block' + %ul.list-inline + %li + = link_to url_for({controller: 'backoffice/dossiers', action: :close, dossier_id: @facade.dossier.id}), class: 'btn btn-success', method: :post, title: 'Accepter', data: { toggle: :tooltip, confirm: "Accepter ce dossier ?" } do + %i.fa.fa-check + %li + = link_to url_for({controller: 'backoffice/dossiers', action: :without_continuation, dossier_id: @facade.dossier.id}), class: 'btn btn-warning', method: :post, title: 'Classer sans suite', data: { toggle: :tooltip, confirm: "Classer sans suite ce dossier ?" } do + %i.fa.fa-circle-o + %li + = link_to url_for({controller: 'backoffice/dossiers', action: :refuse, dossier_id: @facade.dossier.id}), class: 'btn btn-danger', method: :post, title: 'Refuser', data: { toggle: :tooltip, confirm: "Refuser ce dossier ?" } do + %i.fa.fa-times + + = link_to 'Reouvrir', backoffice_dossier_reopen_path(@facade.dossier), method: :post, class: 'btn btn-default btn-block', data: { confirm: "Confirmer vous la réouverture de ce dossier ?" } %hr - if @facade.dossier.archived? @@ -26,7 +28,7 @@ = link_to 'Désarchiver', unarchive_backoffice_dossier_path(@facade.dossier), method: :post, class: 'btn btn-default btn-block' - else - = link_to 'Archiver', archive_backoffice_dossier_path(@facade.dossier), method: :post, class: 'btn btn-default btn-block' + = link_to 'Archiver', archive_backoffice_dossier_path(@facade.dossier), method: :post, class: 'btn btn-default btn-block', data: { confirm: "Confirmer vous l'archivage de ce dossier ?" } @@ -52,9 +54,9 @@ .type= "Un attribut à été changé: #{notification.liste.last}" - elsif ['piece_justificative'].include?(notification.type_notif) - if notification.liste.size > 1 - .type= "Plusieurs pièces justificatives ont été changés, dont: #{notification.liste.join(" ")}" + .type= "Plusieurs pièces jointes ont été changés, dont: #{notification.liste.join(" ")}" - else - .type= "Une pièce justificative à été changée: #{notification.liste.last}" + .type= "Une pièce jointe à été changée: #{notification.liste.last}" - else .type= notification.liste.last .split-hr diff --git a/app/views/layouts/navbars/_navbar_admin_procedurescontroller_index.html.haml b/app/views/layouts/navbars/_navbar_admin_procedurescontroller_index.html.haml index 8adfbc93d..13fdaf3c7 100644 --- a/app/views/layouts/navbars/_navbar_admin_procedurescontroller_index.html.haml +++ b/app/views/layouts/navbars/_navbar_admin_procedurescontroller_index.html.haml @@ -23,4 +23,4 @@ %li = link_to(admin_profile_path, id: :profile) do %i.fa.fa-user -  Profile +  Profil diff --git a/app/views/layouts/navbars/_navbar_backoffice_dossierscontroller_show.html.haml b/app/views/layouts/navbars/_navbar_backoffice_dossierscontroller_show.html.haml index bcf5694b2..d6c9f218f 100644 --- a/app/views/layouts/navbars/_navbar_backoffice_dossierscontroller_show.html.haml +++ b/app/views/layouts/navbars/_navbar_backoffice_dossierscontroller_show.html.haml @@ -38,4 +38,4 @@ %li = form_tag invites_dossier_path(dossier_id: @facade.dossier.id), method: :post, class: 'form-inline', id: 'send-invitation' do = text_field_tag :email, '', class: 'form-control', placeholder: 'Envoyer une invitation', id: 'invitation-email' - = submit_tag 'Ajouter', class: 'btn btn-success' + = submit_tag 'Ajouter', class: 'btn btn-success', data: {confirm: "Envoyer l'invitation ?"} diff --git a/app/views/layouts/navbars/_navbar_users_recapitulatifcontroller_show.html.haml b/app/views/layouts/navbars/_navbar_users_recapitulatifcontroller_show.html.haml index 7a5f4299b..6be6d4927 100644 --- a/app/views/layouts/navbars/_navbar_users_recapitulatifcontroller_show.html.haml +++ b/app/views/layouts/navbars/_navbar_users_recapitulatifcontroller_show.html.haml @@ -28,4 +28,4 @@ %li = form_tag invites_dossier_path(dossier_id: @facade.dossier.id), method: :post, class: 'form-inline', id: 'send-invitation' do = text_field_tag :email, '', class: 'form-control', placeholder: 'Envoyer une invitation', id: 'invitation-email' - = submit_tag 'Ajouter', class: 'btn btn-success' + = submit_tag 'Ajouter', class: 'btn btn-success', data: {confirm: "Envoyer l'invitation ?"} diff --git a/app/views/users/description/_show.html.haml b/app/views/users/description/_show.html.haml index 14b17b160..ac21a126e 100644 --- a/app/views/users/description/_show.html.haml +++ b/app/views/users/description/_show.html.haml @@ -4,7 +4,7 @@ .panel.panel-info{style:'margin-bottom:0'} .panel-body.center .row - .col-md-1.col-lg-1.col-sm-1.col-xs-1 + .col-xs-1 .fa.fa-info-circle.text-info{style:'font-size: 2em; margin-top: 20%'} .col-xs-10{style:'padding-right: 0px'} %b @@ -22,7 +22,7 @@ -if !@procedure.lien_demarche.blank? || @procedure.cerfa_flag || @dossier.types_de_piece_justificative.size > 0 %br - %h3 Documents administratifs + %h3 Pièces jointes //TODO a refactorer @@ -30,17 +30,6 @@ .col-lg-8 = render partial: 'users/description/pieces_justificatives', locals: { dossier: @dossier } - #state_description.row{style:'width: 50%; margin-left:20px'} - .panel.panel-info - .panel-body.center - .row - .col-md-1.col-lg-1.col-sm-1.col-xs-1 - .fa.fa-info-circle.text-info{style:'font-size: 2em; margin-top: 20%'} - .col-xs-11 - Les documents administratifs ne sont pas indispensables afin d'initier votre dossier. - Vous pourrez dans tous les cas les compléter plus tard si vous ne les possédez pas de suite. - - -route = Rails.application.routes.recognize_path(request.referrer) # WTF ? - unless route[:controller].match('admin') %div{style: 'text-align:right'} diff --git a/app/views/users/description/champs/_checkbox.html.haml b/app/views/users/description/champs/_checkbox.html.haml index bae7b55ad..db7928656 100644 --- a/app/views/users/description/champs/_checkbox.html.haml +++ b/app/views/users/description/champs/_checkbox.html.haml @@ -1,2 +1 @@ -%input{type: 'hidden', name:"champs['#{champ.id}']", id: "champs_#{champ.id}", value: ''} -%input{type: 'checkbox', style:'margin-left: 15px;', name:"champs['#{champ.id}']", id: "champs_#{champ.id}", checked: ('checked' if champ.value == 'on')} +%input{type: 'checkbox', style:'margin-left: 15px;', name:"champs['#{champ.id}']", id: "champs_#{champ.id}", checked: ('checked' if champ.object.value == 'on')} diff --git a/app/views/users/description/champs/_departements.html.haml b/app/views/users/description/champs/_departements.html.haml index 018a60526..5fd949ccd 100644 --- a/app/views/users/description/champs/_departements.html.haml +++ b/app/views/users/description/champs/_departements.html.haml @@ -1 +1,2 @@ -= render partial: 'users/description/champs/drop_down_template', locals: {values: Champ.departements, champ: champ} += select_tag("champs['#{champ.id}']", + options_for_select(Champ.departements, selected: champ.object.value)) diff --git a/app/views/users/description/champs/_drop_down_list.html.haml b/app/views/users/description/champs/_drop_down_list.html.haml index e398f6519..eebb763f1 100644 --- a/app/views/users/description/champs/_drop_down_list.html.haml +++ b/app/views/users/description/champs/_drop_down_list.html.haml @@ -1,2 +1,6 @@ -- unless champ.drop_down_list.nil? - = render partial: 'users/description/champs/drop_down_template', locals: {values: champ.drop_down_list.options, champ: champ} +- if champ.drop_down_list && champ.drop_down_list.options.any? + = select_tag("champs['#{champ.id}']", + options_for_select(champ.drop_down_list.options, selected: champ.drop_down_list.selected_options(champ), + disabled: champ.drop_down_list.disabled_options), + multiple: champ.drop_down_list.multiple, + class: champ.drop_down_list.multiple ? 'select2' : nil) diff --git a/app/views/users/description/champs/_drop_down_template.html.haml b/app/views/users/description/champs/_drop_down_template.html.haml deleted file mode 100644 index e3956e3c1..000000000 --- a/app/views/users/description/champs/_drop_down_template.html.haml +++ /dev/null @@ -1,18 +0,0 @@ -%select{ name:"champs['#{champ.id}']", - id: "champs_#{champ.id}" } - - - unless values.blank? - %option - = '' - - - values.each do |option| - - if (option=~ /^--.*--$/).nil? - - if champ.value == option - %option{selected:''} - = option - - else - %option - = option - -else - %option{disabled:''} - = option diff --git a/app/views/users/description/champs/_header_section.html.haml b/app/views/users/description/champs/_header_section.html.haml index b2d4662d0..cc2c1099f 100644 --- a/app/views/users/description/champs/_header_section.html.haml +++ b/app/views/users/description/champs/_header_section.html.haml @@ -1,9 +1,9 @@ .default_data_block.default_visible - %div.row.show-block.infos - %div.header - %div.col-lg-12.col-md-12.col-sm-12.col-xs-12.title - %div.carret-right - %div.carret-down + .row.show-block.infos + .header + .col-xs-12.title + .carret-right + .carret-down =libelle - %div.body - = render partial: 'users/description/champs/render_list_champs', locals: {champs: champs, order_place: order_place} \ No newline at end of file + .body + = render partial: 'users/description/champs/render_list_champs', locals: {champs: champs, order_place: order_place} diff --git a/app/views/users/description/champs/_pays.html.haml b/app/views/users/description/champs/_pays.html.haml index ac4a842bf..2f530b683 100644 --- a/app/views/users/description/champs/_pays.html.haml +++ b/app/views/users/description/champs/_pays.html.haml @@ -1 +1,2 @@ -= render partial: 'users/description/champs/drop_down_template', locals: {values: Champ.pays, champ: champ} += select_tag("champs['#{champ.id}']", + options_for_select(Champ.pays, selected: champ.object.value)) diff --git a/app/views/users/description/champs/_regions.html.haml b/app/views/users/description/champs/_regions.html.haml index 280e8e959..613b6af27 100644 --- a/app/views/users/description/champs/_regions.html.haml +++ b/app/views/users/description/champs/_regions.html.haml @@ -1,3 +1,2 @@ -= render partial: 'users/description/champs/drop_down_template', locals: {values: Champ.regions, champ: champ} - - += select_tag("champs['#{champ.id}']", + options_for_select(Champ.regions, selected: champ.object.value)) diff --git a/app/views/users/description/champs/_render_list_champs.html.haml b/app/views/users/description/champs/_render_list_champs.html.haml index 261ef88e1..1c131361e 100644 --- a/app/views/users/description/champs/_render_list_champs.html.haml +++ b/app/views/users/description/champs/_render_list_champs.html.haml @@ -26,7 +26,7 @@ - elsif champ.type_champ == 'yes_no' = render partial: 'users/description/champs/yes_no', locals: { champ: champ } - - elsif champ.type_champ == 'drop_down_list' + - elsif %w(drop_down_list multiple_drop_down_list).include?(champ.type_champ) = render partial: 'users/description/champs/drop_down_list', locals: { champ: champ } - elsif champ.type_champ == 'pays' @@ -41,6 +41,8 @@ - elsif champ.type_champ == 'departements' = render partial: 'users/description/champs/departements', locals: { champ: champ } + - elsif champ.type_champ == 'explication' + - else %input.form-control{name:"champs['#{ champ.id }']", placeholder: champ.libelle, diff --git a/app/views/users/registrations/new.html.haml b/app/views/users/registrations/new.html.haml index 12e3165cc..d8270c4a9 100644 --- a/app/views/users/registrations/new.html.haml +++ b/app/views/users/registrations/new.html.haml @@ -47,7 +47,7 @@ = f.email_field :email, class: 'form-control', placeholder: 'Email', value: params[:user_email] %br %h4 - = f.label :password + = f.label :password, 'Mot de passe' .input-group .input-group-addon %span.fa.fa-asterisk diff --git a/app/workers/auto_archive_procedure_worker.rb b/app/workers/auto_archive_procedure_worker.rb new file mode 100644 index 000000000..61701b4ff --- /dev/null +++ b/app/workers/auto_archive_procedure_worker.rb @@ -0,0 +1,14 @@ +class AutoArchiveProcedureWorker + include Sidekiq::Worker + + def perform(*args) + procedures_to_archive = Procedure.not_archived.where("auto_archive_on <= ?", Date.today) + + procedures_to_archive.each do |p| + p.dossiers.en_construction.update_all(state: :received) + end + + procedures_to_archive.update_all(archived: true, auto_archive_on: nil) + + end +end diff --git a/config/database.yml b/config/database.yml index 09ce42682..00832cfbc 100644 --- a/config/database.yml +++ b/config/database.yml @@ -13,4 +13,4 @@ test: adapter: sqlite3 pool: 5 timeout: 5000 - database: db/test<%= ENV['TEST_ENV_NUMBER'] %>.sqlite3 + database: db/test.sqlite3 diff --git a/config/deploy.rb b/config/deploy.rb index 8c9306ae9..bc9960d27 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -74,9 +74,11 @@ set :shared_paths, [ 'public/system', 'public/uploads', 'config/database.yml', + "config/newrelic.yml", "config/fog_credentials.yml", 'config/initializers/secret_token.rb', 'config/initializers/features.yml', + 'config/initializers/sidekiq.rb', "config/environments/#{rails_env}.rb", "config/initializers/token.rb", "config/initializers/urls.rb", diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb new file mode 100644 index 000000000..f5dd670d6 --- /dev/null +++ b/config/initializers/sidekiq.rb @@ -0,0 +1,7 @@ +Sidekiq.configure_server do |config| + Sidekiq::Logging.logger = Rails.logger + + schedule_file = "config/schedule.yml" + Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file) +end + diff --git a/config/locales/models/type_de_champ/fr.yml b/config/locales/models/type_de_champ/fr.yml index 83d87828b..06206a682 100644 --- a/config/locales/models/type_de_champ/fr.yml +++ b/config/locales/models/type_de_champ/fr.yml @@ -21,4 +21,6 @@ fr: regions: 'Régions' departements: 'Départements' engagement: 'Engagement' - header_section: 'Titre de section' \ No newline at end of file + header_section: 'Titre de section' + explication: 'Explication' + multiple_drop_down_list: 'Menu déroulant à choix multiples' diff --git a/config/newrelic.yml b/config/newrelic.yml new file mode 100644 index 000000000..be46869da --- /dev/null +++ b/config/newrelic.yml @@ -0,0 +1,49 @@ +# +# This file configures the New Relic Agent. New Relic monitors Ruby, Java, +# .NET, PHP, Python and Node applications with deep visibility and low +# overhead. For more information, visit www.newrelic.com. +# +# Generated March 02, 2017 +# +# This configuration file is custom generated for SGMAP +# +# For full documentation of agent configuration options, please refer to +# https://docs.newrelic.com/docs/agents/ruby-agent/installation-configuration/ruby-agent-configuration + +common: &default_settings + # Required license key associated with your New Relic account. + license_key: <%= ENV['NEWRELIC_LICENSE_KEY'] %> + + # Your application name. Renaming here affects where data displays in New + # Relic. For more details, see https://docs.newrelic.com/docs/apm/new-relic-apm/maintenance/renaming-applications + app_name: Téléprocédure Simplifiée + + # To disable the agent regardless of other settings, uncomment the following: + # agent_enabled: false + + # Logging level for log/newrelic_agent.log + log_level: info + + +# Environment-specific settings are in this section. +# RAILS_ENV or RACK_ENV (as appropriate) is used to determine the environment. +# If your application has other named environments, configure them here. +development: + <<: *default_settings + app_name: Téléprocédure Simplifiée (Development) + + # NOTE: There is substantial overhead when running in developer mode. + # Do not use for production or load testing. + developer_mode: true + +test: + <<: *default_settings + # It doesn't make sense to report to New Relic from automated test runs. + monitor_mode: false + +staging: + <<: *default_settings + app_name: Téléprocédure Simplifiée (Staging) + +production: + <<: *default_settings diff --git a/config/routes.rb b/config/routes.rb index 716893f09..5811b4890 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -42,9 +42,15 @@ Rails.application.routes.draw do get 'admin' => 'admin#index' get 'backoffice' => 'backoffice#index' - resources :administrations, only: [:index, :create] - namespace :administrations do - resources :stats, only: [:index] + authenticate :administration do + resources :administrations, only: [:index, :create] + namespace :administrations do + resources :stats, only: [:index] + + require 'sidekiq/web' + require 'sidekiq/cron/web' + mount Sidekiq::Web => '/sidekiq' + end end namespace :france_connect do @@ -208,6 +214,4 @@ Rails.application.routes.draw do end apipie - - mount ActionCable.server => '/cable' end diff --git a/config/schedule.yml b/config/schedule.yml new file mode 100644 index 000000000..79dbdefc9 --- /dev/null +++ b/config/schedule.yml @@ -0,0 +1,3 @@ +auto_archive_procedure: + cron: "* * * * *" + class: "AutoArchiveProcedureWorker" diff --git a/config/sidekiq.yml b/config/sidekiq.yml new file mode 100644 index 000000000..9431fe006 --- /dev/null +++ b/config/sidekiq.yml @@ -0,0 +1,7 @@ +:concurrency: 5 +staging: + :concurrency: 2 +production: + :concurrency: 2 +:queues: + - default \ No newline at end of file diff --git a/db/migrate/20170313140834_add_auto_archive_to_procedure.rb b/db/migrate/20170313140834_add_auto_archive_to_procedure.rb new file mode 100644 index 000000000..7d7275651 --- /dev/null +++ b/db/migrate/20170313140834_add_auto_archive_to_procedure.rb @@ -0,0 +1,5 @@ +class AddAutoArchiveToProcedure < ActiveRecord::Migration[5.0] + def change + add_column :procedures, :auto_archive_on, :date + end +end diff --git a/db/schema.rb b/db/schema.rb index db86ebfaf..0ff0aa06a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170307092820) do +ActiveRecord::Schema.define(version: 20170313140834) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -344,6 +344,7 @@ ActiveRecord::Schema.define(version: 20170307092820) do t.string "lien_notice" t.boolean "for_individual", default: false t.boolean "individual_with_siret", default: false + t.date "auto_archive_on" end create_table "quartier_prioritaires", force: :cascade do |t| diff --git a/doc/apipie_examples.json b/doc/apipie_examples.json index 968788243..e14456d96 100644 --- a/doc/apipie_examples.json +++ b/doc/apipie_examples.json @@ -86,6 +86,18 @@ } } ], + "champs_private": [ + { + "value": null, + "type_de_champ": { + "id": 1, + "libelle": "Description privée", + "type_champ": "text", + "order_place": 0, + "description": "description privée" + } + } + ], "pieces_justificatives": [ { "url": null, diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 72752b1f1..6d77ce488 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -364,14 +364,14 @@ describe Users::DossiersController, type: :controller do context 'when procedure is for individual' do let(:params) { {id: dossier_id, dossier: {id: dossier_id, autorisation_donnees: '1', individual_attributes: individual_params}} } - let(:individual_params) { {gender: 'Mr', nom: 'Julien', prenom: 'Xavier', birthdate: '20/01/1991'} } + let(:individual_params) { {gender: 'M.', nom: 'Julien', prenom: 'Xavier', birthdate: '20/01/1991'} } let(:procedure) { create(:procedure, :published, for_individual: true) } before do dossier.reload end - it { expect(dossier.individual.gender).to eq 'Mr' } + it { expect(dossier.individual.gender).to eq 'M.' } it { expect(dossier.individual.nom).to eq 'Julien' } it { expect(dossier.individual.prenom).to eq 'Xavier' } it { expect(dossier.individual.birthdate).to eq '20/01/1991' } diff --git a/spec/decorators/champ_decorator_spec.rb b/spec/decorators/champ_decorator_spec.rb index 5d25679ca..c8b15056c 100644 --- a/spec/decorators/champ_decorator_spec.rb +++ b/spec/decorators/champ_decorator_spec.rb @@ -1,19 +1,18 @@ require 'spec_helper' describe ChampDecorator do - let(:champ) {create :champ, type_de_champ: (create :type_de_champ_public, type_champ: :checkbox)} + let(:champ) {create :champ, type_de_champ: (create :type_de_champ_public, type_champ: type_champ)} let(:decorator) { champ.decorate } + describe 'value' do subject { decorator.value } - context 'when type_champ is checkbox' do + describe 'for a checkbox' do + let(:type_champ) { :checkbox } context 'when value is on' do - before do - champ.update value: 'on' - end - + before { champ.update value: 'on' } it { is_expected.to eq 'Oui' } end @@ -21,5 +20,19 @@ describe ChampDecorator do it { is_expected.to eq 'Non' } end end + + describe 'for a multiple_drop_down_list' do + let(:type_champ) { :multiple_drop_down_list } + + context 'when value is an array' do + before { champ.update value: '["1", "2"]' } + it { is_expected.to eq '1, 2' } + end + + context 'when value is empty' do + before { champ.update value: '' } + it { is_expected.to eq '' } + end + end end end diff --git a/spec/decorators/france_connect_inforation_decorator_spec.rb b/spec/decorators/france_connect_inforation_decorator_spec.rb index 9d273c487..d6d642fc3 100644 --- a/spec/decorators/france_connect_inforation_decorator_spec.rb +++ b/spec/decorators/france_connect_inforation_decorator_spec.rb @@ -8,7 +8,7 @@ describe FranceConnectInformationDecorator do context 'when france connect user is a male' do let(:gender) { 'male' } - it { is_expected.to eq 'Mr' } + it { is_expected.to eq 'M.' } end context 'when france connect user is a female' do diff --git a/spec/decorators/type_de_champ_decorator_spec.rb b/spec/decorators/type_de_champ_decorator_spec.rb index 7ab455e00..dd5d75307 100644 --- a/spec/decorators/type_de_champ_decorator_spec.rb +++ b/spec/decorators/type_de_champ_decorator_spec.rb @@ -16,8 +16,8 @@ describe TypeDeChampDecorator do subject { type_de_champ_0.decorate } let(:button_up) { type_de_champ_.decorate } - it 'returns a button up' do - expect(subject.button_up(params)).to be(nil) + it 'hide a button up' do + expect(subject.button_up(params)).to include('visibility: hidden') end it 'returns a button down' do expect(subject.button_down(params)).to match(/fa-chevron-down/) @@ -45,11 +45,12 @@ describe TypeDeChampDecorator do it 'returns a button up' do expect(subject.button_up(params)).to match(/fa-chevron-up/) end - it 'returns a button down' do - expect(subject.button_down(params)).to be(nil) + + it 'hide a button down' do + expect(subject.button_down(params)).to include('visibility: hidden') end end end -end \ No newline at end of file +end diff --git a/spec/factories/type_de_champ_public.rb b/spec/factories/type_de_champ_public.rb index 937921d0d..3dad7603b 100644 --- a/spec/factories/type_de_champ_public.rb +++ b/spec/factories/type_de_champ_public.rb @@ -5,5 +5,9 @@ FactoryGirl.define do type_champ 'text' order_place 1 mandatory false + + trait :checkbox do + type_champ 'checkbox' + end end end diff --git a/spec/models/drop_down_list_spec.rb b/spec/models/drop_down_list_spec.rb index 523ab2ae1..0455985fc 100644 --- a/spec/models/drop_down_list_spec.rb +++ b/spec/models/drop_down_list_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe DropDownList do + describe 'database columns' do it { is_expected.to have_db_column(:value) } end @@ -9,15 +10,16 @@ describe DropDownList do it { is_expected.to belong_to(:type_de_champ) } end + let(:dropdownlist) { create :drop_down_list, value: value } + describe '#options' do let(:value) { "Cohésion sociale Dév.Eco / Emploi Cadre de vie / Urb. Pilotage / Ingénierie " } - let(:dropdownlist) { create :drop_down_list, value: value } - it { expect(dropdownlist.options).to eq ["Cohésion sociale", "Dév.Eco / Emploi", "Cadre de vie / Urb.", "Pilotage / Ingénierie"] } + it { expect(dropdownlist.options).to eq ['', 'Cohésion sociale', 'Dév.Eco / Emploi', 'Cadre de vie / Urb.', 'Pilotage / Ingénierie'] } context 'when one value is empty' do let(:value) { "Cohésion sociale @@ -26,7 +28,36 @@ Cadre de vie / Urb. Pilotage / Ingénierie " } - it { expect(dropdownlist.options).to eq ["Cohésion sociale", "Cadre de vie / Urb.", "Pilotage / Ingénierie"] } + it { expect(dropdownlist.options).to eq ['', 'Cohésion sociale', 'Cadre de vie / Urb.', 'Pilotage / Ingénierie'] } + end + end + + describe 'disabled_options' do + let(:value) { "tip +--top-- +--troupt-- +ouaich" } + + it { expect(dropdownlist.disabled_options).to match(['--top--', '--troupt--']) } + end + + describe 'selected_options' do + let(:dropdownlist) do + create(:drop_down_list, type_de_champ: type_de_champ) + end + + context 'when multiple' do + let(:type_de_champ) { TypeDeChamp.new(type_champ: 'multiple_drop_down_list') } + + let(:champ) { Champ.new(value: '["1","2"]').decorate } + it { expect(dropdownlist.selected_options(champ)).to match(['1', '2']) } + end + + context 'when simple' do + let(:type_de_champ) { TypeDeChamp.new(type_champ: 'drop_down_list') } + + let(:champ) { Champ.new(value: '1').decorate } + it { expect(dropdownlist.selected_options(champ)).to match(['1']) } end end end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 5a6074a30..c841cb0cb 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -183,10 +183,6 @@ describe Procedure do expect(subject.received_mail.id).not_to be nil expect(subject.received_mail.procedure_id).not_to eq procedure.received_mail.procedure_id expect(subject.received_mail.procedure_id).not_to be nil - expect(subject.received_mail.created_at).not_to eq procedure.received_mail.created_at - expect(subject.received_mail.created_at).not_to be nil - expect(subject.received_mail.updated_at).not_to eq procedure.received_mail.updated_at - expect(subject.received_mail.updated_at).not_to be nil end it 'should not duplicate default mail_template' do diff --git a/spec/services/type_de_champ_service_spec.rb b/spec/services/type_de_champ_service_spec.rb new file mode 100644 index 000000000..e1e61ef91 --- /dev/null +++ b/spec/services/type_de_champ_service_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe TypesDeChampService do + let(:params) do + ActionController::Parameters.new({ + procedure: { + types_de_champ_attributes: { + "0" => { + libelle: 'top', + drop_down_list_attributes: { + value: "un\r\n deux\r\n -- commentaire --\r\n trois", + id: '5218' + } + } + } + } + }) + end + + let(:result) { TypesDeChampService.create_update_procedure_params(params) } + + describe 'self.create_update_procedure_params' do + describe 'the drop down list attributes' do + subject { result['types_de_champ_attributes']['0']['drop_down_list_attributes'] } + it 'has its value stripped' do + expect(subject['value']).to eq("un\r\ndeux\r\n-- commentaire --\r\ntrois") + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4e7319f2a..f3b8d6030 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,12 +19,6 @@ ENV['RAILS_ENV'] ||= 'test' -if ENV['COV'] - require 'simplecov' - SimpleCov.start 'rails' - puts "required simplecov" -end - require File.expand_path('../../config/environment', __FILE__) require 'rspec/rails' require 'capybara/rspec' @@ -38,7 +32,7 @@ require 'capybara/poltergeist' Capybara.javascript_driver = :poltergeist Capybara.ignore_hidden_elements = false Capybara.register_driver :poltergeist do |app| - Capybara::Poltergeist::Driver.new(app, js_errors: true, port: 44_678 + ENV['TEST_ENV_NUMBER'].to_i, phantomjs_options: ['--proxy-type=none'], timeout: 180) + Capybara::Poltergeist::Driver.new(app, js_errors: true, port: 44_678, phantomjs_options: ['--proxy-type=none'], timeout: 180) end ActiveSupport::Deprecation.silenced = true diff --git a/spec/views/admin/previsualisations/show.html.haml_spec.rb b/spec/views/admin/previsualisations/show.html.haml_spec.rb index f0983b660..cfed1dd02 100644 --- a/spec/views/admin/previsualisations/show.html.haml_spec.rb +++ b/spec/views/admin/previsualisations/show.html.haml_spec.rb @@ -129,22 +129,5 @@ describe 'admin/previsualisations/show.html.haml', type: :view do it { expect(rendered).not_to have_content 'Documents administratifs' } end - context 'when dossier have pj' do - let(:dossier) { create(:dossier) } - - it { expect(rendered).to have_content 'Documents administratifs' } - end - - context 'when procedure have demarche link' do - let(:procedure) { create :procedure } - - it { expect(rendered).to have_content 'Documents administratifs' } - end - - context 'when procedure have cerfa flag true' do - let(:procedure) {create(:procedure, cerfa_flag: true)} - - it { expect(rendered).to have_content 'Documents administratifs' } - end end end diff --git a/spec/views/admin/types_de_champ/show.html.haml_spec.rb b/spec/views/admin/types_de_champ/show.html.haml_spec.rb index bed11f3d4..acac3297a 100644 --- a/spec/views/admin/types_de_champ/show.html.haml_spec.rb +++ b/spec/views/admin/types_de_champ/show.html.haml_spec.rb @@ -33,8 +33,8 @@ describe 'admin/types_de_champ/show.html.haml', type: :view do end context 'when there is only one field in database' do let!(:type_de_champ_0) { create(:type_de_champ_public, procedure: procedure, order_place: 0) } - it { expect(subject).not_to have_css('#btn_down_0') } - it { expect(subject).not_to have_css('#btn_up_0') } + it { expect(subject).to have_css('#btn_down_0[style*="visibility: hidden"]') } + it { expect(subject).to have_css('#btn_up_0[style*="visibility: hidden"]') } it { expect(subject).not_to have_css('#btn_up_1') } it { expect(subject).not_to have_css('#btn_down_1') } end @@ -42,9 +42,9 @@ describe 'admin/types_de_champ/show.html.haml', type: :view do let!(:type_de_champ_0) { create(:type_de_champ_public, procedure: procedure, order_place: 0) } let!(:type_de_champ_1) { create(:type_de_champ_public, procedure: procedure, order_place: 1) } it { expect(subject).to have_css('#btn_down_0') } - it { expect(subject).not_to have_css('#btn_up_0') } + it { expect(subject).to have_css('#btn_up_0[style*="visibility: hidden"]') } it { expect(subject).to have_css('#btn_up_1') } - it { expect(subject).not_to have_css('#btn_down_1') } + it { expect(subject).to have_css('#btn_down_1[style*="visibility: hidden"]') } end end -end \ No newline at end of file +end diff --git a/spec/views/admin/types_de_champ_private/show.html.haml_spec.rb b/spec/views/admin/types_de_champ_private/show.html.haml_spec.rb index 829050748..510224e9c 100644 --- a/spec/views/admin/types_de_champ_private/show.html.haml_spec.rb +++ b/spec/views/admin/types_de_champ_private/show.html.haml_spec.rb @@ -30,7 +30,7 @@ describe 'admin/types_de_champ/show.html.haml', type: :view do describe 'mandatory checkbox' do it 'no mandatory checkbox are present' do - expect(subject).not_to have_css('.form-group.mandatory') + expect(subject).to have_css('.form-group.mandatory[style*="visibility: hidden"]') end end @@ -41,8 +41,8 @@ describe 'admin/types_de_champ/show.html.haml', type: :view do end context 'when there is only one field in database' do let!(:type_de_champ_0) { create(:type_de_champ_private, procedure: procedure, order_place: 0) } - it { expect(subject).not_to have_css('#btn_down_0') } - it { expect(subject).not_to have_css('#btn_up_0') } + it { expect(subject).to have_css('#btn_down_0[style*="visibility: hidden"]') } + it { expect(subject).to have_css('#btn_up_0[style*="visibility: hidden"]') } it { expect(subject).not_to have_css('#btn_up_1') } it { expect(subject).not_to have_css('#btn_down_1') } end @@ -50,10 +50,10 @@ describe 'admin/types_de_champ/show.html.haml', type: :view do let!(:type_de_champ_0) { create(:type_de_champ_private, procedure: procedure, order_place: 0) } let!(:type_de_champ_1) { create(:type_de_champ_private, procedure: procedure, order_place: 1) } it { expect(subject).to have_css('#btn_down_0') } - it { expect(subject).not_to have_css('#btn_up_0') } + it { expect(subject).to have_css('#btn_up_0[style*="visibility: hidden"]') } it { expect(subject).to have_css('#btn_up_1') } - it { expect(subject).not_to have_css('#btn_down_1') } + it { expect(subject).to have_css('#btn_down_1[style*="visibility: hidden"]') } end end end -end \ No newline at end of file +end diff --git a/spec/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show_spec.rb b/spec/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show_spec.rb index fc7322a97..53be1ef91 100644 --- a/spec/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show_spec.rb +++ b/spec/views/layouts/left_panels/_left_panel_backoffice_dossierscontroller_show_spec.rb @@ -75,9 +75,9 @@ describe 'layouts/left_panels/_left_panel_backoffice_dossierscontroller_show.htm it { expect(rendered).to have_content('En instruction') } it 'button accepter / refuser / classer sans suite are present' do - expect(rendered).to have_css('form[data-toggle="tooltip"][title="Accepter"]') - expect(rendered).to have_css('form[data-toggle="tooltip"][title="Classer sans suite"]') - expect(rendered).to have_css('form[data-toggle="tooltip"][title="Refuser"]') + expect(rendered).to have_css('a[title="Accepter"]') + expect(rendered).to have_css('a[title="Classer sans suite"]') + expect(rendered).to have_css('a[title="Refuser"]') end end diff --git a/spec/views/users/description/champs/_departements.html.haml_spec.rb b/spec/views/users/description/champs/_departements.html.haml_spec.rb new file mode 100644 index 000000000..d0d6d4fa1 --- /dev/null +++ b/spec/views/users/description/champs/_departements.html.haml_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +describe 'users/description/champs/departements.html.haml', vcr: {cassette_name: 'geoapi_departements'}, type: :view do + let(:champ) { create(:champ) } + + before do + render 'users/description/champs/departements.html.haml', champ: champ.decorate + end + + it 'should render departments drop down list' do + expect(rendered).to include("Ain") + end +end diff --git a/spec/views/users/description/champs/_pays.html.haml_spec.rb b/spec/views/users/description/champs/_pays.html.haml_spec.rb new file mode 100644 index 000000000..78374b392 --- /dev/null +++ b/spec/views/users/description/champs/_pays.html.haml_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +describe 'users/description/champs/pays.html.haml', type: :view do + let(:champ) { create(:champ) } + + before do + render 'users/description/champs/pays.html.haml', champ: champ.decorate + end + + it 'should render pays drop down list' do + expect(rendered).to include("FRANCE") + end +end diff --git a/spec/views/users/description/champs/_regions.html.haml_spec.rb b/spec/views/users/description/champs/_regions.html.haml_spec.rb new file mode 100644 index 000000000..95e9fdef8 --- /dev/null +++ b/spec/views/users/description/champs/_regions.html.haml_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +describe 'users/description/champs/regions.html.haml', vcr: {cassette_name: 'geoapi_regions'}, type: :view do + let(:champ) { create(:champ) } + + before do + render 'users/description/champs/regions.html.haml', champ: champ.decorate + end + + it 'should render regions drop down list' do + expect(rendered).to include("Normandie") + end +end diff --git a/spec/views/users/description/champs/_render_list_champs.html.haml_spec.rb b/spec/views/users/description/champs/_render_list_champs.html.haml_spec.rb new file mode 100644 index 000000000..a60d0e86b --- /dev/null +++ b/spec/views/users/description/champs/_render_list_champs.html.haml_spec.rb @@ -0,0 +1,27 @@ +describe 'users/description/champs/render_list_champs.html.haml', type: :view do + let(:type_champ) { create(:type_de_champ_public, :checkbox) } + + context "with a checkbox champ with value equals nil" do + let!(:champ_checkbox_checked) { create(:champ, type_de_champ: type_champ, value: nil) } + + before do + render 'users/description/champs/render_list_champs.html.haml', champs: Champ.all, order_place: 0 + end + + it 'should not render a checked checkbox' do + expect(rendered).not_to have_css('input[type=checkbox][checked]') + end + end + + context "with a checkbox champ with value equals 'on'" do + let!(:champ_checkbox_checked) { create(:champ, type_de_champ: type_champ, value: 'on') } + + before do + render 'users/description/champs/render_list_champs.html.haml', champs: Champ.all, order_place: 0 + end + + it 'should render a checked checkbox' do + expect(rendered).to have_css('input[type=checkbox][checked]') + end + end +end diff --git a/spec/views/users/description/show.html.haml_spec.rb b/spec/views/users/description/show.html.haml_spec.rb index 8d4434af2..c278c09f1 100644 --- a/spec/views/users/description/show.html.haml_spec.rb +++ b/spec/views/users/description/show.html.haml_spec.rb @@ -125,22 +125,5 @@ describe 'users/description/show.html.haml', type: :view do it { expect(rendered).not_to have_content 'Documents administratifs' } end - context 'when dossier have pj' do - let(:dossier) { create(:dossier) } - - it { expect(rendered).to have_content 'Documents administratifs' } - end - - context 'when procedure have demarche link' do - let(:procedure) { create :procedure } - - it { expect(rendered).to have_content 'Documents administratifs' } - end - - context 'when procedure have cerfa flag true' do - let(:procedure) { create(:procedure, cerfa_flag: true) } - - it { expect(rendered).to have_content 'Documents administratifs' } - end end end diff --git a/spec/workers/auto_archive_procedure_worker_spec.rb b/spec/workers/auto_archive_procedure_worker_spec.rb new file mode 100644 index 000000000..e67a19133 --- /dev/null +++ b/spec/workers/auto_archive_procedure_worker_spec.rb @@ -0,0 +1,78 @@ +require 'rails_helper' + +RSpec.describe AutoArchiveProcedureWorker, type: :worker do + + let!(:procedure) { create(:procedure, archived: false, auto_archive_on: nil )} + let!(:procedure_hier) { create(:procedure, archived: false, auto_archive_on: 1.day.ago )} + let!(:procedure_aujourdhui) { create(:procedure, archived: false, auto_archive_on: Date.today )} + let!(:procedure_demain) { create(:procedure, archived: false, auto_archive_on: 1.day.from_now )} + + subject { AutoArchiveProcedureWorker.new.perform } + + context "when procedures have no auto_archive_on" do + + before do + subject + procedure.reload + end + + it { expect(procedure.archived).to eq false } + + end + + context "when procedures have auto_archive_on set on yesterday or today" do + + describe "titi" do + before do + subject + procedure_hier.reload + procedure_aujourdhui.reload + end + + it { expect(procedure_hier.archived).to eq true } + it { expect(procedure_aujourdhui.archived).to eq true } + + end + + + context "with dossiers" do + + let!(:dossier1) { create(:dossier, procedure: procedure_hier, state: 'draft', archived: false)} + let!(:dossier2) { create(:dossier, procedure: procedure_hier, state: 'initiated', archived: false)} + let!(:dossier3) { create(:dossier, procedure: procedure_hier, state: 'replied', archived: false)} + let!(:dossier4) { create(:dossier, procedure: procedure_hier, state: 'updated', archived: false)} + let!(:dossier5) { create(:dossier, procedure: procedure_hier, state: 'received', archived: false)} + let!(:dossier6) { create(:dossier, procedure: procedure_hier, state: 'closed', archived: false)} + let!(:dossier7) { create(:dossier, procedure: procedure_hier, state: 'refused', archived: false)} + let!(:dossier8) { create(:dossier, procedure: procedure_hier, state: 'without_continuation', archived: false)} + + before do + subject + (1..8).each do |i| + eval "dossier#{i}.reload" + end + end + + it { expect(dossier1.state).to eq 'draft' } + it { expect(dossier2.state).to eq 'received' } + it { expect(dossier3.state).to eq 'received' } + it { expect(dossier4.state).to eq 'received' } + it { expect(dossier5.state).to eq 'received' } + it { expect(dossier6.state).to eq 'closed' } + it { expect(dossier7.state).to eq 'refused' } + it { expect(dossier8.state).to eq 'without_continuation' } + + end + end + + context "when procedures have auto_archive_on set on future" do + + before do + subject + end + + it { expect(procedure_demain.archived).to eq false } + + end + +end