decidim-access_requests 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +105 -0
- data/Rakefile +17 -0
- data/app/assets/config/decidim_access_requests_manifest.css +3 -0
- data/app/assets/stylesheets/decidim/access_requests/verification.scss +4 -0
- data/app/assets/stylesheets/decidim/access_requests/verification/_step-bullets.scss +30 -0
- data/app/assets/stylesheets/decidim/access_requests/verification/_variables.scss +2 -0
- data/app/commands/decidim/access_requests/verification/admin/confirm_user_access_request.rb +67 -0
- data/app/commands/decidim/access_requests/verification/admin/destroy_authorization.rb +40 -0
- data/app/controllers/concerns/decidim/access_requests/verification/detectable_verification_manifest.rb +23 -0
- data/app/controllers/decidim/access_requests/verification/admin/granted_authorizations_controller.rb +117 -0
- data/app/controllers/decidim/access_requests/verification/admin/pending_authorizations_controller.rb +76 -0
- data/app/controllers/decidim/access_requests/verification/authorizations_controller.rb +68 -0
- data/app/events/decidim/access_requests/access_request_confirmed_event.rb +31 -0
- data/app/forms/decidim/access_requests/verification/request_form.rb +25 -0
- data/app/presenters/decidim/access_requests/verification/authorization_presenter.rb +16 -0
- data/app/views/decidim/access_requests/verification/admin/granted_authorizations/index.html.erb +44 -0
- data/app/views/decidim/access_requests/verification/admin/granted_authorizations/new.html.erb +52 -0
- data/app/views/decidim/access_requests/verification/admin/pending_authorizations/index.html.erb +48 -0
- data/app/views/decidim/access_requests/verification/authorizations/_steps.html.erb +40 -0
- data/app/views/decidim/access_requests/verification/authorizations/edit.html.erb +13 -0
- data/app/views/decidim/access_requests/verification/authorizations/new.html.erb +25 -0
- data/config/locales/en.yml +70 -0
- data/config/locales/fi.yml +68 -0
- data/config/locales/sv.yml +70 -0
- data/lib/decidim/access_requests.rb +9 -0
- data/lib/decidim/access_requests/verification.rb +5 -0
- data/lib/decidim/access_requests/verification/admin.rb +12 -0
- data/lib/decidim/access_requests/verification/admin_engine.rb +21 -0
- data/lib/decidim/access_requests/verification/engine.rb +24 -0
- data/lib/decidim/access_requests/version.rb +8 -0
- 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,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,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
|
data/app/controllers/decidim/access_requests/verification/admin/granted_authorizations_controller.rb
ADDED
@@ -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
|
data/app/controllers/decidim/access_requests/verification/admin/pending_authorizations_controller.rb
ADDED
@@ -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
|