Add SDG phases cards management

These cards will be displayed in the SDG homepage.

Note there seems to be a strange behavior in cancancan. If we define
these rules:

can :manage, Widget::Card, page_type: "SDG::Phase"
can :manage, Widget::Card

The expected behavior is the first rule will always be ignored because
the second one overwrites it. However, when creating a new card with
`load_and_authorize_resource` will automatically add `page_type:
"SDG::Phase"`.

Similarly, if we do something like:

can :manage, Widget::Card, id: 3
can :manage, Widget::Card

Then the new card will have `3` as an ID.

Maybe upgrading cancancan solves the issue; we haven't tried it. For now
we're defining a different rule when creating widget cards.
This commit is contained in:
Javi Martín
2021-01-09 18:23:19 +01:00
parent 739236d585
commit 7aee4f6241
17 changed files with 127 additions and 0 deletions

View File

@@ -31,4 +31,5 @@
@import "admin/*";
@import "sdg/**/*";
@import "sdg_management/*";
@import "sdg_management/**/*";
@import "widgets/**/*";

View File

@@ -208,6 +208,11 @@
}
}
@mixin regular-button($color: $brand) {
@include button($background: $color);
@extend %button;
}
@mixin hollow-button($color: $link) {
@include button($style: hollow, $background: $color);
@extend %button;

View File

@@ -0,0 +1,11 @@
.phase-cards {
> header {
align-items: flex-start;
display: flex;
a {
@include regular-button;
margin-left: auto;
}
}
}

View File

@@ -1 +1,15 @@
<%= header %>
<% phases.each do |phase| %>
<section class="phase-cards <%= phase.kind %>-cards">
<header>
<h3><%= phase.title %></h3>
<%= link_to create_card_text(phase), new_sdg_management_sdg_phase_widget_card_path(phase) %>
</header>
<%= render Admin::Widget::Cards::TableComponent.new(
phase.cards,
no_cards_message: no_cards_message
) %>
</section>
<% end %>

View File

@@ -12,4 +12,12 @@ class SDGManagement::Homepage::ShowComponent < ApplicationComponent
def title
t("sdg_management.homepage.title")
end
def create_card_text(phase)
t("sdg_management.homepage.create_card", phase: phase.title.downcase)
end
def no_cards_message
t("sdg_management.homepage.no_cards")
end
end

View File

@@ -0,0 +1,13 @@
class SDGManagement::CardsController < SDGManagement::BaseController
include Admin::Widget::CardsActions
helper_method :index_path
load_and_authorize_resource :phase, class: "SDG::Phase", id_param: "sdg_phase_id"
load_and_authorize_resource :card, through: :phase, class: "Widget::Card"
private
def index_path
sdg_management_homepage_path
end
end

View File

@@ -6,5 +6,7 @@ class Abilities::SDG::Manager
can :read, ::SDG::Target
can :manage, ::SDG::LocalTarget
can [:read, :update, :destroy], Widget::Card, cardable_type: "SDG::Phase"
can(:create, Widget::Card) { |card| card.cardable_type == "SDG::Phase" }
end
end

View File

@@ -1,8 +1,13 @@
class SDG::Phase < ApplicationRecord
include Cardable
enum kind: %w[sensitization planning monitoring]
validates :kind, presence: true, uniqueness: true
def self.[](kind)
find_by!(kind: kind)
end
def title
self.class.human_attribute_name("kind.#{kind}")
end
end

View File

@@ -336,6 +336,10 @@ en:
sdg/local_target/translation:
title: "Title"
description: "Description"
sdg/phase/kind:
sensitization: "Sensitization"
planning: "Planning"
monitoring: "Monitoring"
sdg/target:
code: "Code"
title: "Title"

View File

@@ -6,6 +6,8 @@ en:
title: "SDG content"
homepage:
title: "Homepage configuration"
create_card: "Create %{phase} card"
no_cards: "There are no cards for this phase"
menu:
budget_investments: "Participatory budgets"
debates: "Debates"

View File

@@ -331,6 +331,10 @@ es:
sdg/local_target/translation:
title: "Título"
description: "Descripción"
sdg/phase/kind:
sensitization: "Sensibilización"
planning: "Planificación"
monitoring: "Seguimiento"
sdg/target:
code: "Código"
title: "Título"

View File

@@ -6,6 +6,8 @@ es:
title: "Contenido ODS"
homepage:
title: "Configuración de la página de inicio"
create_card: "Crear tarjeta de %{phase}"
no_cards: "No hay tarjetas para esta fase"
menu:
budget_investments: "Presupuestos participativos"
debates: "Debates"

View File

@@ -6,6 +6,10 @@ namespace :sdg_management do
resources :local_targets, except: [:show]
resource :homepage, controller: :homepage, only: [:show]
resources :phases, only: [], as: :sdg_phases do
resources :cards, except: [:index, :show], as: :widget_cards
end
types = SDG::Related::RELATABLE_TYPES.map(&:tableize)
types_constraint = /#{types.join("|")}/

View File

@@ -30,3 +30,9 @@ section "Creating Sustainable Development Goals" do
end
end
end
section "Creating SDG homepage cards" do
SDG::Phase.all.each do |phase|
Widget::Card.create!(cardable: phase, title: "#{phase.title} card")
end
end

View File

@@ -13,4 +13,9 @@ describe "Abilities::SDG::Manager" do
it { should_not be_able_to(:read, SDG::Manager) }
it { should_not be_able_to(:create, SDG::Manager) }
it { should_not be_able_to(:delete, SDG::Manager) }
it { should_not be_able_to(:update, create(:widget_card)) }
it { should be_able_to(:update, create(:widget_card, cardable: SDG::Phase.sample)) }
it { should_not be_able_to(:create, build(:widget_card)) }
it { should be_able_to(:create, build(:widget_card, cardable: SDG::Phase.sample)) }
end

View File

@@ -195,6 +195,15 @@ describe "Polymorphic routes" do
expect(sdg_management_polymorphic_path(target)).to eq sdg_management_local_target_path(target)
end
it "routes SDG phases widget cards" do
phase = SDG::Phase.sample
card = create(:widget_card, cardable: phase)
expect(sdg_management_polymorphic_path(card)).to eq(
sdg_management_sdg_phase_widget_card_path(phase, card)
)
end
end
end

View File

@@ -16,5 +16,37 @@ describe "SDG homepage configuration", :js do
expect(page).to have_title "SDG content - Homepage configuration"
end
scenario "Create card" do
visit sdg_management_homepage_path
click_link "Create planning card"
within(".translatable-fields") { fill_in "Title", with: "My planning card" }
click_button "Create card"
within(".planning-cards") do
expect(page).to have_content "My planning card"
end
within(".sensitization-cards") do
expect(page).to have_content "There are no cards for this phase"
end
end
scenario "Update card" do
create(:widget_card, cardable: SDG::Phase["monitoring"], title: "My monitoring card")
visit sdg_management_homepage_path
within(".monitoring-cards") { click_link "Edit" }
within(".translatable-fields") { fill_in "Title", with: "Updated monitoring card" }
click_button "Save card"
within(".monitoring-cards") do
expect(page).to have_css "tbody tr", count: 1
expect(page).to have_content "Updated monitoring card"
expect(page).not_to have_content "My monitoring card"
end
end
end
end