decidim-plans 0.16.6 → 0.16.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/app/assets/javascripts/decidim/plans/admin/plans.js.es6 +93 -1
  4. data/app/assets/javascripts/decidim/plans/multifield/dynamic_fields.component.js.es6 +39 -0
  5. data/app/assets/javascripts/decidim/plans/multifield.js.es6 +1 -0
  6. data/app/cells/decidim/plans/plan_m/tags.erb +1 -0
  7. data/app/cells/decidim/plans/plan_m_cell.rb +1 -1
  8. data/app/cells/decidim/plans/tags/show.erb +7 -0
  9. data/app/cells/decidim/plans/tags/taggings.erb +3 -0
  10. data/app/cells/decidim/plans/tags_cell.rb +52 -0
  11. data/app/commands/decidim/plans/admin/answer_plan.rb +3 -0
  12. data/app/commands/decidim/plans/admin/create_tag.rb +44 -0
  13. data/app/commands/decidim/plans/admin/destroy_tag.rb +44 -0
  14. data/app/commands/decidim/plans/admin/update_plan_taggings.rb +53 -0
  15. data/app/commands/decidim/plans/admin/update_tag.rb +47 -0
  16. data/app/commands/decidim/plans/close_plan.rb +9 -1
  17. data/app/commands/decidim/plans/reopen_plan.rb +9 -1
  18. data/app/controllers/decidim/plans/admin/plans_controller.rb +32 -2
  19. data/app/controllers/decidim/plans/admin/tags_controller.rb +126 -0
  20. data/app/controllers/decidim/plans/plans_controller.rb +7 -2
  21. data/app/forms/decidim/plans/admin/tag_form.rb +22 -0
  22. data/app/forms/decidim/plans/admin/taggings_form.rb +20 -0
  23. data/app/helpers/decidim/plans/attached_proposals_helper.rb +18 -2
  24. data/app/helpers/decidim/plans/plan_cells_helper.rb +1 -1
  25. data/app/models/decidim/plans/plan.rb +14 -0
  26. data/app/models/decidim/plans/plan_tagging.rb +13 -0
  27. data/app/models/decidim/plans/tag.rb +20 -0
  28. data/app/permissions/decidim/plans/admin/permissions.rb +14 -4
  29. data/app/permissions/decidim/plans/permissions.rb +3 -1
  30. data/app/presenters/decidim/plans/plan_presenter.rb +4 -0
  31. data/app/queries/decidim/plans/component_plan_tags.rb +35 -0
  32. data/app/queries/decidim/plans/organization_tags.rb +25 -0
  33. data/app/services/decidim/plans/plan_search.rb +6 -0
  34. data/app/views/decidim/plans/admin/plans/_plan-tr.html.erb +13 -2
  35. data/app/views/decidim/plans/admin/plans/index.html.erb +9 -0
  36. data/app/views/decidim/plans/admin/plans/taggings.html.erb +67 -0
  37. data/app/views/decidim/plans/admin/tags/_form.html.erb +21 -0
  38. data/app/views/decidim/plans/admin/tags/edit.html.erb +7 -0
  39. data/app/views/decidim/plans/admin/tags/index.html.erb +52 -0
  40. data/app/views/decidim/plans/admin/tags/new.html.erb +7 -0
  41. data/app/views/decidim/plans/plans/_evaluation_modal.html.erb +22 -0
  42. data/app/views/decidim/plans/plans/_filters.html.erb +4 -0
  43. data/app/views/decidim/plans/plans/show.html.erb +9 -1
  44. data/app/views/decidim/plans/shared/_attachments.html.erb +2 -2
  45. data/app/views/decidim/plans/shared/_tags.html.erb +1 -0
  46. data/config/locales/en.yml +57 -2
  47. data/config/locales/fi.yml +57 -2
  48. data/config/locales/sv.yml +57 -2
  49. data/db/migrate/20190329161710_fix_plan_closing_workflow_states.rb +13 -0
  50. data/db/migrate/20190331141058_create_decidim_plans_tags_and_plan_taggings.rb +17 -0
  51. data/lib/decidim/content_parsers/plan_parser.rb +82 -0
  52. data/lib/decidim/content_renderers/plan_renderer.rb +33 -0
  53. data/lib/decidim/plans/admin_engine.rb +3 -0
  54. data/lib/decidim/plans/component.rb +11 -2
  55. data/lib/decidim/plans/engine.rb +6 -0
  56. data/lib/decidim/plans/test/factories.rb +17 -0
  57. data/lib/decidim/plans/version.rb +1 -1
  58. data/lib/decidim/plans.rb +8 -0
  59. metadata +29 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 870133d81fb0fd7608a2087fbf2fdb7a434a37ebe3437334c9cdb604c2afd3f8
