infinum_id 1.0.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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +40 -0
  5. data/.travis.yml +7 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +262 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +43 -0
  11. data/Rakefile +21 -0
  12. data/app/controllers/api/base_controller.rb +6 -0
  13. data/app/controllers/api/webhooks_controller.rb +42 -0
  14. data/app/controllers/infinum_id/application_controller.rb +6 -0
  15. data/app/controllers/infinum_id/users/omniauth_callbacks_controller.rb +30 -0
  16. data/app/controllers/infinum_id/users_controller.rb +9 -0
  17. data/app/helpers/infinum_id/path_helper.rb +7 -0
  18. data/app/mailers/application_mailer.rb +4 -0
  19. data/app/mailers/user_mailer.rb +20 -0
  20. data/app/models/infinum_id/application_record.rb +5 -0
  21. data/app/services/infinum_id/after_user_update.rb +5 -0
  22. data/app/services/infinum_id/requests/invite_sender.rb +90 -0
  23. data/app/services/infinum_id/users/finder.rb +9 -0
  24. data/app/services/infinum_id/users/invite.rb +29 -0
  25. data/app/services/infinum_id/users/updater.rb +31 -0
  26. data/app/views/user_mailer/invite_email.html.erb +8 -0
  27. data/app/views/user_mailer/invite_email.text.erb +5 -0
  28. data/app/views/user_mailer/welcome_email.html.erb +8 -0
  29. data/app/views/user_mailer/welcome_email.text.erb +5 -0
  30. data/app/workers/infinum_id/users/invite_worker.rb +11 -0
  31. data/bin/console +15 -0
  32. data/bin/setup +8 -0
  33. data/config/initializers/devise.rb +22 -0
  34. data/config/initializers/sidekiq.rb +7 -0
  35. data/config/routes.rb +11 -0
  36. data/infinum_id.gemspec +56 -0
  37. data/lib/generators/infinum_id/install_generator.rb +58 -0
  38. data/lib/generators/templates/migration.rb +25 -0
  39. data/lib/generators/templates/user.rb +19 -0
  40. data/lib/infinum_id/engine.rb +4 -0
  41. data/lib/infinum_id/version.rb +3 -0
  42. data/lib/infinum_id.rb +27 -0
  43. metadata +380 -0
