decidim-department_admin 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +132 -0
  4. data/Rakefile +9 -0
  5. data/app/controllers/decidim/department_admin/admin/application_controller.rb +15 -0
  6. data/app/controllers/decidim/department_admin/application_controller.rb +13 -0
  7. data/app/decorators/decidim/admin/newsletters_controller_decorator.rb +30 -0
  8. data/app/decorators/decidim/admin/users_controller_decorator.rb +128 -0
  9. data/app/decorators/decidim/area_decorator.rb +44 -0
  10. data/app/decorators/decidim/assemblies/admin/assemblies_controller_decorator.rb +25 -0
  11. data/app/decorators/decidim/assemblies/admin/assemblies_helper_decorator.rb +24 -0
  12. data/app/decorators/decidim/assemblies/create_assembly_decorator.rb +19 -0
  13. data/app/decorators/decidim/assemblies/parent_assemblies_for_select_decorator.rb +38 -0
  14. data/app/decorators/decidim/assemblies/permissions_decorator.rb +22 -0
  15. data/app/decorators/decidim/assemblies/update_assembly_decorator.rb +19 -0
  16. data/app/decorators/decidim/assemblies_decorator.rb +21 -0
  17. data/app/decorators/decidim/assemblies_with_user_role_decorator.rb +27 -0
  18. data/app/decorators/decidim/conference_form_decorator.rb +23 -0
  19. data/app/decorators/decidim/conferences/admin/conferences_controller_decorator.rb +27 -0
  20. data/app/decorators/decidim/conferences/create_conference_decorator.rb +52 -0
  21. data/app/decorators/decidim/conferences/permissions_decorator.rb +24 -0
  22. data/app/decorators/decidim/conferences/update_conference_decorator.rb +21 -0
  23. data/app/decorators/decidim/conferences_decorator.rb +27 -0
  24. data/app/decorators/decidim/conferences_with_user_role_decorator.rb +29 -0
  25. data/app/decorators/decidim/decidim_form_helper_decorator.rb +23 -0
  26. data/app/decorators/decidim/invite_user_decorator.rb +56 -0
  27. data/app/decorators/decidim/invite_user_form_decorator.rb +45 -0
  28. data/app/decorators/decidim/newsletter_decorator.rb +20 -0
  29. data/app/decorators/decidim/newsletters_helper_decorator.rb +44 -0
  30. data/app/decorators/decidim/participatory_process_decorator.rb +21 -0
  31. data/app/decorators/decidim/participatory_process_group_decorator.rb +17 -0
  32. data/app/decorators/decidim/participatory_processes/admin/participatory_processes_controller_decorator.rb +25 -0
  33. data/app/decorators/decidim/participatory_processes/create_participatory_process_decorator.rb +19 -0
  34. data/app/decorators/decidim/participatory_processes/permissions_decorator.rb +22 -0
  35. data/app/decorators/decidim/participatory_processes/update_participatory_process_decorator.rb +19 -0
  36. data/app/decorators/decidim/participatory_processes_with_user_role_decorator.rb +27 -0
  37. data/app/decorators/decidim/user_decorator.rb +59 -0
  38. data/app/decorators/lib/decidim/participatory_space_resourceable_decorator.rb +33 -0
  39. data/app/helpers/decidim/admin/user_roles_helper.rb +25 -0
  40. data/app/helpers/decidim/department_admin/application_helper.rb +54 -0
  41. data/app/models/decidim/participatory_space_role_config/department_admin.rb +8 -0
  42. data/app/overrides/decidim/admin/shared/add_radio_buttons_to_filters.rb +6 -0
  43. data/app/packs/entrypoints/decidim_department_admin.js +4 -0
  44. data/app/packs/entrypoints/decidim_department_admin.scss +1 -0
  45. data/app/packs/images/decidim/department_admin/icon.svg +1 -0
  46. data/app/packs/stylesheets/decidim/admin/department_admin.scss +7 -0
  47. data/app/permissions/decidim/assemblies/participatory_space_permissions.rb +14 -0
  48. data/app/permissions/decidim/conferences/participatory_space_permissions.rb +17 -0
  49. data/app/permissions/decidim/department_admin/permissions.rb +240 -0
  50. data/app/permissions/decidim/participatory_processes/participatory_space_permissions.rb +14 -0
  51. data/app/queries/decidim/admin/user_admin_by_space_name_filter.rb +67 -0
  52. data/app/queries/decidim/admin/user_admin_filter.rb +50 -0
  53. data/app/views/decidim/admin/users/_filters.html.erb +32 -0
  54. data/app/views/decidim/admin/users/_form.html.erb +36 -0
  55. data/app/views/decidim/admin/users/index.html.erb +91 -0
  56. data/app/views/decidim/admin/users/show.html.erb +98 -0
  57. data/app/views/decidim/assemblies/admin/assemblies/index.html.erb +139 -0
  58. data/app/views/decidim/conferences/admin/conferences/_form.html.erb +134 -0
  59. data/app/views/decidim/conferences/admin/conferences/index.html.erb +78 -0
  60. data/app/views/decidim/participatory_processes/admin/participatory_processes/index.html.erb +117 -0
  61. data/config/assets.rb +27 -0
  62. data/config/i18n-tasks.yml +148 -0
  63. data/config/initializers/user_roles.rb +4 -0
  64. data/config/locales/ca.yml +61 -0
  65. data/config/locales/cs.yml +46 -0
  66. data/config/locales/en.yml +61 -0
  67. data/config/locales/es.yml +61 -0
  68. data/db/migrate/20190328130102_create_department_admin_areas.rb +10 -0
  69. data/db/migrate/20210420143021_add_area_to_conferences.rb +7 -0
  70. data/lib/decidim/department_admin/admin.rb +10 -0
  71. data/lib/decidim/department_admin/admin_engine.rb +27 -0
  72. data/lib/decidim/department_admin/engine.rb +136 -0
  73. data/lib/decidim/department_admin/test/factories.rb +17 -0
  74. data/lib/decidim/department_admin/version.rb +11 -0
  75. data/lib/decidim/department_admin.rb +15 -0
  76. metadata +189 -0
