Skip to content

Commit

Permalink
Add create authorization to initiative types (decidim#9309)
Browse files Browse the repository at this point in the history
* first version

* fix i18n

* linter

* linter

* fix permissions
fix test

* fix tests
add button when initiative type doesn't need an authorisation but initiative does

* lint

* lint

* change requests

* refactor

* linter

* Improve spec
Fix not authorized modal when choosing initiative type

* linter

* linter

* add refresh when needed

* Update decidim-initiatives/spec/system/create_initiative_spec.rb

Co-authored-by: Antti Hukkanen <[email protected]>

* Update decidim-initiatives/spec/system/create_initiative_spec.rb

Co-authored-by: Antti Hukkanen <[email protected]>

* Update decidim-initiatives/spec/system/create_initiative_spec.rb

Co-authored-by: Antti Hukkanen <[email protected]>

* Update decidim-initiatives/spec/system/create_initiative_spec.rb

Co-authored-by: Antti Hukkanen <[email protected]>

* Update decidim-initiatives/spec/system/create_initiative_spec.rb

Co-authored-by: Antti Hukkanen <[email protected]>

* Update decidim-initiatives/spec/system/create_initiative_spec.rb

Co-authored-by: Antti Hukkanen <[email protected]>

* refactor modal in partial

* linter

Co-authored-by: Antti Hukkanen <[email protected]>
  • Loading branch information
2 people authored and fblupi committed Feb 26, 2024
1 parent 8c79162 commit 5d7a06b
Show file tree
Hide file tree
Showing 14 changed files with 437 additions and 113 deletions.
1 change: 1 addition & 0 deletions config/i18n-tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ ignore_unused:
- decidim.assemblies.admin.assembly_members.form.explanation
- decidim.assemblies.admin.assembly_members.form.image_guide
- decidim.assemblies.admin.assembly_members.form.non_user_avatar_help
- decidim.initiatives.create_initiative.select_initiative_type.*
- decidim.blogs.admin_log.*
- decidim.templates.admin_log.*
- decidim.forms.upload_help.explanation
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module Decidim
module Initiatives
class AuthorizationCreateModalsController < Decidim::Initiatives::ApplicationController
helper_method :authorizations, :authorize_action_path
layout false

def show
@initiative_type = Decidim::InitiativesType.find_by(id: params[:slug])
render template: "decidim/authorization_modals/show"
end

private

def authorize_action_path(handler_name)
authorizations.status_for(handler_name).current_path(redirect_url: URI(request.referer).path)
end

def authorizations
@authorizations ||= action_authorized_to("create", permissions_holder: @initiative_type)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,11 @@ class CreateInitiativeController < Decidim::Initiatives::ApplicationController
before_action :ensure_type_exists, only: :show

def show
enforce_permission_to :create, :initiative
send("#{step}_step", initiative: session_initiative)
end

def update
enforce_permission_to :create, :initiative
enforce_permission_to :create, :initiative, { initiative_type: initiative_type_from_params }
send("#{step}_step", params)
end

Expand Down Expand Up @@ -72,6 +71,9 @@ def select_initiative_type_step(_parameters)

def previous_form_step(parameters)
@form = build_form(Decidim::Initiatives::PreviousForm, parameters)

enforce_permission_to :create, :initiative, { initiative_type: initiative_type }

render_wizard
end

Expand Down Expand Up @@ -170,6 +172,10 @@ def initiative_type
@initiative_type ||= InitiativesType.where(organization: current_organization).find_by(id: initiative_type_id)
end

def initiative_type_from_params
Decidim::InitiativesType.find_by(id: params["initiative"]["type_id"])
end

def initiative_type_id
session_initiative[:type_id] || @form&.type_id
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class InitiativesController < Decidim::Initiatives::ApplicationController
include SingleInitiativeType

helper_method :collection, :initiatives, :filter, :stats
helper_method :initiative_type
helper_method :initiative_type, :available_initiative_types

# GET /initiatives
def index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,26 @@ def popularity_level5?(initiative)
initiative.percentage >= 100
end

def authorized_create_modal_button(type, html_options, &block)
tag = "button"
html_options ||= {}

if current_user
if action_authorized_to("create", permissions_holder: type).ok?
html_options["data-open"] = "not-authorized-modal"
else
html_options["data-open"] = "authorizationModal"
html_options["data-open-url"] = authorization_create_modal_initiative_path(type)
end
else
html_options["data-open"] = "loginModal"
end

html_options["onclick"] = "event.preventDefault();"

send("#{tag}_to", "", html_options, &block)
end

def authorized_vote_modal_button(initiative, html_options, &block)
return if current_user && action_authorized_to("vote", resource: initiative, permissions_holder: initiative.type).ok?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ def update_public_initiative?
def creation_enabled?
Decidim::Initiatives.creation_enabled && (
Decidim::Initiatives.do_not_require_authorization ||
UserAuthorizations.for(user).any? ||
Decidim::UserGroups::ManageableUserGroups.for(user).verified.any?
)
UserAuthorizations.for(user).any? ||
Decidim::UserGroups::ManageableUserGroups.for(user).verified.any?) &&
authorized?(:create, permissions_holder: initiative_type)
end