4
- data.tar.gz: 4e28e6926fbdfe8339eb19ef66c1c455cef50ad9cf42a1940f2c2ec9df0a041f
3
+ metadata.gz: 210bbe22dc50de4ec472503edc4ec7cc7944ccf4623cbd0602ba2f56ac73c59c
4
+ data.tar.gz: 4b6ba7db25df3fc75fcd770511918ad71aeb38247769f0df384b2090f7d7d389
5
5
  SHA512:
6
- metadata.gz: 1cd3865a386f58d321ff9e077e7c8728b011dfe85cffcc52b0c6854759ee91592398eab98506fdb31d162f52022a532a0bc5e18d21191e88798d9fa29fc84858
7
- data.tar.gz: 55e53122d62b560a70532c9ce0d3b2b8466b4ca2187cc54664df4f3710a8697b8f5112c200d597d39e19006271ae4402d6421d5a8dac83e8b5dd254201bfb56f
6
+ metadata.gz: a2c04c5480bad9093b12345eedb2ae702867fa770b3a76eb7b548349620492db1997091c453424f1e5b01f7640a7a404e13cb80d4d1790921bafce4faa4fd79e
7
+ data.tar.gz: 374f57e0e4ce29c5ea888c631b3b6623251a24dbd58890292977d9f9dec60ff7631fb5ea57d781ec4e95b7a30ee20f59481e944826234b571d95a5c8bd2a2147
data/README.md CHANGED
@@ -59,7 +59,8 @@ can start writing the plans when plan creation is enabled.
59
59
 
60
60
  ## Contributing
61
61
 
