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.
- 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
|