def request_membership?
Expand Down
19 changes: 19 additions & 0 deletions decidim-initiatives/app/views/decidim/initiatives/_modal.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div class="reveal not-authorized-reveal" id="not-authorized-modal" aria-hidden="true" role="dialog" aria-modal="true" aria-labelledby="not-authorized-modal-title" data-reveal data-multiple-opened="true">
<div class="reveal__header">
<h2 class="reveal__title" id="not-authorized-modal-title"><%= t(".not_authorized.title") %></h2>
<button class="close-button" data-close aria-label="<%= t(".not_authorized.close") %>"
type="button">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="not-authhorized-content">
<div class="not-authorized-modal-content">
<p>
<%= t(".not_authorized.explanation") %>
</p>
</div>
</div>
<div class="not-authorized-modal-footer reveal__footer">
<%= link_to t(".not_authorized.authorizations_page"), decidim_verifications.authorizations_path(redirect_url: create_initiative_url(:select_initiative_type)), class: "button expanded" %>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,15 @@
<%= raw translated_attribute type.description %>
</div>
<br>
<%= decidim_form_for(@form, url: next_wizard_path, method: :put, html: { id: "new_initiative_#{type.id}", class: "form select-initiative_type-form" }) do |f| %>
<%= f.hidden_field :type_id, value: type.id, id: "initiative_type_id_#{ type.id }" %>
<%= f.submit t(".select"), class: "button" %>
<% if allowed_to?(:create, :initiative, { initiative_type: type }) %>
<%= decidim_form_for(@form, url: next_wizard_path, method: :put, html: { id: "new_initiative_#{type.id}", class: "form select-initiative_type-form" }) do |f| %>
<%= f.hidden_field :type_id, value: type.id, id: "initiative_type_id_#{ type.id }" %>
<%= f.submit t(".select"), class: "button" %>
<% end %>
<% else %>
<%= authorized_create_modal_button(type, remote: true, class: "button") do %>
<%= t(".verification_required") %>
<% end %>
<% end %>
</div>
<% end %>
Expand All @@ -51,3 +57,4 @@
</div>
</div>
</div>
<%= render partial: "decidim/initiatives/modal" %>
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@
<%= render partial: "count" %>
</h1>
<% if Decidim::Initiatives.creation_enabled %>
<% if current_user && allowed_to?(:create, :initiative) %>
<% if current_user && available_initiative_types.size > 1 %>
<%= link_to create_initiative_path(:select_initiative_type), class: "title-action__action button small" do %>
<%= t(".new_initiative") %>
<%= icon "plus", role: "img", "aria-hidden": true %>
<% end %>
<% elsif current_user %>
<button type="button" class="title-action__action button small" data-open="not-authorized-modal" aria-controls="not-authorized-modal" aria-haspopup="dialog" tabindex="0">
<%= t(".new_initiative") %>
<%= icon "plus", role: "img", "aria-hidden": true %>
</button>
<% if allowed_to?(:create, :initiative, { initiative_type: available_initiative_types.first }) %>
<%= link_to create_initiative_path(:select_initiative_type), class: "title-action__action button small" do %>
<%= t(".new_initiative") %>
<%= icon "plus", role: "img", "aria-hidden": true %>
<% end %>
<% else %>
<%= authorized_create_modal_button(available_initiative_types.first, remote: true, class: "title-action__action button small") do %>
<%= icon "plus", role: "img", "aria-hidden": true %>
<%= t(".new_initiative") %>
<% end %>
<% end %>
<% else %>
<% content_for(:redirect_after_login) { create_initiative_url(:select_initiative_type) } %>
<button type="button" class="title-action__action button small" data-open="loginModal" aria-controls="loginModal" aria-haspopup="dialog" tabindex="0">
Expand All @@ -23,22 +30,4 @@
<% end %>
</div>

