diff --git a/README.md b/README.md index 850e2f19..666a9f01 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ This is the open-source repository for "participa", based on [Decidim](https://g - `Decidim::Regulations`, adds Regulations, a new type of Participatory process. - `Decidim::Admin::Extended`, customize admin menu adding custom configurations. - `Decidim::Recaptcha`, use recaptcha instead invisible captcha. +- Static pages admin: adds attachment and gallery support to `Decidim::Admin::StaticPage` (form, command and controller helper) via decorators. ## Deploying the app diff --git a/app/decorators/decidim/admin/static_pages_controller_decorator.rb b/app/decorators/decidim/admin/static_pages_controller_decorator.rb new file mode 100644 index 00000000..f4dda36f --- /dev/null +++ b/app/decorators/decidim/admin/static_pages_controller_decorator.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Decidim::Admin::StaticPagesControllerDecorator + def self.decorate + Decidim::Admin::StaticPagesController.class_eval do + helper_method :tab_panel_items + end + end +end + +Decidim::Admin::StaticPagesControllerDecorator.decorate diff --git a/app/decorators/decidim/admin/static_pages_form_decorator.rb b/app/decorators/decidim/admin/static_pages_form_decorator.rb new file mode 100644 index 00000000..f5ef0c74 --- /dev/null +++ b/app/decorators/decidim/admin/static_pages_form_decorator.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Decidim::Admin::StaticPagesFormDecorator + def self.decorate + Decidim::Admin::StaticPageForm.class_eval do + include Decidim::AttachmentAttributes + include Decidim::HasUploadValidations + + attribute :attachment, ::Decidim::AttachmentForm + attachments_attribute :documents + attachments_attribute :photos + end + end +end + +Decidim::Admin::StaticPagesFormDecorator.decorate diff --git a/app/decorators/decidim/admin/update_static_page_decorator.rb b/app/decorators/decidim/admin/update_static_page_decorator.rb new file mode 100644 index 00000000..63a0d717 --- /dev/null +++ b/app/decorators/decidim/admin/update_static_page_decorator.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module Decidim::Admin::UpdateStaticPageDecorator + def self.decorate # rubocop:disable Metrics/CyclomaticComplexity + Decidim::Admin::UpdateStaticPage.class_eval do + include ::Decidim::MultipleAttachmentsMethods + include ::Decidim::GalleryMethods + + def initialize(form, page) + @form = form + @page = page + @attached_to = page + end + + def call + return broadcast(:invalid) if @form.invalid? + + if process_attachments? + build_attachments + return broadcast(:invalid) if attachments_invalid? + end + + if process_gallery? + build_gallery + return broadcast(:invalid) if gallery_invalid? + end + + transaction do + update_static_page + document_cleanup! + photo_cleanup! + create_attachments if process_attachments? + create_gallery if process_gallery? + broadcast(:ok) + end + end + + def update_static_page + parsed_content = form.content.transform_values do |value| + Decidim::ContentProcessor.parse(value.to_s, current_organization: form.current_organization).rewrite + end + Decidim.traceability.update!( + page, + form.current_user, + title: form.title, + slug: form.slug, + weight: form.weight, + topic: form.topic, + allow_public_access: form.allow_public_access, + content: parsed_content + ) + + return unless form.changed_notably + + Decidim::Admin::UpdateOrganizationTosVersion.call(form.organization, page, form) + end + + private + + attr_reader :form, :page + end + end +end + +Decidim::Admin::UpdateStaticPageDecorator.decorate diff --git a/app/decorators/decidim/pages_controller_decorator.rb b/app/decorators/decidim/pages_controller_decorator.rb new file mode 100644 index 00000000..8d40b8b9 --- /dev/null +++ b/app/decorators/decidim/pages_controller_decorator.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Decidim::PagesControllerDecorator + def self.decorate + Decidim::PagesController.class_eval do + include ::Decidim::AttachmentsHelper + + helper_method :tab_panel_items + + private + + def tab_panel_items + @tab_panel_items ||= attachments_tab_panel_items(@page) + end + end + end +end + +Decidim::PagesControllerDecorator.decorate diff --git a/app/decorators/decidim/static_pages_decorator.rb b/app/decorators/decidim/static_pages_decorator.rb new file mode 100644 index 00000000..08e7458f --- /dev/null +++ b/app/decorators/decidim/static_pages_decorator.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Decidim::StaticPagesDecorator + def self.decorate + Decidim::StaticPage.class_eval do + include Decidim::HasAttachments + end + end +end + +Decidim::StaticPagesDecorator.decorate diff --git a/app/views/decidim/admin/static_pages/_form.html.erb b/app/views/decidim/admin/static_pages/_form.html.erb new file mode 100644 index 00000000..ac4d6359 --- /dev/null +++ b/app/views/decidim/admin/static_pages/_form.html.erb @@ -0,0 +1,66 @@ +
+ <%= description %> +
+Content
", + ca: "Contingut
", + es: "Contenido
" + } + end + + let(:attributes) do + { + static_page: { + slug: "help", + title: { en: "Help", ca: "Ajuda", es: "Ayuda" }, + content:, + attachment: attachment_params + } + } + end + + context "when everything is OK" do + it { is_expected.to be_valid } + end + + describe "attachment attributes added by decorator" do + it "responds to documents" do + expect(subject).to respond_to(:documents) + end + + it "responds to add_documents" do + expect(subject).to respond_to(:add_documents) + end + + it "responds to photos" do + expect(subject).to respond_to(:photos) + end + + it "responds to add_photos" do + expect(subject).to respond_to(:add_photos) + end + + it "responds to attachment" do + expect(subject).to respond_to(:attachment) + end + end +end diff --git a/spec/decorators/decidim/admin/update_static_page_decorator_spec.rb b/spec/decorators/decidim/admin/update_static_page_decorator_spec.rb new file mode 100644 index 00000000..bc61ec6c --- /dev/null +++ b/spec/decorators/decidim/admin/update_static_page_decorator_spec.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +require "rails_helper" +require "spec_helper" + +describe Decidim::Admin::UpdateStaticPage do + let(:form_klass) { Decidim::Admin::StaticPageForm } + + let(:organization) { create(:organization) } + let(:user) { create(:user, :admin, :confirmed, organization:) } + let(:attachment_params) { nil } + let(:uploaded_photos) { [] } + + let(:form) do + form_klass.from_params( + form_params + ).with_context( + current_organization: organization, + current_user: user + ) + end + + let!(:static_page) { create(:static_page, organization:) } + + describe "call" do + let(:form_params) do + { + static_page: { + id: static_page.id, + slug: static_page.slug, + title: { en: "Updated title" }, + content: { en: "Updated content
" }, + weight: 5, + allow_public_access: true, + add_documents: nil, + add_photos: uploaded_photos + } + } + end + + let(:command) do + described_class.new(form, static_page) + end + + describe "when the form is not valid" do + before do + allow(form).to receive(:invalid?).and_return(true) + end + + it "broadcast invalid" do + expect { command.call }.to broadcast(:invalid) + end + + it "does not update the static page" do + expect do + command.call + end.not_to(change { static_page.reload.content }) + end + end + + describe "when the form is valid" do + it "broadcast ok" do + expect { command.call }.to broadcast(:ok) + end + + it "updates the static page content" do + expect do + command.call + end.to(change { static_page.reload.content["en"] }) + end + + it "updates the static page title" do + expect do + command.call + end.to(change { static_page.reload.title["en"] }.to("Updated title")) + end + + it "updates the static page weight" do + expect do + command.call + end.to(change { static_page.reload.weight }.to(5)) + end + + it "updates the static page allow_public_access" do + expect do + command.call + end.to(change { static_page.reload.allow_public_access }.to(true)) + end + + context "when photos are uploaded" do + let(:attachment_params) do + blob = ActiveStorage::Blob.create_and_upload!( + io: Rack::Test::UploadedFile.new(Decidim::Core::Engine.root.join("db", "seeds", "city.jpeg"), "image/jpeg"), + filename: "city.jpeg", + content_type: "image/jpeg" + ) + { + title: "My attachment", + file: blob.signed_id + } + end + let(:uploaded_photos) { [attachment_params] } + + it "creates an attachment for the static page" do + expect { command.call }.to change(Decidim::Attachment, :count).by(1) + last_attachment = Decidim::Attachment.last + expect(last_attachment.attached_to).to eq(static_page) + end + end + end + end +end diff --git a/spec/system/admin/static_pages/admin_static_page_form_spec.rb b/spec/system/admin/static_pages/admin_static_page_form_spec.rb new file mode 100644 index 00000000..ca211552 --- /dev/null +++ b/spec/system/admin/static_pages/admin_static_page_form_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require "rails_helper" + +describe "Admin static page form", type: :system do + let(:organization) { create(:organization) } + let!(:user) { create(:user, :admin, :confirmed, organization:) } + let!(:tos_page) { organization.static_pages.find_by!(slug: "terms-of-service") } + let!(:other_page) { create(:static_page, organization:) } + + before do + switch_to_host(organization.host) + login_as user, scope: :user + end + + describe "editing a terms-of-service static page" do + it "does not show the attachment fields" do + visit decidim_admin.edit_static_page_path(tos_page) + + expect(page).to have_no_css("label", text: /documents/i) + expect(page).to have_no_css("label", text: /imatge/i) + end + end + + describe "editing a regular static page" do + it "shows the attachment fields" do + visit decidim_admin.edit_static_page_path(other_page) + + expect(page).to have_css("legend", text: I18n.t("decidim.admin.static_pages.form.attachment_legend")) + end + end +end