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 %>
+
+
+
+
+ | <%= 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") %> |
+ |
+ |
+
+
+
+ <% @pages.each do |page| %>
+
+ |
+ <%= 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 %>
+ |
+
+ <% end %>
+
+
+
+ <%= 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