Last active
April 30, 2020 07:37
-
-
Save m5rk/0321caa67436711ae47e70480c0a0b32 to your computer and use it in GitHub Desktop.
Slack Sessions Controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/controllers/slack/sessions_controller.rb | |
module Slack | |
class SessionsController < ApplicationController | |
before_action :ensure_no_error! | |
before_action :ensure_ok! | |
before_action :ensure_slack_token_valid! | |
before_action :ensure_account! | |
before_action :ensure_user! | |
expose(:slack_client) { Slack::Web::Client.new } | |
expose(:oauth_token) do | |
slack_client.oauth_access( | |
client_id: Chamber.slack.client_id, | |
client_secret: Chamber.slack.secret, | |
redirect_uri: slack_login_url, | |
code: params[:code]) | |
end | |
expose(:slack_team_from_token) { oauth_token.team } | |
expose(:slack_user_from_token) { oauth_token.user } | |
expose(:team_id) { slack_team_from_token.id } | |
expose(:account) { Account.for_slack_team_id(team_id).first } | |
expose(:user) { account.users.where(email: slack_user_from_token.email).first } | |
def create | |
sign_in_and_redirect(user) | |
end | |
private | |
def ensure_no_error! | |
return unless params[:error] | |
message = if params[:error] == 'access_denied' | |
'You canceled sign in with Slack' | |
else | |
'An error occurred when signing in with Slack' | |
end | |
redirect_to new_user_session_path, alert: message | |
end | |
def ensure_ok! | |
return if oauth_token['ok'] | |
message = 'An error occurred when signing in with Slack' | |
redirect_to new_user_session_path, alert: message | |
end | |
def ensure_slack_token_valid! | |
return unless account | |
return if account.slack_token.auth_test? | |
message = "No account found for Slack Team: #{slack_team_from_token.name}" | |
redirect_to new_user_session_path, alert: message | |
end | |
def ensure_account! | |
return if account | |
message = "No account found for Slack Team: #{slack_team_from_token.name}" | |
redirect_to new_user_session_path, alert: message | |
end | |
def ensure_user! | |
return if user | |
message = "No user found in the Manifestly Account #{account.name} for email #{slack_user_from_token.email}" | |
redirect_to new_user_session_path, alert: message | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# spec/controllers/slack/sessions_controller_spec.rb | |
require 'rails_helper' | |
RSpec.describe Slack::SessionsController do | |
before { allow(SlackUser).to receive(:fetch_all) } | |
describe 'GET #create' do | |
let(:action) { get :create, params } | |
context 'when there is an access_denied error' do | |
let(:params) do | |
{ | |
error: 'access_denied' | |
} | |
end | |
it_behaves_like 'a slack sign in error', 'You canceled sign in with Slack' | |
end | |
context 'when there is any other error' do | |
let(:params) do | |
{ | |
error: 'some other error' | |
} | |
end | |
it_behaves_like 'a slack sign in error', 'An error occurred when signing in with Slack' | |
end | |
context 'when there is an oauth token' do | |
let(:mock_slack_client) { instance_double(Slack::Web::Client) } | |
let(:mock_oauth_access) { Slack::Messages::Message.new(json) } | |
let(:params) do | |
{ | |
code: 'the code' | |
} | |
end | |
let(:ok) { Slack::Messages::Message.new(ok: true) } | |
before do | |
allow(Slack::Web::Client).to receive(:new).and_return(mock_slack_client) | |
allow(mock_slack_client).to receive(:auth_test).and_return(ok) | |
allow(mock_slack_client).to receive(:oauth_access).with( | |
client_id: Chamber.slack.client_id, | |
client_secret: Chamber.slack.secret, | |
redirect_uri: slack_login_url, | |
code: params[:code] | |
).and_return(mock_oauth_access) | |
end | |
context 'when the token is not ok' do | |
let(:json) do | |
{ | |
ok: false | |
} | |
end | |
it_behaves_like 'a slack sign in error', 'An error occurred when signing in with Slack' | |
end | |
context 'when there is no account for the Slack team' do | |
let(:json) do | |
{ | |
ok: true, | |
team: { id: 'foo', name: 'team alpha' } | |
} | |
end | |
it_behaves_like 'a slack sign in error', 'No account found for Slack Team: team alpha' | |
end | |
context 'when the token is no longer valid for the Slack team' do | |
let(:account) { create :account } | |
let(:slack_token) { create :slack_token, :enabled, account: account } | |
let(:json) do | |
{ | |
ok: true, | |
team: { id: slack_token.team_id, name: 'team alpha' } | |
} | |
end | |
before do | |
expect(mock_slack_client).to receive(:auth_test).and_raise(Slack::Web::Api::Error.new('token_revoked')) | |
end | |
it_behaves_like 'a slack sign in error', 'No account found for Slack Team: team alpha' | |
it 'deletes the token' do | |
expect { action }.to change { SlackToken.where(account_id: account.id).count }.to(0) | |
end | |
end | |
context 'when there is no user in the account for the specified email' do | |
let(:account) { create :account, name: 'Acme, Inc.' } | |
let(:slack_token) { create :slack_token, :enabled, account: account } | |
let(:json) do | |
{ | |
ok: true, | |
team: { id: slack_token.team_id }, | |
user: { email: '[email protected]' } | |
} | |
end | |
it_behaves_like 'a slack sign in error', 'No user found in the Manifestly Account Acme, Inc. for email [email protected]' | |
end | |
context 'when the account and user exist' do | |
let(:user) { create :user, current_account: account, email: '[email protected]', sign_in_count: 2 } | |
let(:account) { create :account, name: 'Acme, Inc.' } | |
let(:slack_token) { create :slack_token, :enabled, account: account } | |
let(:json) do | |
{ | |
ok: true, | |
team: { id: slack_token.team_id }, | |
user: { email: user.email } | |
} | |
end | |
it 'redirects to the dashboard' do | |
action | |
expect(response).to redirect_to(dashboard_path) | |
end | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# spec/support/examples/slack_sign_in_error.rb | |
RSpec.shared_examples 'a slack sign in error' do |message| | |
before { action } | |
it 'redirects to sign in' do | |
expect(response).to redirect_to(new_user_session_path) | |
end | |
it 'sets the flash' do | |
is_expected.to set_flash[:alert].to message | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment