decidim-ub 0.1.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.
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Decidim::Ub
2
+
3
+ [![[CI] Lint](https://github.com/Platoniq/decidim-module-ub/actions/workflows/lint.yml/badge.svg)](https://github.com/Platoniq/decidim-module-ub/actions/workflows/lint.yml)
4
+ [![[CI] Test](https://github.com/Platoniq/decidim-module-ub/actions/workflows/test.yml/badge.svg)](https://github.com/Platoniq/decidim-module-ub/actions/workflows/test.yml)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/c975a347c58389448503/maintainability)](https://codeclimate.com/github/Platoniq/decidim-module-ub/maintainability)
6
+ [![Coverage Status](https://coveralls.io/repos/github/Platoniq/decidim-module-ub/badge.svg?branch=main)](https://coveralls.io/github/Platoniq/decidim-module-ub?branch=main)
7
+
8
+ A Decidim module to sync users from Universitat de Barcelona who connect to the platform.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem "decidim-ub", git: "https://github.com/Platoniq/decidim-module-ub"
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ ```bash
21
+ bundle
22
+ bundle exec rails decidim_ub:install:migrations
23
+ bundle exec rails db:migrate
24
+ ```
25
+
26
+ ## Configuration
27
+
28
+ You need to configure some environment variables for the OAuth client:
29
+
30
+ | ENV | Description | Example | Default |
31
+ |------------------|-------------------------------------------|-----------------------------|----------------------------|
32
+ | UB_CLIENT_ID | The OAuth2 client ID | `your-client-id` | |
33
+ | UB_CLIENT_SECRET | The OAuth2 client secret | `your-client-secret` | |
34
+ | UB_SITE | The OAuth2 site | `https://example.org/oauth` | |
35
+ | UB_AUTHORIZE_URL | The path for the authorization URL | `/authorize` | |
36
+ | UB_TOKEN_URL | The path for the token URL | `/token` | |
37
+ | UB_ICON | The path for the icon shown in the button | `media/images/my_icon.svg` | `media/images/ub_logo.svg` |
38
+
39
+ ## Contributing
40
+
41
+ Contributions are welcome !
42
+
43
+ We expect the contributions to follow the [Decidim's contribution guide](https://github.com/decidim/decidim/blob/develop/CONTRIBUTING.adoc).
44
+
45
+ ## Security
46
+
47
+ Security is very important to us. If you have any issue regarding security, please disclose the information responsibly by sending an email to __francisco.bolivar [at] nazaries [dot] com__ and not by creating a Github issue.
48
+
49
+ ## License
50
+
51
+ This engine is distributed under the GNU AFFERO GENERAL PUBLIC LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/dev/common_rake"
4
+ require "fileutils"
5
+
6
+ def install_module(path)
7
+ Dir.chdir(path) do
8
+ system("bundle exec rake decidim_ub:install:migrations")
9
+ system("bundle exec rake db:migrate")
10
+ end
11
+ end
12
+
13
+ def install_initializer(path, env)
14
+ Dir.chdir(path) do
15
+ FileUtils.cp(
16
+ "#{__dir__}/lib/generators/decidim/app_templates/#{env}/initializer.rb",
17
+ "config/initializers/decidim_ub_config.rb"
18
+ )
19
+ end
20
+ end
21
+
22
+ def seed_db(path)
23
+ Dir.chdir(path) do
24
+ system("bundle exec rake db:seed")
25
+ end
26
+ end
27
+
28
+ desc "Generates a dummy app for testing"
29
+ task test_app: "decidim:generate_external_test_app" do
30
+ ENV["RAILS_ENV"] = "test"
31
+ install_initializer("spec/decidim_dummy_app", "test")
32
+ install_module("spec/decidim_dummy_app")
33
+ end
34
+
35
+ desc "Generates a development app."
36
+ task development_app: "decidim:generate_external_development_app" do
37
+ install_module("development_app")
38
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ class SyncUser < Decidim::Command
6
+ # Public: Initializes the command.
7
+ #
8
+ # user - A decidim user
9
+ # roles - The roles of the user
10
+ def initialize(user, roles)
11
+ @user = user
12
+ @roles = roles
13
+ end
14
+
15
+ # Executes the command. Broadcasts these events:
16
+ #
17
+ # - :ok when everything is valid.
18
+ # - :invalid if we couldn't proceed.
19
+ #
20
+ # Returns nothing.
21
+ def call
22
+ update_user!
23
+ ActiveSupport::Notifications.publish("decidim.ub.user.updated", user.id)
24
+ broadcast(:ok)
25
+ rescue StandardError => e
26
+ broadcast(:invalid, e.message)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :user, :roles
32
+
33
+ def update_user!
34
+ return unless user.ub_identity?
35
+
36
+ user.ub_roles = roles
37
+ user.save!
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DeviseAuthenticationMethods
5
+ def first_login_and_not_authorized?(user)
6
+ return false if user.ub_identity?
7
+
8
+ super
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+
5
+ module Decidim
6
+ module Ub
7
+ module Verifications
8
+ class Ub < Decidim::AuthorizationHandler
9
+ validate :user_valid
10
+
11
+ def unique_id
12
+ Digest::SHA512.hexdigest("#{role}/#{uid}-#{Rails.application.secrets.secret_key_base}")
13
+ end
14
+
15
+ protected
16
+
17
+ def organization
18
+ current_organization || user&.organization
19
+ end
20
+
21
+ def uid
22
+ user.ub_identity
23
+ end
24
+
25
+ def user_valid
26
+ errors.add(:user, "decidim.ub.errors.missing_role") unless user.ub_roles.include?(role)
27
+ end
28
+
29
+ def role = raise NotImplementedError
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ module Verifications
6
+ class UbAnt < Ub
7
+ def role = "ANT"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ module Verifications
6
+ class UbEst < Ub
7
+ def role = "EST"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ module Verifications
6
+ class UbPas < Ub
7
+ def role = "PAS"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ module Verifications
6
+ class UbPdi < Ub
7
+ def role = "PDI"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ module Verifications
6
+ class UbPex < Ub
7
+ def role = "PEX"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ module OmniauthHelperOverride
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ alias_method :original_normalize_provider_name, :normalize_provider_name
10
+
11
+ def normalize_provider_name(provider)
12
+ return "Universitat de Barcelona" if provider == :ub
13
+
14
+ original_normalize_provider_name(provider)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ class AutoVerificationJob < ApplicationJob
6
+ queue_as :default
7
+
8
+ def perform(user_id)
9
+ @user = Decidim::User.find(user_id)
10
+ @auths = Decidim::Ub.roles_to_auth_name(@user.ub_roles & Decidim::Ub::ROLES)
11
+ update_auths
12
+ rescue ActiveRecord::RecordNotFound
13
+ Rails.logger.error "AutoVerificationJob: ERROR: model not found for user #{user_id}"
14
+ end
15
+
16
+ private
17
+
18
+ def update_auths
19
+ current_auths = user_auths.pluck(:name)
20
+ (current_auths - @auths).each { |name| remove_auth(user_auths.find_by(name:)) }
21
+ (@auths - current_auths).each { |name| create_auth(name) }
22
+ end
23
+
24
+ def create_auth(name)
25
+ return unless (handler = Decidim::AuthorizationHandler.handler_for(name, user: @user))
26
+
27
+ Decidim::Verifications::AuthorizeUser.call(handler, @user.organization) do
28
+ on(:ok) do
29
+ Rails.logger.info "AutoVerificationJob: Success: created auth #{name} for user #{handler.user.id}"
30
+ end
31
+
32
+ on(:invalid) do
33
+ Rails.logger.error "AutoVerificationJob: ERROR: not created auth #{name} for user #{handler.user&.id}"
34
+ end
35
+ end
36
+ end
37
+
38
+ def remove_auth(auth)
39
+ Decidim::Verifications::DestroyUserAuthorization.call(auth) do
40
+ on(:ok) do
41
+ Rails.logger.info "AutoVerificationJob: Success: removed auth #{auth.name} for user #{auth.user.id}"
42
+ end
43
+
44
+ on(:invalid) do
45
+ Rails.logger.error "AutoVerificationJob: ERROR: not removed auth #{auth.name} for user #{auth.user&.id}"
46
+ end
47
+ end
48
+ end
49
+
50
+ def user_auths
51
+ @user_auths ||= Decidim::Authorization.where(user: @user, name: Decidim::Ub.authorizations)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ class OmniauthUserSyncJob < ApplicationJob
6
+ queue_as :default
7
+
8
+ def perform(data)
9
+ user = Decidim::User.find(data[:user_id])
10
+ return unless user.ub_identity?
11
+
12
+ Decidim::Ub::SyncUser.call(user, data.dig(:raw_data, :info, :roles)) do
13
+ on(:ok) do
14
+ Rails.logger.info "OmniauthUserSyncJob: Success: Ub roles updated for user #{user.id}"
15
+ end
16
+
17
+ on(:invalid) do |message|
18
+ Rails.logger.error "OmniauthUserSyncJob: ERROR: Error updating ub roles '#{message}'"
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Ub
5
+ module UserOverride
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ def ub_identity
10
+ identities.find_by(provider: Decidim::Ub::OMNIAUTH_PROVIDER_NAME)
11
+ end
12
+
13
+ def ub_identity?
14
+ identities.exists?(provider: Decidim::Ub::OMNIAUTH_PROVIDER_NAME)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,2 @@
1
+ // Images
2
+ require.context("../images", true)