From 1464bddfa81db9ccc47c044148b94cf0c6e83047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Salvador=20P=C3=A9rez=20Garc=C3=ADa?= Date: Mon, 11 Jun 2018 18:26:18 +0200 Subject: [PATCH] Fixes #134 Adds an administration interface for the proposal dashboard actions. --- .../admin/proposal_dashboard_actions.coffee | 3 + .../admin/proposal_dashboard_actions.scss | 3 + .../proposal_dashboard_actions_controller.rb | 51 +++++++ .../proposal_dashboard_actions_helper.rb | 8 ++ app/models/abilities/administrator.rb | 1 + app/models/proposal_dashboard_action.rb | 44 ++++++ app/views/admin/_menu.html.erb | 6 + .../_errors.html.erb | 13 ++ .../proposal_dashboard_actions/_form.html.erb | 56 ++++++++ .../proposal_dashboard_actions/edit.html.erb | 9 ++ .../proposal_dashboard_actions/index.html.erb | 41 ++++++ .../proposal_dashboard_actions/new.html.erb | 9 ++ config/locales/en/activerecord.yml | 13 +- config/locales/en/admin.yml | 25 ++++ config/locales/es/activerecord.yml | 12 ++ config/locales/es/admin.yml | 26 ++++ config/routes/admin.rb | 2 + ...72816_create_proposal_dashboard_actions.rb | 17 +++ db/schema.rb | 12 ++ spec/factories.rb | 33 +++++ .../admin/proposal_dashboard_actions_spec.rb | 84 +++++++++++ .../proposal_dashboard_actions_helper_spec.rb | 19 +++ spec/models/abilities/administrator_spec.rb | 1 + spec/models/abilities/common_spec.rb | 1 + spec/models/abilities/everyone_spec.rb | 1 + spec/models/proposal_dashboard_action_spec.rb | 130 ++++++++++++++++++ 26 files changed, 619 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/admin/proposal_dashboard_actions.coffee create mode 100644 app/assets/stylesheets/admin/proposal_dashboard_actions.scss create mode 100644 app/controllers/admin/proposal_dashboard_actions_controller.rb create mode 100644 app/helpers/admin/proposal_dashboard_actions_helper.rb create mode 100644 app/models/proposal_dashboard_action.rb create mode 100644 app/views/admin/proposal_dashboard_actions/_errors.html.erb create mode 100644 app/views/admin/proposal_dashboard_actions/_form.html.erb create mode 100644 app/views/admin/proposal_dashboard_actions/edit.html.erb create mode 100644 app/views/admin/proposal_dashboard_actions/index.html.erb create mode 100644 app/views/admin/proposal_dashboard_actions/new.html.erb create mode 100644 db/migrate/20180611072816_create_proposal_dashboard_actions.rb create mode 100644 spec/features/admin/proposal_dashboard_actions_spec.rb create mode 100644 spec/helpers/admin/proposal_dashboard_actions_helper_spec.rb create mode 100644 spec/models/proposal_dashboard_action_spec.rb diff --git a/app/assets/javascripts/admin/proposal_dashboard_actions.coffee b/app/assets/javascripts/admin/proposal_dashboard_actions.coffee new file mode 100644 index 000000000..24f83d18b --- /dev/null +++ b/app/assets/javascripts/admin/proposal_dashboard_actions.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/admin/proposal_dashboard_actions.scss b/app/assets/stylesheets/admin/proposal_dashboard_actions.scss new file mode 100644 index 000000000..6153445cd --- /dev/null +++ b/app/assets/stylesheets/admin/proposal_dashboard_actions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Admin::ProposalDashboardActions controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/admin/proposal_dashboard_actions_controller.rb b/app/controllers/admin/proposal_dashboard_actions_controller.rb new file mode 100644 index 000000000..ff5126a64 --- /dev/null +++ b/app/controllers/admin/proposal_dashboard_actions_controller.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +class Admin::ProposalDashboardActionsController < Admin::BaseController + helper_method :proposal_dashboard_action + + def index + @proposal_dashboard_actions = ProposalDashboardAction.all + end + + def new + @proposal_dashboard_action = ProposalDashboardAction.new(active: true, day_offset: 0, required_supports: 0, request_to_administrators: true) + end + + def create + @proposal_dashboard_action = ProposalDashboardAction.new(proposal_dashboard_action_params) + if @proposal_dashboard_action.save + redirect_to admin_proposal_dashboard_actions_path, notice: t('admin.proposal_dashboard_actions.create.notice') + else + render :new + end + end + + def edit; end + + def update + if proposal_dashboard_action.update(proposal_dashboard_action_params) + redirect_to admin_proposal_dashboard_actions_path + else + render :edit + end + + end + + def destroy + proposal_dashboard_action.destroy + redirect_to admin_proposal_dashboard_actions_path, notice: t('admin.proposal_dashboard_actions.delete.success') + end + + private + + def proposal_dashboard_action_params + params + .require(:proposal_dashboard_action) + .permit(:title, :description, :link, :request_to_administrators, :day_offset, :required_supports, :order, :active) + end + + + def proposal_dashboard_action + @proposal_dashboard_action ||= ProposalDashboardAction.find(params[:id]) + end +end diff --git a/app/helpers/admin/proposal_dashboard_actions_helper.rb b/app/helpers/admin/proposal_dashboard_actions_helper.rb new file mode 100644 index 000000000..a1cf4be85 --- /dev/null +++ b/app/helpers/admin/proposal_dashboard_actions_helper.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module Admin::ProposalDashboardActionsHelper + def active_human_readable(active) + return t('admin.proposal_dashboard_actions.index.active') if active + t('admin.proposal_dashboard_actions.index.inactive') + end +end diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 6f8a70b5e..1e65978d6 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -48,6 +48,7 @@ module Abilities can [:search, :index], ::User can :manage, Annotation + can :manage, ProposalDashboardAction can [:read, :update, :valuate, :destroy, :summary], SpendingProposal diff --git a/app/models/proposal_dashboard_action.rb b/app/models/proposal_dashboard_action.rb new file mode 100644 index 000000000..8a548cd2b --- /dev/null +++ b/app/models/proposal_dashboard_action.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +class ProposalDashboardAction < ActiveRecord::Base + acts_as_paranoid column: :hidden_at + include ActsAsParanoidAliases + + validates :title, + presence: true, + allow_blank: false, + length: { in: 4..80 } + + validates :description, + presence: true, + allow_blank: false, + length: { in: 4..255 } + + validates :day_offset, + presence: true, + numericality: { + only_integer: true, + greater_than_or_equal_to: 0 + } + + validates :required_supports, + presence: true, + numericality: { + only_integer: true, + greater_than_or_equal_to: 0 + } + + validates :link, + presence: true, + allow_blank: false, + unless: :request_to_administrators? + + default_scope { order(order: :asc, title: :asc) } + + scope :active, -> { where(active: true) } + scope :inactive, -> { where(active: false) } + + def request_to_administrators? + request_to_administrators || false + end +end diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 7e6b94047..428789a82 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -223,6 +223,12 @@ <%= link_to t("admin.menu.geozones"), admin_geozones_path %> +
  • > + + <%= link_to <%= ProposalDashboardAction.model_name.human(count: 2), + admin_proposal_dashboard_actions_path %> +
  • +
  • > <%= link_to t("admin.menu.site_customization.images"), admin_site_customization_images_path %> diff --git a/app/views/admin/proposal_dashboard_actions/_errors.html.erb b/app/views/admin/proposal_dashboard_actions/_errors.html.erb new file mode 100644 index 000000000..34c7c5f2d --- /dev/null +++ b/app/views/admin/proposal_dashboard_actions/_errors.html.erb @@ -0,0 +1,13 @@ +<% if proposal_dashboard_action.errors.any? %> +
    + + + + <%= proposal_dashboard_action.errors.count %> + <%= t('admin.proposal_dashboard_actions.errors.form.error', count: proposal_dashboard_action.errors.count) %> + +
    + +<% end %> diff --git a/app/views/admin/proposal_dashboard_actions/_form.html.erb b/app/views/admin/proposal_dashboard_actions/_form.html.erb new file mode 100644 index 000000000..075aa13c6 --- /dev/null +++ b/app/views/admin/proposal_dashboard_actions/_form.html.erb @@ -0,0 +1,56 @@ +<%= form_for [:admin, proposal_dashboard_action] do |f| %> + + <%= render 'errors' %> + +
    +
    + <%= f.label :title %> + <%= f.text_field :title, label: false %> +
    +
    + +
    +
    + <%= f.label :description %> + <%= f.text_field :description, label: false %> +
    +
    + +
    + <%= f.check_box :request_to_administrators, label: ProposalDashboardAction.human_attribute_name(:request_to_administrators) %> +
    + +
    +
    + <%= f.label :link%> + <%= f.text_field :link, label: false %> +
    +
    + +
    +
    + <%= f.label :day_offset %> + <%= f.number_field :day_offset, label: false, step: 1, min: 0 %> +
    + +
    + <%= f.label :required_supports %> + <%= f.number_field :required_supports, label: false, step: 1, min: 0 %> +
    + +
    + <%= f.label :order %> + <%= f.number_field :order, label: false, step: 1, min: 0 %> +
    +
    + +
    + <%= f.check_box :active, label: ProposalDashboardAction.human_attribute_name(:active) %> +
    + +
    +
    + <%= f.submit(class: 'button expanded', value: t('admin.proposal_dashboard_actions.form.submit_button')) %> +
    +
    +<% end %> diff --git a/app/views/admin/proposal_dashboard_actions/edit.html.erb b/app/views/admin/proposal_dashboard_actions/edit.html.erb new file mode 100644 index 000000000..7c1d44b9b --- /dev/null +++ b/app/views/admin/proposal_dashboard_actions/edit.html.erb @@ -0,0 +1,9 @@ +
    +
    + <%= back_link_to admin_proposal_dashboard_actions_path, t('admin.proposal_dashboard_actions.edit.back') %> + +

    <%= t('admin.proposal_dashboard_actions.edit.editing') %>

    + + <%= render 'form' %> +
    +
    diff --git a/app/views/admin/proposal_dashboard_actions/index.html.erb b/app/views/admin/proposal_dashboard_actions/index.html.erb new file mode 100644 index 000000000..f2897150c --- /dev/null +++ b/app/views/admin/proposal_dashboard_actions/index.html.erb @@ -0,0 +1,41 @@ +<%= link_to t('admin.proposal_dashboard_actions.index.create'), + new_admin_proposal_dashboard_action_path, class: 'button success float-right' %> + +

    + <%= ProposalDashboardAction.model_name.human(count: 2) %> +

    + + + + + + + + + + + + <% if @proposal_dashboard_actions.empty? %> + + + + <% end %> + + <% @proposal_dashboard_actions.each do |action| %> + + + + + + <% end %> + +
    <%= ProposalDashboardAction.human_attribute_name(:title) %><%= ProposalDashboardAction.human_attribute_name(:active) %>
    <%= t 'admin.proposal_dashboard_actions.index.no_records' %>
    <%= action.title %><%= active_human_readable(action.active) %> + <%= link_to t('admin.proposal_dashboard_actions.index.edit'), + edit_admin_proposal_dashboard_action_path(action), + class: 'edit-banner button hollow' %> + <%= link_to t('admin.proposal_dashboard_actions.index.delete'), + admin_proposal_dashboard_action_path(action), + method: :delete, + class: 'button hollow alert', + data: { confirm: t('admin.actions.confirm') } %> +
    diff --git a/app/views/admin/proposal_dashboard_actions/new.html.erb b/app/views/admin/proposal_dashboard_actions/new.html.erb new file mode 100644 index 000000000..7cdc61540 --- /dev/null +++ b/app/views/admin/proposal_dashboard_actions/new.html.erb @@ -0,0 +1,9 @@ +
    +
    + <%= back_link_to admin_proposal_dashboard_actions_path, t('admin.proposal_dashboard_actions.new.back') %> + +

    <%= t('admin.proposal_dashboard_actions.new.creating') %>

    + + <%= render 'form' %> +
    +
    diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 8e44f6ea9..22b83bc1d 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -106,6 +106,9 @@ en: proposal_notification: one: "Proposal notification" other: "Proposal notifications" + proposal_dashboard_action: + one: Proposal dashboard action + other: Proposal dashboard actions attributes: budget: name: "Name" @@ -244,7 +247,6 @@ en: poll/question/answer: title: Answer description: Description - poll/question/answer/video: title: Title url: External video newsletter: @@ -260,6 +262,15 @@ en: link_url: Link URL widget/feed: limit: Number of items + proposal_dashboard_action: + title: Title + description: Description + link: External link + request_to_administrators: Admin request + day_offset: Required days for the activation + required_supports: Required supports for the activation + order: Order + active: Active errors: models: user: diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 34baa743b..de30a03ee 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -1090,6 +1090,31 @@ en: delete: success: Geozone successfully deleted error: This geozone can't be deleted since there are elements attached to it + proposal_dashboard_actions: + index: + create: Create + edit: Edit + delete: Delete + no_records: No records found + active: 'Yes' + inactive: 'No' + new: + creating: New action for the proposals dashboard + back: Back to list + create: + notice: Action created successfully + edit: + editing: Edit action for the proposals dashboard + back: Back to list + delete: + success: Action successfully deleted + form: + submit_button: Save + errors: + form: + error: + one: 'error prevented this action from being saved' + other: 'errors prevented this action from being saved' signature_sheets: author: Author created_at: Creation date diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 2da027031..20ef0b330 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -106,6 +106,9 @@ es: proposal_notification: one: "Notificación de propuesta" other: "Notificaciones de propuestas" + proposal_dashboard_action: + one: Acción del panel de control de propuestas + other: Acciones del panel de control de propuestas attributes: budget: name: "Nombre" @@ -260,6 +263,15 @@ es: link_url: URL del enlace widget/feed: limit: Número de elementos + proposal_dashboard_action: + title: Título + description: Descripción + link: Enlace externo + request_to_administrators: Petición para administrador + day_offset: Días requeridos para la activación + required_supports: Soportes requeridos para la activación + order: Orden + active: Activa errors: models: user: diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index e5a4b125c..a77b9cc07 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -1090,6 +1090,32 @@ es: delete: success: Distrito borrado correctamente error: No se puede borrar el distrito porque ya tiene elementos asociados + proposal_dashboard_actions: + index: + create: Crear + edit: Editar + delete: Borrar + no_records: No se encontraron registros + active: Si + inactive: No + new: + creating: Nueva acción para el dashboard de propuestas + back: Volver a la lista + create: + notice: Acción creada con éxito + edit: + editing: Editar acción para el dashboard de propuestas + back: Volver a la lista + form: + submit_button: Guardar + delete: + success: Acción borrada con éxito + errors: + form: + error: + one: "error impidió guardar la acción" + other: 'errores impidieron guardar la acción.' + signature_sheets: author: Autor created_at: Fecha de creación diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 001456f6e..62c24bd96 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -195,4 +195,6 @@ namespace :admin do resources :cards resources :feeds, only: [:update] end + + resources :proposal_dashboard_actions, only: %i[index new create edit update destroy] end diff --git a/db/migrate/20180611072816_create_proposal_dashboard_actions.rb b/db/migrate/20180611072816_create_proposal_dashboard_actions.rb new file mode 100644 index 000000000..e1bbf0eb8 --- /dev/null +++ b/db/migrate/20180611072816_create_proposal_dashboard_actions.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class CreateProposalDashboardActions < ActiveRecord::Migration + def change + create_table :proposal_dashboard_actions do |t| + t.string :title, limit: 80 + t.string :description + t.string :link + t.boolean :request_to_administrators, default: false + t.integer :day_offset, default: 0 + t.integer :required_supports, default: 0 + t.integer :order, default: 0 + t.boolean :active, default: true + t.datetime :hidden_at + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c9d29246a..8b2b2c2e2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -878,6 +878,18 @@ ActiveRecord::Schema.define(version: 20180711224810) do add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree + create_table "proposal_dashboard_actions", force: :cascade do |t| + t.string "title", limit: 80 + t.string "description" + t.string "link" + t.boolean "request_to_administrators", default: false + t.integer "day_offset", default: 0 + t.integer "required_supports", default: 0 + t.integer "order", default: 0 + t.boolean "active", default: true + t.datetime "hidden_at" + end + create_table "proposal_notifications", force: :cascade do |t| t.string "title" t.text "body" diff --git a/spec/factories.rb b/spec/factories.rb index 693d1abb4..5dce17d4d 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1029,4 +1029,37 @@ LOREM_IPSUM factory :widget_feed, class: 'Widget::Feed' do end + factory :proposal_dashboard_action, class: 'ProposalDashboardAction' do + title { Faker::Lorem.sentence } + description { Faker::Lorem.sentence } + link nil + request_to_administrators true + day_offset 0 + required_supports 0 + order 0 + active true + hidden_at nil + + trait :admin_request do + link nil + request_to_administrators true + end + + trait :external_link do + link { Faker::Internet.url } + request_to_administrators false + end + + trait :inactive do + active false + end + + trait :active do + active true + end + + trait :deleted do + hidden_at { Time.now.utc } + end + end end diff --git a/spec/features/admin/proposal_dashboard_actions_spec.rb b/spec/features/admin/proposal_dashboard_actions_spec.rb new file mode 100644 index 000000000..2156a7711 --- /dev/null +++ b/spec/features/admin/proposal_dashboard_actions_spec.rb @@ -0,0 +1,84 @@ +require 'rails_helper' + +feature 'Admin proposal dasboard actions' do + let(:admin) { create :administrator } + + before do + login_as(admin.user) + end + + context 'when visiting index' do + context 'and no actions defined' do + before do + visit admin_proposal_dashboard_actions_path + end + + it 'shows that there are no records available' do + expect(page).to have_content('No records found') + end + end + + context 'and actions defined' do + let!(:action) { create :proposal_dashboard_action } + + before do + visit admin_proposal_dashboard_actions_path + end + + it 'shows the action data' do + expect(page).to have_content(action.title) + end + end + end + + context 'when creating an action' do + let(:action) { build :proposal_dashboard_action } + + before do + visit admin_proposal_dashboard_actions_path + click_link 'Create' + end + + it 'Creates a new action' do + fill_in 'proposal_dashboard_action_title', with: action.title + fill_in 'proposal_dashboard_action_description', with: action.description + + click_button 'Save' + + expect(page).to have_content(action.title) + end + end + + context 'when editing an action' do + let!(:action) { create :proposal_dashboard_action } + let(:title) { Faker::Lorem.sentence } + + before do + visit admin_proposal_dashboard_actions_path + click_link 'Edit' + end + + it 'Updates the action' do + fill_in 'proposal_dashboard_action_title', with: title + click_button 'Save' + + expect(page).to have_content(title) + end + end + + context 'when destroying an action' do + let!(:action) { create :proposal_dashboard_action } + + before do + visit admin_proposal_dashboard_actions_path + end + + it 'deletes the action', js: true do + page.accept_confirm do + click_button 'Delete' + end + + expect(page).not_to have_content(action.title) + end + end +end diff --git a/spec/helpers/admin/proposal_dashboard_actions_helper_spec.rb b/spec/helpers/admin/proposal_dashboard_actions_helper_spec.rb new file mode 100644 index 000000000..b737dd757 --- /dev/null +++ b/spec/helpers/admin/proposal_dashboard_actions_helper_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Admin::ProposalDashboardActionsHelper do + describe 'active_human_readable' do + context 'when active is true' do + it 'returns label for active state' do + expect(active_human_readable(true)).to eq(t('admin.proposal_dashboard_actions.index.active')) + end + end + + context 'when active is false' do + it 'returns label for inactive state' do + expect(active_human_readable(false)).to eq(t('admin.proposal_dashboard_actions.index.inactive')) + end + end + end +end diff --git a/spec/models/abilities/administrator_spec.rb b/spec/models/abilities/administrator_spec.rb index fc50bc987..8408ab7f7 100644 --- a/spec/models/abilities/administrator_spec.rb +++ b/spec/models/abilities/administrator_spec.rb @@ -87,4 +87,5 @@ describe Abilities::Administrator do it { should be_able_to(:destroy, proposal_document) } it { should_not be_able_to(:destroy, budget_investment_image) } it { should_not be_able_to(:destroy, budget_investment_document) } + it { should be_able_to(:manage, ProposalDashboardAction) } end diff --git a/spec/models/abilities/common_spec.rb b/spec/models/abilities/common_spec.rb index 93ffa9a48..e6cb210bb 100644 --- a/spec/models/abilities/common_spec.rb +++ b/spec/models/abilities/common_spec.rb @@ -104,6 +104,7 @@ describe Abilities::Common do it { should be_able_to(:destroy, own_budget_investment_image) } it { should_not be_able_to(:destroy, budget_investment_image) } + it { is_expected.not_to be_able_to(:manage, ProposalDashboardAction) } describe 'flagging content' do it { should be_able_to(:flag, debate) } diff --git a/spec/models/abilities/everyone_spec.rb b/spec/models/abilities/everyone_spec.rb index 2167c748d..9aa8808e1 100644 --- a/spec/models/abilities/everyone_spec.rb +++ b/spec/models/abilities/everyone_spec.rb @@ -34,4 +34,5 @@ describe Abilities::Everyone do it { should be_able_to(:read_results, finished_budget) } it { should_not be_able_to(:read_results, reviewing_ballot_budget) } + it { is_expected.not_to be_able_to(:manage, ProposalDashboardAction) } end diff --git a/spec/models/proposal_dashboard_action_spec.rb b/spec/models/proposal_dashboard_action_spec.rb new file mode 100644 index 000000000..006970547 --- /dev/null +++ b/spec/models/proposal_dashboard_action_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true +require 'rails_helper' + +describe ProposalDashboardAction do + subject do + build :proposal_dashboard_action, + title: title, + description: description, + day_offset: day_offset, + required_supports: required_supports, + link: link, + request_to_administrators: request_to_administrators + end + + let(:title) { Faker::Lorem.sentence } + let(:description) { Faker::Lorem.sentence } + let(:day_offset) { 0 } + let(:required_supports) { 0 } + let(:link) { nil } + let(:request_to_administrators) { true } + + it { is_expected.to be_valid } + + context 'when validating title' do + context 'and title is blank' do + let(:title) { nil } + + it { is_expected.not_to be_valid } + end + + context 'and title is very short' do + let(:title) { 'abc' } + + it { is_expected.not_to be_valid } + end + + context 'and title is very long' do + let(:title) { 'a' * 81 } + + it { is_expected.not_to be_valid } + end + end + + context 'when validating description' do + context 'and description is blank' do + let(:description) { nil } + + it { is_expected.not_to be_valid } + end + + context 'and description is very short' do + let(:description) { 'abc' } + + it { is_expected.not_to be_valid } + end + + context 'and description is very long' do + let(:description) { 'a' * 256 } + + it { is_expected.not_to be_valid } + end + end + + context 'when validating day_offset' do + context 'and day_offset is nil' do + let(:day_offset) { nil } + + it { is_expected.not_to be_valid } + end + + context 'and day_offset is negative' do + let(:day_offset) { -1 } + + it { is_expected.not_to be_valid } + end + + context 'and day_offset is not an integer' do + let(:day_offset) { 1.23 } + + it { is_expected.not_to be_valid } + end + end + + context 'when validating required_supports' do + context 'and required_supports is nil' do + let(:required_supports) { nil } + + it { is_expected.not_to be_valid } + end + + context 'and required_supports is negative' do + let(:required_supports) { -1 } + + it { is_expected.not_to be_valid } + end + + context 'and required_supports is not an integer' do + let(:required_supports) { 1.23 } + + it { is_expected.not_to be_valid } + end + end + + context 'when url is blank' do + let(:link) { nil } + + context 'and no request_to_administrators' do + let(:request_to_administrators) { false } + + it { is_expected.not_to be_valid } + end + + context 'and request_to_administrators' do + let(:request_to_administrators) { true } + + it { is_expected.to be_valid } + end + end + + context 'when url is not blank' do + let(:link) { Faker::Internet.url } + + context 'and no request_to_administrators' do + let(:request_to_administrators) { false } + + it { is_expected.to be_valid } + end + end +end +