diff --git a/.gitignore b/.gitignore index 35f5651a4..a6f2826c3 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ .DS_Store .ruby-gemset -public/sitemap.xml \ No newline at end of file +public/sitemap.xml +public/system/ diff --git a/Gemfile b/Gemfile index f9c2f54e5..39dee65f8 100644 --- a/Gemfile +++ b/Gemfile @@ -65,6 +65,8 @@ gem 'browser' gem 'turnout', '~> 2.4.0' gem 'redcarpet', '~> 3.4.0' +gem 'paperclip' + group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' diff --git a/Gemfile.lock b/Gemfile.lock index 6c117ea77..67ab5a78b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -238,6 +238,7 @@ GEM mime-types (3.1) mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) + mimemagic (0.3.2) mini_portile2 (2.1.0) minitest (5.10.1) multi_json (1.12.1) @@ -277,6 +278,12 @@ GEM omniauth-oauth (~> 1.1) rack orm_adapter (0.5.0) + paperclip (5.1.0) + activemodel (>= 4.2.0) + activesupport (>= 4.2.0) + cocaine (~> 0.5.5) + mime-types + mimemagic (~> 0.3.0) paranoia (2.2.1) activerecord (>= 4.0, < 5.1) parser (2.4.0.0) @@ -504,6 +511,7 @@ DEPENDENCIES omniauth-facebook (~> 4.0.0) omniauth-google-oauth2 (~> 0.4.0) omniauth-twitter + paperclip paranoia (~> 2.2.1) pg (~> 0.20.0) pg_search @@ -533,4 +541,4 @@ DEPENDENCIES whenever BUNDLED WITH - 1.13.7 + 1.14.6 diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 61214eb23..fac6d35ed 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -529,3 +529,13 @@ table { padding: 0 $line-height/2; } } + +// 07. CMS +// -------------- +.cms_page_list { + + [class^="icon-"] { + padding-right: $menu-icon-spacing; + vertical-align: middle; + } +} 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/content_blocks_controller.rb b/app/controllers/admin/site_customization/content_blocks_controller.rb new file mode 100644 index 000000000..2f0843ccc --- /dev/null +++ b/app/controllers/admin/site_customization/content_blocks_controller.rb @@ -0,0 +1,40 @@ +class Admin::SiteCustomization::ContentBlocksController < Admin::SiteCustomization::BaseController + load_and_authorize_resource :content_block, class: "SiteCustomization::ContentBlock" + + def index + @content_blocks = SiteCustomization::ContentBlock.order(:name, :locale) + end + + def create + if @content_block.save + redirect_to admin_site_customization_content_blocks_path, notice: t('admin.site_customization.content_blocks.create.notice') + else + flash.now[:error] = t('admin.site_customization.content_blocks.create.error') + render :new + end + end + + def update + if @content_block.update(content_block_params) + redirect_to admin_site_customization_content_blocks_path, notice: t('admin.site_customization.content_blocks.update.notice') + else + flash.now[:error] = t('admin.site_customization.content_blocks.update.error') + render :edit + end + end + + def destroy + @content_block.destroy + redirect_to admin_site_customization_content_blocks_path, notice: t('admin.site_customization.content_blocks.destroy.notice') + end + + private + + def content_block_params + params.require(:site_customization_content_block).permit( + :name, + :locale, + :body + ) + end +end diff --git a/app/controllers/admin/site_customization/images_controller.rb b/app/controllers/admin/site_customization/images_controller.rb new file mode 100644 index 000000000..c9f318f41 --- /dev/null +++ b/app/controllers/admin/site_customization/images_controller.rb @@ -0,0 +1,43 @@ +class Admin::SiteCustomization::ImagesController < Admin::SiteCustomization::BaseController + load_and_authorize_resource :image, class: "SiteCustomization::Image" + + def index + @images = SiteCustomization::Image.all_images + end + + def update + if params[:site_customization_image].nil? + redirect_to admin_site_customization_images_path + return + end + + if @image.update(image_params) + redirect_to admin_site_customization_images_path, notice: t('admin.site_customization.images.update.notice') + else + flash.now[:error] = t('admin.site_customization.images.update.error') + + @images = SiteCustomization::Image.all_images + idx = @images.index {|e| e.name == @image.name } + @images[idx] = @image + + render :index + end + end + + def destroy + @image.image = nil + if @image.save + redirect_to admin_site_customization_images_path, notice: t('admin.site_customization.images.destroy.notice') + else + redirect_to admin_site_customization_images_path, notice: t('admin.site_customization.images.destroy.error') + end + end + + private + + def image_params + params.require(:site_customization_image).permit( + :image + ) + 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..4d92a6a1e --- /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') + 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') + 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/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 03f62925a..81d6e8dbd 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -2,7 +2,11 @@ class PagesController < ApplicationController skip_authorization_check def show - render action: params[:id] + if @custom_page = SiteCustomization::Page.published.find_by(slug: params[:id]) + render action: :custom_page + else + render action: params[:id] + end rescue ActionView::MissingTemplate head 404 end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 208ed3d3d..0c23c0d22 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -47,4 +47,12 @@ module ApplicationHelper "".html_safe + t("shared.back") end end + + def image_path_for(filename) + SiteCustomization::Image.image_path_for(filename) || filename + end + + def content_block(name, locale) + SiteCustomization::ContentBlock.block_for(name, locale) + end end diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 34adac19b..8df52e6eb 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -60,6 +60,10 @@ module Abilities can [:create, :destroy], ::Poll::OfficerAssignment can [:read, :create, :update], Poll::Question can :destroy, Poll::Question # , comments_count: 0, votes_up: 0 + + can :manage, SiteCustomization::Page + can :manage, SiteCustomization::Image + can :manage, SiteCustomization::ContentBlock 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/content_block.rb b/app/models/site_customization/content_block.rb new file mode 100644 index 000000000..c08beb52e --- /dev/null +++ b/app/models/site_customization/content_block.rb @@ -0,0 +1,11 @@ +class SiteCustomization::ContentBlock < ActiveRecord::Base + VALID_BLOCKS = %w(top_links footer) + + validates :locale, presence: true, inclusion: { in: I18n.available_locales.map(&:to_s) } + validates :name, presence: true, uniqueness: { scope: :locale }, inclusion: { in: VALID_BLOCKS } + + def self.block_for(name, locale) + locale ||= I18n.default_locale + find_by(name: name, locale: locale).try(:body) + end +end diff --git a/app/models/site_customization/image.rb b/app/models/site_customization/image.rb new file mode 100644 index 000000000..2230a96ce --- /dev/null +++ b/app/models/site_customization/image.rb @@ -0,0 +1,48 @@ +class SiteCustomization::Image < ActiveRecord::Base + VALID_IMAGES = { + "icon_home" => [330, 240], + "logo_header" => [80, 80], + "social-media-icon" => [200, 200], + "apple-touch-icon-200" => [200, 200] + } + + has_attached_file :image + + validates :name, presence: true, uniqueness: true, inclusion: { in: VALID_IMAGES.keys } + validates_attachment_content_type :image, :content_type => ["image/png"] + validate :check_image + + def self.all_images + VALID_IMAGES.keys.map do |image_name| + find_by(name: image_name) || create!(name: image_name.to_s) + end + end + + def self.image_path_for(filename) + image_name = filename.split(".").first + + if i = find_by(name: image_name) + i.image.exists? ? i.image.url : nil + end + end + + def required_width + VALID_IMAGES[name].try(:first) + end + + def required_height + VALID_IMAGES[name].try(:second) + end + + private + + def check_image + return unless image? + + dimensions = Paperclip::Geometry.from_file(image.queued_for_write[:original].path) + + errors.add(:image, :image_width, required_width: required_width) unless dimensions.width == required_width + errors.add(:image, :image_height, required_height: required_height) unless dimensions.height == required_height + end + +end diff --git a/app/models/site_customization/page.rb b/app/models/site_customization/page.rb new file mode 100644 index 000000000..c2a9b1467 --- /dev/null +++ b/app/models/site_customization/page.rb @@ -0,0 +1,16 @@ +class SiteCustomization::Page < ActiveRecord::Base + VALID_STATUSES = %w(draft published) + + validates :slug, presence: true, + 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') } + scope :with_more_info_flag, -> { where(status: 'published', more_info_flag: true).order('id ASC') } + + def url + "/#{slug}" + end +end diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index d30ac954c..fecd29419 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -142,5 +142,25 @@ <% end %> <% end %> + +
  • + + + <%= t("admin.menu.title_site_customization") %> + + +
  • diff --git a/app/views/admin/site_customization/content_blocks/_form.html.erb b/app/views/admin/site_customization/content_blocks/_form.html.erb new file mode 100644 index 000000000..b5a692d87 --- /dev/null +++ b/app/views/admin/site_customization/content_blocks/_form.html.erb @@ -0,0 +1,47 @@ +<%= form_for [:admin, @content_block], html: {class: "edit_page", data: {watch_changes: true}} do |f| %> + + <% if @content_block.errors.any? %> + +
    + + + + <%= @content_block.errors.count %> + <%= t("admin.site_customization.content_blocks.errors.form.error", count: @content_block.errors.count) %> + +
    + + <% end %> + +
    + <%= f.label :name %> + <%= f.select :name, SiteCustomization::ContentBlock::VALID_BLOCKS, label: false %> +
    +
    + <%= f.label :locale %> + <%= f.select :locale, I18n.available_locales, label: false %> +
    + +
    + <%= f.label :body %> + <%= f.text_area :body, label: false, rows: 10 %> + <%= f.submit class: "button success" %> +
    + +<% end %> + +

    <%= t('.content_blocks_information') %>

    + +

    <%= t('.content_block_about') %>

    + +

    <%= t('.content_block_top_links_html') %>

    +
    +<li><a href="http://site1.com">Site 1</a></li>
    +<li><a href="http://site2.com">Site 2</a></li>
    +<li><a href="http://site3.com">Site 3</a></li>
    +
    +
    + +

    <%= t('.content_block_footer_html') %>

    diff --git a/app/views/admin/site_customization/content_blocks/edit.html.erb b/app/views/admin/site_customization/content_blocks/edit.html.erb new file mode 100644 index 000000000..c96f9a810 --- /dev/null +++ b/app/views/admin/site_customization/content_blocks/edit.html.erb @@ -0,0 +1,15 @@ +<% provide :title do %> + Admin - <%= t("admin.menu.site_customization.content_blocks") %> - <%= @content_block.name %> (<%= @content_block.locale %>) +<% end %> + +<%= link_to admin_site_customization_content_blocks_path, class: "back" do %> + + <%= t("admin.site_customization.content_blocks.edit.back") %> +<% end %> + +<%= button_to t("admin.site_customization.content_blocks.index.delete"), admin_site_customization_content_block_path(@content_block), method: :delete, class: "button hollow alert float-right margin-right" %> + +
    +

    <%= t("admin.site_customization.content_blocks.edit.title") %>

    + <%= render 'form' %> +
    diff --git a/app/views/admin/site_customization/content_blocks/index.html.erb b/app/views/admin/site_customization/content_blocks/index.html.erb new file mode 100644 index 000000000..653e3e731 --- /dev/null +++ b/app/views/admin/site_customization/content_blocks/index.html.erb @@ -0,0 +1,29 @@ +<% provide :title do %> + Admin - <%= t("admin.menu.site_customization.content_blocks") %> +<% end %> + +<%= link_to t("admin.site_customization.content_blocks.index.create"), new_admin_site_customization_content_block_path, class: "button float-right margin-right" %> +

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

    + + + + + + + + + + + <% @content_blocks.each do |content_block| %> + + + + + + <% end %> + +
    <%= t("admin.site_customization.content_blocks.content_block.name") %><%= t("admin.site_customization.content_blocks.content_block.body") %>
    <%= link_to "#{content_block.name} (#{content_block.locale})", edit_admin_site_customization_content_block_path(content_block) %><%= content_block.body %> + <%= button_to t("admin.site_customization.content_blocks.index.delete"), + admin_site_customization_content_block_path(content_block), + method: :delete, class: "button hollow alert" %> +
    diff --git a/app/views/admin/site_customization/content_blocks/new.html.erb b/app/views/admin/site_customization/content_blocks/new.html.erb new file mode 100644 index 000000000..75ff5f389 --- /dev/null +++ b/app/views/admin/site_customization/content_blocks/new.html.erb @@ -0,0 +1,14 @@ +<% provide :title do %> + Admin - <%= t("admin.menu.site_customization.content_blocks") %> - <%= t("admin.site_customization.content_blocks.new.title") %> +<% end %> + +<%= link_to admin_site_customization_content_blocks_path, class: "back" do %> + + <%= t("admin.site_customization.content_blocks.new.back") %> +<% end %> + +
    +

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

    + <%= render 'form' %> +
    + diff --git a/app/views/admin/site_customization/images/index.html.erb b/app/views/admin/site_customization/images/index.html.erb new file mode 100644 index 000000000..b9de152d1 --- /dev/null +++ b/app/views/admin/site_customization/images/index.html.erb @@ -0,0 +1,25 @@ +

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

    + + + + <% @images.each do |image| %> + + + + + <% end %> + +
    + <%= image.name %> (<%= image.required_width %>x<%= image.required_height %>) + + <%= form_for([:admin, image], html: { id: "edit_#{dom_id(image)}"}) do |f| %> +
    + <%= image_tag image.image.url if image.image.exists? %> + <%= f.file_field :image, label: false %> +
    +
    + <%= f.submit(t('admin.site_customization.images.index.update'), class: "button hollow") %> + <%= link_to t('admin.site_customization.images.index.delete'), admin_site_customization_image_path(image), method: :delete, class: "button hollow alert" if image.image.exists? %> +
    + <% 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..197520631 --- /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.page.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..eef3370e6 --- /dev/null +++ b/app/views/admin/site_customization/pages/index.html.erb @@ -0,0 +1,43 @@ +<% provide :title do %> + Admin - <%= t("admin.menu.site_customization.pages") %> +<% end %> + +<%= link_to t("admin.site_customization.pages.index.create"), new_admin_site_customization_page_path, class: "button float-right margin-right" %> +

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

    + +

    <%= 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.site_customization.pages.page.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/app/views/layouts/_admin_header.html.erb b/app/views/layouts/_admin_header.html.erb index c2f0e47a7..8597b41de 100644 --- a/app/views/layouts/_admin_header.html.erb +++ b/app/views/layouts/_admin_header.html.erb @@ -21,7 +21,7 @@

    <%= link_to namespaced_root_path, class: "hide-for-small-only" do %> - <%= image_tag('logo_header.png', class: 'hide-for-small-only float-left', size: '80x80', alt: t("layouts.header.logo")) %> + <%= image_tag(image_path_for('logo_header.png'), class: 'hide-for-small-only float-left', size: '80x80', alt: t("layouts.header.logo")) %> <%= setting['org_name'] %>  | <%= namespaced_header_title %> <% end %> @@ -38,4 +38,4 @@

    - \ No newline at end of file + diff --git a/app/views/layouts/_footer.html.erb b/app/views/layouts/_footer.html.erb index 4b5e90523..0bce1cd67 100644 --- a/app/views/layouts/_footer.html.erb +++ b/app/views/layouts/_footer.html.erb @@ -1,5 +1,5 @@ diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb index 9a33662c6..a3162bb8c 100644 --- a/app/views/layouts/_header.html.erb +++ b/app/views/layouts/_header.html.erb @@ -22,7 +22,7 @@
    <%= link_to root_path, class: "hide-for-small-only", accesskey: "0" do %> - <%= image_tag('logo_header.png', class: 'hide-for-small-only float-left', size: '80x80', alt: t("layouts.header.logo")) %> + <%= image_tag(image_path_for('logo_header.png'), class: 'hide-for-small-only float-left', size: '80x80', alt: t("layouts.header.logo")) %> <%= setting['org_name'] %> <% end %>
    diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 4f92768dc..7f66b524e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -14,7 +14,7 @@ <%= javascript_include_tag "application", 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> <%= favicon_link_tag "favicon.ico" %> - <%= favicon_link_tag "apple-touch-icon-200.png", + <%= favicon_link_tag image_path_for("apple-touch-icon-200.png"), rel: "icon apple-touch-icon", sizes: "200x200", type: "image/png" %> diff --git a/app/views/layouts/devise.html.erb b/app/views/layouts/devise.html.erb index a0e9eaaff..50b84287d 100644 --- a/app/views/layouts/devise.html.erb +++ b/app/views/layouts/devise.html.erb @@ -17,7 +17,7 @@

    <%= link_to root_path do %> - <%= image_tag('logo_header.png', class: 'float-left', alt: t("layouts.header.logo")) %> + <%= image_tag(image_path_for('logo_header.png'), class: 'float-left', alt: t("layouts.header.logo")) %> <%= setting['org_name'] %> <% end %>

    diff --git a/app/views/layouts/management.html.erb b/app/views/layouts/management.html.erb index 8e497bf24..21367d8ab 100644 --- a/app/views/layouts/management.html.erb +++ b/app/views/layouts/management.html.erb @@ -35,7 +35,7 @@
    <%= link_to management_root_path, class: "hide-for-small-only" do %> - <%= image_tag('logo_header.png', class: 'hide-for-small-only float-left', size: '80x80', alt: t("layouts.header.logo")) %> + <%= image_tag(image_path_for('logo_header.png'), class: 'hide-for-small-only float-left', size: '80x80', alt: t("layouts.header.logo")) %> <%= setting['org_name'] %>  | <%= t("management.dashboard.index.title") %> <% end %> diff --git a/app/views/pages/custom_page.html.erb b/app/views/pages/custom_page.html.erb new file mode 100644 index 000000000..f14eba7d9 --- /dev/null +++ b/app/views/pages/custom_page.html.erb @@ -0,0 +1,15 @@ +<% provide :title do %><%= @custom_page.title %><% end %> + +
    + +
    +

    <%= @custom_page.title %>

    +

    <%= @custom_page.subtitle %>

    + + <%= raw @custom_page.content %> +
    + +
    + <%= render '/shared/print' if @custom_page.print_content_flag %> +
    +
    diff --git a/app/views/pages/more_info/_other.html.erb b/app/views/pages/more_info/_other.html.erb index d0718294c..5501c9e31 100644 --- a/app/views/pages/more_info/_other.html.erb +++ b/app/views/pages/more_info/_other.html.erb @@ -4,4 +4,8 @@
  • <%= link_to t("pages.more_info.other.how_to_use", org_name: setting['org_name']), faq_path %>
  • <%= link_to t("pages.more_info.other.facts"), participation_facts_path %>
  • <%= link_to t("pages.more_info.other.world"), participation_world_path %>
  • + + <% SiteCustomization::Page.with_more_info_flag.each do |custom_page| %> +
  • <%= link_to custom_page.title, page_path(custom_page.slug) %>
  • + <% end %> diff --git a/app/views/sandbox/admin_cms.html.erb b/app/views/sandbox/admin_cms.html.erb new file mode 100644 index 000000000..26cc96f5c --- /dev/null +++ b/app/views/sandbox/admin_cms.html.erb @@ -0,0 +1,62 @@ +Crear nueva página +

    Editar páginas

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NombreCreadaÚltima actualizaciónEstado
    + Política de privacidad + + Hace 20 días + + Hace 15 días + + Publicada + + + Ver página + + + Borrar página +
    + FAQ + + Hace 6 días + + Hace 3 días + + + Borrador + + + Ver página + + + Borrar página +
    diff --git a/app/views/sandbox/admin_cms_page.html.erb b/app/views/sandbox/admin_cms_page.html.erb new file mode 100644 index 000000000..ea65176b8 --- /dev/null +++ b/app/views/sandbox/admin_cms_page.html.erb @@ -0,0 +1,61 @@ + + + + Volver + + + + +
    + +
    +

    Editar Política de privacidad

    + +
    + + + + + + + + + +
    + + +
    +
    +
    +
    +
    +

    Opciones

    + + + +
    + +

    Estado

    + + +
    + + +
    + +
    + + +
    + + +
    + +
    +
    + + diff --git a/app/views/shared/_social_media_meta_tags.html.erb b/app/views/shared/_social_media_meta_tags.html.erb index 50a2efec9..c0e6a5e8a 100644 --- a/app/views/shared/_social_media_meta_tags.html.erb +++ b/app/views/shared/_social_media_meta_tags.html.erb @@ -3,7 +3,7 @@ - + <% if setting['url'] %> @@ -14,7 +14,7 @@ <% end %> - + diff --git a/app/views/shared/_top_links.html.erb b/app/views/shared/_top_links.html.erb index b97499232..8a71130d6 100644 --- a/app/views/shared/_top_links.html.erb +++ b/app/views/shared/_top_links.html.erb @@ -1,21 +1,25 @@ diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index 32124a950..1eb6cf38c 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -12,7 +12,7 @@
    - <%= image_tag("icon_home.png", size: "330x240", alt:"") %> + <%= image_tag(image_path_for("icon_home.png"), size: "330x240", alt:"") %>
    diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index aa9473201..ca6eae46e 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -156,6 +156,7 @@ ignore_unused: - 'views.pagination.*' # kaminari - 'shared.suggest.*' - 'invisible_captcha.*' + - 'admin.site_customization.pages.page.status_*' # - '{devise,kaminari,will_paginate}.*' # - 'simple_form.{yes,no}' # - 'simple_form.{placeholders,hints,labels}.*' diff --git a/config/locales/activerecord.en.yml b/config/locales/activerecord.en.yml index 6a7aebcbd..608803579 100644 --- a/config/locales/activerecord.en.yml +++ b/config/locales/activerecord.en.yml @@ -46,6 +46,15 @@ en: spending_proposal: one: "Spending proposal" other: "Spending proposals" + site_customization/page: + one: Custom page + other: Custom pages + site_customization/image: + one: Custom image + other: Custom images + site_customization/content_block: + one: Custom content block + other: Custom content blocks attributes: budget: name: "Name" @@ -120,6 +129,23 @@ 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 + site_customization/image: + name: Name + image: Image + site_customization/content_block: + name: Name + locale: locale + body: Body errors: models: user: @@ -156,3 +182,12 @@ 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 -" + site_customization/image: + attributes: + image: + image_width: "Width must be %{required_width}px" + image_height: "Height must be %{required_height}px" diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml index 1451b2fe8..71e166026 100644 --- a/config/locales/activerecord.es.yml +++ b/config/locales/activerecord.es.yml @@ -46,6 +46,15 @@ es: spending_proposal: one: "Propuesta de inversión" other: "Propuestas de inversión" + site_customization/page: + one: Página + other: Páginas + site_customization/image: + one: Imagen + other: Imágenes + site_customization/content_block: + one: Bloque + other: Bloques attributes: budget: name: "Nombre" @@ -115,6 +124,23 @@ 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 + site_customization/image: + name: Nombre + image: Imagen + site_customization/content_block: + name: Nombre + locale: Idioma + body: Contenido errors: models: user: @@ -151,3 +177,12 @@ 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 -" + site_customization/image: + attributes: + image: + image_width: "Debe tener %{required_width}px de ancho" + image_height: "Debe tener %{required_height}px de alto" diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 564137a09..5ae6d6f49 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -215,12 +215,17 @@ en: spending_proposals: Spending proposals stats: Statistics signature_sheets: Signature Sheets + site_customization: + pages: Custom Pages + images: Custom Images + content_blocks: Custom content blocks title_categories: Categories title_moderated_content: Moderated content title_budgets: Budgets title_polls: Polls title_profiles: Profiles title_banners: Banners + title_site_customization: Site customization moderators: index: title: Moderators @@ -657,3 +662,77 @@ en: phone_not_given: Phone not given sms_code_not_confirmed: Has not confirmed the sms code title: Incomplete verifications + site_customization: + content_blocks: + form: + content_blocks_information: Information about content blocks + content_block_about: You can create HTML content blocks to be inserted in the header or the footer of your Consul. + content_block_top_links_html: "Header blocks (top_links) are blocks of links that must have this format:" + content_block_footer_html: "Footer blocks can have any format and can be used to insert Javascript, CSS or custom HTML." + create: + notice: Content block created successfully + error: Content block couldn't be created + update: + notice: Content block updated successfully + error: Content block couldn't be updated + destroy: + notice: Content block deleted successfully + edit: + title: Editing content block + back: Back + errors: + form: + error: Error + index: + create: Create new content block + delete: Delete + title: Content blocks + new: + back: Back + title: Create new content block + content_block: + body: Body + name: Name + images: + index: + title: Custom images + update: Update + delete: Delete + update: + notice: Image updated successfully + error: Image couldn't be updated + destroy: + notice: Image deleted successfully + error: Image couldn't be deleted + pages: + create: + notice: Page created successfully + error: Page 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 + status_draft: Draft + status_published: Published diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index aaf83e275..f5db64135 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -215,12 +215,17 @@ es: spending_proposals: Propuestas de inversión stats: Estadísticas signature_sheets: Hojas de firmas + site_customization: + pages: Personalizar páginas + images: Personalizar imágenes + content_blocks: Personalizar bloques title_categories: Categorías title_moderated_content: Contenido moderado title_budgets: Presupuestos title_polls: Votaciones title_profiles: Perfiles title_banners: Banners + title_site_customization: Personalizar sitio moderators: index: title: Moderadores @@ -657,3 +662,77 @@ 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: + content_blocks: + form: + content_blocks_information: Información sobre los bloques de texto + content_block_about: Puedes crear bloques de HTML que se incrustarán en la cabecera o el pie de tu Cónsul. + content_block_top_links_html: "Los bloques de la cabecera (top_links) son bloques de enlaces que deben crearse con este formato:" + content_block_footer_html: "Los bloques del pie (footer) pueden tener cualquier formato y se pueden utilizar para guardar huellas Javascript, contenido CSS o contenido HTML personalizado." + create: + notice: Bloque creado correctamente + error: No se ha podido crear el bloque + update: + notice: Bloque actualizado correctamente + error: No se ha podido actualizar el bloque + destroy: + notice: Bloque borrado correctamente + edit: + title: Editar bloque + back: Volver + errors: + form: + error: Error + index: + create: Crear nuevo bloque + delete: Borrar + title: Bloques + new: + back: Volver + title: Crear nuevo bloque + content_block: + body: Contenido + name: Nombre + images: + index: + title: Personalizar imágenes + update: Actualizar + delete: Borrar + update: + notice: Imagen actualizada correctamente + error: No se ha podido actualizar la imagen + destroy: + notice: Imagen borrada correctamente + error: No se ha podido borrar la imagen + pages: + create: + notice: Página creada correctamente + error: No se ha podido crear la página + update: + notice: Página actualizada correctamente + 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 + status_draft: Borrador + status_published: Publicada diff --git a/config/locales/settings.en.yml b/config/locales/settings.en.yml index 23040d827..d96b9db27 100755 --- a/config/locales/settings.en.yml +++ b/config/locales/settings.en.yml @@ -21,6 +21,8 @@ en: youtube_handle: "Youtube handle" telegram_handle: "Telegram handle" blog_url: "Blog URL" + transparency_url: "Transparency URL" + opendata_url: "Open Data URL" url: "Main URL" org_name: "Organization" place_name: "Place" diff --git a/config/locales/settings.es.yml b/config/locales/settings.es.yml index 1e1fd1ddd..97ab56dc9 100644 --- a/config/locales/settings.es.yml +++ b/config/locales/settings.es.yml @@ -21,6 +21,8 @@ es: youtube_handle: "Usuario de Youtube" telegram_handle: "Usuario de Telegram" blog_url: "URL del blog" + transparency_url: "URL de transparencia" + opendata_url: "URL de open data" url: "URL general de la web" org_name: "Nombre de la organización" place_name: "Nombre del lugar" diff --git a/config/routes.rb b/config/routes.rb index cffd0a113..5fd94eaaf 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -248,6 +248,12 @@ Rails.application.routes.draw do end resources :geozones, only: [:index, :new, :create, :edit, :update, :destroy] + + namespace :site_customization do + resources :pages, except: [:show] + resources :images, only: [:index, :update, :destroy] + resources :content_blocks, except: [:show] + 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/migrate/20170322145702_create_site_customization_images.rb b/db/migrate/20170322145702_create_site_customization_images.rb new file mode 100644 index 000000000..4f980b566 --- /dev/null +++ b/db/migrate/20170322145702_create_site_customization_images.rb @@ -0,0 +1,11 @@ +class CreateSiteCustomizationImages < ActiveRecord::Migration + def change + create_table :site_customization_images do |t| + t.string :name, null: false + t.attachment :image + t.timestamps null: false + end + + add_index :site_customization_images, :name, unique: true + end +end diff --git a/db/migrate/20170324101716_create_site_customization_content_blocks.rb b/db/migrate/20170324101716_create_site_customization_content_blocks.rb new file mode 100644 index 000000000..d0e4c3822 --- /dev/null +++ b/db/migrate/20170324101716_create_site_customization_content_blocks.rb @@ -0,0 +1,13 @@ +class CreateSiteCustomizationContentBlocks < ActiveRecord::Migration + def change + create_table :site_customization_content_blocks do |t| + t.string :name + t.string :locale + t.text :body + + t.timestamps null: false + end + + add_index :site_customization_content_blocks, [:name, :locale], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 96d0becbf..1227f8675 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: 20170212123435) do +ActiveRecord::Schema.define(version: 20170324101716) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -627,6 +627,40 @@ ActiveRecord::Schema.define(version: 20170212123435) do t.datetime "updated_at" end + create_table "site_customization_content_blocks", force: :cascade do |t| + t.string "name" + t.string "locale" + t.text "body" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "site_customization_content_blocks", ["name", "locale"], name: "index_site_customization_content_blocks_on_name_and_locale", unique: true, using: :btree + + create_table "site_customization_images", force: :cascade do |t| + t.string "name", null: false + t.string "image_file_name" + t.string "image_content_type" + t.integer "image_file_size" + t.datetime "image_updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "site_customization_images", ["name"], name: "index_site_customization_images_on_name", unique: true, using: :btree + + 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/db/seeds.rb b/db/seeds.rb index 3ef166bc7..0f1a4f7a3 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -51,6 +51,8 @@ Setting["facebook_handle"] = nil Setting["youtube_handle"] = nil Setting["telegram_handle"] = nil Setting["blog_url"] = nil +Setting["transparency_url"] = nil +Setting["opendata_url"] = "/opendata" # Public-facing URL of the app. Setting["url"] = "http://example.com" diff --git a/spec/factories.rb b/spec/factories.rb index de67a9c23..b295fd60c 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -583,4 +583,28 @@ 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 + + factory :site_customization_content_block, class: 'SiteCustomization::ContentBlock' do + name "top_links" + locale "en" + body "Some top links content" + end end diff --git a/spec/features/admin/site_customization/content_blocks_spec.rb b/spec/features/admin/site_customization/content_blocks_spec.rb new file mode 100644 index 000000000..cc5dca34c --- /dev/null +++ b/spec/features/admin/site_customization/content_blocks_spec.rb @@ -0,0 +1,107 @@ +require 'rails_helper' + +feature "Admin custom content blocks" do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario "Index" do + block = create(:site_customization_content_block) + visit admin_site_customization_content_blocks_path + + expect(page).to have_content(block.name) + expect(page).to have_content(block.body) + end + + context "Create" do + scenario "Valid custom block" do + visit admin_root_path + + within("#side_menu") do + click_link "Custom content blocks" + end + + expect(page).to_not have_content "footer (es)" + + click_link "Create new content block" + + select "footer", from: "site_customization_content_block_name" + select "es", from: "site_customization_content_block_locale" + fill_in "site_customization_content_block_body", with: "Some custom content" + + click_button "Create Custom content block" + + expect(page).to have_content "footer (es)" + expect(page).to have_content "Some custom content" + end + + scenario "Invalid custom block" do + block = create(:site_customization_content_block) + + visit admin_root_path + + within("#side_menu") do + click_link "Custom content blocks" + end + + expect(page).to have_content "top_links (en)" + + click_link "Create new content block" + + select "top_links", from: "site_customization_content_block_name" + select "en", from: "site_customization_content_block_locale" + fill_in "site_customization_content_block_body", with: "Some custom content" + + click_button "Create Custom content block" + + expect(page).to have_content "Content block couldn't be created" + expect(page).to have_content "has already been taken" + end + end + + context "Update" do + scenario "Valid custom block" do + block = create(:site_customization_content_block) + visit admin_root_path + + within("#side_menu") do + click_link "Custom content blocks" + end + + click_link "top_links (en)" + + fill_in "site_customization_content_block_body", with: "Some other custom content" + click_button "Update Custom content block" + + expect(page).to have_content "Content block updated successfully" + expect(page).to have_content "Some other custom content" + end + end + + context "Delete" do + scenario "From index page" do + block = create(:site_customization_content_block) + visit admin_site_customization_content_blocks_path + + expect(page).to have_content("#{block.name} (#{block.locale})") + expect(page).to have_content(block.body) + + click_button "Delete" + + expect(page).to_not have_content("#{block.name} (#{block.locale})") + expect(page).to_not have_content(block.body) + end + + scenario "From edit page" do + block = create(:site_customization_content_block) + visit edit_admin_site_customization_content_block_path(block) + + click_button "Delete" + + expect(page).to_not have_content("#{block.name} (#{block.locale})") + expect(page).to_not have_content(block.body) + end + end +end diff --git a/spec/features/admin/site_customization/images_spec.rb b/spec/features/admin/site_customization/images_spec.rb new file mode 100644 index 000000000..094ac19bf --- /dev/null +++ b/spec/features/admin/site_customization/images_spec.rb @@ -0,0 +1,62 @@ +require 'rails_helper' + +feature "Admin custom images" do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario "Upload valid image" do + visit admin_root_path + + within("#side_menu") do + click_link "Custom Images" + end + + within("tr.logo_header") do + attach_file "site_customization_image_image", "spec/fixtures/files/logo_header.png" + click_button "Update" + end + + expect(page).to have_css("tr.logo_header img[src*='logo_header.png']") + expect(page).to have_css("img[src*='logo_header.png']", count: 2) # one in the admin form an one in the page header + end + + scenario "Upload invalid image" do + visit admin_root_path + + within("#side_menu") do + click_link "Custom Images" + end + + within("tr.icon_home") do + attach_file "site_customization_image_image", "spec/fixtures/files/logo_header.png" + click_button "Update" + end + + expect(page).to have_content("Width must be 330px") + expect(page).to have_content("Height must be 240px") + end + + scenario "Delete image" do + visit admin_root_path + + within("#side_menu") do + click_link "Custom Images" + end + + within("tr.social-media-icon") do + attach_file "site_customization_image_image", "spec/fixtures/files/social-media-icon.png" + click_button "Update" + end + + expect(page).to have_css("img[src*='social-media-icon.png']") + + within("tr.social-media-icon") do + click_link "Delete" + end + + expect(page).to_not have_css("img[src*='social-media-icon.png']") + 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..5d03638d8 --- /dev/null +++ b/spec/features/admin/site_customization/pages_spec.rb @@ -0,0 +1,69 @@ +require 'rails_helper' + +feature "Admin custom pages" do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario "Index" do + custom_page = create(:site_customization_page) + visit admin_site_customization_pages_path + + expect(page).to have_content(custom_page.title) + 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 + 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 + + scenario "Delete" do + custom_page = create(:site_customization_page, title: "An example custom page") + visit edit_admin_site_customization_page_path(custom_page) + + click_button "Delete" + + expect(page).to_not have_content("An example custom page") + end +end diff --git a/spec/features/site_customization/content_blocks_spec.rb b/spec/features/site_customization/content_blocks_spec.rb new file mode 100644 index 000000000..995982063 --- /dev/null +++ b/spec/features/site_customization/content_blocks_spec.rb @@ -0,0 +1,33 @@ +require 'rails_helper' + +feature "Custom content blocks" do + scenario "top links" do + create(:site_customization_content_block, name: "top_links", locale: "en", body: "content for top links") + create(:site_customization_content_block, name: "top_links", locale: "es", body: "contenido para top links") + + visit "/?locale=en" + + expect(page).to have_content("content for top links") + expect(page).to_not have_content("contenido para top links") + + visit "/?locale=es" + + expect(page).to have_content("contenido para top links") + expect(page).to_not have_content("content for top links") + end + + scenario "footer" do + create(:site_customization_content_block, name: "footer", locale: "en", body: "content for footer") + create(:site_customization_content_block, name: "footer", locale: "es", body: "contenido para footer") + + visit "/?locale=en" + + expect(page).to have_content("content for footer") + expect(page).to_not have_content("contenido para footer") + + visit "/?locale=es" + + expect(page).to have_content("contenido para footer") + expect(page).to_not have_content("content for footer") + end +end diff --git a/spec/features/site_customization/custom_pages_spec.rb b/spec/features/site_customization/custom_pages_spec.rb new file mode 100644 index 000000000..2e2fac84a --- /dev/null +++ b/spec/features/site_customization/custom_pages_spec.rb @@ -0,0 +1,102 @@ +require 'rails_helper' + +feature "Custom Pages" do + context "Override existing page" do + scenario "See default content when custom page is not published" do + custom_page = create(:site_customization_page, + slug: "conditions", + title: "Custom conditions", + content: "New text for conditions page", + print_content_flag: true + ) + + visit custom_page.url + + expect(page).to have_title("Terms of use") + expect(page).to have_selector("h1", text: "Terms and conditions of use") + expect(page).to have_content("Página de información sobre las condiciones de uso, privacidad y protección de datos personales.") + expect(page).to have_content("Print this info") + end + + scenario "See custom content when custom page is published" do + custom_page = create(:site_customization_page, :published, + slug: "conditions", + title: "Custom conditions", + content: "New text for conditions page", + print_content_flag: true + ) + + visit custom_page.url + + expect(page).to have_title("Custom conditions") + expect(page).to have_selector("h1", text: "Custom conditions") + expect(page).to have_content("New text for conditions page") + expect(page).to have_content("Print this info") + end + end + + context "New custom page" do + context "Draft" do + scenario "See page" do + custom_page = create(:site_customization_page, + slug: "other-slug", + title: "Custom page", + content: "Text for new custom page", + print_content_flag: false + ) + + visit custom_page.url + + expect(page.status_code).to eq(404) + end + end + + context "Published" do + scenario "See page" do + custom_page = create(:site_customization_page, :published, + slug: "other-slug", + title: "Custom page", + content: "Text for new custom page", + print_content_flag: false + ) + + visit custom_page.url + + expect(page).to have_title("Custom page") + expect(page).to have_selector("h1", text: "Custom page") + expect(page).to have_content("Text for new custom page") + expect(page).to_not have_content("Print this info") + end + + scenario "Listed in more information page" do + custom_page = create(:site_customization_page, :published, + slug: "another-slug", title: "Another custom page", + subtitle: "Subtitle for custom page", + more_info_flag: true + ) + + visit more_info_path + + expect(page).to have_content("Another custom page") + end + + scenario "Not listed in more information page" do + custom_page = create(:site_customization_page, :published, + slug: "another-slug", title: "Another custom page", + subtitle: "Subtitle for custom page", + more_info_flag: false + ) + + visit more_info_path + + expect(page).to_not have_content("Another custom page") + + visit custom_page.url + + expect(page).to have_title("Another custom page") + expect(page).to have_selector("h1", text: "Another custom page") + expect(page).to have_content("Subtitle for custom page") + end + end + end +end diff --git a/spec/fixtures/files/logo_header.png b/spec/fixtures/files/logo_header.png new file mode 100644 index 000000000..5f5355574 Binary files /dev/null and b/spec/fixtures/files/logo_header.png differ diff --git a/spec/fixtures/files/social-media-icon.png b/spec/fixtures/files/social-media-icon.png new file mode 100644 index 000000000..fcd00e212 Binary files /dev/null and b/spec/fixtures/files/social-media-icon.png differ diff --git a/spec/models/site_customization/content_block_spec.rb b/spec/models/site_customization/content_block_spec.rb new file mode 100644 index 000000000..2eb6279f6 --- /dev/null +++ b/spec/models/site_customization/content_block_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +RSpec.describe SiteCustomization::ContentBlock, type: :model do + let(:block) { build(:site_customization_content_block) } + + it "should be valid" do + expect(block).to be_valid + end + + it "name is unique per locale" do + create(:site_customization_content_block, name: "top_links", locale: "en") + invalid_block = build(:site_customization_content_block, name: "top_links", locale: "en") + + expect(invalid_block).to be_invalid + expect(invalid_block.errors.full_messages).to include("Name has already been taken") + + valid_block = build(:site_customization_content_block, name: "top_links", locale: "es") + expect(valid_block).to be_valid + 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