From 31c1223b3970487c7352c1b10c5eefcc325b0f74 Mon Sep 17 00:00:00 2001 From: Eugene Haisenka Date: Tue, 24 Dec 2019 16:41:35 +0300 Subject: [PATCH] [#256] Ability to connect another integration --- .env | 2 +- app/controllers/sessions_controller.rb | 20 +++++++++++++++- app/controllers/users_controller.rb | 20 ++++++++++++++++ app/policies/user_policy.rb | 9 ++++++++ app/services/auth/accessibility_check.rb | 2 +- app/services/auth/auth_info_params_builder.rb | 1 + app/services/auth/user_wrapper.rb | 4 ++++ app/views/layouts/_header.html.slim | 1 + app/views/users/show.html.slim | 23 +++++++++++++++++++ config/routes.rb | 3 ++- 10 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 app/controllers/users_controller.rb create mode 100644 app/policies/user_policy.rb create mode 100644 app/views/users/show.html.slim diff --git a/.env b/.env index 4aec14e7..88359ed6 100644 --- a/.env +++ b/.env @@ -35,7 +35,7 @@ ROLLBAR_POST_CLIENT_ITEM_TOKEN="" GITLAB_APP_ID= GITLAB_APP_SECRET= GITLAB_REDIRECT_URI= -GITLAB_API_ENDPOINT= +GITLAB_API_ENDPOINT="https://gitlab.com/api/v4" GITLAB_WEBHOOK_SECRET= GITLAB_DEPLOYQA_BOT_ID= GITLAB_DEPLOYQA_BOT_TOKEN= diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 3ee3a00a..36abda87 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -7,7 +7,7 @@ class SessionsController < ApplicationController def show; end def create - result = user_from_omniauth + result = current_user.present? ? connect_user : user_from_omniauth if result.error? flash.notice = result.errors.join("/n") @@ -29,6 +29,24 @@ def setup_session(session, user) ::Auth::SessionHandler.new(session).set!(user_id: user.id, provider: auth_info_presenter.provider) end + def connect_user + user_reference = UserReference.find_by(auth_uid: auth_info_presenter.uid, auth_provider: auth_info_presenter.provider) + + raise if user_reference && (user_reference.auth_info.present? || user_reference.user_id.present?) + raise if current_user.auth_info.email != auth_info_presenter.email + + if user_reference.present? + user_reference.update!(user: current_user.actual_user) + else + user_reference = UserReference.create!(user: current_user.actual_user, auth_uid: auth_info_presenter.uid, auth_provider: auth_info_presenter.provider, full_name: auth_info_presenter.full_name) + end + + auth_info_params = Auth::AuthInfoParamsBuilder.new(auth_info_presenter, user_reference).call + AuthInfo.create!(auth_info_params.merge) + + ReturnValue.ok(current_user.actual_user) + end + def user_from_omniauth result = ::Auth::UserAuthenticator.new(auth_info_presenter).call ::Auth::SetupUserProjectsMembership.new(result.object, auth_info_presenter.provider).call if result.ok? diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 00000000..8adf22d8 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class UsersController < ApplicationController + IMAGE_PATH = { + ::ProjectsConstants::Providers::GITHUB => "media/images/logos/github-logo.svg", + ::ProjectsConstants::Providers::GITLAB => "media/images/logos/gitlab-logo.svg" + }.freeze + + def show + @user = find_user + @github_auth = @user.user_references.find { |reference| reference.auth_provider == OmniauthConstants::GITHUB } + @gitlab_auth = @user.user_references.find { |reference| reference.auth_provider == OmniauthConstants::GITLAB } + end + + private + + def find_user + authorize User.includes(user_references: :auth_info).find(params[:id]), :show?, policy_class: UserPolicy + end +end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb new file mode 100644 index 00000000..1c3332aa --- /dev/null +++ b/app/policies/user_policy.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class UserPolicy < ApplicationPolicy + def show? + return true if user.system_role == UserConstants::SystemRoles::ADMIN + + user.actual_user == record + end +end diff --git a/app/services/auth/accessibility_check.rb b/app/services/auth/accessibility_check.rb index 2777980c..69808477 100644 --- a/app/services/auth/accessibility_check.rb +++ b/app/services/auth/accessibility_check.rb @@ -14,7 +14,7 @@ def call return if @user_reference.auth_info.blank? return if @user_reference.auth_info.primary? - raise ::Auth::NotPermittedError, "Please login with another provider" + raise ::Auth::NotPermittedError, "You've already registered in another provider with the same email" end def auth_info_email_occupied? diff --git a/app/services/auth/auth_info_params_builder.rb b/app/services/auth/auth_info_params_builder.rb index c21434e5..a3b3629a 100644 --- a/app/services/auth/auth_info_params_builder.rb +++ b/app/services/auth/auth_info_params_builder.rb @@ -24,6 +24,7 @@ def call def load_email(params) return if params[:email].present? + # TODO: why do we need USER_API_CLIENT? GitLab always have an email and there is no :email method in ProviderAPI::Gitlab::UserClient api_client = USER_API_CLIENT.fetch(@omniauth_info_presenter.provider).new(@omniauth_info_presenter.token) email = api_client.emails.find { |email_info| email_info[:primary] }.fetch(:email) params[:email] = email diff --git a/app/services/auth/user_wrapper.rb b/app/services/auth/user_wrapper.rb index 0367b026..7c24ba78 100644 --- a/app/services/auth/user_wrapper.rb +++ b/app/services/auth/user_wrapper.rb @@ -24,5 +24,9 @@ def email def token auth_info.token end + + def actual_user + @user + end end end diff --git a/app/views/layouts/_header.html.slim b/app/views/layouts/_header.html.slim index 415e32ae..2d3299a5 100644 --- a/app/views/layouts/_header.html.slim +++ b/app/views/layouts/_header.html.slim @@ -10,4 +10,5 @@ nav.navbar.navbar-expand-lg.navbar-light.bg-light a.nav-link.dropdown-toggle href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" = current_user.full_name .dropdown-menu aria-labelledby="navbarDropdown" + = link_to "User preferences", user_path(current_user.actual_user), class: "dropdown-item" = link_to "Log out", sessions_path, method: :delete, class: "dropdown-item" diff --git a/app/views/users/show.html.slim b/app/views/users/show.html.slim new file mode 100644 index 00000000..41be1903 --- /dev/null +++ b/app/views/users/show.html.slim @@ -0,0 +1,23 @@ +.container + = render partial: "shared/breadcrumb", locals: {\ + text_link_hash: {\ + "User" => nil\ + }, + class: "mt-4" } + + + .d-flex.justify-content-between.mt-4 + h1 = current_user.full_name + .mt-4 + p + = image_pack_tag("media/images/logos/github-logo.svg", size: "32x32", class: "mr-2") + - if @github_auth.present? + span.text-success Github integration connected! + - else + = link_to "Click to connect Github", omniauth_path("github"), method: :post + p + = image_pack_tag("media/images/logos/gitlab-logo.svg", size: "32x32", class: "mr-2") + - if @gitlab_auth.present? + span.text-success Gitlab integration connected! + - else + = link_to "Click to connect Gitlab", omniauth_path("gitlab", some_data: "123"), method: :post diff --git a/config/routes.rb b/config/routes.rb index 6e63376f..603e657f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -12,13 +12,14 @@ get "/auth/slack/callback", to: "slack/authentications#create" get "/auth/failure", to: "slack/authentications#show" get "/auth/:provider/callback", to: "sessions#create" - get "/auth/:provider", to: "sessions#show", as: "omniauth" + post "/auth/:provider", to: "sessions#show", as: "omniauth" constraints Routes::LoggedUserConstraint.new(SidekiqPolicy) do mount Sidekiq::Web => "/sidekiq" end resource :sessions, only: %i[show create destroy] + resources :users, only: %i[show] namespace :webhooks do resources :github, only: %i[create]