62
- For instructions how to setup your development environment for Decidim, see [Decidim](https://github.com/decidim/decidim). Also follow Decidim's general
62
+ For instructions how to setup your development environment for Decidim, see
63
+ [Decidim](https://github.com/decidim/decidim). Also follow Decidim's general
63
64
  instructions for development for this project as well.
64
65
 
65
66
  ### Developing
@@ -1,3 +1,95 @@
1
1
  $(() => {
2
- // Add the needed JS initialization code here
2
+ const $search = $("#data_picker-autocomplete");
3
+ const $results = $("#plan-tags-results");
4
+ const $template = $(".decidim-template", $results);
5
+ const $form = $search.parents("form");
6
+ const addRowItem = function(id, title) {
7
+ let template = $template.html();
8
+ template = template.replace(new RegExp("{{tag_id}}", "g"), id);
9
+ template = template.replace(new RegExp("{{tag_name}}", "g"), title);
10
+ const $newRow = $(template);
11
+ $("table tbody", $results).append($newRow);
12
+ $results.removeClass("hide");
13
+
14
+ // Add it to the autocomplete form
15
+ const $field = $(`<input type="hidden" name="tags[]" value="${id}">`);
16
+ $form.append($field);
17
+
18
+ // Listen to the click event on the remove button
19
+ $(".remove-tagging", $newRow).on("click", function(ev) {
20
+ ev.preventDefault();
21
+ $newRow.remove();
22
+ $field.remove();
23
+
24
+ if ($("table tbody tr", $results).length < 1) {
25
+ $results.addClass("hide");
26
+ }
27
+ });
28
+ };
29
+ let xhr = null;
30
+ let currentSearch = "";
31
+
32
+ $search.on("keyup", function() {
33
+ currentSearch = $search.val();
34
+ });
35
+
36
+ $search.autoComplete({
37
+ minChars: 2,
38
+ cache: 0,
39
+ source: function(term, response) {
40
+ try {
41
+ xhr.abort();
42
+ } catch (exception) { xhr = null; }
43
+
44
+ const url = $form.attr("action");
45
+ xhr = $.getJSON(
46
+ url,
47
+ $form.serializeArray(),
48
+ function(data) {
49
+ if (data.length > 0) {
50
+ response(data);
51
+ } else {
52
+ response([
53
+ [null, $search.data("no-results-text"), term]
54
+ ]);
55
+ }
56
+ }
57
+ );
58
+ },
59
+ renderItem: function (item, search) {
60
+ const sanitizedSearch = search.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
61
+ const re = new RegExp(`(${sanitizedSearch.split(" ").join("|")})`, "gi");
62
+ const modelId = item[0];
63
+ const title = item[1];
64
+ const val = `${title}`;
65
+
66
+ if (modelId === null) {
67
+ // Empty result
68
+ const term = item[2];
69
+ const url = $search.data("no-results-url").replace("{{term}}", encodeURIComponent(term));
70
+ return `<div><a href="${url}">${val.replace("{{term}}", term)}</a></div>`;
71
+ }
72
+ return `<div class="autocomplete-suggestion" data-model-id="${modelId}" data-val="${title}">${val.replace(re, "<b>$1</b>")}</div>`;
73
+ },
74
+ onSelect: function(event, term, item) {
75
+ const $suggestions = $search.data("sc");
76
+ const modelId = item.data("modelId");
77
+ const title = item.data("val");
78
+
79
+ addRowItem(modelId, title);
80
+
81
+ $search.val(currentSearch);
82
+ setTimeout(function() {
83
+ $(`[data-model-id="${modelId}"]`, $suggestions).remove();
84
+ $suggestions.show();
85
+ }, 20);
86
+ }
87
+ });
88
+
89
+ const resultsArray = $results.data("results");
90
+ if (Array.isArray(resultsArray)) {
91
+ resultsArray.forEach((value) => {
92
+ addRowItem(value[0], value[1]);
93
+ });
94
+ }
3
95
  });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Extends / overrides:
3
+ * decidim/admin/dynamic_fields.component
4
+ *
5
+ * Fixes broken attachments in IE11 by overriding the `_addField` method in the
6
+ *`DynamicFieldsComponent` coming from the `decidim-admin` component.
7
+ *
8
+ * For further details, see:
9
+ * https://github.com/mainio/decidim-module-plans/issues/13
10
+ **/
11
+
12
+ ((exports) => {
13
+ const { DynamicFieldsComponent } = exports.DecidimAdmin;
14
+
15
+ class DynamicFieldsComponentExtended extends DynamicFieldsComponent {
16
+ _addField() {
17
+ const $container = $(this.wrapperSelector).find(this.containerSelector);
18
+ // START OVERRIDE
19
+ const $template = $(this.wrapperSelector).children(".decidim-template");
20
+ // END OVERRIDE
21
+ const $newField = $($template.html()).template(this.placeholderId, this._getUID());
22
+
23
+ $newField.find("ul.tabs").attr("data-tabs", true);
24
+
25
+ $newField.appendTo($container);
26
+ $newField.foundation();
27
+
28
+ if (this.onAddField) {
29
+ this.onAddField($newField);
30
+ }
31
+ }
32
+ }
33
+
34
+ exports.DecidimAdmin = exports.DecidimAdmin || {};
35
+ exports.DecidimAdmin.DynamicFieldsComponent = DynamicFieldsComponentExtended;
36
+ exports.DecidimAdmin.createDynamicFields = (options) => {
37
+ return new DynamicFieldsComponentExtended(options);
38
+ };
39
+ })(window);
@@ -1,5 +1,6 @@
1
1
  // = require decidim/admin/auto_buttons_by_position.component
2
2
  // = require decidim/admin/auto_label_by_position.component
3
3
  // = require decidim/admin/dynamic_fields.component
4
+ // = require decidim/plans/multifield/dynamic_fields.component
4
5
  // = require decidim/admin/sort_list.component
5
6
  // = require decidim/plans/multifield/component
@@ -0,0 +1 @@
1
+ <%= render partial: "decidim/plans/shared/tags.html", locals: { resource: model, tags_class_extra: "tags--proposal" } %>
@@ -31,7 +31,7 @@ module Decidim
31
31
  end
32
32
 
33
33
  def has_badge?
34
- answered? || withdrawn?
34
+ closed? || answered? || withdrawn?
35
35
  end
36
36
 
37
37
  def has_link_to_resource?
@@ -0,0 +1,7 @@
1
+ <%= content_tag :ul, class: tags_classes do %>
2
+ <%= cell("decidim/plans/tags", model).category %>
3
+
4
+ <%= cell("decidim/plans/tags", model).scope %>
5
+
6
+ <%= cell("decidim/plans/tags", model).taggings %>
7
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% model.tags.each do |tag| %>
2
+ <%= content_tag :li, link_to_tag(tag) %>
3
+ <% end %>
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Plans
5
+ # This cell renders:
6
+ # - The category of a resource shown with the translated name (parent)
7
+ # - The scope of a resource shown with the translated name (parent)
8
+ # - The assigned tags from the plans
9
+ #
10
+ # The context `resource` must be present example use inside another `cell`:
11
+ # <%= cell("decidim/category", model.category, context: {resource: model}) %>
12
+ #
13
+ class TagsCell < Decidim::TagsCell
14
+ def show
15
+ render if category? || scope? || taggings?
16
+ end
17
+
18
+ def taggings
19
+ render if taggings?
20
+ end
21
+
22
+ private
23
+
24
+ def category?
25
+ model.category.present?
26
+ end
27
+
28
+ def scope?
29
+ has_visible_scopes?(model)
30
+ end
31
+
32
+ def taggings?
33
+ model.tags.any?
34
+ end
35
+
36
+ def link_to_tag(tag)
37
+ end
38
+
39
+ def link_to_tag(tag)
40
+ link_to tag_name(tag), tag_path(tag)
41
+ end
42
+
43
+ def tag_name(tag)
44
+ translated_attribute(tag.name)
45
+ end
46
+
47
+ def tag_path(tag)
48
+ resource_locator(model).index(filter: { tag_id: [tag.id] })
49
+ end
50
+ end
51
+ end
52
+ end
@@ -39,7 +39,10 @@ module Decidim
39
39
  plan,
40
40
  form.current_user
41
41
  ) do
42
+ closed_at = plan.closed_at || Time.current
43
+
42
44
  plan.update!(
45
+ closed_at: closed_at,
43
46
  state: @form.state,
44
47
  answer: @form.answer,
45
48
  answered_at: Time.current
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Plans
5
+ module Admin
6
+ # A command with all the business logic when a user creates a new tag.
7
+ class CreateTag < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # form - A form object with the params.
11
+ def initialize(form)
12
+ @form = form
13
+ end
14
+
15
+ # Executes the command. Broadcasts these events:
16
+ #
17
+ # - :ok when everything is valid, together with the tag.
18
+ # - :invalid if the form wasn't valid and we couldn't proceed.
19
+ #
20
+ # Returns nothing.
21
+ def call
22
+ return broadcast(:invalid) if form.invalid?
23
+
24
+ create_tag
25
+
26
+ broadcast(:ok, tag)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :form, :tag
32
+
33
+ def create_tag
34
+ @tag = Decidim.traceability.create(
35
+ Tag,
36
+ form.current_user,
37
+ name: form.name,
38
+ organization: form.organization
39
+ )
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Plans
5
+ module Admin
6
+ # A command with all the business logic when a user destroys a tag.
7
+ class DestroyTag < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # tag - The target object to be destroyed.
11
+ # current_user - the user performing the action.
12
+ def initialize(tag, current_user)
13
+ @tag = tag
14
+ @current_user = current_user
15
+ end
16
+
17
+ # Destroys the tag if valid.
18
+ #
19
+ # Broadcasts :ok if successful, :invalid otherwise.
20
+ #
21
+ # Returns nothing.
22
+ def call
23
+ destroy_tag
24
+
25
+ broadcast(:ok)
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :tag, :current_user
31
+
32
+ def destroy_tag
33
+ Decidim.traceability.perform_action!(
34
+ :delete,
35
+ tag,
36
+ current_user
37
+ ) do
38
+ tag.destroy!
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Plans
5
+ module Admin
6
+ # A command with all the business logic when a user updates a tag.
7
+ class UpdatePlanTaggings < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # form - A form object with the params.
11
+ # plan - The target object to be updated.
12
+ def initialize(form, plan)
13
+ @form = form
14
+ @plan = plan
15
+ end
16
+
17
+ # Executes the command. Broadcasts these events:
18
+ #
19
+ # - :ok when everything is valid, together with the plan.
20
+ # - :invalid if the form wasn't valid and we couldn't proceed.
21
+ #
22
+ # Returns nothing.
23
+ def call
24
+ return broadcast(:invalid) if form.invalid?
25
+
26
+ update_plan_taggings
27
+
28
+ broadcast(:ok, plan)
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :form, :plan
34
+
35
+ def update_plan_taggings
36
+ Decidim.traceability.perform_action!(
37
+ :update,
38
+ plan,
39
+ form.current_user
40
+ ) do
41
+ plan.taggings.destroy_all
42
+ plan.update!(
43
+ tags: Tag.where(
44
+ id: form.tags,
45
+ organization: plan.component.organization
46
+ )
47
+ )
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Plans
5
+ module Admin
6
+ # A command with all the business logic when a user updates a tag.
7
+ class UpdateTag < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # form - A form object with the params.
11
+ # tag - The target object to be updated.
12
+ def initialize(form, tag)
13
+ @form = form
14
+ @tag = tag
15
+ end
16
+
17
+ # Executes the command. Broadcasts these events:
18
+ #
19
+ # - :ok when everything is valid, together with the plan.
20
+ # - :invalid if the form wasn't valid and we couldn't proceed.
21
+ #
22
+ # Returns nothing.
23
+ def call
24
+ return broadcast(:invalid) if form.invalid?
25
+
26
+ update_tag
27
+
28
+ broadcast(:ok, tag)
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :form, :tag
34
+
35
+ def update_tag
36
+ Decidim.traceability.perform_action!(
37
+ :update,
38
+ tag,
39
+ form.current_user
40
+ ) do
41
+ tag.update!(name: form.name)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -36,7 +36,15 @@ module Decidim
36
36
  @current_user,
37
37
  visibility: "public-only"
38
38
  ) do
39
- @plan.update closed_at: Time.current
39
+ # Unless the plan has already been answered, change the state to
40
+ # "evaluating".
41
+ state = @plan.state
42
+ state = "evaluating" unless @plan.answered?
43
+
44
+ @plan.update!(
45
+ state: state,
46
+ closed_at: Time.current
47
+ )
40
48
  end
41
49
  end
42
50
  end
@@ -36,7 +36,15 @@ module Decidim
36
36
  @current_user,
37
37
  visibility: "public-only"
38
38
  ) do