data/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # Decidim::DepartmentAdmin
2
+
3
+ This Dedicim's module produces a new \"department admin\" role which restricts the permissions of an Admin into participatory spaces of a given Area.
4
+
5
+ The module currently only affects the following participatory spaces and admin blocks:
6
+
7
+ - Participatory Processes: administer processes with the same area as the user's one.
8
+ - Assemblies: administer assemblies with the same area as the user's one.
9
+ - Newsletters: send newsletters to participants in the spaces with the same area as user's one.
10
+ - Conferences: administer conferences with the same area as the user's one.
11
+
12
+ ## Usage
13
+
14
+ DepartmentAdmin will only affect users with the "department admin" role. The rest of the users should behave as usual.
15
+
16
+ To create a user with a department admin role, go to admin panel/PARTICIPANTS/Administrators/New Participant. There, select the "Administrador de departament" role, and then the area. Finally Invite the user.
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile if you would like to always have the latest (edge) version:
21
+
22
+ ```ruby
23
+ gem "decidim-department_admin", git: "https://github.com/gencat/decidim-module-department-admin.git"
24
+ ```
25
+
26
+ Or, add a line like the following to your application's Gemfile if you would like to have the latest stable from the version of your choice, in this case `0.4.x`:
27
+
28
+ ```ruby
29
+ gem "decidim-department_admin", "~> 0.4.2", git: "https://github.com/gencat/decidim-module-department-admin.git"
30
+ ```
31
+
32
+ Edit your app's `config/application.rb` file to enforce railties ordering:
33
+ ```ruby
34
+ module YourDecidimApp
35
+ class Application < Rails::Application
36
+
37
+ ...
38
+ config.railties_order = [:main_app, ::Decidim::DepartmentAdmin::Engine, :all]
39
+ ...
40
+
41
+ end
42
+ end
43
+ ```
44
+
45
+ And then execute:
46
+
47
+ ```bash
48
+ bundle
49
+ bundle exec rails decidim_department_admin:install:migrations
50
+ bundle exec rails db:migrate
51
+ ```
52
+
53
+ ## Overrides
54
+ Beware that this module overrides many core features of Decidim. Thus, modified features may have required to override, change or extend source code from Decidim.
55
+
56
+ Most of the times the overrides and modifications will be found in `app/decorators`.
57
+
58
+ ## How it works
59
+ Although some other artifacts exist, the key places to search for in this module are 3:
60
+ - lib/decidim/department_admin/engine.rb
61
+ - app/permissions/decidim/department_admin/permissions.rb
62
+ - app/decorators
63
+
64
+ ### Engine
65
+ The mission of the Engine in this module is to reconfigure the permissions_registry for some artifacts so that they depend upon `Decidim::DepartmentAdmin::Permissions` instead of their standard permissions chain.
66
+
67
+ The engine also configures de `app/decorators` directory to be loaded during rails initialization.
68
+
69
+ ### Custom Permissions
70
+ The `Decidim::DepartmentAdmin::Permissions` class is the responsible to allow all permissions related with the "departmen admin" role.
71
+
72
+ `Decidim::Assemblies::ParticipatorySpacePermissions`, `Decidim::ParticipatoryProcesses::ParticipatorySpacePermissions` and
73
+ `Decidim::Conferences::ParticipatorySpacePermissions` are subclassing `Decidim::DepartmentAdmin::Permissions` in order to force the permissions classes where they delegate.
74
+
75
+ ### Decorators
76
+ Inside `app/decorators` there are all the tricks done in order for department_admin module to work.
77
+
78
+ All decorator artifacts are extensions or modifications to the standard Decidim behavior.
79
+
80
+ ### Temporal fixes
81
+
82
+ #### Temporal fix: added & in case role_name check.
83
+
84
+ Currently, in the file:
85
+ - lib/decidim/participatory_space_resourceable.rb
86
+ we have overridden `user_role_config_for` method, in role_name case check.
87
+
88
+ The reason for this, is that this method is called from `user_role_config` in `Decidim::Admin::UserRolesHelper` file, with second param `role_name` that can be nil as it is called as `role&.role`.
89
+ This happens only when logged in user is Departmental Admin type and this can be possible because this module is only available in this repo.
90
+ So, to avoid error when role_name passed is nil, we override this param check with a simple `role_name&.to_sym`
91
+
92
+ In next versions, this issue will be patched in `decidim/decidim`, so this override could be removed:
93
+ - lib/decidim/participatory_space_resourceable.rb
94
+
95
+ ### Run tests
96
+
97
+ Create a dummy app in your application (if not present):
98
+
99
+ ```bash
100
+ bin/rails decidim:generate_external_test_app
101
+ cd spec/decidim_dummy_app/
102
+ bundle exec rails decidim_department_admin:install:migrations
103
+ RAILS_ENV=test bundle exec rails db:migrate
104
+ sed -ie '/^ class Application < Rails::Application/a config.railties_order = [:main_app, ::Decidim::DepartmentAdmin::Engine, :all]' config/application.rb
105
+ ```
106
+
107
+ This last line modifies dummy_app's `config/application.rb` file to enforce railties ordering, adding:
108
+ ```ruby
109
+ module DecidimDepartmentAdminTestApp
110
+ class Application < Rails::Application
111
+ config.railties_order = [:main_app, ::Decidim::DepartmentAdmin::Engine, :all]
112
+ ...
113
+
114
+ end
115
+ end
116
+ ```
117
+
118
+ And run tests:
119
+
120
+ ```bash
121
+ bundle exec rspec spec
122
+ ```
123
+
124
+ ## Contributing
125
+
126
+ See [Decidim](https://github.com/decidim/decidim).
127
+
128
+ ## License
129
+
130
+ This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
131
+
132
+ Authored by [CodiTramuntana](http://coditramuntana.com).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/dev/common_rake"
4
+
5
+ desc "Generates a dummy app for testing"
6
+ task test_app: "decidim:generate_external_test_app"
7
+
8
+ desc "Generates a development app."
9
+ task development_app: "decidim:generate_external_development_app"
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DepartmentAdmin
5
+ module Admin
6
+ # This controller is the abstract class from which all other controllers of
7
+ # this engine inherit.
8
+ #
9
+ # Note that it inherits from `Decidim::Admin::Components::BaseController`, which
10
+ # override its layout and provide all kinds of useful methods.
11
+ class ApplicationController < Decidim::Admin::Components::BaseController
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DepartmentAdmin
5
+ # This controller is the abstract class from which all other controllers of
6
+ # this engine inherit.
7
+ #
8
+ # Note that it inherits from `Decidim::Components::BaseController`, which
9
+ # override its layout and provide all kinds of useful methods.
10
+ class ApplicationController < Decidim::Components::BaseController
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "decidim/admin/newsletters_controller"
4
+
5
+ module Decidim::Admin::NewslettersControllerDecorator
6
+ # Sort Admins by role and area
7
+ def self.decorate
8
+ ::Decidim::Admin::NewslettersController.class_eval do
9
+ alias_method :original_collection, :collection
10
+
11
+ private
12
+
13
+ def collection
14
+ return original_collection unless current_user.department_admin?
15
+
16
+ @collection ||= Decidim::Newsletter.where(organization: current_organization)
17
+ .joins(author: :areas)
18
+ .where(department_admin_areas: { decidim_area_id: current_user_areas.pluck(:id) })
19
+ end
20
+
21
+ def current_user_areas
22
+ return unless current_user.department_admin?
23
+
24
+ current_user.areas
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ Decidim::Admin::NewslettersControllerDecorator.decorate
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "decidim/admin/users_controller"
4
+
5
+ # This decorator adds the capability to the controller to query users
6
+ # filtering by User role `department_admin`.
7
+ module Decidim::Admin::UsersControllerDecorator
8
+ # rubocop: disable Metrics/CyclomaticComplexity
9
+ # rubocop: disable Metrics/PerceivedComplexity
10
+ def self.decorate
11
+ # Sort Admins by role and area
12
+ ::Decidim::Admin::UsersController.class_eval do
13
+ alias_method :original_collection, :collection
14
+
15
+ include ::Decidim::DepartmentAdmin::ApplicationHelper
16
+ helper_method :roles_with_title, :filtered_collection
17
+
18
+ before_action :read_params, only: :index
19
+
20
+ def read_params
21
+ @role = params[:role]
22
+ @by_process_name = params[:filter_search] == "by_process_name"
23
+ term = params.dig(:q, :name_or_nickname_or_email_cont)
24
+ @search_text = term
25
+ end
26
+
27
+ def collection
28
+ @collection ||= begin
29
+ filtered = if @by_process_name
30
+ ::Decidim::Admin::UserAdminBySpaceNameFilter.for(@search_text, current_organization, current_locale)
31
+ else
32
+ ::Decidim::Admin::UserAdminFilter.for(original_collection, @search_text, @role, current_organization)
33
+ end
34
+ if current_user.department_admin?
35
+ filtered.joins(:areas)
36
+ .where("'department_admin' = ANY(roles)")
37
+ .where("decidim_areas.id": current_user.areas.pluck(:id))
38
+ else
39
+ filtered
40
+ end
41
+ end
42
+ end
43
+
44
+ # override decidim-admin/app/controllers/concerns/decidim/admin/filterable.rb#filtered_collection default behavior.
45
+ def filtered_collection
46
+ @filtered_collection ||= begin
47
+ users = @by_process_name ? collection : query.result
48
+ sorted_users = users.uniq.sort { |u_1, u_2| "#{u_1.active_role}||#{u_1.areas.first&.name}" <=> "#{u_2.active_role}||#{u_2.areas.first&.name}" }
49
+ paginate(Kaminari.paginate_array(sorted_users))
50
+ end
51
+ end
52
+
53
+ def show
54
+ locale = params[:locale] || "ca"
55
+ @user ||= original_collection.find(params[:id])
56
+ @spaces = []
57
+ @user.participatory_processes.each do |process|
58
+ type = if process.participatory_process_group
59
+ process.participatory_process_group&.title&.[](locale).presence || process.participatory_process_group&.title&.[]("ca")
60
+ else
61
+ t("models.user.fields.process_type", scope: "decidim.admin")
62
+ end
63
+ process_title = process.title[locale]
64
+ process_title = process.title["ca"] if process_title.blank?
65
+
66
+ @spaces.push("title" => process_title,
67
+ "type" => type,
68
+ "area" => process.area.nil? ? "" : process.area&.name&.[](locale),
69
+ "created_at" => process.created_at,
70
+ "private" => process.private_space?,
71
+ "published" => process.published?)
72
+ end
73
+
74
+ @user.assemblies.each do |assembly|
75
+ area_name = if assembly.area && assembly.area.name
76
+ assembly.area.name[locale]
77
+ else
78
+ ""
79
+ end
80
+
81
+ assembly_title = assembly.title[locale]
82
+ assembly_title = assembly.title["ca"] if assembly_title.blank?
83
+
84
+ @spaces.push("title" => assembly_title,
85
+ "type" => t("models.user.fields.assembly_type", scope: "decidim.admin"),
86
+ "area" => area_name,
87
+ "created_at" => assembly.created_at,
88
+ "private" => assembly.private_space?,
89
+ "published" => assembly.published?)
90
+ end
91
+
92
+ if Decidim::DepartmentAdmin.conferences_defined?
93
+ @user.conferences.each do |conference|
94
+ area_name = conference.area&.name.try(:[], locale) || ""
95
+
96
+ conference_title = conference.title[locale]
97
+ conference_title = conference.title["ca"] if conference_title.blank?
98
+
99
+ @spaces.push("title" => conference_title,
100
+ "type" => t("models.user.fields.conference_type", scope: "decidim.admin"),
101
+ "area" => area_name,
102
+ "created_at" => conference.created_at,
103
+ "private" => conference.private_space?,
104
+ "published" => conference.published?)
105
+ end
106
+ end
107
+
108
+ # rubocop: disable Style/NestedTernaryOperator
109
+ if (params[:sort_column] == "published" || params[:sort_column] == "private") && params[:sort_order] == "asc"
110
+ @spaces.sort! { |x, y| x[params[:sort_column]] ? 0 : (1 <=> y[params[:sort_column]] ? 0 : 1) }
111
+ elsif (params[:sort_column] == "published" || params[:sort_column] == "private") && params[:sort_order] == "desc"
112
+ @spaces.sort! { |x, y| y[params[:sort_column]] ? 0 : 1 <=> x[params[:sort_column]] ? 0 : 1 }
113
+ elsif params[:sort_column] && params[:sort_order] && params[:sort_order] == "asc"
114
+ @spaces.sort! { |x, y| x[params[:sort_column]] <=> y[params[:sort_column]] }
115
+ elsif params[:sort_column] && params[:sort_order] && params[:sort_order] == "desc"
116
+ @spaces.sort! { |x, y| y[params[:sort_column]] <=> x[params[:sort_column]] }
117
+ else
118
+ @spaces.sort! { |x, y| y["title"] <=> x["title"] }
119
+ end
120
+ # rubocop: enable Style/NestedTernaryOperator
121
+ end
122
+ end
123
+ end
124
+ # rubocop: enable Metrics/CyclomaticComplexity
125
+ # rubocop: enable Metrics/PerceivedComplexity
126
+ end
127
+
128
+ Decidim::Admin::UsersControllerDecorator.decorate
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "decidim/area"
4
+
5
+ module Decidim::AreaDecorator
6
+ def self.decorate
7
+ Decidim::Area.class_eval do
8
+ before_destroy :abort_if_department_admins
9
+
10
+ has_and_belongs_to_many :users,
11
+ -> { where('\'department_admin\'=ANY("decidim_users"."roles")') },
12
+ join_table: :department_admin_areas,
13
+ foreign_key: :decidim_area_id,
14
+ association_foreign_key: :decidim_user_id,
15
+ validate: false
16
+
17
+ has_many :participatory_process,
18
+ class_name: "ParticipatoryProcess",
19
+ foreign_key: "decidim_department_id"
20
+
21
+ has_many :assemblies,
22
+ class_name: "Assemblies",
23
+ foreign_key: "decidim_area_id"
24
+
25
+ if Decidim::DepartmentAdmin.conferences_defined?
26
+ has_many :conferences,
27
+ class_name: "Conferences",
28
+ foreign_key: "decidim_area_id"
29
+ end
30
+
31
+ def has_department_admins?
32
+ Decidim::User.where(organization:).any? do |u|
33
+ u.areas.exists?(id)
34
+ end
35
+ end
36
+
37
+ def abort_if_department_admins
38
+ throw(:abort) if has_department_admins?
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ Decidim::AreaDecorator.decorate
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::Assemblies::Admin::AssembliesControllerDecorator
4
+ #
5
+ # This decorator adds the capability to the controller to query assemblies
6
+ # filtering by User role `department_admin`.
7
+ #
8
+ def self.decorate
9
+ Decidim::Assemblies::Admin::AssembliesController.class_eval do
10
+ private
11
+
12
+ alias_method :original_organization_assemblies, :collection
13
+
14
+ def collection
15
+ if current_user.department_admin?
16
+ ::Decidim::Assemblies::AssembliesWithUserRole.for(current_user)
17
+ else
18
+ original_organization_assemblies
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ Decidim::Assemblies::Admin::AssembliesControllerDecorator.decorate
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::Assemblies::Admin::AssembliesHelperDecorator
4
+ #
5
+ # This decorator sends current_user as argument when it's a department admin.
6
+ #
7
+ def self.decorate
8
+ Decidim::Assemblies::Admin::AssembliesHelper.class_eval do
9
+ alias_method :parent_assemblies_for_select_original, :parent_assemblies_for_select
10
+
11
+ # Public: A collection of Assemblies that can be selected as parent
12
+ # assemblies for another assembly; to be used in forms.
13
+ def parent_assemblies_for_select
14
+ if current_user.department_admin?
15
+ @parent_assemblies_for_select ||= Decidim::Assemblies::ParentAssembliesForSelect.for(current_organization, current_assembly, current_user)
16
+ else
17
+ parent_assemblies_for_select_original
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ Decidim::Assemblies::Admin::AssembliesHelperDecorator.decorate
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::Assemblies::CreateAssemblyDecorator
4
+ # Intercepts the `call` method and forces the Area of the user if it is a
5
+ # department_admin user.
6
+ def self.decorate
7
+ Decidim::Assemblies::Admin::CreateAssembly.class_eval do
8
+ alias_method :original_call, :call
9
+
10
+ def call
11
+ author = form.current_user
12
+ form.area_id = author.areas.first.id if author.department_admin?
13
+ original_call
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Decidim::Assemblies::CreateAssemblyDecorator.decorate
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::Assemblies::ParentAssembliesForSelectDecorator
4
+ # This decorator adds current_user as an argument to be able to check
5
+ # it's department in the query and filter the assemblies by area.
6
+ def self.decorate
7
+ Decidim::Assemblies::ParentAssembliesForSelect.class_eval do
8
+ # Syntactic sugar to initialize the class and return the queried objects.
9
+ def self.for(organization, assembly, current_user = nil)
10
+ new(organization, assembly, current_user).query
11
+ end
12
+
13
+ # Initializes the class.
14
+ def initialize(organization, assembly, current_user)
15
+ @organization = organization
16
+ @assembly = assembly
17
+ @current_user = current_user
18
+ end
19
+
20
+ # Finds the available assemblies
21
+ #
22
+ # Returns an ActiveRecord::Relation.
23
+ def query
24
+ available_assemblies = if @current_user.present? && @current_user.department_admin?
25
+ Decidim::Assembly.where(area: @current_user.areas).where.not(id: @assembly)
26
+ else
27
+ Decidim::Assembly.where(organization: @organization).where.not(id: @assembly)
28
+ end
29
+
30
+ return available_assemblies if @assembly.blank?
31
+
32
+ available_assemblies.where.not(id: descendant_ids)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ Decidim::Assemblies::ParentAssembliesForSelectDecorator.decorate
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::Assemblies::PermissionsDecorator
4
+ def self.decorate
5
+ Decidim::Assemblies::Permissions.class_eval do
6
+ # Intercept the `has_manageable_assemblies?` method
7
+ # always returns true if the user is a department_admin. Otherwise delegates to the original method.
8
+ # This is a fix to avoid permissions crashing when there are no assemblies with the user's area.
9
+ alias_method :original_has_manageable_assemblies?, :has_manageable_assemblies?
10
+
11
+ # rubocop: disable Lint/UnusedMethodArgument
12
+ def has_manageable_assemblies?(role: :any)
13
+ return unless user
14
+
15
+ user.department_admin? || original_has_manageable_assemblies?
16
+ end
17
+ # rubocop: enable Lint/UnusedMethodArgument
18
+ end
19
+ end
20
+ end
21
+
22
+ Decidim::Assemblies::PermissionsDecorator.decorate
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::Assemblies::UpdateAssemblyDecorator
4
+ # Intercepts the `call` method and forces the Area of the user if it is a
5
+ # department_admin user.
6
+ def self.decorate
7
+ Decidim::Assemblies::Admin::UpdateAssembly.class_eval do
8
+ alias_method :original_call, :call
9
+
10
+ def call
11
+ author = form.current_user
12
+ form.area_id = author.areas.first.id if author.department_admin?
13
+ original_call
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Decidim::Assemblies::UpdateAssemblyDecorator.decorate
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency "decidim/assembly"
4
+
5
+ module Decidim::AssembliesDecorator
6
+ #
7
+ # This decorator adds required associations between Decidim::ParticipatoryProcess and Departaments.
8
+ #
9
+ def self.decorate
10
+ Decidim::Assembly.class_eval do
11
+ has_and_belongs_to_many :users_with_any_role,
12
+ class_name: "Decidim::User",
13
+ join_table: :decidim_assembly_user_roles,
14
+ foreign_key: :decidim_assembly_id,
15
+ association_foreign_key: :decidim_user_id,
16
+ validate: false
17
+ end
18
+ end
19
+ end
20
+
21
+ Decidim::AssembliesDecorator.decorate
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::AssembliesWithUserRoleDecorator
4
+ #
5
+ # This decorator adds the capability to query participatory_processes
6
+ # filtering by User role `department_admin`.
7
+ #
8
+ def self.decorate
9
+ Decidim::Assemblies::AssembliesWithUserRole.class_eval do
10
+ private
11
+
12
+ alias_method :assembly_ids_by_assemblies_user_table, :assembly_ids
13
+
14
+ def assembly_ids
15
+ ids = [assembly_ids_by_assemblies_user_table]
16
+ if user&.department_admin?
17
+ ids << ::Decidim::Assembly
18
+ .where("decidim_area_id" => user.areas.pluck(:id)).pluck(:id)
19
+ end
20
+
21
+ ::Decidim::Assembly.where(id: ids.flatten.uniq)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ Decidim::AssembliesWithUserRoleDecorator.decorate
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::ConferenceFormDecorator
4
+ #
5
+ # This decorator adds the attribute area_id to the ConferenceForm and
6
+ # extends it with utility methods for the view and command.
7
+ #
8
+ def self.decorate
9
+ return unless Decidim::DepartmentAdmin.conferences_defined?
10
+
11
+ Decidim::Conferences::Admin::ConferenceForm.class_eval do
12
+ attribute :area_id, Integer
13
+
14
+ validates :area, presence: true, if: proc { |object| object.area_id.present? }
15
+
16
+ def area
17
+ @area ||= current_organization.areas.find_by(id: area_id)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ Decidim::ConferenceFormDecorator.decorate
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim::Conferences::Admin::ConferencesControllerDecorator
4
+ #
5
+ # This decorator adds the capability to the controller to query conferences
6
+ # filtering by User role `department_admin`.
7
+ #
8
+ def self.decorate
9
+ return unless Decidim::DepartmentAdmin.conferences_defined?
10
+
11
+ Decidim::Conferences::Admin::ConferencesController.class_eval do
12
+ private
13
+
14
+ alias_method :original_collection, :collection
15
+
16
+ def collection
17
+ @collection ||= if current_user.admin?
18
+ original_collection
19
+ else
20
+ ::Decidim::Conferences::ConferencesWithUserRole.for(current_user)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ Decidim::Conferences::Admin::ConferencesControllerDecorator.decorate