+
+ <% if allowed_to? :read, :share_tokens, current_participatory_space: initiative %>
+ <%= icon_link_to "share-line", decidim_admin_initiatives.initiative_share_tokens_path(initiative), t("actions.share_tokens", scope: "decidim.admin"), class: "action-icon--new" %>
+ <% else %>
+
+ <% end %>
+
<% if allowed_to? :edit, :initiative, initiative: initiative %>
<%= icon_link_to "pencil-line",
decidim_admin_initiatives.edit_initiative_path(initiative.to_param),
diff --git a/decidim-initiatives/lib/decidim/initiatives/admin_engine.rb b/decidim-initiatives/lib/decidim/initiatives/admin_engine.rb
index 14b388d96c111..d0148422fe7ab 100644
--- a/decidim-initiatives/lib/decidim/initiatives/admin_engine.rb
+++ b/decidim-initiatives/lib/decidim/initiatives/admin_engine.rb
@@ -64,6 +64,7 @@ class AdminEngine < ::Rails::Engine
get :share
put :hide
end
+ resources :component_share_tokens, except: [:show], path: "share_tokens", as: "share_tokens"
resources :exports, only: :create
end
@@ -75,6 +76,8 @@ class AdminEngine < ::Rails::Engine
end
resources :reports, controller: "moderations/reports", only: [:index, :show]
end
+
+ resources :initiative_share_tokens, except: [:show], path: "share_tokens"
end
scope "/initiatives/:initiative_slug/components/:component_id/manage" do
diff --git a/decidim-initiatives/lib/decidim/initiatives/menu.rb b/decidim-initiatives/lib/decidim/initiatives/menu.rb
index d11c73efc938c..8ef0c64f090c7 100644
--- a/decidim-initiatives/lib/decidim/initiatives/menu.rb
+++ b/decidim-initiatives/lib/decidim/initiatives/menu.rb
@@ -66,6 +66,7 @@ def self.register_admin_initiatives_components_menu!
active: is_active_link?(manage_component_path(component)) ||
is_active_link?(decidim_admin_initiatives.edit_component_path(current_participatory_space, component)) ||
is_active_link?(decidim_admin_initiatives.edit_component_permissions_path(current_participatory_space, component)) ||
+ is_active_link?(decidim_admin_initiatives.component_share_tokens_path(current_participatory_space, component)) ||
participatory_space_active_link?(component),
if: component.manifest.admin_engine # && user_role_config.component_is_accessible?(component.manifest_name)
end
@@ -106,6 +107,13 @@ def self.register_admin_initiative_menu!
decidim_admin_initiatives.moderations_path(current_participatory_space),
icon_name: "flag-line",
if: allowed_to?(:read, :moderation)
+
+ menu.add_item :initiatives_share_tokens,
+ I18n.t("menu.share_tokens", scope: "decidim.admin"),
+ decidim_admin_initiatives.initiative_share_tokens_path(current_participatory_space),
+ active: is_active_link?(decidim_admin_initiatives.initiative_share_tokens_path(current_participatory_space)),
+ icon_name: "share-line",
+ if: allowed_to?(:read, :share_tokens, current_participatory_space:)
end
end
diff --git a/decidim-initiatives/spec/system/admin/admin_manages_initiative_component_share_tokens_spec.rb b/decidim-initiatives/spec/system/admin/admin_manages_initiative_component_share_tokens_spec.rb
new file mode 100644
index 0000000000000..430c509f2d8b6
--- /dev/null
+++ b/decidim-initiatives/spec/system/admin/admin_manages_initiative_component_share_tokens_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe "Admin manages initiative component share tokens" do
+ let(:organization) { create(:organization) }
+ let(:user) { create(:user, :admin, :confirmed, organization:) }
+ let!(:participatory_space) do
+ create(:initiative, organization:)
+ end
+
+ it_behaves_like "manage component share tokens" do
+ let(:participatory_space_engine) { decidim_admin_initiatives }
+ end
+end
diff --git a/decidim-initiatives/spec/system/admin/admin_manages_initiative_components_spec.rb b/decidim-initiatives/spec/system/admin/admin_manages_initiative_components_spec.rb
index 8e2778924f772..559bbe6a37a3a 100644
--- a/decidim-initiatives/spec/system/admin/admin_manages_initiative_components_spec.rb
+++ b/decidim-initiatives/spec/system/admin/admin_manages_initiative_components_spec.rb
@@ -199,8 +199,6 @@
expect(page).to have_css(".action-icon--unpublish")
end
end
-
- it_behaves_like "manage component share tokens"
end
context "when the component is published" do
diff --git a/decidim-initiatives/spec/system/admin/admin_manages_initiative_share_tokens_spec.rb b/decidim-initiatives/spec/system/admin/admin_manages_initiative_share_tokens_spec.rb
new file mode 100644
index 0000000000000..0c043121fe04f
--- /dev/null
+++ b/decidim-initiatives/spec/system/admin/admin_manages_initiative_share_tokens_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe "Admin manages initiative share tokens" do
+ let(:organization) { create(:organization) }
+ let(:user) { create(:user, :admin, :confirmed, organization:) }
+ let!(:participatory_space) do
+ create(:initiative, organization:)
+ end
+
+ it_behaves_like "manage participatory space share tokens" do
+ let(:participatory_space_path) { decidim_admin_initiatives.edit_initiative_path(participatory_space) }
+ let(:participatory_spaces_path) { decidim_admin_initiatives.initiatives_path }
+ end
+end
diff --git a/decidim-initiatives/spec/system/preview_initiative_with_share_token_spec.rb b/decidim-initiatives/spec/system/preview_initiative_with_share_token_spec.rb
new file mode 100644
index 0000000000000..bf19aec9acd24
--- /dev/null
+++ b/decidim-initiatives/spec/system/preview_initiative_with_share_token_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe "Preview initiative with share token" do
+ let(:organization) { create(:organization) }
+ let!(:participatory_space) { create(:initiative, :created, organization:) }
+ let(:resource_path) { decidim_initiatives.initiative_path(participatory_space) }
+
+ it_behaves_like "preview participatory space with a share_token"
+end
diff --git a/decidim-meetings/spec/system/preview_meetings_with_share_token_spec.rb b/decidim-meetings/spec/system/preview_meetings_with_share_token_spec.rb
index 844f7892e22e4..5e6bacd873887 100644
--- a/decidim-meetings/spec/system/preview_meetings_with_share_token_spec.rb
+++ b/decidim-meetings/spec/system/preview_meetings_with_share_token_spec.rb
@@ -2,9 +2,9 @@
require "spec_helper"
-describe "Preview meetings with share token" do
+describe "preview meetings with a share token" do
let(:manifest_name) { "meetings" }
include_context "with a component"
- it_behaves_like "preview component with share_token"
+ it_behaves_like "preview component with a share_token"
end
diff --git a/decidim-pages/spec/system/preview_pages_with_share_token_spec.rb b/decidim-pages/spec/system/preview_pages_with_share_token_spec.rb
index 657244defaed9..273ee7869d23f 100644
--- a/decidim-pages/spec/system/preview_pages_with_share_token_spec.rb
+++ b/decidim-pages/spec/system/preview_pages_with_share_token_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-describe "Preview pages with share token" do
+describe "preview pages with a share token" do
let(:manifest_name) { "pages" }
let(:body) do
@@ -16,5 +16,5 @@
let!(:page_component) { create(:page, component:, body:) }
include_context "with a component"
- it_behaves_like "preview component with share_token"
+ it_behaves_like "preview component with a share_token"
end
diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/component_share_tokens_controller.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/component_share_tokens_controller.rb
new file mode 100644
index 0000000000000..14442d7b4b773
--- /dev/null
+++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/component_share_tokens_controller.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Decidim
+ module ParticipatoryProcesses
+ module Admin
+ # This controller allows sharing unpublished things.
+ # It is targeted for customizations for sharing unpublished things that lives under
+ # an process.
+ class ComponentShareTokensController < Decidim::Admin::ShareTokensController
+ include Concerns::ParticipatoryProcessAdmin
+
+ def resource
+ @resource ||= current_participatory_space.components.find(params[:component_id])
+ end
+ end
+ end
+ end
+end
diff --git a/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_share_tokens_controller.rb b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_share_tokens_controller.rb
new file mode 100644
index 0000000000000..c2ede3047a5ab
--- /dev/null
+++ b/decidim-participatory_processes/app/controllers/decidim/participatory_processes/admin/participatory_process_share_tokens_controller.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Decidim
+ module ParticipatoryProcesses
+ module Admin
+ # This controller allows admins to manage moderations in a participatory process.
+ class ParticipatoryProcessShareTokensController < Decidim::Admin::ShareTokensController
+ include Concerns::ParticipatoryProcessAdmin
+
+ def resource
+ current_participatory_process
+ end
+ end
+ end
+ end
+end
diff --git a/decidim-participatory_processes/app/models/decidim/participatory_process.rb b/decidim-participatory_processes/app/models/decidim/participatory_process.rb
index 8c81a08369445..acb1c4001e461 100644
--- a/decidim-participatory_processes/app/models/decidim/participatory_process.rb
+++ b/decidim-participatory_processes/app/models/decidim/participatory_process.rb
@@ -24,6 +24,7 @@ class ParticipatoryProcess < ApplicationRecord
include Decidim::TranslatableResource
include Decidim::HasArea
include Decidim::FilterableResource
+ include Decidim::ShareableWithToken
translatable_fields :title, :subtitle, :short_description, :description, :developer_group, :meta_scope, :local_area,
:target, :participatory_scope, :participatory_structure, :announcement
@@ -201,6 +202,10 @@ def attachment_context
:admin
end
+ def shareable_url(share_token)
+ EngineRouter.main_proxy(self).participatory_process_url(self, share_token: share_token.token)
+ end
+
# Allow ransacker to search for a key in a hstore column (`title`.`en`)
ransacker_i18n :title
diff --git a/decidim-participatory_processes/app/permissions/decidim/participatory_processes/permissions.rb b/decidim-participatory_processes/app/permissions/decidim/participatory_processes/permissions.rb
index ba4ae1589bb76..103d2f435fe04 100644
--- a/decidim-participatory_processes/app/permissions/decidim/participatory_processes/permissions.rb
+++ b/decidim-participatory_processes/app/permissions/decidim/participatory_processes/permissions.rb
@@ -118,6 +118,7 @@ def public_read_process_action?
return disallow! unless can_view_private_space?
return allow! if user&.admin?
return allow! if process.published?
+ return allow! if user_can_preview_space?
toggle_allow(can_manage_process?)
end
@@ -238,6 +239,7 @@ def process_admin_action?
:process_step,
:process_user_role,
:export_space,
+ :share_tokens,
:import
].include?(permission_action.subject)
allow! if is_allowed
@@ -257,11 +259,18 @@ def org_admin_action?
:process_step,
:process_user_role,
:export_space,
+ :share_tokens,
:import
].include?(permission_action.subject)
allow! if is_allowed
end
+ def user_can_preview_space?
+ context[:share_token].present? && Decidim::ShareToken.use!(token_for: process, token: context[:share_token], user:)
+ rescue ActiveRecord::RecordNotFound, StandardError
+ nil
+ end
+
def taxonomy_filter_action?
return unless permission_action.subject == :taxonomy_filter
return disallow! unless user.admin?
diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb
index 829ded669fe09..84cfd004e7767 100644
--- a/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb
+++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb
@@ -58,6 +58,11 @@
<% end %>
+ <% if allowed_to? :read, :share_tokens, current_participatory_space: process %>
+ <%= icon_link_to "share-line", decidim_admin_participatory_processes.participatory_process_share_tokens_path(process), t("actions.share_tokens", scope: "decidim.admin"), class: "action-icon--new" %>
+ <% else %>
+
+ <% end %>
<% if allowed_to? :update, :process, process: process %>
<%= icon_link_to "pencil-line", edit_participatory_process_path(process), t("actions.configure", scope: "decidim.admin"), class: "action-icon--new" %>
diff --git a/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb b/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb
index f7b4a97b6a0bd..5873af194be35 100644
--- a/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb
+++ b/decidim-participatory_processes/lib/decidim/participatory_processes/admin_engine.rb
@@ -65,6 +65,7 @@ class AdminEngine < ::Rails::Engine
get :share
put :hide
end
+ resources :component_share_tokens, except: [:show], path: "share_tokens", as: "share_tokens"
resources :exports, only: :create
resources :imports, only: [:new, :create] do
get :example, on: :collection
@@ -91,6 +92,8 @@ class AdminEngine < ::Rails::Engine
end
end
end
+
+ resources :participatory_process_share_tokens, except: [:show], path: "share_tokens"
end
scope "/participatory_processes/:participatory_process_slug/components/:component_id/manage" do
diff --git a/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb b/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb
index d5ec86d3f5c58..295931459b12c 100644
--- a/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb
+++ b/decidim-participatory_processes/lib/decidim/participatory_processes/menu.rb
@@ -101,6 +101,7 @@ def self.register_admin_participatory_process_components_menu!
active: is_active_link?(manage_component_path(component)) ||
is_active_link?(decidim_admin_participatory_processes.edit_component_path(current_participatory_space, component)) ||
is_active_link?(decidim_admin_participatory_processes.edit_component_permissions_path(current_participatory_space, component)) ||
+ is_active_link?(decidim_admin_participatory_processes.component_share_tokens_path(current_participatory_space, component)) ||
participatory_space_active_link?(component),
if: component.manifest.admin_engine && user_role_config.component_is_accessible?(component.manifest_name)
end
@@ -174,6 +175,13 @@ def self.register_admin_participatory_process_menu!
active: is_active_link?(decidim_admin_participatory_processes.moderations_path(current_participatory_space)),
icon_name: "flag-line",
if: allowed_to?(:read, :moderation, current_participatory_space:)
+
+ menu.add_item :participatory_process_share_tokens,
+ I18n.t("menu.share_tokens", scope: "decidim.admin"),
+ decidim_admin_participatory_processes.participatory_process_share_tokens_path(current_participatory_space),
+ active: is_active_link?(decidim_admin_participatory_processes.participatory_process_share_tokens_path(current_participatory_space)),
+ icon_name: "share-line",
+ if: allowed_to?(:read, :share_tokens, current_participatory_space:)
end
end
diff --git a/decidim-participatory_processes/spec/shared/manage_process_components_examples.rb b/decidim-participatory_processes/spec/shared/manage_process_components_examples.rb
index d2a9bcc3b8ff3..c6e3f6e7db168 100644
--- a/decidim-participatory_processes/spec/shared/manage_process_components_examples.rb
+++ b/decidim-participatory_processes/spec/shared/manage_process_components_examples.rb
@@ -26,8 +26,6 @@
find(".dummy").click
end
- expect(page).to have_no_content("Share tokens")
-
within ".item__edit-form .new_component" do
fill_in_i18n(
:component_name,
@@ -300,14 +298,6 @@
end
context "when the component is unpublished" do
- it "shows the share tokens section" do
- within ".component-#{component.id}" do
- click_on "Configure"
- end
-
- expect(page).to have_content("Share tokens")
- end
-
it "publishes the component" do
within ".component-#{component.id}" do
click_on "Publish"
@@ -337,21 +327,11 @@
}
))
end
-
- it_behaves_like "manage component share tokens"
end
context "when the component is published" do
let(:published_at) { Time.current }
- it "does not show the share tokens section" do
- within ".component-#{component.id}" do
- click_on "Configure"
- end
-
- expect(page).to have_no_content("Share tokens")
- end
-
it "hides the component from the menu" do
within ".component-#{component.id}" do
click_on "Hide"
diff --git a/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_process_component_share_tokens_spec.rb b/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_process_component_share_tokens_spec.rb
new file mode 100644
index 0000000000000..dd663d92b6691
--- /dev/null
+++ b/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_process_component_share_tokens_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe "Admin manages participatory process component share tokens" do
+ include_context "when admin administrating a participatory process"
+
+ it_behaves_like "manage component share tokens" do
+ let(:participatory_space) { participatory_process }
+ let(:participatory_space_engine) { decidim_admin_participatory_processes }
+ end
+end
diff --git a/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_process_share_tokens_spec.rb b/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_process_share_tokens_spec.rb
new file mode 100644
index 0000000000000..acd0a914561e6
--- /dev/null
+++ b/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_process_share_tokens_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe "Admin manages participatory process share tokens" do
+ include_context "when admin administrating a participatory process"
+ let(:participatory_space) { participatory_process }
+ let(:participatory_space_path) { decidim_admin_participatory_processes.edit_participatory_process_path(participatory_process) }
+ let(:participatory_spaces_path) { decidim_admin_participatory_processes.participatory_processes_path }
+
+ it_behaves_like "manage participatory space share tokens"
+
+ context "when the user is a process admin" do
+ let(:user) { create(:user, :confirmed, :admin_terms_accepted, organization:) }
+ let!(:role) { create(:participatory_process_user_role, user:, participatory_process:, role: :admin) }
+
+ it_behaves_like "manage participatory space share tokens"
+ end
+end
diff --git a/decidim-participatory_processes/spec/system/preview_participatory_process_with_share_token_spec.rb b/decidim-participatory_processes/spec/system/preview_participatory_process_with_share_token_spec.rb
new file mode 100644
index 0000000000000..7dadba5d57f27
--- /dev/null
+++ b/decidim-participatory_processes/spec/system/preview_participatory_process_with_share_token_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe "Preview participatory process with share token" do
+ let(:organization) { create(:organization) }
+ let!(:participatory_space) { create(:participatory_process, organization:, published_at: nil) }
+ let(:resource_path) { decidim_participatory_processes.participatory_process_path(participatory_space) }
+
+ it_behaves_like "preview participatory space with a share_token"
+end
diff --git a/decidim-proposals/spec/system/preview_proposals_with_share_token_spec.rb b/decidim-proposals/spec/system/preview_proposals_with_share_token_spec.rb
index 6b92928203077..fc36958a99eba 100644
--- a/decidim-proposals/spec/system/preview_proposals_with_share_token_spec.rb
+++ b/decidim-proposals/spec/system/preview_proposals_with_share_token_spec.rb
@@ -2,9 +2,9 @@
require "spec_helper"
-describe "Preview proposals with share token" do
+describe "preview proposals with a share token" do
let(:manifest_name) { "proposals" }
include_context "with a component"
- it_behaves_like "preview component with share_token"
+ it_behaves_like "preview component with a share_token"
end
diff --git a/decidim-sortitions/spec/system/decidim/sortitions/preview_sortitions_with_share_token_spec.rb b/decidim-sortitions/spec/system/decidim/sortitions/preview_sortitions_with_share_token_spec.rb
index a3cbcc00a7d1b..cdf94b1a9d781 100644
--- a/decidim-sortitions/spec/system/decidim/sortitions/preview_sortitions_with_share_token_spec.rb
+++ b/decidim-sortitions/spec/system/decidim/sortitions/preview_sortitions_with_share_token_spec.rb
@@ -2,9 +2,9 @@
require "spec_helper"
-describe "Preview sortitions with share token" do
+describe "preview sortitions with a share token" do
let(:manifest_name) { "sortitions" }
include_context "with a component"
- it_behaves_like "preview component with share_token"
+ it_behaves_like "preview component with a share_token"
end
diff --git a/decidim-surveys/app/views/decidim/surveys/admin/component/_actions.html.erb b/decidim-surveys/app/views/decidim/surveys/admin/component/_actions.html.erb
index 3c9fec22c0f61..f1c87caab50a0 100644
--- a/decidim-surveys/app/views/decidim/surveys/admin/component/_actions.html.erb
+++ b/decidim-surveys/app/views/decidim/surveys/admin/component/_actions.html.erb
@@ -4,11 +4,12 @@
<% end %>
-<% if allowed_to? :share, :component, component: component %>
- <%= icon_link_to "share-line", url_for(action: :share, id: component, controller: "components"), t("actions.share", scope: "decidim.admin"), target: :blank, class: "action-icon--share" %>
+<% if component.manifest.admin_engine && allowed_to?(:share, :component, component: component) %>
+ <%= icon_link_to "share-line", component_share_tokens_path(component_id: component), t("actions.share", scope: "decidim.admin"), class: "action-icon--share" %>
<% else %>
<% end %>
+
<% if allowed_to? :update, :component, component: component %>
<%= icon_link_to "settings-4-line", url_for(action: :edit, id: component, controller: "components"), t("actions.configure", scope: "decidim.admin"), class: "action-icon--configure" %>
<% else %>
@@ -17,7 +18,11 @@
<% if allowed_to?(:update, :component, component: component) %>
<% if component.published? %>
- <%= icon_link_to "close-circle-line", url_for(action: :unpublish, id: component, controller: "components"), t("actions.unpublish", scope: "decidim.admin"), class: "action-icon--unpublish", method: :put %>
+ <% if component.visible? %>
+ <%= icon_link_to "eye-close", url_for(action: :hide, id: component, controller: "components"), t("actions.menu_hidden", scope: "decidim.admin"), class: "action-icon--unpublish", method: :put %>
+ <% else %>
+ <%= icon_link_to "close-circle-line", url_for(action: :unpublish, id: component, controller: "components"), t("actions.unpublish", scope: "decidim.admin"), class: "action-icon--menu-hidden", method: :put %>
+ <% end %>
<% else %>
<%= icon_link_to "check-line", url_for(action: :publish, id: component, controller: "components"), t("actions.publish", scope: "decidim.admin"), class: "action-icon--publish", method: :put, data: { confirm: t(".answers_alert") } %>
<% end %>
diff --git a/decidim-surveys/spec/system/survey_spec.rb b/decidim-surveys/spec/system/survey_spec.rb
index f38404f4f534f..d845b4051e030 100644
--- a/decidim-surveys/spec/system/survey_spec.rb
+++ b/decidim-surveys/spec/system/survey_spec.rb
@@ -33,7 +33,7 @@
include_context "with a component"
- it_behaves_like "preview component with share_token"
+ it_behaves_like "preview component with a share_token"
context "when the survey does not allow answers" do
it "does not allow answering the survey" do
diff --git a/docs/modules/develop/pages/share_tokens.adoc b/docs/modules/develop/pages/share_tokens.adoc
index 9c787a8afcde5..741f0c32d73a8 100644
--- a/docs/modules/develop/pages/share_tokens.adoc
+++ b/docs/modules/develop/pages/share_tokens.adoc
@@ -1,6 +1,6 @@
= Share tokens
-Share tokens can be assigned to any model to provide a system to share unpublished resources with expirable and manageable tokens.
+Share tokens can be assigned to any model to provide a system to share unpublished resources with expiration dates through the creation/destruction of tokens.
A share token is created by a user with an expiration time, and can be added as a query param to access otherwise restricted locations.
@@ -12,7 +12,7 @@ The model must `include Decidim::ShareableWithToken` and implement `shareable_ur
----
# Public: Public URL for your_resource with given share token as query parameter
def shareable_url(share_token)
- your_resource_public_path(self, share_token: share_token.token)
+ your_resource_public_url(self, share_token: share_token.token)
end
----
@@ -31,27 +31,169 @@ return unless token.present?
allow! if Decidim::ShareToken.use!(token_for: your_resource, token: token)
----
+Note that, if you are using a controller who is inheriting from `Decidim::ApplicationController`, you do not need to include the `:share_token` in the context when calling methods like `enforce_permission_to`, as it is already included in the `Decidim::NeedsPermissions` class through the method `store_share_token`.
+
== Manage tokens
-Render the partial `decidim-admin/app/views/decidim/admin/share_tokens/_share_tokens.html.erb` inside a view, with:
+By default, participatory spaces like process, assemblies, conferences and initiatives are configured to have share tokens, as well as the individual components that are included in them. Participatory spaces have a "Share tokens" tab in the admin view, where you can create new tokens, see the list of existing ones, and revoke them.
+Tokens can also be managed in the components view similarly as other resources to give pre-access (with and action icon like permissions for instance).
+
+Tokens generated for a participatory space are valid for all the components included in it (regardless of their publication status), and tokens generated for a component are valid for that component only.
+
+== Implementation for participatory spaces
+
+In order to implement share tokens for a participatory spaces, you need to:
+
+=== 1. Routes
+
+Add the `share_tokens` CRUD routes in your `admin_engine.rb` file:
+
+[source,ruby]
+----
+scope "/assemblies/:assembly_slug" do
+ ...
+ resources :assembly_share_tokens, except: [:show], path: "share_tokens"
+ ...
+end
+----
+
+=== 2. Controller
+
+Add the controller for the participatory space, it only requires to inherit from `Decidim::Admin::ShareTokensController` and define the `resource` method to return the participatory space:
+
+[source,ruby]
+----
+# frozen_string_literal: true
+
+module Decidim
+ module Assemblies
+ module Admin
+ # This controller allows sharing unpublished things.
+ # It is targeted for customizations for sharing unpublished things that lives under
+ # an assembly.
+ class AssemblyShareTokensController < Decidim::Admin::ShareTokensController
+ include Concerns::AssemblyAdmin
+
+ def resource
+ current_assembly
+ end
+ end
+ end
+ end
+end
+----
+
+=== 3. Menu entry
+
+Add the menu entry for the share tokens in the participatory space admin view. In Decidim we do this in the `menu.rb` file for each participatory space:
+
+[source,ruby]
+----
+Decidim.menu :admin_assembly_menu do |menu|
+ ...
+ menu.add_item :assembly_share_tokens,
+ I18n.t("menu.share_tokens", scope: "decidim.admin"),
+ decidim_admin_assemblies.assembly_share_tokens_path(current_participatory_space),
+ active: is_active_link?(decidim_admin_assemblies.assembly_share_tokens_path(current_participatory_space)),
+ icon_name: "share-line",
+ if: allowed_to?(:read, :share_tokens, current_participatory_space:)
+ ...
+end
+----
+
+=== 4. Model
+
+Ensure your participatory space model includes the `Decidim::ShareableWithToken` module and implements the `shareable_url` method:
+
+[source,ruby]
+----
+module Decidim
+ class Assembly < ApplicationRecord
+ ...
+ include Decidim::ShareableWithToken
+ ...
+ def shareable_url(share_token)
+ EngineRouter.main_proxy(self).assembly_url(self, share_token: share_token.token)
+ end
+ ...
+ end
+end
+----
+
+=== 5. Permissions
+
+Add the permissions logic to the participatory space controller in the `permissions.rb` file:
+
+For admin controllers:
[source,ruby]
----
-locals: { share_tokens: your_share_tokens_variable }
+allow! if permission_action.subject == :share_tokens
+----
+
+For frontend controllers:
+
+[source,ruby]
+----
+token = context[:share_token]
+
+return unless token.present?
+
+allow! if Decidim::ShareToken.use!(token_for: current_assembly, token: token)
----
-to let admins see and manage tokens for that resource.
+== Implementation for components
-== Link to url with token
+Components all inherit from `Decidim::Component`, so they already have the `Decidim::ShareableWithToken` module included. But you still need to do some steps:
-Implement a `share` action (see below) in the resource controller (admin scope), redirecting to a url with a newly generated token, so you can call `share_my_resource_url`.
+=== 1. Routes
+
+Add the `share_tokens` CRUD routes in your `admin_engine.rb` file:
[source,ruby]
----
-def share
- @your_resource = YourResource.find(params[:id]) # or whatever
- share_token = @your_resource.share_tokens.create!(user: current_user, organization: current_organization)
+scope "/assemblies/:assembly_slug" do
+ ...
+ resources :components do
+ ...
+ resources :component_share_tokens, except: [:show], path: "share_tokens", as: "share_tokens"
+ ...
+ end
+end
+----
+
+=== 2. Controller
+
+Add the controller for the component, it only requires to inherit from `Decidim::Admin::ShareTokensController` and define the `resource` method to return the component:
- redirect_to share_token.url
+[source,ruby]
+----
+# frozen_string_literal: true
+
+module Decidim
+ module Assemblies
+ module Admin
+ # This controller allows sharing unpublished things.
+ # It is targeted for customizations for sharing unpublished things that lives under
+ # an assembly.
+ class ComponentShareTokensController < Decidim::Admin::ShareTokensController
+ include Concerns::AssemblyAdmin
+
+ def resource
+ @resource ||= current_participatory_space.components.find(params[:component_id])
+ end
+ end
+ end
+ end
end
----
+
+=== 3. Permissions
+
+Similarly, add the same permissions logic to the component controller in the `permissions.rb` file as for participatory spaces.
+
+
+== Other implementations
+
+You can implement share tokens for any other model by following the same steps as for participatory spaces and components.
+In that case, however, you might have to override some methods from the `Decidim::Admin::ShareTokensController` to adapt them to your model (check the source code for details).
\ No newline at end of file