39
- @plan.update closed_at: nil
39
+ # Unless the plan has already been answered, change the state back to
40
+ # "open".
41
+ state = @plan.state
42
+ state = "open" unless @plan.answered?
43
+
44
+ @plan.update!(
45
+ state: state,
46
+ closed_at: nil
47
+ )
40
48
  end
41
49
  end
42
50
  end
@@ -11,7 +11,7 @@ module Decidim
11
11
  helper Plans::ApplicationHelper
12
12
  helper Plans::AttachmentsHelper
13
13
  helper Plans::RemainingCharactersHelper
14
- helper_method :plans, :query, :form_presenter, :attached_proposals_picker_field
14
+ helper_method :plans, :plan, :query, :counts, :form_presenter, :attached_proposals_picker_field
15
15
 
16
16
  def new
17
17
  enforce_permission_to :create, :plans
@@ -89,16 +89,46 @@ module Decidim
89
89
  end
90
90
  end
91
91
 
92
+ def taggings
93
+ enforce_permission_to :edit_taggings, :plan, plan: plan
94
+
95
+ @form = form(Admin::TaggingsForm).from_model(plan)
96
+ end
97
+
98
+ def update_taggings
99
+ enforce_permission_to :edit_taggings, :plan, plan: plan
100
+
101
+ @form = form(Admin::TaggingsForm).from_params(params)
102
+ Admin::UpdatePlanTaggings.call(@form, plan) do
103
+ on(:ok) do
104
+ flash[:notice] = I18n.t("plans.update_taggings.success", scope: "decidim.plans.admin")
105
+ redirect_to plans_path
106
+ end
107
+
108
+ on(:invalid) do
109
+ flash.now[:alert] = I18n.t("plans.update_taggings.invalid", scope: "decidim.plans.admin")
110
+ render :taggings
111
+ end
112
+ end
113
+ end
114
+
92
115
  private
