decidim-access_requests 0.15.0

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 (33) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +105 -0
  4. data/Rakefile +17 -0
  5. data/app/assets/config/decidim_access_requests_manifest.css +3 -0
  6. data/app/assets/stylesheets/decidim/access_requests/verification.scss +4 -0
  7. data/app/assets/stylesheets/decidim/access_requests/verification/_step-bullets.scss +30 -0
  8. data/app/assets/stylesheets/decidim/access_requests/verification/_variables.scss +2 -0
  9. data/app/commands/decidim/access_requests/verification/admin/confirm_user_access_request.rb +67 -0
  10. data/app/commands/decidim/access_requests/verification/admin/destroy_authorization.rb +40 -0
  11. data/app/controllers/concerns/decidim/access_requests/verification/detectable_verification_manifest.rb +23 -0
  12. data/app/controllers/decidim/access_requests/verification/admin/granted_authorizations_controller.rb +117 -0
  13. data/app/controllers/decidim/access_requests/verification/admin/pending_authorizations_controller.rb +76 -0
  14. data/app/controllers/decidim/access_requests/verification/authorizations_controller.rb +68 -0
  15. data/app/events/decidim/access_requests/access_request_confirmed_event.rb +31 -0
  16. data/app/forms/decidim/access_requests/verification/request_form.rb +25 -0
  17. data/app/presenters/decidim/access_requests/verification/authorization_presenter.rb +16 -0
  18. data/app/views/decidim/access_requests/verification/admin/granted_authorizations/index.html.erb +44 -0
  19. data/app/views/decidim/access_requests/verification/admin/granted_authorizations/new.html.erb +52 -0
  20. data/app/views/decidim/access_requests/verification/admin/pending_authorizations/index.html.erb +48 -0
  21. data/app/views/decidim/access_requests/verification/authorizations/_steps.html.erb +40 -0
  22. data/app/views/decidim/access_requests/verification/authorizations/edit.html.erb +13 -0
  23. data/app/views/decidim/access_requests/verification/authorizations/new.html.erb +25 -0
  24. data/config/locales/en.yml +70 -0
  25. data/config/locales/fi.yml +68 -0
  26. data/config/locales/sv.yml +70 -0
  27. data/lib/decidim/access_requests.rb +9 -0
  28. data/lib/decidim/access_requests/verification.rb +5 -0
  29. data/lib/decidim/access_requests/verification/admin.rb +12 -0
  30. data/lib/decidim/access_requests/verification/admin_engine.rb +21 -0
  31. data/lib/decidim/access_requests/verification/engine.rb +24 -0
  32. data/lib/decidim/access_requests/version.rb +8 -0
  33. metadata +132 -0
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # Decidim::AccessRequests
2
+
3
+ A [Decidim](https://github.com/decidim/decidim) module that provides a new
4
+ verification method that allows system administrators to define new verification
5
+ workflows where the admins can provide access to specific users.
6
+
7
+ This module does not itself register any verification workflows because these
8
+ access request workflows are generally specific to the system in question. For
9
+ example, if the admins want to provide access only for specific users to add
10
+ new proposals in a specific participatory space, they can define a new workflow
11
+ for that.
12
+
13
+ The access request workflow works as follows:
14
+
15
+ - User requests access against the registered workflow
16
+ - An admin will review the request
17
+ - Admin will either approve or reject the access request
18
+ - The user will get notified that their access request has been either approved
19
+ or rejected
20
+
21
+ Alternatively, the admins can also provide access directly to specific users
22
+ from the admin panel. This way, the users won't have to create the access
23
+ requests themselves and they are automatically granted the access once the admin
24
+ has given it.
25
+
26
+ The gem has been developed by [Mainio Tech](https://www.mainiotech.fi/).
27
+
28
+ ## Installation
29
+
30
+ Add this line to your application's Gemfile:
31
+
32
+ ```ruby
33
+ gem 'decidim-access_requests', :git => 'git@github.com:mainio/decidim-module-access_requests.git'
34
+ ```
35
+
36
+ And then execute:
37
+
38
+ ```bash
39
+ $ bundle
40
+ ```
41
+
42
+ After installation, add this to your verifications initializer:
43
+
44
+ ```ruby
45
+ # config/initializers/decidim_verifications.rb
46
+ Decidim::Verifications.register_workflow(:your_requests) do |workflow|
47
+ workflow.engine = Decidim::AccessRequests::Verification::Engine
48
+ workflow.admin_engine = Decidim::AccessRequests::Verification::AdminEngine
49
+ end
50
+ ```
51
+
52
+ And finally, add these lines to your localization files to describe the workflow
53
+ you just registered:
54
+
55
+ ```yaml
56
+ en:
57
+ decidim:
58
+ authorization_handlers:
59
+ your_requests:
60
+ explanation: An admin will approve or deny access
61
+ name: Your access requests
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ TODO
67
+
68
+ ## Contributing
69
+
70
+ See [Decidim](https://github.com/decidim/decidim).
71
+
72
+ ### Testing
73
+
74
+ To run the tests run the following in the gem development path:
75
+
76
+ ```bash
77
+ $ bundle
78
+ $ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake test_app
79
+ $ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rspec
80
+ ```
81
+
82
+ Note that the database user has to have rights to create and drop a database in
83
+ order to create the dummy test app database.
84
+
85
+ In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
86
+ [rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
87
+ can add these environment variables to the root directory of the project in a
88
+ file named `.rbenv-vars`. In this case, you can omit defining these in the
89
+ commands shown above.
90
+
91
+ ### Test code coverage
92
+
93
+ If you want to generate the code coverage report for the tests, you can use
94
+ the `SIMPLECOV=1` environment variable in the rspec command as follows:
95
+
96
+ ```bash
97
+ SIMPLECOV=1 bundle exec rspec
98
+ ```
99
+
100
+ This will generate a folder named `coverage` in the project root which contains
101
+ the code coverage report.
102
+
103
+ ## License
104
+
105
+ See [LICENSE-AGPLv3.txt](LICENSE-AGPLv3.txt).
data/Rakefile ADDED
@@ -0,0 +1,17 @@
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"
10
+
11
+ # Run all tests, include all
12
+ RSpec::Core::RakeTask.new(:spec) do |t, task_args|
13
+ t.verbose = false
14
+ end
15
+
16
+ # Run both by default
17
+ task default: [:spec]
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= link decidim/access_requests/verification.scss
3
+ */
@@ -0,0 +1,4 @@
1
+ @import "decidim/variables";
2
+ @import "decidim/utils/settings";
3
+ @import "decidim/access_requests/verification/variables";
4
+ @import "decidim/access_requests/verification/step-bullets";
@@ -0,0 +1,30 @@
1
+ .step-bullets{
2
+ margin-bottom: 3rem;
3
+ }
4
+
5
+ .step-bullet{
6
+ &.completed{
7
+ .step-bullet__icon{
8
+ border-color: $step-completed-color;
9
+ color: $step-completed-color;
10
+ }
11
+ }
12
+
13
+ .step-bullet__icon{
14
+ position: relative;
15
+ width: 6em;
16
+ height: 6em;
17
+ margin: 0 auto 1rem;
18
+ border: 4px solid $step-pending-color;
19
+ border-radius: 50%;
20
+ color: $step-pending-color;
21
+
22
+ .icon{
23
+ position: relative;
24
+ top: 50%;
25
+ transform: translateY(-50%);
26
+ width: 3em;
27
+ height: 3em;
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,2 @@
1
+ $step-pending-color: $medium-gray !default;
2
+ $step-completed-color: $body-font-color !default;
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module AccessRequests
5
+ module Verification
6
+ module Admin
7
+ # A command to confirm a previous partial authorization.
8
+ # This is just a wrapper class to call the ConfirmUserAuthorization
9
+ # command because we add the email notifications here.
10
+ class ConfirmUserAccessRequest < Rectify::Command
11
+ # Public: Initializes the command.
12
+ #
13
+ # authorization - An Authorization to be confirmed.
14
+ # form - A form object with the verification data to confirm it.
15
+ def initialize(authorization, form)
16
+ @authorization = authorization
17
+ @form = form
18
+ end
19
+
20
+ # Executes the command. Broadcasts these events:
21
+ #
22
+ # - :ok when everything is valid.
23
+ # - :invalid if the handler wasn't valid and we couldn't proceed.
24
+ #
25
+ # Returns nothing.
26
+ def call
27
+ parent = self
28
+
29
+ Decidim::Verifications::ConfirmUserAuthorization.call(authorization, form) do
30
+ on(:ok) do
31
+ send_notification
32
+ parent.send(:broadcast, :ok)
33
+ end
34
+
35
+ on(:invalid) do
36
+ parent.send(:broadcast, :invalid)
37
+ end
38
+
39
+ on(:already_confirmed) do
40
+ parent.send(:broadcast, :invalid)
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :authorization, :form
48
+
49
+ def send_notification
50
+ Decidim::EventsManager.publish(
51
+ event: "decidim.events.access_requests.confirmed",
52
+ event_class: AccessRequestConfirmedEvent,
53
+ resource: authorization,
54
+ # affected_users: [authorization.user], # 0.16+
55
+ recipient_ids: [authorization.user.id],
56
+ extra: {
57
+ user_name: authorization.user.name,
58
+ user_nickname: authorization.user.nickname,
59
+ handler_name: authorization.name
60
+ }
61
+ )
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module AccessRequests
5
+ module Verification
6
+ module Admin
7
+ # A command to destroy an authorization.
8
+ class DestroyAuthorization < Rectify::Command
9
+ # Public: Initializes the command.
10
+ #
11
+ # authorization - The authorization object to destroy.
12
+ def initialize(authorization)
13
+ @authorization = authorization
14
+ end
15
+
16
+ # Executes the command. Broadcasts these events:
17
+ #
18
+ # - :ok when everything is valid.
19
+ # - :invalid if the authorization couldn't be destroyed.
20
+ #
21
+ # Returns nothing.
22
+ def call
23
+ return broadcast(:invalid) unless authorization
24
+
25
+ destroy_authorization
26
+ broadcast(:ok)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :authorization
32
+
33
+ def destroy_authorization
34
+ authorization.destroy!
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module AccessRequests
5
+ module Verification
6
+ module DetectableVerificationManifest
7
+ include ActiveSupport::Concern
8
+
9
+ def verification_manifest
10
+ if verification_manifest_handle
11
+ Decidim::Verifications.workflows.to_a.find do |verification|
12
+ verification.name == verification_manifest_handle
13
+ end
14
+ end
15
+ end
16
+
17
+ def verification_manifest_handle
18
+ request.path.split("/")[2] if request.path =~ %r{^/admin/}
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module AccessRequests
5
+ module Verification
6
+ module Admin
7
+ class GrantedAuthorizationsController < Decidim::Admin::ApplicationController
8
+ include DetectableVerificationManifest
9
+
10
+ layout "decidim/admin/users"
11
+
12
+ helper Decidim::Messaging::ConversationHelper
13
+
14
+ before_action :check_verification_manifest
15
+ before_action :load_user, only: [:create]
16
+ before_action :load_authorization, only: [:create]
17
+
18
+ def index
19
+ enforce_permission_to :index, :authorization
20
+
21
+ @granted_authorizations = AuthorizationPresenter.for_collection(
22
+ granted_authorizations
23
+ )
24
+ end
25
+
26
+ def new
27
+ enforce_permission_to :read, :authorization
28
+ @query = params[:q]
29
+ @state = params[:state]
30
+
31
+ authorized_user_ids = granted_authorizations.pluck(:decidim_user_id)
32
+
33
+ @users =
34
+ Decidim::Admin::UserFilter.for(
35
+ current_organization.users.not_deleted
36
+ .where.not(
37
+ id: authorized_user_ids
38
+ ),
39
+ @query,
40
+ @state
41
+ )
42
+ .page(params[:page])
43
+ .per(15)
44
+ end
45
+
46
+ def create
47
+ enforce_permission_to :create, :authorization, authorization: @authorization
48
+
49
+ @form = RequestForm.new(
50
+ handler_handle: verification_manifest.name
51
+ ).with_context(current_organization: current_organization)
52
+
53
+ ConfirmUserAccessRequest.call(authorization, @form) do
54
+ on(:ok) do
55
+ flash[:notice] = t("pending_authorizations.update.success", scope: "decidim.access_requests.verification.admin")
56
+ redirect_to granted_authorizations_path
57
+ end
58
+
59
+ on(:invalid) do
60
+ flash[:alert] = t("pending_authorizations.update.error", scope: "decidim.access_requests.verification.admin")
61
+ redirect_to granted_authorizations_path
62
+ end
63
+ end
64
+ end
65
+
66
+ def destroy
67
+ enforce_permission_to :destroy, :authorization, authorization: authorization
68
+
69
+ DestroyAuthorization.call(authorization) do
70
+ on(:ok) do
71
+ flash[:notice] = t("granted_authorizations.destroy.success", scope: "decidim.access_requests.verification.admin")
72
+ redirect_to granted_authorizations_path
73
+ end
74
+
75
+ on(:invalid) do
76
+ flash[:alert] = t("granted_authorizations.destroy.error", scope: "decidim.access_requests.verification.admin")
77
+ redirect_to granted_authorizations_path
78
+ end
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def check_verification_manifest
85
+ redirect_to decidim_admin.users_path if verification_manifest.nil?
86
+ end
87
+
88
+ def granted_authorizations
89
+ Decidim::Verifications::Authorizations.new(
90
+ organization: current_organization,
91
+ name: verification_manifest.name,
92
+ granted: true
93
+ )
94
+ end
95
+
96
+ def authorization
97
+ @authorization ||= Authorization.find_by(
98
+ id: params[:id],
99
+ name: verification_manifest.name
100
+ )
101
+ end
102
+
103
+ def load_authorization
104
+ @authorization = Authorization.find_or_initialize_by(
105
+ user: @user,
106
+ name: verification_manifest.name
107
+ )
108
+ end
109
+
110
+ def load_user
111
+ @user = User.find(params[:user_id])
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module AccessRequests
5
+ module Verification
6
+ module Admin
7
+ class PendingAuthorizationsController < Decidim::Admin::ApplicationController
8
+ include DetectableVerificationManifest
9
+
10
+ layout "decidim/admin/users"
11
+
12
+ def index
13
+ enforce_permission_to :index, :authorization
14
+
15
+ @pending_authorizations = AuthorizationPresenter.for_collection(
16
+ pending_authorizations
17
+ )
18
+ end
19
+
20
+ def update
21
+ enforce_permission_to :edit, :authorization, authorization: authorization
22
+
23
+ @form = RequestForm.new(
24
+ handler_handle: verification_manifest.name
25
+ ).with_context(current_organization: current_organization)
26
+
27
+ ConfirmUserAccessRequest.call(authorization, @form) do
28
+ on(:ok) do
29
+ flash[:notice] = t("pending_authorizations.update.success", scope: "decidim.access_requests.verification.admin")
30
+ redirect_to pending_authorizations_path
31
+ end
32
+
33
+ on(:invalid) do
34
+ flash.now[:alert] = t("pending_authorizations.update.error", scope: "decidim.access_requests.verification.admin")
35
+ redirect_to pending_authorizations_path
36
+ end
37
+ end
38
+ end
39
+
40
+ def destroy
41
+ enforce_permission_to :destroy, :authorization, authorization: authorization
42
+
43
+ DestroyAuthorization.call(authorization) do
44
+ on(:ok) do
45
+ flash[:notice] = t("pending_authorizations.destroy.success", scope: "decidim.access_requests.verification.admin")
46
+ redirect_to pending_authorizations_path
47
+ end
48
+
49
+ on(:invalid) do
50
+ flash.now[:alert] = t("pending_authorizations.destroy.error", scope: "decidim.access_requests.verification.admin")
51
+ redirect_to pending_authorizations_path
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def pending_authorizations
59
+ Decidim::Verifications::Authorizations.new(
60
+ organization: current_organization,
61
+ name: verification_manifest.name,
62
+ granted: false
63
+ )
64
+ end
65
+
66
+ def authorization
67
+ @authorization ||= Authorization.find_by(
68
+ id: params[:id],
69
+ name: verification_manifest.name
70
+ )
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end