diff --git a/app/controllers/champs/carte_controller.rb b/app/controllers/champs/carte_controller.rb index b94d8db57..0d5f58024 100644 --- a/app/controllers/champs/carte_controller.rb +++ b/app/controllers/champs/carte_controller.rb @@ -15,18 +15,26 @@ class Champs::CarteController < ApplicationController if geo_area.nil? geo_area = champ.geo_areas.build(source: params_source, properties: {}) - save_feature!(geo_area, create_params_feature) - end - render json: { feature: geo_area.to_feature }, status: :created + if save_feature(geo_area, create_params_feature) + render json: { feature: geo_area.to_feature }, status: :created + else + render json: { errors: geo_area.errors.full_messages }, status: :unprocessable_entity + end + else + render json: { feature: geo_area.to_feature }, status: :ok + end end def update champ = policy_scope(Champ).find(params[:champ_id]) geo_area = champ.geo_areas.find(params[:id]) - save_feature!(geo_area, update_params_feature) - head :no_content + if save_feature(geo_area, update_params_feature) + head :no_content + else + render json: { errors: geo_area.errors.full_messages }, status: :unprocessable_entity + end end def destroy @@ -66,13 +74,13 @@ class Champs::CarteController < ApplicationController end end - def save_feature!(geo_area, feature) + def save_feature(geo_area, feature) if feature[:geometry] geo_area.geometry = feature[:geometry] end if feature[:properties] geo_area.properties.merge!(feature[:properties]) end - geo_area.save! + geo_area.save end end diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index da40645a5..827e3ac83 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -374,7 +374,7 @@ type Demarche { """ Date de la publication. """ - datePublication: ISO8601DateTime! + datePublication: ISO8601DateTime """ L’état de dossier pour une démarche déclarative @@ -1131,7 +1131,8 @@ type Entreprise { } type File { - byteSize: Int! + byteSize: Int! @deprecated(reason: "Utilisez le champ `byteSizeBigInt` à la place.") + byteSizeBigInt: BigInt! checksum: String! contentType: String! filename: String! @@ -1588,6 +1589,11 @@ type Revision { Date de la création. """ dateCreation: ISO8601DateTime! + + """ + Date de la publication. + """ + datePublication: ISO8601DateTime id: ID! } diff --git a/app/graphql/types/demarche_type.rb b/app/graphql/types/demarche_type.rb index 9cf7b8e98..42aae2d43 100644 --- a/app/graphql/types/demarche_type.rb +++ b/app/graphql/types/demarche_type.rb @@ -24,7 +24,7 @@ module Types field :declarative, DossierDeclarativeState, "L’état de dossier pour une démarche déclarative", null: true, method: :declarative_with_state field :date_creation, GraphQL::Types::ISO8601DateTime, "Date de la création.", null: false, method: :created_at - field :date_publication, GraphQL::Types::ISO8601DateTime, "Date de la publication.", null: false, method: :published_at + field :date_publication, GraphQL::Types::ISO8601DateTime, "Date de la publication.", null: true, method: :published_at field :date_derniere_modification, GraphQL::Types::ISO8601DateTime, "Date de la dernière modification.", null: false, method: :updated_at field :date_depublication, GraphQL::Types::ISO8601DateTime, "Date de la dépublication.", null: true, method: :unpublished_at field :date_fermeture, GraphQL::Types::ISO8601DateTime, "Date de la fermeture.", null: true, method: :closed_at diff --git a/app/graphql/types/file.rb b/app/graphql/types/file.rb index 0fc4cf1bd..22a8e1afd 100644 --- a/app/graphql/types/file.rb +++ b/app/graphql/types/file.rb @@ -2,7 +2,8 @@ module Types class File < Types::BaseObject field :url, Types::URL, null: false field :filename, String, null: false - field :byte_size, Int, null: false + field :byte_size, Int, null: false, deprecation_reason: "Utilisez le champ `byteSizeBigInt` à la place." + field :byte_size_big_int, GraphQL::Types::BigInt, null: false, method: :byte_size field :checksum, String, null: false field :content_type, String, null: false diff --git a/app/graphql/types/revision_type.rb b/app/graphql/types/revision_type.rb index 3f1ef0847..372dbebb2 100644 --- a/app/graphql/types/revision_type.rb +++ b/app/graphql/types/revision_type.rb @@ -2,6 +2,7 @@ module Types class RevisionType < Types::BaseObject global_id_field :id field :date_creation, GraphQL::Types::ISO8601DateTime, "Date de la création.", null: false, method: :created_at + field :date_publication, GraphQL::Types::ISO8601DateTime, "Date de la publication.", null: true, method: :published_at field :champ_descriptors, [Types::ChampDescriptorType], null: false field :annotation_descriptors, [Types::ChampDescriptorType], null: false diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 27ceb25c5..0aa534ad3 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -248,10 +248,10 @@ class Procedure < ApplicationRecord state :close state :depubliee - event :publish, before: :before_publish, after: :after_publish do - transitions from: :brouillon, to: :publiee - transitions from: :close, to: :publiee - transitions from: :depubliee, to: :publiee + event :publish, before: :before_publish do + transitions from: :brouillon, to: :publiee, after: :after_publish + transitions from: :close, to: :publiee, after: :after_republish + transitions from: :depubliee, to: :publiee, after: :after_republish end event :close, after: :after_close do @@ -550,7 +550,7 @@ class Procedure < ApplicationRecord end def whitelist! - update_attribute('whitelisted_at', Time.zone.now) + touch(:whitelisted_at) end def closed_mail_template_attestation_inconsistency_state @@ -693,15 +693,21 @@ class Procedure < ApplicationRecord end def after_publish(canonical_procedure = nil) - update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure, draft_revision: create_new_revision, published_revision: draft_revision) + update!(canonical_procedure: canonical_procedure, draft_revision: create_new_revision, published_revision: draft_revision) + touch(:published_at) + published_revision.touch(:published_at) + end + + def after_republish(canonical_procedure = nil) + touch(:published_at) end def after_close - update!(closed_at: Time.zone.now) + touch(:closed_at) end def after_unpublish - update!(unpublished_at: Time.zone.now) + touch(:unpublished_at) end def update_juridique_required diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index e4da229c8..42c646ee2 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -3,6 +3,7 @@ # Table name: procedure_revisions # # id :bigint not null, primary key +# published_at :datetime # created_at :datetime not null # updated_at :datetime not null # procedure_id :bigint not null diff --git a/app/services/serializer_service.rb b/app/services/serializer_service.rb index 04d816f3c..3ded29254 100644 --- a/app/services/serializer_service.rb +++ b/app/services/serializer_service.rb @@ -232,7 +232,7 @@ class SerializerService fragment FileFragment on File { filename checksum - byteSize + byteSize: byteSizeBigInt contentType } GRAPHQL diff --git a/app/views/manager/users/emails.html.erb b/app/views/manager/users/emails.html.erb index b6ef69f21..1b9991d72 100644 --- a/app/views/manager/users/emails.html.erb +++ b/app/views/manager/users/emails.html.erb @@ -93,7 +93,7 @@ https://www.demarches-simplifiees.fr/users/password/new Bien cordialement <% else %> -
Ce compte n’est pas activé. Vous pouvez lui <%= link_to('renvoyer l’email de confirmation', [:resend_confirmation_instructions, namespace, 'user'], method: :post, class: 'button') %>, puis un email.
+Ce compte n’est pas activé. Vous pouvez lui <%= link_to('renvoyer l’email de confirmation', [:resend_confirmation_instructions, namespace, :user], method: :post, class: 'button') %>, puis un email.
Bonjour, diff --git a/db/migrate/20210120121240_add_published_at_to_procedure_revisions.rb b/db/migrate/20210120121240_add_published_at_to_procedure_revisions.rb new file mode 100644 index 000000000..5e1d8de0d --- /dev/null +++ b/db/migrate/20210120121240_add_published_at_to_procedure_revisions.rb @@ -0,0 +1,5 @@ +class AddPublishedAtToProcedureRevisions < ActiveRecord::Migration[6.0] + def change + add_column :procedure_revisions, :published_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 0955c73f6..1f272774e 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: 2021_05_06_135603) do +ActiveRecord::Schema.define(version: 2021_05_07_135603) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -533,6 +533,7 @@ ActiveRecord::Schema.define(version: 2021_05_06_135603) do t.bigint "procedure_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.datetime "published_at" t.index ["procedure_id"], name: "index_procedure_revisions_on_procedure_id" end diff --git a/lib/tasks/deployment/20210525114448_fix_published_revisions.rake b/lib/tasks/deployment/20210525114448_fix_published_revisions.rake new file mode 100644 index 000000000..781c0d9f0 --- /dev/null +++ b/lib/tasks/deployment/20210525114448_fix_published_revisions.rake @@ -0,0 +1,56 @@ +namespace :after_party do + desc 'Deployment task: fix_published_revisions' + task fix_published_revisions: :environment do + puts "Running deploy task 'fix_published_revisions'" + + procedure_ids = Procedure + .with_discarded + .joins(:revisions) + .group('procedures.id') + .having('count(procedure_id) > 2') + .map(&:id) + + # Remove wrongfully created revisions. Every procedure should have only a draft revision + # and a published revision for published procedure + revisions = ProcedureRevision + .joins(:procedure) + .where(procedure_id: procedure_ids) + .where('procedure_revisions.id != procedures.draft_revision_id AND procedure_revisions.id != procedures.published_revision_id') + + dossiers = Dossier.with_discarded.joins(:procedure).where(revision_id: revisions) + progress = ProgressReport.new(dossiers.count) + dossiers.find_each do |dossier| + dossier.update_column(:revision_id, dossier.procedure.published_revision_id) + progress.inc + end + progress.finish + + types_de_champ = TypeDeChamp.joins(:procedure).where(revision_id: revisions) + progress = ProgressReport.new(types_de_champ.count) + types_de_champ.find_each do |type_de_champ| + type_de_champ.update_column(:revision_id, type_de_champ.procedure.published_revision_id) + progress.inc + end + progress.finish + + ProcedureRevisionTypeDeChamp.where(revision_id: revisions).delete_all + revisions.delete_all + + # Fill published_at column on all published revisions + published_revisions = ProcedureRevision + .joins(:procedure) + .where(published_at: nil) + .where('procedure_revisions.id = procedures.published_revision_id') + progress = ProgressReport.new(published_revisions.count) + published_revisions.find_each do |revision| + revision.update_column(:published_at, revision.procedure.published_at) + progress.inc + end + progress.finish + + # Update task as completed. If you remove the line below, the task will + # run with every deploy (or every time you call after_party:run). + AfterParty::TaskRecord + .create version: AfterParty::TaskRecorder.new(__FILE__).timestamp + end +end diff --git a/package.json b/package.json index c9aa65e27..263362691 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "debounce": "^1.2.0", "dom4": "^2.1.5", "email-butler": "^1.0.13", - "highcharts": "^8.1.1", + "highcharts": "^9.0.0", "intersection-observer": "^0.12.0", "is-hotkey": "^0.2.0", "mapbox-gl": "^1.3.0", diff --git a/spec/controllers/api/v2/graphql_controller_spec.rb b/spec/controllers/api/v2/graphql_controller_spec.rb index e732ec43a..8e2a3ae0b 100644 --- a/spec/controllers/api/v2/graphql_controller_spec.rb +++ b/spec/controllers/api/v2/graphql_controller_spec.rb @@ -649,6 +649,73 @@ describe API::V2::GraphqlController do end end + context "champ" do + let(:champ) { create(:champ_piece_justificative, dossier: dossier) } + let(:byte_size) { 2712286911 } + + context "byteSize" do + let(:query) do + "{ + dossier(number: #{dossier.id}) { + champs(id: \"#{champ.to_typed_id}\") { + ... on PieceJustificativeChamp { + file { byteSize } + } + } + } + }" + end + + it { + expect(gql_errors).to be_nil + expect(gql_data).to eq(dossier: { champs: [{ file: { byteSize: 4 } }] }) + } + end + + context "when file is really big" do + before do + champ.piece_justificative_file.blob.update(byte_size: byte_size) + end + + context "byteSize" do + let(:query) do + "{ + dossier(number: #{dossier.id}) { + champs(id: \"#{champ.to_typed_id}\") { + ... on PieceJustificativeChamp { + file { byteSize } + } + } + } + }" + end + + it { + expect(gql_errors).not_to be_nil + } + end + + context "byteSizeBigInt" do + let(:query) do + "{ + dossier(number: #{dossier.id}) { + champs(id: \"#{champ.to_typed_id}\") { + ... on PieceJustificativeChamp { + file { byteSizeBigInt } + } + } + } + }" + end + + it { + expect(gql_errors).to be_nil + expect(gql_data).to eq(dossier: { champs: [{ file: { byteSizeBigInt: '2712286911' } }] }) + } + end + end + end + context "groupeInstructeur" do let(:groupe_instructeur) { procedure.groupe_instructeurs.first } let(:query) do diff --git a/spec/controllers/champs/carte_controller_spec.rb b/spec/controllers/champs/carte_controller_spec.rb index d618a1dad..8c469c77a 100644 --- a/spec/controllers/champs/carte_controller_spec.rb +++ b/spec/controllers/champs/carte_controller_spec.rb @@ -41,23 +41,38 @@ describe Champs::CarteController, type: :controller do post :create, params: params end - it { expect(response.status).to eq 201 } + context 'success' do + it { expect(response.status).to eq 201 } + end + + context 'error' do + let(:feature) { attributes_for(:geo_area, :invalid_right_hand_rule_polygon) } + let(:params) do + { + champ_id: champ.id, + feature: feature, + source: GeoArea.sources.fetch(:selection_utilisateur) + } + end + + it { expect(response.status).to eq 422 } + end end describe 'PATCH #update' do + let(:params) do + { + champ_id: champ.id, + id: geo_area.id, + feature: feature + } + end + before do patch :update, params: params end context 'update geometry' do - let(:params) do - { - champ_id: champ.id, - id: geo_area.id, - feature: feature - } - end - it { expect(response.status).to eq 204 } end @@ -69,19 +84,18 @@ describe Champs::CarteController, type: :controller do } } end - let(:params) do - { - champ_id: champ.id, - id: geo_area.id, - feature: feature - } - end it { expect(response.status).to eq 204 expect(geo_area.reload.description).to eq('un point') } end + + context 'error' do + let(:feature) { attributes_for(:geo_area, :invalid_right_hand_rule_polygon) } + + it { expect(response.status).to eq 422 } + end end describe 'DELETE #destroy' do diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index f4101ccc1..e81764862 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -625,6 +625,7 @@ describe Procedure do expect(procedure.draft_revision).not_to be_nil expect(procedure.revisions.count).to eq(2) expect(procedure.revisions).to eq([procedure.published_revision, procedure.draft_revision]) + expect(procedure.published_revision.published_at).to eq(now) end end @@ -649,12 +650,37 @@ describe Procedure do expect(procedure.canonical_procedure).to eq(canonical_procedure) expect(procedure.closed_at).to be_nil expect(procedure.published_at).to eq(now) + expect(procedure.published_revision.published_at).to eq(now) end it 'unpublishes parent procedure' do expect(parent_procedure.unpublished_at).to eq(now) end end + + context 'when republishing a previously closed procedure' do + let(:procedure) { create(:procedure, :published, administrateurs: [administrateur]) } + + before do + procedure.close! + Timecop.freeze(now) do + procedure.publish_or_reopen!(administrateur) + end + end + + it 'changes the procedure state to published' do + expect(procedure.closed_at).to be_nil + expect(procedure.published_at).to eq(now) + expect(procedure.published_revision.published_at).not_to eq(now) + end + + it "doesn't create a new revision" do + expect(procedure.published_revision).not_to be_nil + expect(procedure.draft_revision).not_to be_nil + expect(procedure.revisions.count).to eq(2) + expect(procedure.revisions).to eq([procedure.published_revision, procedure.draft_revision]) + end + end end describe "#unpublish!" do diff --git a/yarn.lock b/yarn.lock index 171f3b1ab..efa031308 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6339,10 +6339,10 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== -highcharts@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-8.1.1.tgz#7dc011e260289ab64d775807df0d13b85ed88338" - integrity sha512-DSkI+fAqkqYDslOVLcEk8DX7W9itRIwzsdS0uVEOnVf0LF1hSKZtDINHP7ze/uBN9NdWQV9HydtiPTrkLx0lXg== +highcharts@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-9.0.0.tgz#2e5d382481f71c50ac7f086e7bdead394fab71d4" + integrity sha512-MJCtidFytGSQvsV3OEM+vFTLpjUcp7jmFpLn8h3oL4WKp0gxUOQg6Nw00sqMWGdiadst0gOZO4804zynTcYjZQ== highlight-words-core@1.2.2: version "1.2.2"