decidim-budgets 0.21.0 → 0.23.2
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.
- checksums.yaml +4 -4
- data/README.md +38 -3
- data/app/assets/images/decidim/budgets/icon.svg +1 -11
- data/app/assets/javascripts/decidim/budgets/projects.js.es6 +26 -4
- data/app/assets/stylesheets/decidim/budgets/budget/_budget-list.scss +152 -24
- data/app/cells/decidim/budgets/base_cell.rb +22 -0
- data/app/cells/decidim/budgets/budget_cell.rb +21 -0
- data/app/cells/decidim/budgets/budget_information_modal/show.erb +28 -0
- data/app/cells/decidim/budgets/budget_information_modal_cell.rb +22 -0
- data/app/cells/decidim/budgets/budget_list_item/show.erb +22 -0
- data/app/cells/decidim/budgets/budget_list_item_cell.rb +40 -0
- data/app/cells/decidim/budgets/budget_m/data.erb +12 -0
- data/app/cells/decidim/budgets/budget_m/footer.erb +5 -0
- data/app/cells/decidim/budgets/budget_m_cell.rb +16 -0
- data/app/cells/decidim/budgets/budgets_header/show.erb +7 -0
- data/app/cells/decidim/budgets/budgets_header_cell.rb +14 -0
- data/app/cells/decidim/budgets/budgets_list/card_list.erb +7 -0
- data/app/cells/decidim/budgets/budgets_list/highlighted.erb +11 -0
- data/app/cells/decidim/budgets/budgets_list/show.erb +20 -0
- data/app/cells/decidim/budgets/budgets_list/voted.erb +43 -0
- data/app/cells/decidim/budgets/budgets_list_cell.rb +39 -0
- data/app/cells/decidim/budgets/limit_announcement_cell.rb +52 -0
- data/app/cells/decidim/budgets/project_list_item/project_data.erb +19 -0
- data/app/cells/decidim/budgets/project_list_item/project_data_vote_button.erb +15 -0
- data/app/cells/decidim/budgets/project_list_item/project_image.erb +5 -0
- data/app/cells/decidim/budgets/project_list_item/project_text.erb +23 -0
- data/app/cells/decidim/budgets/project_list_item/show.erb +5 -0
- data/app/cells/decidim/budgets/project_list_item_cell.rb +66 -0
- data/app/cells/decidim/budgets/project_m/data.erb +3 -3
- data/app/cells/decidim/budgets/project_m/footer.erb +1 -1
- data/app/cells/decidim/budgets/project_m_cell.rb +4 -0
- data/app/cells/decidim/budgets/project_selected_status_cell.rb +28 -0
- data/app/cells/decidim/budgets/project_tags/show.erb +5 -0
- data/app/cells/decidim/budgets/project_tags_cell.rb +18 -0
- data/app/cells/decidim/budgets/project_voted_hint_cell.rb +33 -0
- data/app/cells/decidim/budgets/project_votes_count_cell.rb +44 -0
- data/app/commands/decidim/budgets/add_line_item.rb +7 -10
- data/app/commands/decidim/budgets/admin/create_budget.rb +48 -0
- data/app/commands/decidim/budgets/admin/create_project.rb +26 -11
- data/app/commands/decidim/budgets/admin/destroy_budget.rb +42 -0
- data/app/commands/decidim/budgets/admin/import_proposals_to_budgets.rb +26 -25
- data/app/commands/decidim/budgets/admin/update_budget.rb +48 -0
- data/app/commands/decidim/budgets/admin/update_project.rb +20 -2
- data/app/commands/decidim/budgets/checkout.rb +7 -6
- data/app/commands/decidim/budgets/remove_line_item.rb +3 -2
- data/app/controllers/concerns/decidim/budgets/needs_current_order.rb +18 -2
- data/app/controllers/concerns/decidim/budgets/orderable.rb +57 -0
- data/app/controllers/decidim/budgets/admin/application_controller.rb +10 -2
- data/app/controllers/decidim/budgets/admin/attachment_collections_controller.rb +1 -1
- data/app/controllers/decidim/budgets/admin/attachments_controller.rb +2 -2
- data/app/controllers/decidim/budgets/admin/budgets_controller.rb +82 -0
- data/app/controllers/decidim/budgets/admin/projects_controller.rb +15 -12
- data/app/controllers/decidim/budgets/admin/proposals_imports_controller.rb +10 -2
- data/app/controllers/decidim/budgets/application_controller.rb +23 -0
- data/app/controllers/decidim/budgets/budgets_controller.rb +24 -0
- data/app/controllers/decidim/budgets/line_items_controller.rb +10 -6
- data/app/controllers/decidim/budgets/orders_controller.rb +20 -6
- data/app/controllers/decidim/budgets/projects_controller.rb +24 -19
- data/app/forms/decidim/budgets/admin/budget_form.rb +39 -0
- data/app/forms/decidim/budgets/admin/component_form.rb +44 -0
- data/app/forms/decidim/budgets/admin/project_form.rb +25 -9
- data/app/forms/decidim/budgets/admin/project_import_proposals_form.rb +4 -0
- data/app/helpers/decidim/budgets/admin/application_helper.rb +13 -0
- data/app/helpers/decidim/budgets/application_helper.rb +10 -0
- data/app/helpers/decidim/budgets/projects_helper.rb +13 -0
- data/app/jobs/decidim/budgets/send_order_summary_job.rb +15 -0
- data/app/mailers/decidim/budgets/order_summary_mailer.rb +36 -0
- data/app/models/decidim/budgets/budget.rb +34 -0
- data/app/models/decidim/budgets/line_item.rb +4 -4
- data/app/models/decidim/budgets/order.rb +47 -16
- data/app/models/decidim/budgets/project.rb +37 -4
- data/app/permissions/decidim/budgets/admin/permissions.rb +23 -10
- data/app/permissions/decidim/budgets/permissions.rb +28 -6
- data/app/presenters/decidim/budgets/admin_log/budget_presenter.rb +42 -0
- data/app/queries/decidim/budgets/filtered_projects.rb +9 -1
- data/app/queries/decidim/budgets/metrics/budget_followers_metric_measure.rb +3 -2
- data/app/queries/decidim/budgets/metrics/budget_participants_metric_measure.rb +6 -5
- data/app/serializers/decidim/budgets/data_portability_budgets_order_serializer.rb +3 -2
- data/app/services/decidim/budgets/project_search.rb +12 -24
- data/app/types/decidim/budgets/budget_type.rb +24 -0
- data/app/types/decidim/budgets/budgets_type.rb +6 -6
- data/app/types/decidim/budgets/project_type.rb +2 -1
- data/app/views/decidim/budgets/admin/budgets/_form.html.erb +23 -0
- data/app/views/decidim/budgets/admin/budgets/edit.html.erb +7 -0
- data/app/views/decidim/budgets/admin/budgets/index.html.erb +58 -0
- data/app/views/decidim/budgets/admin/budgets/new.html.erb +7 -0
- data/app/views/decidim/budgets/admin/projects/_form.html.erb +15 -10
- data/app/views/decidim/budgets/admin/projects/edit.html.erb +2 -2
- data/app/views/decidim/budgets/admin/projects/index.html.erb +20 -7
- data/app/views/decidim/budgets/admin/projects/new.html.erb +2 -2
- data/app/views/decidim/budgets/admin/projects/proposals_picker.html.erb +1 -0
- data/app/views/decidim/budgets/admin/proposals_imports/new.html.erb +1 -1
- data/app/views/decidim/budgets/budgets/index.html.erb +5 -0
- data/app/views/decidim/budgets/order_summary_mailer/order_summary.html.erb +22 -0
- data/app/views/decidim/budgets/projects/_budget_confirm.html.erb +3 -3
- data/app/views/decidim/budgets/projects/_budget_summary.html.erb +26 -7
- data/app/views/decidim/budgets/projects/_filters.html.erb +15 -7
- data/app/views/decidim/budgets/projects/_linked_projects.html.erb +2 -2
- data/app/views/decidim/budgets/projects/_order_progress.html.erb +14 -18
- data/app/views/decidim/budgets/projects/_order_selected_projects.html.erb +3 -3
- data/app/views/decidim/budgets/projects/_project.html.erb +1 -57
- data/app/views/decidim/budgets/projects/_project_budget_button.html.erb +36 -7
- data/app/views/decidim/budgets/projects/_projects.html.erb +8 -1
- data/app/views/decidim/budgets/projects/index.html.erb +15 -7
- data/app/views/decidim/budgets/projects/index.js.erb +8 -0
- data/app/views/decidim/budgets/projects/show.html.erb +22 -13
- data/config/locales/am-ET.yml +1 -0
- data/config/locales/ar.yml +2 -16
- data/config/locales/bg-BG.yml +7 -0
- data/config/locales/bg.yml +6 -0
- data/config/locales/ca.yml +125 -11
- data/config/locales/cs.yml +148 -34
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/da.yml +1 -0
- data/config/locales/de.yml +143 -29
- data/config/locales/el.yml +168 -0
- data/config/locales/en.yml +125 -11
- data/config/locales/eo.yml +1 -0
- data/config/locales/es-MX.yml +125 -11
- data/config/locales/es-PY.yml +125 -11
- data/config/locales/es.yml +125 -11
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/et.yml +1 -0
- data/config/locales/eu.yml +5 -13
- data/config/locales/fi-plain.yml +126 -12
- data/config/locales/fi.yml +136 -22
- data/config/locales/fr-CA.yml +267 -0
- data/config/locales/fr.yml +125 -11
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +70 -15
- data/config/locales/hr-HR.yml +1 -0
- data/config/locales/hr.yml +1 -0
- data/config/locales/hu.yml +18 -12
- data/config/locales/id-ID.yml +2 -11
- data/config/locales/is-IS.yml +0 -11
- data/config/locales/is.yml +114 -0
- data/config/locales/it.yml +96 -12
- data/config/locales/ja-JP.yml +172 -0
- data/config/locales/ja.yml +262 -0
- data/config/locales/ko-KR.yml +1 -0
- data/config/locales/ko.yml +1 -0
- data/config/locales/lt-LT.yml +1 -0
- data/config/locales/lt.yml +1 -0
- data/config/locales/lv.yml +164 -0
- data/config/locales/mt-MT.yml +1 -0
- data/config/locales/mt.yml +1 -0
- data/config/locales/nl.yml +112 -12
- data/config/locales/no.yml +42 -13
- data/config/locales/om-ET.yml +1 -0
- data/config/locales/pl.yml +175 -61
- data/config/locales/pt-BR.yml +3 -13
- data/config/locales/pt.yml +62 -46
- data/config/locales/ro-RO.yml +172 -0
- data/config/locales/ru.yml +2 -14
- data/config/locales/si-LK.yml +1 -0
- data/config/locales/sk-SK.yml +180 -0
- data/config/locales/sk.yml +166 -0
- data/config/locales/sl.yml +1 -0
- data/config/locales/so-SO.yml +1 -0
- data/config/locales/sr-CS.yml +27 -0
- data/config/locales/sv.yml +125 -11
- data/config/locales/sw-KE.yml +1 -0
- data/config/locales/ti-ER.yml +1 -0
- data/config/locales/tr-TR.yml +152 -38
- data/config/locales/uk.yml +2 -14
- data/config/locales/vi-VN.yml +1 -0
- data/config/locales/vi.yml +1 -0
- data/config/locales/zh-CN.yml +260 -0
- data/config/locales/zh-TW.yml +1 -0
- data/db/migrate/20200617105120_create_decidim_budgets.rb +15 -0
- data/db/migrate/20200629072626_rename_budget_to_budget_ammount.rb +7 -0
- data/db/migrate/20200629134013_add_budget_reference_to_project.rb +7 -0
- data/db/migrate/20200706142609_add_budget_reference_to_order.rb +7 -0
- data/db/migrate/20200714103519_move_budgets_to_own_model.rb +109 -0
- data/db/migrate/20200717140012_add_scope_to_budgets.rb +7 -0
- data/db/migrate/20200728075039_add_selected_at_to_project.rb +7 -0
- data/db/migrate/20200804175222_votes_enabled_to_votes_choices.rb +35 -0
- data/db/migrate/20200827154129_add_commentable_counter_cache_to_projects.rb +9 -0
- data/lib/decidim/budgets.rb +1 -0
- data/lib/decidim/budgets/admin_engine.rb +12 -5
- data/lib/decidim/budgets/component.rb +87 -38
- data/lib/decidim/budgets/engine.rb +8 -6
- data/lib/decidim/budgets/seeds/city.jpeg +0 -0
- data/lib/decidim/budgets/test/factories.rb +71 -9
- data/lib/decidim/budgets/version.rb +1 -1
- data/lib/decidim/budgets/workflows.rb +17 -0
- data/lib/decidim/budgets/workflows/all.rb +20 -0
- data/lib/decidim/budgets/workflows/base.rb +132 -0
- data/lib/decidim/budgets/workflows/one.rb +33 -0
- metadata +123 -19
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
class SendOrderSummaryJob < ApplicationJob
|
6
|
+
queue_as :default
|
7
|
+
|
8
|
+
def perform(order)
|
9
|
+
return if order&.user&.email.blank?
|
10
|
+
|
11
|
+
OrderSummaryMailer.order_summary(order).deliver_now
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
class OrderSummaryMailer < Decidim::ApplicationMailer
|
6
|
+
include Decidim::TranslationsHelper
|
7
|
+
include Decidim::SanitizeHelper
|
8
|
+
|
9
|
+
helper Decidim::TranslationsHelper
|
10
|
+
|
11
|
+
# Send an email to an user with the summary of the order.
|
12
|
+
#
|
13
|
+
# order - the order that was just created
|
14
|
+
def order_summary(order)
|
15
|
+
user = order.user
|
16
|
+
|
17
|
+
with_user(user) do
|
18
|
+
@user = user
|
19
|
+
@order = order
|
20
|
+
@budget = order.budget
|
21
|
+
@space = order.budget.participatory_space
|
22
|
+
@component = order.budget.component
|
23
|
+
@organization = order.budget.participatory_space.organization
|
24
|
+
|
25
|
+
subject = I18n.t(
|
26
|
+
"order_summary.subject",
|
27
|
+
scope: "decidim.budgets.order_summary_mailer",
|
28
|
+
budget_name: translated_attribute(@budget.title),
|
29
|
+
space_name: translated_attribute(@space.title)
|
30
|
+
)
|
31
|
+
mail(to: user.email, subject: subject)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
# The data store for a budget in the Decidim::Budgets component.
|
6
|
+
class Budget < ApplicationRecord
|
7
|
+
include Decidim::Resourceable
|
8
|
+
include Decidim::ScopableResource
|
9
|
+
include Decidim::HasComponent
|
10
|
+
include Decidim::Searchable
|
11
|
+
include Traceable
|
12
|
+
include Loggable
|
13
|
+
|
14
|
+
component_manifest_name "budgets"
|
15
|
+
|
16
|
+
has_many :projects, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Project", inverse_of: :budget, dependent: :destroy
|
17
|
+
has_many :orders, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Order", inverse_of: :budget, dependent: :destroy
|
18
|
+
|
19
|
+
delegate :participatory_space, :manifest, :settings, to: :component
|
20
|
+
|
21
|
+
searchable_fields({
|
22
|
+
participatory_space: { component: :participatory_space },
|
23
|
+
A: :title,
|
24
|
+
D: [:description, :total_budget]
|
25
|
+
},
|
26
|
+
index_on_create: ->(budget) { budget.visible? },
|
27
|
+
index_on_update: ->(budget) { budget.visible? })
|
28
|
+
|
29
|
+
def self.log_presenter_class_for(_log)
|
30
|
+
Decidim::Budgets::AdminLog::BudgetPresenter
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -2,19 +2,19 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Budgets
|
5
|
-
# The data store for a LineItem in the
|
5
|
+
# The data store for a LineItem in the Budget resource. It describes an
|
6
6
|
# association between an order and a project.
|
7
7
|
class LineItem < Budgets::ApplicationRecord
|
8
8
|
belongs_to :order, class_name: "Decidim::Budgets::Order", foreign_key: "decidim_order_id"
|
9
9
|
belongs_to :project, class_name: "Decidim::Budgets::Project", foreign_key: "decidim_project_id"
|
10
10
|
|
11
11
|
validates :order, uniqueness: { scope: :project }
|
12
|
-
validate :
|
12
|
+
validate :same_budget
|
13
13
|
|
14
|
-
def
|
14
|
+
def same_budget
|
15
15
|
return unless order && project
|
16
16
|
|
17
|
-
errors.add(:order, :invalid) unless order.
|
17
|
+
errors.add(:order, :invalid) unless order.budget == project.budget
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -5,18 +5,17 @@ module Decidim
|
|
5
5
|
# The data store for a Order in the Decidim::Budgets component. It is unique for each
|
6
6
|
# user and component and contains a collection of projects
|
7
7
|
class Order < Budgets::ApplicationRecord
|
8
|
-
include Decidim::HasComponent
|
9
8
|
include Decidim::DataPortability
|
10
9
|
include Decidim::NewsletterParticipant
|
11
10
|
|
12
|
-
component_manifest_name "budgets"
|
13
|
-
|
14
11
|
belongs_to :user, class_name: "Decidim::User", foreign_key: "decidim_user_id"
|
15
|
-
|
12
|
+
belongs_to :budget, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Budget", inverse_of: :orders
|
13
|
+
has_one :component, through: :budget, foreign_key: "decidim_component_id", class_name: "Decidim::Component"
|
16
14
|
has_many :line_items, class_name: "Decidim::Budgets::LineItem", foreign_key: "decidim_order_id", dependent: :destroy
|
17
15
|
has_many :projects, through: :line_items, class_name: "Decidim::Budgets::Project", foreign_key: "decidim_project_id"
|
18
16
|
|
19
|
-
validates :user, uniqueness: { scope: :
|
17
|
+
validates :user, uniqueness: { scope: :budget }
|
18
|
+
validates :budget, presence: true
|
20
19
|
validate :user_belongs_to_organization
|
21
20
|
|
22
21
|
validates :total_budget, numericality: {
|
@@ -27,12 +26,14 @@ module Decidim
|
|
27
26
|
less_than_or_equal_to: :maximum_budget
|
28
27
|
}
|
29
28
|
|
29
|
+
validate :reach_minimum_projects, if: :checked_out?
|
30
|
+
|
30
31
|
scope :finished, -> { where.not(checked_out_at: nil) }
|
31
32
|
scope :pending, -> { where(checked_out_at: nil) }
|
32
33
|
|
33
34
|
# Public: Returns the sum of project budgets
|
34
35
|
def total_budget
|
35
|
-
projects.to_a.sum(&:
|
36
|
+
projects.to_a.sum(&:budget_amount)
|
36
37
|
end
|
37
38
|
|
38
39
|
# Public: Returns true if the order has been checked out
|
@@ -42,26 +43,45 @@ module Decidim
|
|
42
43
|
|
43
44
|
# Public: Check if the order total budget is enough to checkout
|
44
45
|
def can_checkout?
|
45
|
-
|
46
|
+
if minimum_projects_rule?
|
47
|
+
projects.count >= minimum_projects
|
48
|
+
else
|
49
|
+
total_budget.to_f >= minimum_budget
|
50
|
+
end
|
46
51
|
end
|
47
52
|
|
48
53
|
# Public: Returns the order budget percent from the settings total budget
|
49
54
|
def budget_percent
|
50
|
-
(total_budget.to_f /
|
55
|
+
(total_budget.to_f / budget.total_budget.to_f) * 100
|
51
56
|
end
|
52
57
|
|
53
58
|
# Public: Returns the required minimum budget to checkout
|
54
59
|
def minimum_budget
|
55
|
-
return 0 unless
|
60
|
+
return 0 unless budget
|
61
|
+
return 0 if minimum_projects_rule?
|
56
62
|
|
57
|
-
|
63
|
+
budget.total_budget.to_f * (budget.settings.vote_threshold_percent.to_f / 100)
|
58
64
|
end
|
59
65
|
|
60
66
|
# Public: Returns the required maximum budget to checkout
|
61
67
|
def maximum_budget
|
62
|
-
return 0 unless
|
68
|
+
return 0 unless budget
|
69
|
+
|
70
|
+
budget.total_budget.to_f
|
71
|
+
end
|
72
|
+
|
73
|
+
# Public: Returns if it is required a minimum projects limit to checkout
|
74
|
+
def minimum_projects_rule?
|
75
|
+
return unless budget
|
63
76
|
|
64
|
-
|
77
|
+
budget.settings.vote_rule_minimum_budget_projects_enabled
|
78
|
+
end
|
79
|
+
|
80
|
+
# Public: Returns the required minimum projects to checkout
|
81
|
+
def minimum_projects
|
82
|
+
return 0 unless budget
|
83
|
+
|
84
|
+
budget.settings.vote_minimum_budget_projects_number
|
65
85
|
end
|
66
86
|
|
67
87
|
def self.user_collection(user)
|
@@ -73,20 +93,31 @@ module Decidim
|
|
73
93
|
end
|
74
94
|
|
75
95
|
def self.newsletter_participant_ids(component)
|
76
|
-
Decidim::Budgets::Order.
|
77
|
-
.
|
78
|
-
.
|
96
|
+
Decidim::Budgets::Order.finished
|
97
|
+
.joins(budget: [:component])
|
98
|
+
.where(budget: {
|
99
|
+
decidim_components: { id: component.id }
|
100
|
+
})
|
101
|
+
.group(:decidim_user_id)
|
102
|
+
.pluck(:decidim_user_id)
|
103
|
+
.flatten.compact
|
79
104
|
end
|
80
105
|
|
81
106
|
private
|
82
107
|
|
83
108
|
def user_belongs_to_organization
|
84
|
-
organization = component
|
109
|
+
organization = budget.try(:component).try(:organization)
|
85
110
|
|
86
111
|
return if !user || !organization
|
87
112
|
|
88
113
|
errors.add(:user, :invalid) unless user.organization == organization
|
89
114
|
end
|
115
|
+
|
116
|
+
def reach_minimum_projects
|
117
|
+
return unless minimum_projects_rule?
|
118
|
+
|
119
|
+
errors.add(:projects, :invalid) if minimum_projects > projects.count
|
120
|
+
end
|
90
121
|
end
|
91
122
|
end
|
92
123
|
end
|
@@ -6,8 +6,7 @@ module Decidim
|
|
6
6
|
# title, description and any other useful information to render a custom project.
|
7
7
|
class Project < Budgets::ApplicationRecord
|
8
8
|
include Decidim::Resourceable
|
9
|
-
include Decidim::
|
10
|
-
include Decidim::ScopableComponent
|
9
|
+
include Decidim::ScopableResource
|
11
10
|
include Decidim::HasCategory
|
12
11
|
include Decidim::HasAttachments
|
13
12
|
include Decidim::HasAttachmentCollections
|
@@ -18,11 +17,17 @@ module Decidim
|
|
18
17
|
include Decidim::Loggable
|
19
18
|
include Decidim::Randomable
|
20
19
|
include Decidim::Searchable
|
20
|
+
include Decidim::TranslatableResource
|
21
21
|
|
22
|
-
|
22
|
+
translatable_fields :title, :description
|
23
|
+
|
24
|
+
belongs_to :budget, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Budget", inverse_of: :projects
|
25
|
+
has_one :component, through: :budget, foreign_key: "decidim_component_id", class_name: "Decidim::Component"
|
23
26
|
has_many :line_items, class_name: "Decidim::Budgets::LineItem", foreign_key: "decidim_project_id", dependent: :destroy
|
24
27
|
has_many :orders, through: :line_items, foreign_key: "decidim_project_id", class_name: "Decidim::Budgets::Order"
|
25
28
|
|
29
|
+
delegate :organization, :participatory_space, to: :component
|
30
|
+
|
26
31
|
searchable_fields(
|
27
32
|
scope_id: :decidim_scope_id,
|
28
33
|
participatory_space: { component: :participatory_space },
|
@@ -31,10 +36,26 @@ module Decidim
|
|
31
36
|
datetime: :created_at
|
32
37
|
)
|
33
38
|
|
39
|
+
def self.ordered_ids(ids)
|
40
|
+
# Make sure each ID in the matching text has a "," character as their
|
41
|
+
# delimiter. Otherwise e.g. ID 2 would match ID "26" in the original
|
42
|
+
# array. This is why we search for match ",2," instead to get the actual
|
43
|
+
# position for ID 2.
|
44
|
+
order(Arel.sql("position(concat(',', id::text, ',') in ',#{ids.join(",")},')"))
|
45
|
+
end
|
46
|
+
|
34
47
|
def self.log_presenter_class_for(_log)
|
35
48
|
Decidim::Budgets::AdminLog::ProjectPresenter
|
36
49
|
end
|
37
50
|
|
51
|
+
def polymorphic_resource_path(url_params)
|
52
|
+
::Decidim::ResourceLocatorPresenter.new([budget, self]).path(url_params)
|
53
|
+
end
|
54
|
+
|
55
|
+
def polymorphic_resource_url(url_params)
|
56
|
+
::Decidim::ResourceLocatorPresenter.new([budget, self]).url(url_params)
|
57
|
+
end
|
58
|
+
|
38
59
|
# Public: Overrides the `commentable?` Commentable concern method.
|
39
60
|
def commentable?
|
40
61
|
component.settings.comments_enabled?
|
@@ -67,7 +88,19 @@ module Decidim
|
|
67
88
|
|
68
89
|
# Public: Whether the object can have new comments or not.
|
69
90
|
def user_allowed_to_comment?(user)
|
70
|
-
can_participate_in_space?(user)
|
91
|
+
component.can_participate_in_space?(user)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Public: Checks if the project has been selected or not.
|
95
|
+
#
|
96
|
+
# Returns Boolean.
|
97
|
+
def selected?
|
98
|
+
selected_at.present?
|
99
|
+
end
|
100
|
+
|
101
|
+
# Public: Returns the attachment context for this record.
|
102
|
+
def attachment_context
|
103
|
+
:admin
|
71
104
|
end
|
72
105
|
end
|
73
106
|
end
|
@@ -5,18 +5,27 @@ module Decidim
|
|
5
5
|
module Admin
|
6
6
|
class Permissions < Decidim::DefaultPermissions
|
7
7
|
def permissions
|
8
|
-
# The public part needs to be implemented yet
|
9
8
|
return permission_action if permission_action.scope != :admin
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
10
|
+
case permission_action.subject
|
11
|
+
when :budget
|
12
|
+
case permission_action.action
|
13
|
+
when :create, :read
|
14
|
+
allow!
|
15
|
+
when :update
|
16
|
+
toggle_allow(budget)
|
17
|
+
when :delete, :publish, :unpublish
|
18
|
+
toggle_allow(budget && budget.projects.empty?)
|
19
|
+
end
|
20
|
+
when :project, :projects
|
21
|
+
case permission_action.action
|
22
|
+
when :create
|
23
|
+
permission_action.allow!
|
24
|
+
when :import_proposals
|
25
|
+
permission_action.allow!
|
26
|
+
when :update, :destroy
|
27
|
+
permission_action.allow! if project.present?
|
28
|
+
end
|
20
29
|
end
|
21
30
|
|
22
31
|
permission_action
|
@@ -24,6 +33,10 @@ module Decidim
|
|
24
33
|
|
25
34
|
private
|
26
35
|
|
36
|
+
def budget
|
37
|
+
@budget ||= context.fetch(:budget, nil)
|
38
|
+
end
|
39
|
+
|
27
40
|
def project
|
28
41
|
@project ||= context.fetch(:project, nil)
|
29
42
|
end
|
@@ -10,15 +10,19 @@ module Decidim
|
|
10
10
|
return Decidim::Budgets::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
|
11
11
|
return permission_action if permission_action.scope != :public
|
12
12
|
|
13
|
-
return permission_action
|
13
|
+
return permission_action unless [:project, :order].include? permission_action.subject
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
if permission_action.subject == :project
|
16
|
+
case permission_action.action
|
17
|
+
when :vote
|
18
|
+
can_vote?(false) if can_vote_project?(project || order&.projects&.first)
|
19
|
+
when :report
|
20
|
+
permission_action.allow!
|
21
|
+
end
|
20
22
|
end
|
21
23
|
|
24
|
+
can_vote?(true) if permission_action.action == :create && permission_action.subject == :order
|
25
|
+
|
22
26
|
permission_action
|
23
27
|
end
|
24
28
|
|
@@ -32,6 +36,24 @@ module Decidim
|
|
32
36
|
@order ||= context.fetch(:order, nil)
|
33
37
|
end
|
34
38
|
|
39
|
+
def budget
|
40
|
+
@budget ||= context.fetch(:budget, nil)
|
41
|
+
end
|
42
|
+
|
43
|
+
def workflow
|
44
|
+
@workflow ||= context.fetch(:workflow, nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
def can_vote?(active_allow)
|
48
|
+
is_allowed = workflow.vote_allowed?(budget)
|
49
|
+
|
50
|
+
if !is_allowed
|
51
|
+
disallow!
|
52
|
+
elsif active_allow
|
53
|
+
allow!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
35
57
|
def can_vote_project?(a_project)
|
36
58
|
is_allowed = a_project && authorized?(:vote, resource: project)
|
37
59
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
module AdminLog
|
6
|
+
# This class holds the logic to present a `Decidim::Budgets::Budget`
|
7
|
+
# for the `AdminLog` log.
|
8
|
+
#
|
9
|
+
# Usage should be automatic and you shouldn't need to call this class
|
10
|
+
# directly, but here's an example:
|
11
|
+
#
|
12
|
+
# action_log = Decidim::ActionLog.last
|
13
|
+
# view_helpers # => this comes from the views
|
14
|
+
# BudgetPresenter.new(action_log, view_helpers).present
|
15
|
+
class BudgetPresenter < Decidim::Log::BasePresenter
|
16
|
+
private
|
17
|
+
|
18
|
+
def action_string
|
19
|
+
case action
|
20
|
+
when "create", "delete", "update"
|
21
|
+
"decidim.budgets.admin_log.budget.#{action}"
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def diff_fields_mapping
|
28
|
+
{
|
29
|
+
title: :i18n,
|
30
|
+
weight: :integer,
|
31
|
+
description: :i18n,
|
32
|
+
total_budget: :currency
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def i18n_labels_scope
|
37
|
+
"activemodel.attributes.budget"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|