@@ -0,0 +1,90 @@
1
+ module InfinumId
2
+ module Requests
3
+ class InviteSender
4
+ def initialize(user_id, current_user_uid)
5
+ @user = User.find(user_id)
6
+ @current_user_uid = current_user_uid
7
+ end
8
+
9
+ def self.call(user_id, current_user_uid)
10
+ new(user_id, current_user_uid).call
11
+ end
12
+
13
+ def call
14
+ send_invite_request
15
+ handle_response
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :user, :current_user_uid, :response
21
+
22
+ def send_invite_request
23
+ @response = HTTP.headers(headers).post(invitation_url, json: invitation_params)
24
+ end
25
+
26
+ def handle_response
27
+ case response.code
28
+ when 200
29
+ update_user
30
+ send_email if Rails.configuration.infinum_id_send_email
31
+ when 400, 403, 404
32
+ return response.to_s
33
+ when 401..599
34
+ raise response.to_s
35
+ end
36
+ end
37
+
38
+ def update_user
39
+ user.update(user_params)
40
+ end
41
+
42
+ def send_email
43
+ params[:invitation_accept_path].blank? ? send_welcome_email : send_invite_email
44
+ end
45
+
46
+ def send_invite_email
47
+ UserMailer.with(
48
+ user_id: user.id, invited_by_uid: current_user_uid,
49
+ accept_path: params[:invitation_accept_path]
50
+ ).invite_email.deliver_later
51
+ end
52
+
53
+ def send_welcome_email
54
+ UserMailer.with(
55
+ user_id: user.id, invited_by_uid: current_user_uid
56
+ ).welcome_email.deliver_later
57
+ end
58
+
59
+ def params
60
+ @params ||= ActionController::Parameters.new(response.parse)
61
+ end
62
+
63
+ def user_params
64
+ params.require(:user).permit(
65
+ :uid, :email, :first_name, :last_name, :slack_username,
66
+ :time_zone, :deactivated_at, :avatar_url
67
+ )
68
+ end
69
+
70
+ def headers
71
+ {
72
+ client_id: InfinumId.client_id,
73
+ client_secret: InfinumId.client_secret
74
+ }
75
+ end
76
+
77
+ def invitation_params
78
+ {
79
+ user: user.as_json,
80
+ invited_by_uid: current_user_uid,
81
+ send_invitation: !Rails.configuration.infinum_id_send_email
82
+ }
83
+ end
84
+
85
+ def invitation_url
86
+ "#{InfinumId.url}/api/invitations"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,9 @@
1
+ module InfinumId
2
+ module Users
3
+ class Finder
4
+ def self.from_omniauth(auth)
5
+ User.find_by(provider: auth.provider, uid: auth.uid) if defined?(User)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ module InfinumId
2
+ module Users
3
+ class Invite
4
+ def initialize(user_params, current_user)
5
+ @user_params = user_params
6
+ @current_user = current_user
7
+ end
8
+
9
+ def self.call(user_params, current_user)
10
+ new(user_params, current_user).call
11
+ end
12
+
13
+ def call
14
+ @user = User.create(@user_params)
15
+
16
+ send_invite_request if @user.errors.empty?
17
+ @user
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :current_user, :user
23
+
24
+ def send_invite_request
25
+ InfinumId::Users::InviteWorker.perform_async(@user.id, current_user.uid)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ module InfinumId
2
+ module Users
3
+ class Updater
4
+ def initialize(params, user)
5
+ @user_params = params.slice(*user_column_names).deep_symbolize_keys
6
+ @user = user
7
+ end
8
+
9
+ def self.call(params, user)
10
+ new(params, user).call
11
+ end
12
+
13
+ def call
14
+ update_user
15
+ InfinumId::AfterUserUpdate.call(user)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :user_params, :user
21
+
22
+ def update_user
23
+ user.update(user_params)
24
+ end
25
+
26
+ def user_column_names
27
+ User.column_names
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ <h1>Hi <%= @user.email %></h1>
2
+ <p>
3
+ <%= @invited_by.email %> invited you to <%= @service_name %>.
4
+ </p>
5
+
6
+ <p>
7
+ Click <%= link_to 'here', @accept_path %> to accept the invitation.
8
+ </p>
@@ -0,0 +1,5 @@
1
+ Hi <%= @user.email %>
2
+
3
+ <%= @invited_by.email %> invited you to <%= @service_name %>.
4
+
5
+ Click <%= link_to 'here', @accept_path %> to accept the invitation.
@@ -0,0 +1,8 @@
1
+ <h1>Hi <%= @user.email %></h1>
2
+ <p>
3
+ <%= @invited_by.email %> added you to <%= @service_name %>.
4
+ </p>
5
+
6
+ <p>
7
+ Click <%= link_to 'here', @service_url %> to go to the service.
8
+ </p>
@@ -0,0 +1,5 @@
1
+ Hi <%= @user.email %>
2
+
3
+ <%= @invited_by.email %> added you to <%= @service_name %>.
4
+
5
+ Click <%= link_to 'here', @service_url %> to go to the service.
@@ -0,0 +1,11 @@
1
+ module InfinumId
2
+ module Users
3
+ class InviteWorker
4
+ include Sidekiq::Worker
5
+
6
+ def perform(user_id, current_user_uid)
7
+ InfinumId::Requests::InviteSender.call(user_id, current_user_uid)
8
+ end
9
+ end
10
+ end
11
+ end
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require 'rails/all'
5
+ require "infinum_id"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ require "pry"
12
+ Pry.start
13
+
14
+ # require "irb"
15
+ # IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,22 @@
1
+ Devise.setup do |config|
2
+ require 'devise/orm/active_record'
3
+
4
+ config.case_insensitive_keys = [:email]
5
+ config.strip_whitespace_keys = [:email]
6
+
7
+ config.skip_session_storage = [:http_auth]
8
+
9
+ config.stretches = Rails.env.test? ? 1 : 11
10
+
11
+ config.reconfirmable = true
12
+
13
+ config.expire_all_remember_me_on_sign_out = true
14
+
15
+ config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
16
+
17
+ config.sign_out_via = :get
18
+
19
+ # ==> OmniAuth
20
+ config.omniauth :infinum_id, InfinumId.client_id, InfinumId.client_secret,
21
+ client_options: { site: InfinumId.url }
22
+ end
@@ -0,0 +1,7 @@
1
+ Sidekiq.configure_server do |config|
2
+ config.redis = { url: Rails.application.secrets[:redis_server_url] }
3
+ end
4
+
5
+ Sidekiq.configure_client do |config|
6
+ config.redis = { url: Rails.application.secrets[:redis_client_url] }
7
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,11 @@
1
+ Rails.application.routes.draw do
2
+
3
+ get '/logout', to: 'infinum_id/users#destroy'
4
+
5
+ namespace :api do
6
+ scope '/webhooks', :controller => :webhooks do
7
+ post :update_user_callback
8
+ post :create_user_callback
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,56 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'infinum_id/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'infinum_id'
7
+ spec.version = InfinumId::VERSION
8
+ spec.authors = ['Dajana Jeroncic']
9
+ spec.email = ['dajana.jeroncic@infinum.hr']
10
+
11
+ spec.summary = 'Write a short summary, because RubyGems requires one.'
12
+ spec.description = 'Write a longer description or delete this line.'
13
+ spec.homepage = 'https://github.com/infinum/rails-infinum-id-engine'
14
+ spec.license = 'MIT'
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
+ else
21
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
22
+ 'public gem pushes.'
23
+ end
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
28
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
29
+ end
30
+ spec.bindir = 'exe'
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ['lib']
33
+
34
+ spec.add_development_dependency 'bundler'
35
+ spec.add_development_dependency 'pry'
36
+ spec.add_development_dependency 'factory_bot_rails'
37
+ spec.add_development_dependency 'faker'
38
+ spec.add_development_dependency 'pry-rails'
39
+ spec.add_development_dependency 'pry-byebug'
40
+ spec.add_development_dependency 'rake', '~> 10.0'
41
+ spec.add_development_dependency 'rspec', '~> 3.0'
42
+ spec.add_development_dependency 'rspec-rails'
43
+ spec.add_development_dependency 'rails'
44
+ spec.add_development_dependency 'simplecov'
45
+ spec.add_development_dependency 'sqlite3'
46
+ spec.add_development_dependency 'webmock'
47
+
48
+ spec.add_dependency 'bundler'
49
+ spec.add_dependency 'devise'
50
+ spec.add_dependency 'http'
51
+ spec.add_dependency 'omniauth-infinum_id'
52
+ spec.add_dependency 'redis'
53
+ spec.add_dependency 'redis-namespace'
54
+ spec.add_dependency 'responders'
55
+ spec.add_dependency 'sidekiq'
56
+ end
@@ -0,0 +1,58 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module InfinumId
4
+ module Generators
5
+ class InstallGenerator < ::Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+
8
+ source_root File.expand_path('../templates', __dir__)
9
+
10
+ def inject_secrets
11
+ insert_into_file 'config/secrets.yml', secrets_template,
12
+ after: "bugsnag_api_key: <%= Figaro.env.bugsnag_api_key! %>\n"
13
+ end
14
+
15
+ def copy_migration
16
+ migration_template 'migration.rb', 'db/migrate/create_users.rb'
17
+ end
18
+
19
+ def copy_model
20
+ template 'user.rb', 'app/models/user.rb'
21
+ end
22
+
23
+ def inject_routes
24
+ insert_into_file 'config/routes.rb', routes_template,
25
+ after: "Rails.application.routes.draw do\n"
26
+ end
27
+
28
+ def self.next_migration_number(dirname)
29
+ ActiveRecord::Generators::Base.next_migration_number(dirname)
30
+ end
31
+
32
+ def migration_version
33
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
34
+ end
35
+
36
+ private
37
+
38
+ def routes_template
39
+ <<RUBY
40
+ devise_for :users, controllers: {
41
+ omniauth_callbacks: 'infinum_id/users/omniauth_callbacks'
42
+ }
43
+ RUBY
44
+ end
45
+
46
+ def secrets_template
47
+ <<RUBY
48
+ redis_server_url: <%= Figaro.env.redis_server_url %>
49
+ redis_client_url: <%= Figaro.env.redis_client_url %>
50
+ infinum_id:
51
+ client_id: <%= Figaro.env.infinum_id_client_id %>
52
+ client_secret: <%= Figaro.env.infinum_id_client_secret %>
53
+ url: <%= Figaro.env.infinum_id_client_url %>
54
+ RUBY
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,25 @@
1
+ class CreateUsers < ActiveRecord::Migration<%= migration_version %>
2
+ def change # rubocop:disable Metrics/MethodLength
3
+ create_table :users do |t|
4
+ t.string :email, null: false, default: ''
5
+
6
+ t.string :first_name
7
+ t.string :last_name
8
+
9
+ t.string :slack_username
10
+ t.string :time_zone
11
+
12
+ t.string :avatar_url
13
+
14
+ # Omniauth
15
+ t.string :provider
16
+ t.string :uid
17
+
18
+ t.datetime :deactivated_at
19
+
20
+ t.timestamps null: false
21
+ end
22
+
23
+ add_index :users, :email, unique: true
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ class User < ApplicationRecord
2
+ devise :omniauthable, omniauth_providers: [:infinum_id]
3
+
4
+ validates :email, uniqueness: true
5
+
6
+ def active_for_authentication?
7
+ super && !deactivated_at
8
+ end
9
+
10
+ def as_json
11
+ {
12
+ email: email,
13
+ first_name: first_name,
14
+ last_name: last_name,
15
+ slack_username: slack_username,
16
+ time_zone: time_zone
17
+ }
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module InfinumId
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module InfinumId
2
+ VERSION = '1.0.0'
3
+ end
data/lib/infinum_id.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'infinum_id/version'
2
+ require 'omniauth/infinum_id'
3
+ require 'infinum_id/engine'
4
+ require 'devise'
5
+ require 'sidekiq'
6
+
7
+ module InfinumId
8
+ def self.url
9
+ dig_secret(:url)
10
+ end
11
+
12
+ def self.client_id
13
+ dig_secret(:client_id)
14
+ end
15
+
16
+ def self.client_secret
17
+ dig_secret(:client_secret)
18
+ end
19
+
20
+ def self.dig_secret(key)
21
+ if Rails::VERSION::MAJOR >= 5
22
+ Rails.application.secrets.dig(:infinum_id, key)
23
+ else
24
+ Rails.application.secrets.dig(:infinum_id, key.to_s)
25
+ end
26
+ end
27
+ end