diff --git a/app/controllers/admin/site_customization/base_controller.rb b/app/controllers/admin/site_customization/base_controller.rb new file mode 100644 index 000000000..18422f66e --- /dev/null +++ b/app/controllers/admin/site_customization/base_controller.rb @@ -0,0 +1,10 @@ +class Admin::SiteCustomization::BaseController < Admin::BaseController + helper_method :namespace + + private + + def namespace + "admin" + end + +end diff --git a/app/controllers/admin/site_customization/pages_controller.rb b/app/controllers/admin/site_customization/pages_controller.rb new file mode 100644 index 000000000..0b838054e --- /dev/null +++ b/app/controllers/admin/site_customization/pages_controller.rb @@ -0,0 +1,44 @@ +class Admin::SiteCustomization::PagesController < Admin::SiteCustomization::BaseController + load_and_authorize_resource :page, class: "SiteCustomization::Page" + + def index + @pages = SiteCustomization::Page.order('slug').page(params[:page]) + end + + def create + if @page.save + redirect_to admin_site_customization_pages_path, notice: t('admin.site_customization.pages.create.notice', link: @page.slug.html_safe) + else + flash.now[:error] = t('admin.site_customization.pages.create.error') + render :new + end + end + + def update + if @page.update(page_params) + redirect_to admin_site_customization_pages_path, notice: t('admin.site_customization.pages.update.notice', link: @page.slug.html_safe) + else + flash.now[:error] = t('admin.site_customization.pages.update.error') + render :edit + end + end + + def destroy + @page.destroy + redirect_to admin_site_customization_pages_path, notice: t('admin.site_customization.pages.destroy.notice') + end + + private + + def page_params + params.require(:site_customization_page).permit( + :slug, + :title, + :subtitle, + :content, + :more_info_flag, + :print_content_flag, + :status + ) + end +end diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 8e721b2b8..8df9270a3 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -51,6 +51,8 @@ module Abilities can [:search, :edit, :update, :create, :index, :destroy], Banner can [:index, :create, :edit, :update, :destroy], Geozone + + can :manage, SiteCustomization::Page end end end diff --git a/app/models/site_customization.rb b/app/models/site_customization.rb new file mode 100644 index 000000000..e5d2f2137 --- /dev/null +++ b/app/models/site_customization.rb @@ -0,0 +1,5 @@ +module SiteCustomization + def self.table_name_prefix + 'site_customization_' + end +end diff --git a/app/models/site_customization/page.rb b/app/models/site_customization/page.rb new file mode 100644 index 000000000..565e6352a --- /dev/null +++ b/app/models/site_customization/page.rb @@ -0,0 +1,14 @@ +class SiteCustomization::Page < ActiveRecord::Base + VALID_STATUSES = %w(draft published) + + validates :slug, uniqueness: { case_sensitive: false }, + format: { with: /\A[0-9a-zA-Z\-_]*\Z/, message: :slug_format } + validates :title, presence: true + validates :status, presence: true, inclusion: { in: VALID_STATUSES } + + scope :published, -> { where(status: 'published').order('id DESC') } + + def url + "/#{slug}" + end +end diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index d603dbf16..448da1662 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -122,5 +122,11 @@ <%= t("admin.menu.stats") %> <% end %> + +
  • > + <%= link_to admin_site_customization_pages_path do %> + <%= t("admin.menu.site_customization.pages") %> + <% end %> +
  • diff --git a/app/views/admin/site_customization/pages/_form.html.erb b/app/views/admin/site_customization/pages/_form.html.erb new file mode 100644 index 000000000..3881885d2 --- /dev/null +++ b/app/views/admin/site_customization/pages/_form.html.erb @@ -0,0 +1,52 @@ +<%= form_for [:admin, @page], html: {class: "edit_page", data: {watch_changes: true}} do |f| %> + + <% if @page.errors.any? %> + +
    + + + + <%= @page.errors.count %> + <%= t("admin.site_customization.pages.errors.form.error", count: @page.errors.count) %> + +
    + + <% end %> + +
    + + <%= f.label :title %> + <%= f.text_field :title, label: false %> + + <%= f.label :subtitle %> + <%= f.text_field :subtitle, label: false, size: 80, maxlength: 80 %> + + <%= f.label :slug %> + <%= f.text_field :slug, label: false, size: 80, maxlength: 80 %> + +
    + <%= f.label :content %> + <%= f.cktext_area :content, label: false, cols: 80, rows: 10, ckeditor: { language: I18n.locale } %> +
    +
    +
    +
    +

    <%= t("admin.site_customization.pages.form.options") %>

    + <%= f.check_box :more_info_flag %> + <%= f.check_box :print_content_flag %> +
    + +

    <%= f.label :status %>

    + <% ::SiteCustomization::Page::VALID_STATUSES.each do |status| %> + <%= f.radio_button :status, status, label: false %> + <%= f.label "status_#{status}", t("admin.site_customization.pages.status_#{status}") %> +
    + <% end %> + + <%= f.submit class: "button success" %> +
    + +
    +<% end %> diff --git a/app/views/admin/site_customization/pages/edit.html.erb b/app/views/admin/site_customization/pages/edit.html.erb new file mode 100644 index 000000000..c92933cbf --- /dev/null +++ b/app/views/admin/site_customization/pages/edit.html.erb @@ -0,0 +1,15 @@ +<% provide :title do %> + Admin - <%= t("admin.menu.site_customization.pages") %> - <%= @page.title %> +<% end %> + +<%= link_to admin_site_customization_pages_path, class: "back" do %> + + <%= t("admin.site_customization.pages.edit.back") %> +<% end %> + +<%= button_to t("admin.site_customization.pages.index.delete"), admin_site_customization_page_path(@page), method: :delete, class: "button hollow alert float-right margin-right" %> + +
    +

    <%= t("admin.site_customization.pages.edit.title", page_title: @page.title) %>

    + <%= render 'form' %> +
    diff --git a/app/views/admin/site_customization/pages/index.html.erb b/app/views/admin/site_customization/pages/index.html.erb new file mode 100644 index 000000000..356a1813b --- /dev/null +++ b/app/views/admin/site_customization/pages/index.html.erb @@ -0,0 +1,52 @@ +<% provide :title do %> + Admin - <%= t("admin.menu.site_customization.pages") %> +<% end %> + +
    +
    +
    +

    <%= t("admin.site_customization.pages.index.title") %>

    +
    +
    + <%= link_to t("admin.site_customization.pages.index.create"), new_admin_site_customization_page_path, class: "button" %> +
    +
    + +

    <%= page_entries_info @pages %>

    + + + + + + + + + + + + + + <% @pages.each do |page| %> + + + + + + + + + <% end %> + +
    <%= t("admin.site_customization.pages.page.title") %><%= t("admin.site_customization.pages.page.created_at") %><%= t("admin.site_customization.pages.page.updated_at") %><%= t("admin.site_customization.pages.page.status") %>
    + <%= link_to page.title, edit_admin_site_customization_page_path(page) %> + <%= I18n.l page.created_at, format: :short %><%= I18n.l page.created_at, format: :short %><%= t("admin.legislation.processes.process.status_#{page.status}") %> + + <%= link_to t("admin.site_customization.pages.index.see_page"), page.url %> + + + <%= link_to t("admin.site_customization.pages.index.delete"), admin_site_customization_page_path(page), method: :delete %> +
    + + <%= paginate @pages %> + +
    diff --git a/app/views/admin/site_customization/pages/new.html.erb b/app/views/admin/site_customization/pages/new.html.erb new file mode 100644 index 000000000..43a86d108 --- /dev/null +++ b/app/views/admin/site_customization/pages/new.html.erb @@ -0,0 +1,14 @@ +<% provide :title do %> + Admin - <%= t("admin.menu.site_customization.pages") %> - <%= t("admin.site_customization.pages.new.title") %> +<% end %> + +<%= link_to admin_site_customization_pages_path, class: "back" do %> + + <%= t("admin.site_customization.pages.new.back") %> +<% end %> + +
    +

    <%= t("admin.site_customization.pages.new.title") %>

    + <%= render 'form' %> +
    + diff --git a/config/locales/activerecord.en.yml b/config/locales/activerecord.en.yml index 04c5cc9d0..e8354b88e 100644 --- a/config/locales/activerecord.en.yml +++ b/config/locales/activerecord.en.yml @@ -40,6 +40,9 @@ en: spending_proposal: one: "Spending proposal" other: "Spending proposals" + site_customization/page: + one: Custom page + other: Custom pages attributes: budget: name: "Name" @@ -103,6 +106,16 @@ en: signable_type: "Signable type" signable_id: "Signable ID" document_numbers: "Documents numbers" + site_customization/page: + content: Content + created_at: Created at + subtitle: Subtitle + slug: Slug + status: Status + title: Title + updated_at: Updated at + more_info_flag: Show in more information page + print_content_flag: Print content button errors: models: user: @@ -134,3 +147,7 @@ en: document_number: not_in_census: 'Not verified by Census' already_voted: 'Already voted this proposal' + site_customization/page: + attributes: + slug: + slug_format: "must be letters, numbers, _ and -" diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml index 542406d0a..32b26223b 100644 --- a/config/locales/activerecord.es.yml +++ b/config/locales/activerecord.es.yml @@ -40,6 +40,9 @@ es: spending_proposal: one: "Propuesta de inversión" other: "Propuestas de inversión" + site_customization/page: + one: Página + other: Páginas attributes: budget: name: "Nombre" @@ -98,6 +101,16 @@ es: signable_type: "Tipo de hoja de firmas" signable_id: "ID Propuesta ciudadana/Propuesta inversión" document_numbers: "Números de documentos" + site_customization/page: + content: Contenido + created_at: Creada + subtitle: Subtítulo + slug: Slug + status: Estado + title: Título + updated_at: última actualización + more_info_flag: Mostrar en la página de más información + print_content_flag: Botón de imprimir contenido errors: models: user: @@ -129,3 +142,7 @@ es: document_number: not_in_census: 'No verificado por Padrón' already_voted: 'Ya ha votado esta propuesta' + site_customization/page: + attributes: + slug: + slug_format: "deber ser letras, números, _ y -" diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 460319748..d44179ce8 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -207,6 +207,8 @@ en: spending_proposals: Spending proposals stats: Statistics signature_sheets: Signature Sheets + site_customization: + pages: Custom Pages moderators: index: title: Moderators @@ -475,3 +477,34 @@ en: phone_not_given: Phone not given sms_code_not_confirmed: Has not confirmed the sms code title: Incomplete verifications + site_customization: + pages: + create: + notice: 'Page created successfully.' + error: Process couldn't be created + update: + notice: 'Page updated successfully.' + error: Page couldn't be updated + destroy: + notice: Page deleted successfully + edit: + title: Editing %{page_title} + back: Back + errors: + form: + error: Error + form: + options: Options + index: + create: Create new page + delete: Delete + title: Custom Pages + see_page: See page + new: + back: Back + title: Create new custom page + page: + created_at: Created at + status: Status + title: Title + updated_at: Updated at diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 7d6438416..f93433546 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -207,6 +207,8 @@ es: spending_proposals: Propuestas de inversión stats: Estadísticas signature_sheets: Hojas de firmas + site_customization: + pages: Páginas moderators: index: title: Moderadores @@ -475,3 +477,34 @@ es: phone_not_given: No ha dado su teléfono sms_code_not_confirmed: No ha introducido su código de seguridad title: Verificaciones incompletas + site_customization: + pages: + create: + notice: 'Página creada correctamente.' + error: No se ha podido crear la página + update: + notice: 'Página actualizada correctamente.s' + error: No se ha podido actualizar la página + destroy: + notice: Página eliminada correctamente + edit: + title: Editar %{page_title} + back: Volver + errors: + form: + error: Error + form: + options: Opciones + index: + create: Crear nueva página + delete: Borrar + title: Páginas + see_page: Ver página + new: + back: Back + title: Página nueva + page: + created_at: Creada + status: Estado + title: Título + updated_at: Última actualización diff --git a/config/routes.rb b/config/routes.rb index b1a6d57b2..e31bd86a0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -222,6 +222,10 @@ Rails.application.routes.draw do end resources :geozones, only: [:index, :new, :create, :edit, :update, :destroy] + + namespace :site_customization do + resources :pages + end end namespace :moderation do diff --git a/db/migrate/20170316174351_create_site_customization_pages.rb b/db/migrate/20170316174351_create_site_customization_pages.rb new file mode 100644 index 000000000..3c4fbe846 --- /dev/null +++ b/db/migrate/20170316174351_create_site_customization_pages.rb @@ -0,0 +1,15 @@ +class CreateSiteCustomizationPages < ActiveRecord::Migration + def change + create_table :site_customization_pages do |t| + t.string :slug, null: false + t.string :title, null: false + t.string :subtitle + t.text :content + t.boolean :more_info_flag + t.boolean :print_content_flag + t.string :status, default: 'draft' + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index fb563c8db..0b38a4196 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170114154421) do +ActiveRecord::Schema.define(version: 20170316174351) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -439,6 +439,18 @@ ActiveRecord::Schema.define(version: 20170114154421) do t.datetime "updated_at" end + create_table "site_customization_pages", force: :cascade do |t| + t.string "slug", null: false + t.string "title", null: false + t.string "subtitle" + t.text "content" + t.boolean "more_info_flag" + t.boolean "print_content_flag" + t.string "status", default: "draft" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "spending_proposals", force: :cascade do |t| t.string "title" t.text "description" diff --git a/spec/factories.rb b/spec/factories.rb index e058adf15..20a1f463c 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -450,4 +450,22 @@ FactoryGirl.define do signature_sheet sequence(:document_number) { |n| "#{n}A" } end + + factory :site_customization_page, class: 'SiteCustomization::Page' do + slug "example-page" + title "Example page" + subtitle "About an example" + content "This page is about..." + more_info_flag false + print_content_flag false + status 'draft' + + trait :published do + status "published" + end + + trait :display_in_more_info do + more_info_flag true + end + end end diff --git a/spec/features/admin/site_customization/pages_spec.rb b/spec/features/admin/site_customization/pages_spec.rb new file mode 100644 index 000000000..b9ebeb273 --- /dev/null +++ b/spec/features/admin/site_customization/pages_spec.rb @@ -0,0 +1,62 @@ +require 'rails_helper' + +feature 'Admin custom pages' do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + context "Index" do + scenario 'Displaying custom pages' do + custom_page = create(:site_customization_page) + visit admin_site_customization_pages_path + + expect(page).to have_content(custom_page.title) + end + end + + context 'Create' do + scenario 'Valid custom page' do + visit admin_root_path + + within('#side_menu') do + click_link "Custom Pages" + end + + expect(page).to_not have_content 'An example custom page' + + click_link "Create new page" + + fill_in 'site_customization_page_title', with: 'An example custom page' + fill_in 'site_customization_page_subtitle', with: 'Page subtitle' + fill_in 'site_customization_page_slug', with: 'example-page' + fill_in 'site_customization_page_content', with: 'This page is about...' + + click_button 'Create Custom page' + + expect(page).to have_content 'An example custom page' + end + end + + context 'Update' do + scenario 'Valid custom page' do + custom_page = create(:site_customization_page, title: 'An example custom page') + visit admin_root_path + + within('#side_menu') do + click_link "Custom Pages" + end + + click_link "An example custom page" + + expect(page).to have_selector("h2", text: "An example custom page") + + fill_in 'site_customization_page_title', with: 'Another example custom page' + click_button "Update Custom page" + + expect(page).to have_content "Page updated successfully" + expect(page).to have_content 'Another example custom page' + end + end +end diff --git a/spec/models/site_customization/page_spec.rb b/spec/models/site_customization/page_spec.rb new file mode 100644 index 000000000..2868f62d1 --- /dev/null +++ b/spec/models/site_customization/page_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe SiteCustomization::Page, type: :model do + let(:custom_page) { build(:site_customization_page) } + + it "should be valid" do + expect(custom_page).to be_valid + end + + it "is invalid if slug has symbols" do + custom_page = build(:site_customization_page, slug: "as/as*la") + expect(custom_page).to be_invalid + end +end