93
116
 
94
117
  def query
95
- @query ||= Plan.where(component: current_component).ransack(params[:q])
118
+ @query ||= Plan.published.where(component: current_component).ransack(params[:q])
96
119
  end
97
120
 
98
121
  def plans
99
122
  @plans ||= query.result.page(params[:page]).per(15)
100
123
  end
101
124
 
125
+ def counts
126
+ @counts ||= {
127
+ published: Plan.published.where(component: current_component).count,
128
+ drafts: Plan.drafts.where(component: current_component).count
129
+ }
130
+ end
131
+
102
132
  def plan
103
133
  @plan ||= Plan.where(component: current_component).find(params[:id])
104
134
  end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Plans
5
+ module Admin
6
+ # This controller allows admins to the tags related to plans.
7
+ class TagsController < Admin::ApplicationController
8
+ include TranslatableAttributes
9
+
10
+ helper_method :plan, :tags
11
+
12
+ def index
13
+ enforce_permission_to :read, :plan_tag
14
+
15
+ respond_to do |format|
16
+ format.html do
17
+ render :index
18
+ end
19
+ format.json do
20
+ return render json: [] unless params.has_key?(:term)
21
+
22
+ tags = OrganizationTags.new(current_organization).query.where(
23
+ "name ->> '#{current_locale}' ILIKE ?",
24
+ "%#{params[:term]}%"
25
+ ).where.not(
26
+ id: plan.tags.pluck(:id)
27
+ )
28
+ render json: tags.map { |t| [t.id, translated_attribute(t.name)] }
29
+ end
30
+ end
31
+ end
32
+
33
+ def new
34
+ enforce_permission_to :create, :plan_tags
35
+
36
+ dummy_tag = Tag.new(organization: current_organization)
37
+ dummy_tag.name = {}
38
+ current_organization.available_locales.map do |locale|
39
+ dummy_tag.name[locale] = params[:name]
40
+ end
41
+
42
+ @form = form(Admin::TagForm).from_model(dummy_tag)
43
+ @form.back_to_plan = true if params[:back_to_plan].to_i == 1
44
+ end
45
+
46
+ def create
47
+ enforce_permission_to :create, :plan_tags
48
+ @form = form(Admin::TagForm).from_params(params)
49
+
50
+ Admin::CreateTag.call(@form) do
51
+ on(:ok) do
52
+ flash[:notice] = I18n.t("create.success", scope: i18n_flashes_scope)
53
+
54
+ return redirect_to taggings_plan_path(plan) if @form.back_to_plan
55
+
56
+ redirect_to plan_tags_path(plan)
57
+ end
58
+
59
+ on(:invalid) do
60
+ flash.now[:alert] = I18n.t("create.invalid", scope: i18n_flashes_scope)
61
+ render action: "new"
62
+ end
63
+ end
64
+ end
65
+
66
+ def edit
67
+ enforce_permission_to :edit, :plan_tags, tag: tag
68
+ @form = form(Admin::TagForm).from_model(tag)
69
+ end
70
+
71
+ def update
72
+ enforce_permission_to :edit, :plan_tags, tag: tag
73
+
74
+ @form = form(Admin::TagForm).from_params(params)
75
+ Admin::UpdateTag.call(@form, @tag) do
76
+ on(:ok) do
77
+ flash[:notice] = I18n.t("update.success", scope: i18n_flashes_scope)
78
+ redirect_to plan_tags_path(plan)
79
+ end
80
+
81
+ on(:invalid) do
82
+ flash.now[:alert] = I18n.t("update.invalid", scope: i18n_flashes_scope)
83
+ render :edit
84
+ end
85
+ end
86
+ end
87
+
88
+ def destroy
89
+ enforce_permission_to :destroy, :plan_tags, tag: tag
90
+
91
+ Admin::DestroyTag.call(@tag, current_user) do
92
+ on(:ok) do
93
+ flash[:notice] = I18n.t("destroy.success", scope: i18n_flashes_scope)
94
+ redirect_to plan_tags_path(plan)
95
+ end
96
+
97
+ on(:invalid) do
98
+ flash.now[:alert] = I18n.t("destroy.error", scope: i18n_flashes_scope)
99
+ redirect_to plan_tags_path(plan)
100
+ end
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def i18n_flashes_scope
107
+ "decidim.plans.admin.tags"
108
+ end
109
+
110
+ def tag
111
+ @tag ||= Tag.where(organization: current_organization).find(params[:id])
112
+ end
113
+
114
+ def plan
115
+ @plan ||= Plan.where(component: current_component).find(params[:plan_id])
116
+ end
117
+
118
+ def tags
119
+ @tags ||= OrganizationTags.new(
120
+ current_organization
121
+ ).query.page(params[:page]).per(30)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end