Restructure omni services and add Chatwoot research snapshot

This commit is contained in:
Ruslan Bakiev
2026-02-21 11:11:27 +07:00
parent edea7a0034
commit b73babbbf6
7732 changed files with 978203 additions and 32 deletions

View File

@@ -0,0 +1,52 @@
require 'rails_helper'
RSpec.describe 'Token Confirmation', type: :request do
describe 'POST /auth/confirmation' do
let(:response_json) { JSON.parse(response.body, symbolize_names: true) }
before do
create(:user, email: 'john.doe@gmail.com', **user_attributes)
post user_confirmation_url, params: { confirmation_token: confirmation_token }
end
context 'when token is valid' do
let(:user_attributes) { { confirmation_token: '12345', skip_confirmation: false } }
let(:confirmation_token) { '12345' }
it 'has status 200' do
expect(response).to have_http_status :ok
end
it 'returns "auth data"' do
expect(response.body).to include('john.doe@gmail.com')
end
end
context 'when token is invalid' do
let(:user_attributes) { { confirmation_token: '12345' } }
let(:confirmation_token) { '' }
it 'has status 422' do
expect(response).to have_http_status :unprocessable_entity
end
it 'returns message "Invalid token"' do
expect(response_json).to eq({ message: 'Invalid token', redirect_url: '/' })
end
end
context 'when user had already been confirmed' do
let(:user_attributes) { { confirmation_token: '12345' } }
let(:confirmation_token) { '12345' }
it 'has status 422' do
expect(response).to have_http_status :unprocessable_entity
end
it 'returns message "Already confirmed"' do
expect(response_json).to eq({ message: 'Already confirmed', redirect_url: '/' })
end
end
end
end

View File

@@ -0,0 +1,148 @@
require 'rails_helper'
RSpec.describe 'DeviseOverrides::OmniauthCallbacksController', type: :request do
let(:account_builder) { double }
let(:user_double) { object_double(:user) }
let(:email_validation_service) { instance_double(Account::SignUpEmailValidationService) }
def set_omniauth_config(for_email = 'test@example.com')
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:google_oauth2] = OmniAuth::AuthHash.new(
provider: 'google',
uid: '123545',
info: {
name: 'test',
email: for_email,
image: 'https://example.com/image.jpg'
}
)
end
before do
allow(Account::SignUpEmailValidationService).to receive(:new).and_return(email_validation_service)
end
describe '#omniauth_sucess' do
before do
GlobalConfig.clear_cache
end
it 'allows signup' do
with_modified_env ENABLE_ACCOUNT_SIGNUP: 'true', FRONTEND_URL: 'http://www.example.com' do
set_omniauth_config('test_not_preset@example.com')
allow(AccountBuilder).to receive(:new).and_return(account_builder)
allow(account_builder).to receive(:perform).and_return(user_double)
allow(Avatar::AvatarFromUrlJob).to receive(:perform_later).and_return(true)
allow(email_validation_service).to receive(:perform).and_return(true)
get '/omniauth/google_oauth2/callback'
# expect a 302 redirect to auth/google_oauth2/callback
expect(response).to redirect_to('http://www.example.com/auth/google_oauth2/callback')
follow_redirect!
expect(AccountBuilder).to have_received(:new).with({
account_name: 'example',
user_full_name: 'test',
email: 'test_not_preset@example.com',
locale: I18n.locale,
confirmed: nil
})
expect(account_builder).to have_received(:perform)
end
end
it 'blocks personal accounts signup' do
with_modified_env ENABLE_ACCOUNT_SIGNUP: 'true', FRONTEND_URL: 'http://www.example.com' do
set_omniauth_config('personal@gmail.com')
allow(email_validation_service).to receive(:perform).and_raise(CustomExceptions::Account::InvalidEmail.new({ valid: false, disposable: nil }))
get '/omniauth/google_oauth2/callback'
# expect a 302 redirect to auth/google_oauth2/callback
expect(response).to redirect_to('http://www.example.com/auth/google_oauth2/callback')
follow_redirect!
# expect a 302 redirect to app/login with error disallowing personal accounts
expect(response).to redirect_to(%r{/app/login\?error=business-account-only$})
end
end
it 'blocks personal accounts signup with different Gmail case variations' do
with_modified_env ENABLE_ACCOUNT_SIGNUP: 'true', FRONTEND_URL: 'http://www.example.com' do
# Test different case variations of Gmail
['personal@Gmail.com', 'personal@GMAIL.com', 'personal@Gmail.COM'].each do |email|
set_omniauth_config(email)
allow(email_validation_service).to receive(:perform).and_raise(CustomExceptions::Account::InvalidEmail.new({ valid: false,
disposable: nil }))
get '/omniauth/google_oauth2/callback'
# expect a 302 redirect to auth/google_oauth2/callback
expect(response).to redirect_to('http://www.example.com/auth/google_oauth2/callback')
follow_redirect!
# expect a 302 redirect to app/login with error disallowing personal accounts
expect(response).to redirect_to(%r{/app/login\?error=business-account-only$})
end
end
end
# This test does not affect line coverage, but it is important to ensure that the logic
# does not allow any signup if the ENV explicitly disables it
it 'blocks signup if ENV disabled' do
with_modified_env ENABLE_ACCOUNT_SIGNUP: 'false', FRONTEND_URL: 'http://www.example.com' do
set_omniauth_config('does-not-exist-for-sure@example.com')
allow(email_validation_service).to receive(:perform).and_return(true)
get '/omniauth/google_oauth2/callback'
# expect a 302 redirect to auth/google_oauth2/callback
expect(response).to redirect_to('http://www.example.com/auth/google_oauth2/callback')
follow_redirect!
# expect a 302 redirect to app/login with error disallowing signup
expect(response).to redirect_to(%r{/app/login\?error=no-account-found$})
end
end
it 'allows login' do
with_modified_env FRONTEND_URL: 'http://www.example.com' do
create(:user, email: 'test@example.com')
set_omniauth_config('test@example.com')
get '/omniauth/google_oauth2/callback'
# expect a 302 redirect to auth/google_oauth2/callback
expect(response).to redirect_to('http://www.example.com/auth/google_oauth2/callback')
follow_redirect!
expect(response).to redirect_to(%r{/app/login\?email=.+&sso_auth_token=.+$})
# expect app/login page to respond with 200 and render
follow_redirect!
expect(response).to have_http_status(:ok)
end
end
# from a line coverage point of view this may seem redundant
# but to ensure that the logic allows for existing users even if they have a gmail account
# we need to test this explicitly
it 'allows personal account login' do
with_modified_env FRONTEND_URL: 'http://www.example.com' do
create(:user, email: 'personal-existing@gmail.com')
set_omniauth_config('personal-existing@gmail.com')
get '/omniauth/google_oauth2/callback'
# expect a 302 redirect to auth/google_oauth2/callback
expect(response).to redirect_to('http://www.example.com/auth/google_oauth2/callback')
follow_redirect!
expect(response).to redirect_to(%r{/app/login\?email=.+&sso_auth_token=.+$})
# expect app/login page to respond with 200 and render
follow_redirect!
expect(response).to have_http_status(:ok)
end
end
end
end