<div class="reveal not-authorized-reveal" id="not-authorized-modal" aria-hidden="true" role="dialog" aria-modal="true" aria-labelledby="not-authorized-modal-title" data-reveal data-multiple-opened="true">
<div class="reveal__header">
<h2 class="reveal__title" id="not-authorized-modal-title"><%= t(".not_authorized.title") %></h2>
<button class="close-button" data-close aria-label="<%= t(".not_authorized.close") %>"
type="button">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="not-authhorized-content">
<div class="not-authorized-modal-content">
<p>
<%= t(".not_authorized.explanation") %>
</p>
</div>
</div>
<div class="not-authorized-modal-footer reveal__footer">
<%= link_to t(".not_authorized.authorizations_page"), decidim_verifications.authorizations_path(redirect_url: create_initiative_url(:select_initiative_type)), class: "button expanded" %>
</div>
</div>
<%= render partial: "decidim/initiatives/modal" %>
13 changes: 8 additions & 5 deletions decidim-initiatives/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ en:
more_information: "(More information)"
select: I want to promote this initiative
select_initiative_type_help: Initiatives are a means by which the participants can intervene so that the organization can undertake actions in defence of the general interest. Which initiative do you want to launch?
verification_required: Verify your account to promote this initiative
share_committee_link:
continue: Continue
invite_to_committee_help: Link to invite people that will be part of the promoter committee
Expand Down Expand Up @@ -505,11 +506,6 @@ en:
unfold: Unfold
index_header:
new_initiative: New initiative
not_authorized:
authorizations_page: View authorizations
close: Close
explanation: You need to be verified in order to create a new initiative.
title: Authorization required
initiatives:
closed_initiatives_warning: Currently, there are no open initiatives, but here you can find all the closed initiatives listed.
no_initiatives_warning: No initiatives match your search criteria.
Expand Down Expand Up @@ -586,6 +582,12 @@ en:
status_change_for: The initiative %{title} has changed its status
last_activity:
new_initiative: New initiative
modal:
not_authorized:
authorizations_page: View authorizations
close: Close
explanation: You need to be verified in order to create a new initiative.
title: Authorization required
pages:
home:
highlighted_initiatives:
Expand Down Expand Up @@ -619,6 +621,7 @@ en:
comment: Comment
initiatives_type:
actions:
create: Create
title: Actions
vote: Sign
layouts:
Expand Down
1 change: 1 addition & 0 deletions decidim-initiatives/lib/decidim/initiatives/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Engine < ::Rails::Engine

member do
get :authorization_sign_modal, to: "authorization_sign_modals#show"
get :authorization_create_modal, to: "authorization_create_modals#show"
get :print, to: "initiatives#print", as: "print"
get :send_to_technical_validation, to: "initiatives#send_to_technical_validation"
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

participatory_space.register_resource(:initiatives_type) do |resource|
resource.model_class_name = "Decidim::InitiativesType"
resource.actions = %w(vote)
resource.actions = %w(vote create)
end

participatory_space.model_class_name = "Decidim::Initiative"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@
let(:action) do
{ scope: :public, action: :create, subject: :initiative }
end
let(:context) do
{ initiative_type: initiative.type }
end

context "when creation is enabled" do
before do
Expand Down Expand Up @@ -236,6 +239,34 @@

it { is_expected.to be true }
end

context "when the initiative type has permissions to create" do
before do
initiative.type.create_resource_permission(
permissions: {
"create" => {
"authorization_handlers" => {
"dummy_authorization_handler" => { "options" => {} },
"another_dummy_authorization_handler" => { "options" => {} }
}
}
}
)
end

context "when user is not verified" do
it { is_expected.to be false }
end

context "when user is fully verified" do
before do
create(:authorization, name: "dummy_authorization_handler", user: user, granted_at: 2.seconds.ago)
create(:authorization, name: "another_dummy_authorization_handler", user: user, granted_at: 2.seconds.ago)
end

it { is_expected.to be true }
end
end
end

context "when creation is not enabled" do
Expand Down
Loading

0 comments on commit 5d7a06b

Please sign in to comment.