decidim-access_requests 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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