decidim-budgets 0.13.1 → 0.14.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/budgets/project_cell.rb +1 -1
- data/app/commands/decidim/budgets/admin/import_proposals_to_budgets.rb +76 -0
- data/app/controllers/decidim/budgets/admin/attachment_collections_controller.rb +0 -4
- data/app/controllers/decidim/budgets/admin/attachments_controller.rb +0 -4
- data/app/controllers/decidim/budgets/admin/proposals_imports_controller.rb +32 -0
- data/app/controllers/decidim/budgets/line_items_controller.rb +1 -1
- data/app/controllers/decidim/budgets/orders_controller.rb +1 -1
- data/app/forms/decidim/budgets/admin/project_form.rb +4 -1
- data/app/forms/decidim/budgets/admin/project_import_proposals_form.rb +35 -0
- data/app/models/decidim/budgets/project.rb +5 -0
- data/app/permissions/decidim/budgets/admin/permissions.rb +3 -1
- data/app/permissions/decidim/budgets/permissions.rb +18 -0
- data/app/views/decidim/budgets/admin/projects/index.html.erb +4 -1
- data/app/views/decidim/budgets/admin/proposals_imports/new.html.erb +27 -0
- data/app/views/decidim/budgets/line_items/update_budget.js.erb +6 -6
- data/app/views/decidim/budgets/projects/_project.html.erb +1 -1
- data/app/views/decidim/budgets/projects/show.html.erb +10 -1
- data/config/locales/ca.yml +10 -0
- data/config/locales/en.yml +10 -0
- data/config/locales/es-PY.yml +10 -0
- data/config/locales/es.yml +10 -0
- data/config/locales/eu.yml +10 -0
- data/config/locales/fi.yml +43 -33
- data/config/locales/fr.yml +10 -0
- data/config/locales/gl.yml +10 -0
- data/config/locales/hu.yml +153 -0
- data/config/locales/it.yml +10 -0
- data/config/locales/nl.yml +10 -0
- data/config/locales/pl.yml +10 -0
- data/config/locales/pt-BR.yml +15 -5
- data/config/locales/pt.yml +10 -0
- data/config/locales/ru.yml +13 -3
- data/config/locales/sv.yml +35 -25
- data/config/locales/uk.yml +54 -44
- data/lib/decidim/budgets/admin_engine.rb +4 -0
- data/lib/decidim/budgets/component.rb +2 -0
- data/lib/decidim/budgets/test/factories.rb +3 -3
- data/lib/decidim/budgets/version.rb +1 -1
- metadata +18 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c4245371508038885cb48f6ed330288461ea8554a24678fc0a250a928cbff4a
|
4
|
+
data.tar.gz: 00d30ac4b1662d12100a97767a53594f7412a15e71ce55d3827f841358c2665b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c3847ceb6895e9720c993cd147db952e1147b22c6293be831bb486680161edefc188602e4f774d74819b78fae0ab9207c7d67867874bc9d363e1c17c40b8c44
|
7
|
+
data.tar.gz: 4b71590a413f024134ceb00827291c1f51acaad882537e249d0e4adeef85e9f856ff2b5bee0563af2234caf1ce9def5f6c5ff87ba11fca1298d36aad68dd15a0
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic when an admin imports proposals from
|
7
|
+
# one component to budget component.
|
8
|
+
class ImportProposalsToBudgets < Rectify::Command
|
9
|
+
# Public: Initializes the command.
|
10
|
+
#
|
11
|
+
# form - A form object with the params.
|
12
|
+
def initialize(form)
|
13
|
+
@form = form
|
14
|
+
end
|
15
|
+
|
16
|
+
# Executes the command. Broadcasts these events:
|
17
|
+
#
|
18
|
+
# - :ok when everything is valid.
|
19
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
20
|
+
#
|
21
|
+
# Returns nothing.
|
22
|
+
def call
|
23
|
+
return broadcast(:invalid) unless @form.valid?
|
24
|
+
|
25
|
+
broadcast(:ok, create_projects_from_accepted_proposals)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :form
|
31
|
+
|
32
|
+
def create_projects_from_accepted_proposals
|
33
|
+
transaction do
|
34
|
+
proposals.map do |original_proposal|
|
35
|
+
next if proposal_already_copied?(original_proposal, target_component)
|
36
|
+
|
37
|
+
project = Decidim::Budgets::Project.new
|
38
|
+
project.title = project_localized(original_proposal.title)
|
39
|
+
project.description = project_localized(original_proposal.body)
|
40
|
+
project.budget = form.default_budget
|
41
|
+
project.category = original_proposal.category
|
42
|
+
project.component = target_component
|
43
|
+
project.save!
|
44
|
+
|
45
|
+
project.link_resources([original_proposal], "included_proposals")
|
46
|
+
end.compact
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def proposals
|
51
|
+
Decidim::Proposals::Proposal.where(component: origin_component).where(state: "accepted")
|
52
|
+
end
|
53
|
+
|
54
|
+
def origin_component
|
55
|
+
@form.origin_component
|
56
|
+
end
|
57
|
+
|
58
|
+
def target_component
|
59
|
+
@form.current_component
|
60
|
+
end
|
61
|
+
|
62
|
+
def proposal_already_copied?(original_proposal, target_component)
|
63
|
+
original_proposal.linked_resources(:projects, "included_proposals").any? do |proposal|
|
64
|
+
proposal.component == target_component
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def project_localized(text)
|
69
|
+
Decidim.available_locales.inject({}) do |result, locale|
|
70
|
+
result.update(locale => text)
|
71
|
+
end.with_indifferent_access
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
module Admin
|
6
|
+
class ProposalsImportsController < Admin::ApplicationController
|
7
|
+
def new
|
8
|
+
enforce_permission_to :import_proposals, :projects
|
9
|
+
|
10
|
+
@form = form(Admin::ProjectImportProposalsForm).instance
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
enforce_permission_to :import_proposals, :projects
|
15
|
+
|
16
|
+
@form = form(Admin::ProjectImportProposalsForm).from_params(params)
|
17
|
+
Admin::ImportProposalsToBudgets.call(@form) do
|
18
|
+
on(:ok) do |projects|
|
19
|
+
flash[:notice] = I18n.t("proposals_imports.create.success", scope: "decidim.budgets.admin", number: projects.length)
|
20
|
+
redirect_to EngineRouter.admin_proxy(current_component).root_path
|
21
|
+
end
|
22
|
+
|
23
|
+
on(:invalid) do
|
24
|
+
flash[:alert] = I18n.t("proposals_imports.create.invalid", scope: "decidim.budgets.admin")
|
25
|
+
render action: "new"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -7,6 +7,7 @@ module Decidim
|
|
7
7
|
class ProjectForm < Decidim::Form
|
8
8
|
include TranslatableAttributes
|
9
9
|
include TranslationsHelper
|
10
|
+
include Decidim::ApplicationHelper
|
10
11
|
|
11
12
|
translatable_attribute :title, String
|
12
13
|
translatable_attribute :description, String
|
@@ -36,7 +37,9 @@ module Decidim
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def proposals
|
39
|
-
@proposals ||= Decidim.find_resource_manifest(:proposals).try(:resource_scope, current_component)
|
40
|
+
@proposals ||= Decidim.find_resource_manifest(:proposals).try(:resource_scope, current_component)
|
41
|
+
&.order(title: :asc)
|
42
|
+
&.map { |proposal| [present(proposal).title, proposal.id] }
|
40
43
|
end
|
41
44
|
|
42
45
|
# Finds the Category from the decidim_category_id.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
module Admin
|
6
|
+
# A form object to be used when admin users want to import a collection of proposals
|
7
|
+
# from another component into projects component.
|
8
|
+
class ProjectImportProposalsForm < Decidim::Form
|
9
|
+
mimic :proposals_import
|
10
|
+
|
11
|
+
attribute :origin_component_id, Integer
|
12
|
+
attribute :default_budget, Integer
|
13
|
+
attribute :import_all_accepted_proposals, Boolean
|
14
|
+
|
15
|
+
validates :origin_component_id, :origin_component, :current_component, presence: true
|
16
|
+
validates :import_all_accepted_proposals, allow_nil: false, acceptance: true
|
17
|
+
validates :default_budget, presence: true, numericality: { greater_than: 0 }
|
18
|
+
|
19
|
+
def origin_component
|
20
|
+
@origin_component ||= origin_components.find_by(id: origin_component_id)
|
21
|
+
end
|
22
|
+
|
23
|
+
def origin_components
|
24
|
+
@origin_components ||= current_participatory_space.components.where(manifest_name: :proposals)
|
25
|
+
end
|
26
|
+
|
27
|
+
def origin_components_collection
|
28
|
+
origin_components.map do |component|
|
29
|
+
[component.name[I18n.locale.to_s], component.id]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -49,6 +49,11 @@ module Decidim
|
|
49
49
|
def confirmed_orders_count
|
50
50
|
orders.finished.count
|
51
51
|
end
|
52
|
+
|
53
|
+
# Public: Overrides the `allow_resource_permissions?` Resourceable concern method.
|
54
|
+
def allow_resource_permissions?
|
55
|
+
component.settings.resources_permissions_enabled
|
56
|
+
end
|
52
57
|
end
|
53
58
|
end
|
54
59
|
end
|
@@ -8,11 +8,13 @@ module Decidim
|
|
8
8
|
# The public part needs to be implemented yet
|
9
9
|
return permission_action if permission_action.scope != :admin
|
10
10
|
|
11
|
-
return permission_action
|
11
|
+
return permission_action unless [:project, :projects].include?(permission_action.subject)
|
12
12
|
|
13
13
|
case permission_action.action
|
14
14
|
when :create
|
15
15
|
permission_action.allow!
|
16
|
+
when :import_proposals
|
17
|
+
permission_action.allow!
|
16
18
|
when :update, :destroy
|
17
19
|
permission_action.allow! if project.present?
|
18
20
|
end
|
@@ -13,12 +13,30 @@ module Decidim
|
|
13
13
|
return permission_action if permission_action.subject != :project
|
14
14
|
|
15
15
|
case permission_action.action
|
16
|
+
when :vote
|
17
|
+
can_vote_project?(project || order&.projects&.first)
|
16
18
|
when :report
|
17
19
|
permission_action.allow!
|
18
20
|
end
|
19
21
|
|
20
22
|
permission_action
|
21
23
|
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def project
|
28
|
+
@project ||= context.fetch(:project, nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
def order
|
32
|
+
@order ||= context.fetch(:order, nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
def can_vote_project?(a_project)
|
36
|
+
is_allowed = a_project && authorized?(:vote, resource: project)
|
37
|
+
|
38
|
+
toggle_allow(is_allowed)
|
39
|
+
end
|
22
40
|
end
|
23
41
|
end
|
24
42
|
end
|
@@ -2,7 +2,8 @@
|
|
2
2
|
<div class="card-divider">
|
3
3
|
<h2 class="card-title">
|
4
4
|
<%= t(".title") %>
|
5
|
-
<%= link_to t("actions.new", scope: "decidim.budgets"), new_project_path, class: "button tiny button--title" if allowed_to? :create, :project %>
|
5
|
+
<%= link_to t("actions.new", scope: "decidim.budgets"), new_project_path, class: "button tiny button--title new" if allowed_to? :create, :project %>
|
6
|
+
<%= link_to t("actions.import", scope: "decidim.budgets", name: t("models.project.name", scope: "decidim.budgets.admin")), new_proposals_import_path, class: "button tiny button--title" if allowed_to? :import_proposals, :project %>
|
6
7
|
</h2>
|
7
8
|
</div>
|
8
9
|
|
@@ -40,6 +41,8 @@
|
|
40
41
|
<%= icon_link_to "paperclip", project_attachments_path(project), t("actions.attachments", scope: "decidim.budgets"), class: "action-icon--attachments" %>
|
41
42
|
<% end %>
|
42
43
|
|
44
|
+
<%= resource_permissions_link(project) %>
|
45
|
+
|
43
46
|
<% if allowed_to? :destroy, :project, project: project %>
|
44
47
|
<%= icon_link_to "circle-x", project_path(project), t("actions.destroy", scope: "decidim.budgets"), method: :delete, class: "action-icon--remove", data: { confirm: t("actions.confirm_destroy", scope: "decidim.budgets") } %>
|
45
48
|
<% end %>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<%= decidim_form_for(@form, url: proposals_import_path, html: { class: "form import_proposals" }) do |f| %>
|
2
|
+
<% if @form.origin_components.any? %>
|
3
|
+
<div class="card">
|
4
|
+
<div class="card-divider">
|
5
|
+
<h2 class="card-title"><%= title %></h2>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="card-section">
|
9
|
+
<div class="row column">
|
10
|
+
<%= f.select :origin_component_id, @form.origin_components_collection, prompt: t(".select_component") %>
|
11
|
+
</div>
|
12
|
+
<div class="row column">
|
13
|
+
<%= f.number_field :default_budget %>
|
14
|
+
</div>
|
15
|
+
<div class="row column">
|
16
|
+
<%= f.check_box :import_all_accepted_proposals %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="button--double form-general-submit">
|
22
|
+
<%= f.submit t(".create") %>
|
23
|
+
</div>
|
24
|
+
<% else %>
|
25
|
+
<p><%= t(".no_components") %></p>
|
26
|
+
<% end %>
|
27
|
+
<% end %>
|
@@ -5,20 +5,20 @@ var $projectItem = $('#project-<%= project.id %>-item');
|
|
5
5
|
var $projectBudgetButton = $('#project-<%= project.id %>-budget-button');
|
6
6
|
var $budgetConfirm = $('#budget-confirm');
|
7
7
|
|
8
|
-
morphdom($orderTotalBudget[0], '<%= j(render partial:
|
9
|
-
morphdom($orderSelectedProjects[0], '<%= j(render partial:
|
10
|
-
morphdom($orderProgress[0], '<%= j(render partial:
|
11
|
-
morphdom($budgetConfirm[0], '<%= j(render partial:
|
8
|
+
morphdom($orderTotalBudget[0], '<%= j(render partial: "decidim/budgets/projects/order_total_budget").strip.html_safe %>');
|
9
|
+
morphdom($orderSelectedProjects[0], '<%= j(render partial: "decidim/budgets/projects/order_selected_projects").strip.html_safe %>');
|
10
|
+
morphdom($orderProgress[0], '<%= j(render partial: "decidim/budgets/projects/order_progress").strip.html_safe %>');
|
11
|
+
morphdom($budgetConfirm[0], '<%= j(render partial: "decidim/budgets/projects/budget_confirm").strip.html_safe %>')
|
12
12
|
|
13
13
|
$("#order-progress").foundation();
|
14
14
|
$(".budget-summary__selected").foundation();
|
15
15
|
|
16
16
|
if ($projectItem.length > 0) {
|
17
|
-
morphdom($projectItem[0], '<%= j(render partial:
|
17
|
+
morphdom($projectItem[0], '<%= j(render partial: "decidim/budgets/projects/project", locals: { project: project }).strip.html_safe %>');
|
18
18
|
}
|
19
19
|
|
20
20
|
if ($projectBudgetButton.length > 0) {
|
21
|
-
morphdom($projectBudgetButton[0], '<%= j(render partial:
|
21
|
+
morphdom($projectBudgetButton[0], '<%= j(render partial: "decidim/budgets/projects/project_budget_button", locals: { project: project }).strip.html_safe %>');
|
22
22
|
}
|
23
23
|
|
24
24
|
window.DecidimBudgets.checkProgressPosition();
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<%= translated_attribute project.title %>
|
7
7
|
</h5>
|
8
8
|
<% end %>
|
9
|
-
<%= cell "decidim/tags", project, context: {extra_classes: ["tags--project"]} %>
|
9
|
+
<%= cell "decidim/tags", project, context: { extra_classes: ["tags--project"] } %>
|
10
10
|
</div>
|
11
11
|
</div>
|
12
12
|
<% if current_user.present? %>
|
@@ -3,6 +3,15 @@
|
|
3
3
|
description: translated_attribute(project.description)
|
4
4
|
) %>
|
5
5
|
|
6
|
+
<%
|
7
|
+
edit_link(
|
8
|
+
resource_locator(project).edit,
|
9
|
+
:update,
|
10
|
+
:project,
|
11
|
+
project: project
|
12
|
+
)
|
13
|
+
%>
|
14
|
+
|
6
15
|
<div class="row column view-header">
|
7
16
|
<% if current_user.present? && current_settings.votes_enabled? && current_participatory_space.can_participate?(current_user) %>
|
8
17
|
<%= render partial: "budget_summary", locals: { include_heading: false } %>
|
@@ -38,7 +47,7 @@
|
|
38
47
|
<div class="columns mediumlarge-8 mediumlarge-pull-4">
|
39
48
|
<div class="section">
|
40
49
|
<%= decidim_sanitize translated_attribute project.description %>
|
41
|
-
<%= cell "decidim/tags", project, context: {extra_classes: ["tags--project"]} %>
|
50
|
+
<%= cell "decidim/tags", project, context: { extra_classes: ["tags--project"] } %>
|
42
51
|
</div>
|
43
52
|
<%= linked_resources_for project, :proposals, "included_proposals" %>
|
44
53
|
<%= linked_resources_for project, :results, "included_projects" %>
|
data/config/locales/ca.yml
CHANGED
@@ -21,6 +21,7 @@ ca:
|
|
21
21
|
confirm_destroy: Segur que vols eliminar aquest projecte?
|
22
22
|
destroy: Esborrar
|
23
23
|
edit: Editar
|
24
|
+
import: Importa propostes a projectes
|
24
25
|
new: Nou projecte
|
25
26
|
preview: Previsualitzar
|
26
27
|
title: Accions
|
@@ -47,6 +48,14 @@ ca:
|
|
47
48
|
update:
|
48
49
|
invalid: Hi ha hagut un problema actualitzant aquest projecte
|
49
50
|
success: Projecte actualitzat correctament
|
51
|
+
proposals_imports:
|
52
|
+
create:
|
53
|
+
invalid: Hi ha hagut un problema en importar les propostes en projectes
|
54
|
+
success: "S'ha importat amb èxit %{number} propostes en projectes"
|
55
|
+
new:
|
56
|
+
create: Importa propostes a projectes
|
57
|
+
no_components: No hi ha cap component de propostes en aquest espai participatiu per importar les propostes a projectes.
|
58
|
+
select_component: Selecciona un component
|
50
59
|
admin_log:
|
51
60
|
project:
|
52
61
|
create: "%{user_name} ha creat el projecte %{resource_name} a l'espai %{space_name}"
|
@@ -121,6 +130,7 @@ ca:
|
|
121
130
|
announcement: Anunci
|
122
131
|
comments_enabled: Comentaris habilitats
|
123
132
|
projects_per_page: Projectes per pàgina
|
133
|
+
resources_permissions_enabled: Es poden establir permisos d'accions per a cada trobada
|
124
134
|
total_budget: Pressupost total
|
125
135
|
vote_threshold_percent: Percentatge del pressupost mínim per fer el vot
|
126
136
|
step:
|
data/config/locales/en.yml
CHANGED
@@ -22,6 +22,7 @@ en:
|
|
22
22
|
confirm_destroy: Are you sure you want to delete this project?
|
23
23
|
destroy: Delete
|
24
24
|
edit: Edit
|
25
|
+
import: Import proposals to projects
|
25
26
|
new: New project
|
26
27
|
preview: Preview
|
27
28
|
title: Actions
|
@@ -48,6 +49,14 @@ en:
|
|
48
49
|
update:
|
49
50
|
invalid: There's been a problem updating this project
|
50
51
|
success: Project successfully updated
|
52
|
+
proposals_imports:
|
53
|
+
create:
|
54
|
+
invalid: There's been a problem importing the proposals into projects
|
55
|
+
success: "%{number} proposals successfully imported into projects"
|
56
|
+
new:
|
57
|
+
create: Import proposals to projects
|
58
|
+
no_components: There are no other proposal components in this participatory space to import the proposals into projects.
|
59
|
+
select_component: Please select a component
|
51
60
|
admin_log:
|
52
61
|
project:
|
53
62
|
create: "%{user_name} created the %{resource_name} project in the %{space_name} space"
|
@@ -122,6 +131,7 @@ en:
|
|
122
131
|
announcement: Announcement
|
123
132
|
comments_enabled: Comments enabled
|
124
133
|
projects_per_page: Projects per page
|
134
|
+
resources_permissions_enabled: Actions permissions can be set for each meeting
|
125
135
|
total_budget: Total budget
|
126
136
|
vote_threshold_percent: Vote threshold percent
|
127
137
|
step:
|