View File

@@ -0,0 +1,96 @@
require 'rails_helper'
RSpec.describe 'Session', type: :request do
describe 'GET /sign_in' do
let!(:account) { create(:account) }
context 'when it is invalid credentials' do
it 'returns unauthorized' do
params = { email: 'invalid@invalid.com', password: 'invalid' }
post new_user_session_url,
params: params,
as: :json
expect(response).to have_http_status(:unauthorized)
expect(response.body).to include('Invalid login credentials')
end
end
context 'when it is valid credentials' do
let!(:user) { create(:user, password: 'Password1!', account: account) }
let!(:user_with_new_pwd) { create(:user, password: 'Password1!.><?', account: account) }
it 'returns successful auth response' do
params = { email: user.email, password: 'Password1!' }
post new_user_session_url,
params: params,
as: :json
expect(response).to have_http_status(:success)
expect(response.body).to include(user.email)
end
it 'returns successful auth response with new password special characters' do
params = { email: user_with_new_pwd.email, password: 'Password1!.><?' }
post new_user_session_url,
params: params,
as: :json
expect(response).to have_http_status(:success)
expect(response.body).to include(user_with_new_pwd.email)
end
it 'returns the permission of the user' do
params = { email: user.email, password: 'Password1!' }
post new_user_session_url,
params: params,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['data']['accounts'].first['permissions']).to eq(['agent'])
end
end
context 'when it is invalid sso auth token' do
let!(:user) { create(:user, password: 'Password1!', account: account) }
it 'returns unauthorized' do
params = { email: user.email, sso_auth_token: SecureRandom.hex(32) }
post new_user_session_url,
params: params,
as: :json
expect(response).to have_http_status(:unauthorized)
expect(response.body).to include('Invalid login credentials')
end
end
context 'when with valid sso auth token' do
let!(:user) { create(:user, password: 'Password1!', account: account) }
it 'returns successful auth response' do
params = { email: user.email, sso_auth_token: user.generate_sso_auth_token }
post new_user_session_url, params: params, as: :json
expect(response).to have_http_status(:success)
expect(response.body).to include(user.email)
# token won't work on a subsequent request
post new_user_session_url, params: params, as: :json
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'GET /auth/sign_in' do
it 'redirects to the frontend login page with error' do
get new_user_session_url
expect(response).to redirect_to(%r{/app/login\?error=access-denied$})
end
end
end

View File

@@ -0,0 +1,26 @@
require 'rails_helper'
RSpec.describe 'Token Validation API', type: :request do
describe 'GET /validate_token' do
let(:account) { create(:account) }
context 'when it is an invalid token' do
it 'returns unauthorized' do
get '/auth/validate_token'
expect(response).to have_http_status(:unauthorized)
end
end
context 'when it is a valid token' do
let(:agent) { create(:user, account: account, role: :agent) }
it 'returns all the labels for the conversation' do
get '/auth/validate_token',
headers: agent.create_new_auth_token
expect(response).to have_http_status(:success)
expect(response.body).to include('payload')
end
end
end
end