feat: Add Platform APIs (#1456)
This commit is contained in:
parent
75c2a7cb2f
commit
7542330d61
25 changed files with 688 additions and 20 deletions
|
@ -48,6 +48,7 @@ Rails/ApplicationController:
|
||||||
- 'app/controllers/dashboard_controller.rb'
|
- 'app/controllers/dashboard_controller.rb'
|
||||||
- 'app/controllers/widget_tests_controller.rb'
|
- 'app/controllers/widget_tests_controller.rb'
|
||||||
- 'app/controllers/widgets_controller.rb'
|
- 'app/controllers/widgets_controller.rb'
|
||||||
|
- 'app/controllers/platform_controller.rb'
|
||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
EnforcedStyle: compact
|
EnforcedStyle: compact
|
||||||
Exclude:
|
Exclude:
|
||||||
|
|
|
@ -6,13 +6,6 @@
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
# versions of RuboCop, may require this file to be generated again.
|
# versions of RuboCop, may require this file to be generated again.
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
# Configuration parameters: EnforcedStyle.
|
|
||||||
# SupportedStyles: native, lf, crlf
|
|
||||||
Layout/EndOfLine:
|
|
||||||
Exclude:
|
|
||||||
- 'deploy/after_restart.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
Lint/DuplicateMethods:
|
Lint/DuplicateMethods:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ApplicationController < ActionController::Base
|
||||||
render_unauthorized('You are not authorized to do this action')
|
render_unauthorized('You are not authorized to do this action')
|
||||||
ensure
|
ensure
|
||||||
# to address the thread variable leak issues in Puma/Thin webserver
|
# to address the thread variable leak issues in Puma/Thin webserver
|
||||||
Current.user = nil
|
Current.reset
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_current_user
|
def set_current_user
|
||||||
|
|
29
app/controllers/platform/api/v1/account_users_controller.rb
Normal file
29
app/controllers/platform/api/v1/account_users_controller.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
class Platform::Api::V1::AccountUsersController < PlatformController
|
||||||
|
before_action :set_resource
|
||||||
|
before_action :validate_platform_app_permissible
|
||||||
|
|
||||||
|
def index
|
||||||
|
render json: @resource.account_users
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@account_user = @resource.account_users.find_or_initialize_by(user_id: account_user_params[:user_id])
|
||||||
|
@account_user.update!(account_user_params)
|
||||||
|
render json: @account_user
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@resource.account_users.find_by(user_id: account_user_params[:user_id])&.destroy
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_resource
|
||||||
|
@resource = Account.find(params[:account_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_user_params
|
||||||
|
params.permit(:user_id, :role)
|
||||||
|
end
|
||||||
|
end
|
32
app/controllers/platform/api/v1/accounts_controller.rb
Normal file
32
app/controllers/platform/api/v1/accounts_controller.rb
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
class Platform::Api::V1::AccountsController < PlatformController
|
||||||
|
def create
|
||||||
|
@resource = Account.new(account_params)
|
||||||
|
@resource.save!
|
||||||
|
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
|
||||||
|
render json: @resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: @resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@resource.update!(account_params)
|
||||||
|
render json: @resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
# TODO: obfusicate account
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_resource
|
||||||
|
@resource = Account.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_params
|
||||||
|
params.permit(:name)
|
||||||
|
end
|
||||||
|
end
|
43
app/controllers/platform/api/v1/users_controller.rb
Normal file
43
app/controllers/platform/api/v1/users_controller.rb
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
class Platform::Api::V1::UsersController < PlatformController
|
||||||
|
# ref: https://stackoverflow.com/a/45190318/939299
|
||||||
|
# set resource is called for other actions already in platform controller
|
||||||
|
# we want to add login to that chain as well
|
||||||
|
before_action(only: [:login]) { set_resource }
|
||||||
|
before_action(only: [:login]) { validate_platform_app_permissible }
|
||||||
|
|
||||||
|
def create
|
||||||
|
@resource = (User.find_by(email: user_params[:email]) || User.new(user_params))
|
||||||
|
@resource.confirm
|
||||||
|
@resource.save!
|
||||||
|
@platform_app.platform_app_permissibles.find_or_create_by(permissible: @resource)
|
||||||
|
render json: @resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def login
|
||||||
|
render json: { url: "#{ENV['FRONTEND_URL']}/app/login?email=#{@resource.email}&sso_auth_token=#{@resource.generate_sso_auth_token}" }
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: @resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@resource.update!(user_params)
|
||||||
|
render json: @resource
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
# TODO: obfusicate user
|
||||||
|
head :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_resource
|
||||||
|
@resource = User.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_params
|
||||||
|
params.permit(:name, :email, :password)
|
||||||
|
end
|
||||||
|
end
|
37
app/controllers/platform_controller.rb
Normal file
37
app/controllers/platform_controller.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
class PlatformController < ActionController::Base
|
||||||
|
protect_from_forgery with: :null_session
|
||||||
|
|
||||||
|
before_action :ensure_access_token
|
||||||
|
before_action :set_platform_app
|
||||||
|
before_action :set_resource, only: [:update, :show, :destroy]
|
||||||
|
before_action :validate_platform_app_permissible, only: [:update, :show, :destroy]
|
||||||
|
|
||||||
|
def show; end
|
||||||
|
|
||||||
|
def update; end
|
||||||
|
|
||||||
|
def destroy; end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ensure_access_token
|
||||||
|
token = request.headers[:api_access_token] || request.headers[:HTTP_API_ACCESS_TOKEN]
|
||||||
|
@access_token = AccessToken.find_by(token: token) if token.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_platform_app
|
||||||
|
@platform_app = @access_token.owner if @access_token && @access_token.owner.is_a?(PlatformApp)
|
||||||
|
render json: { error: 'Invalid access_token' }, status: :unauthorized if @platform_app.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_resource
|
||||||
|
# set @resource in your controller
|
||||||
|
raise 'Overwrite this method your controller'
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_platform_app_permissible
|
||||||
|
return if @platform_app.platform_app_permissibles.find_by(permissible: @resource)
|
||||||
|
|
||||||
|
render json: { error: 'Non permissible resource' }, status: :unauthorized
|
||||||
|
end
|
||||||
|
end
|
|
@ -32,7 +32,6 @@ class Inbox < ApplicationRecord
|
||||||
|
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
|
|
||||||
# TODO: should add associations for the channel types
|
|
||||||
belongs_to :channel, polymorphic: true, dependent: :destroy
|
belongs_to :channel, polymorphic: true, dependent: :destroy
|
||||||
|
|
||||||
has_many :contact_inboxes, dependent: :destroy
|
has_many :contact_inboxes, dependent: :destroy
|
||||||
|
|
16
app/models/platform_app.rb
Normal file
16
app/models/platform_app.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: platform_apps
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# name :string not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
class PlatformApp < ApplicationRecord
|
||||||
|
include AccessTokenable
|
||||||
|
|
||||||
|
validates :name, presence: true
|
||||||
|
|
||||||
|
has_many :platform_app_permissibles, dependent: :destroy
|
||||||
|
end
|
26
app/models/platform_app_permissible.rb
Normal file
26
app/models/platform_app_permissible.rb
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: platform_app_permissibles
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# permissible_type :string not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# permissible_id :bigint not null
|
||||||
|
# platform_app_id :bigint not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_platform_app_permissibles_on_permissibles (permissible_type,permissible_id)
|
||||||
|
# index_platform_app_permissibles_on_platform_app_id (platform_app_id)
|
||||||
|
# unique_permissibles_index (platform_app_id,permissible_id,permissible_type) UNIQUE
|
||||||
|
#
|
||||||
|
class PlatformAppPermissible < ApplicationRecord
|
||||||
|
include AccessTokenable
|
||||||
|
|
||||||
|
validates :platform_app, presence: true
|
||||||
|
validates :platform_app_id, uniqueness: { scope: [:permissible_id, :permissible_type] }
|
||||||
|
|
||||||
|
belongs_to :platform_app
|
||||||
|
belongs_to :permissible, polymorphic: true, dependent: :destroy
|
||||||
|
end
|
|
@ -155,13 +155,25 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :twitter do
|
# ----------------------------------------------------------------------
|
||||||
resource :authorization, only: [:create]
|
# Routes for platform APIs
|
||||||
resource :callback, only: [:show]
|
namespace :platform, defaults: { format: 'json' } do
|
||||||
end
|
namespace :api do
|
||||||
|
namespace :v1 do
|
||||||
namespace :twilio do
|
resources :users, only: [:create, :show, :update, :destroy] do
|
||||||
resources :callback, only: [:create]
|
member do
|
||||||
|
get :login
|
||||||
|
end
|
||||||
|
end
|
||||||
|
resources :accounts, only: [:create, :show, :update, :destroy] do
|
||||||
|
resources :account_users, only: [:index, :create] do
|
||||||
|
collection do
|
||||||
|
delete :destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
@ -173,14 +185,19 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Routes for social integrations
|
# Routes for channel integrations
|
||||||
mount Facebook::Messenger::Server, at: 'bot'
|
mount Facebook::Messenger::Server, at: 'bot'
|
||||||
get 'webhooks/twitter', to: 'api/v1/webhooks#twitter_crc'
|
get 'webhooks/twitter', to: 'api/v1/webhooks#twitter_crc'
|
||||||
post 'webhooks/twitter', to: 'api/v1/webhooks#twitter_events'
|
post 'webhooks/twitter', to: 'api/v1/webhooks#twitter_events'
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
namespace :twitter do
|
||||||
# Routes for testing
|
resource :authorization, only: [:create]
|
||||||
resources :widget_tests, only: [:index] unless Rails.env.production?
|
resource :callback, only: [:show]
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :twilio do
|
||||||
|
resources :callback, only: [:create]
|
||||||
|
end
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Routes for external service verifications
|
# Routes for external service verifications
|
||||||
|
@ -216,4 +233,8 @@ Rails.application.routes.draw do
|
||||||
# Routes for swagger docs
|
# Routes for swagger docs
|
||||||
get '/swagger/*path', to: 'swagger#respond'
|
get '/swagger/*path', to: 'swagger#respond'
|
||||||
get '/swagger', to: 'swagger#respond'
|
get '/swagger', to: 'swagger#respond'
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Routes for testing
|
||||||
|
resources :widget_tests, only: [:index] unless Rails.env.production?
|
||||||
end
|
end
|
||||||
|
|
8
db/migrate/20201123195011_create_platform_apps.rb
Normal file
8
db/migrate/20201123195011_create_platform_apps.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
class CreatePlatformApps < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
create_table :platform_apps do |t|
|
||||||
|
t.string :name, null: false
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,11 @@
|
||||||
|
class CreatePlatformAppPermissibles < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
create_table :platform_app_permissibles do |t|
|
||||||
|
t.references :platform_app, index: true, null: false
|
||||||
|
t.references :permissible, null: false, polymorphic: true, index: { name: :index_platform_app_permissibles_on_permissibles }
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :platform_app_permissibles, [:platform_app_id, :permissible_id, :permissible_type], unique: true, name: 'unique_permissibles_index'
|
||||||
|
end
|
||||||
|
end
|
18
db/schema.rb
18
db/schema.rb
|
@ -10,6 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2021_01_09_211805) do
|
ActiveRecord::Schema.define(version: 2021_01_09_211805) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
|
@ -428,6 +429,23 @@ ActiveRecord::Schema.define(version: 2021_01_09_211805) do
|
||||||
t.index ["user_id"], name: "index_notifications_on_user_id"
|
t.index ["user_id"], name: "index_notifications_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "platform_app_permissibles", force: :cascade do |t|
|
||||||
|
t.bigint "platform_app_id", null: false
|
||||||
|
t.string "permissible_type", null: false
|
||||||
|
t.bigint "permissible_id", null: false
|
||||||
|
t.datetime "created_at", precision: 6, null: false
|
||||||
|
t.datetime "updated_at", precision: 6, null: false
|
||||||
|
t.index ["permissible_type", "permissible_id"], name: "index_platform_app_permissibles_on_permissibles"
|
||||||
|
t.index ["platform_app_id", "permissible_id", "permissible_type"], name: "unique_permissibles_index", unique: true
|
||||||
|
t.index ["platform_app_id"], name: "index_platform_app_permissibles_on_platform_app_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "platform_apps", force: :cascade do |t|
|
||||||
|
t.string "name", null: false
|
||||||
|
t.datetime "created_at", precision: 6, null: false
|
||||||
|
t.datetime "updated_at", precision: 6, null: false
|
||||||
|
end
|
||||||
|
|
||||||
create_table "super_admins", force: :cascade do |t|
|
create_table "super_admins", force: :cascade do |t|
|
||||||
t.string "email", default: "", null: false
|
t.string "email", default: "", null: false
|
||||||
t.string "encrypted_password", default: "", null: false
|
t.string "encrypted_password", default: "", null: false
|
||||||
|
|
|
@ -7,4 +7,10 @@ module Current
|
||||||
super
|
super
|
||||||
Time.zone = account.timezone
|
Time.zone = account.timezone
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.reset
|
||||||
|
Current.user = nil
|
||||||
|
Current.account = nil
|
||||||
|
Current.account_user = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Platform Account Users API', type: :request do
|
||||||
|
let!(:account) { create(:account) }
|
||||||
|
|
||||||
|
describe 'GET /platform/api/v1/accounts/{account_id}/account_users' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/platform/api/v1/accounts/#{account.id}/account_users"
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
let!(:account_user) { create(:account_user, account: account) }
|
||||||
|
|
||||||
|
it 'returns all the account users for the account' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: account)
|
||||||
|
|
||||||
|
get "/platform/api/v1/accounts/#{account.id}/account_users",
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(response.body).to include(account_user.id.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /platform/api/v1/accounts/{account_id}/account_users' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post "/platform/api/v1/accounts/#{account.id}/account_users"
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'creates a new account user for the account' do
|
||||||
|
user = create(:user)
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: account)
|
||||||
|
|
||||||
|
post "/platform/api/v1/accounts/#{account.id}/account_users",
|
||||||
|
params: { user_id: user.id, role: 'administrator' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
expect(data['user_id']).to eq(user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the new account user for the account' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: account)
|
||||||
|
account_user = create(:account_user, account: account, role: 'agent')
|
||||||
|
|
||||||
|
post "/platform/api/v1/accounts/#{account.id}/account_users",
|
||||||
|
params: { user_id: account_user.user_id, role: 'administrator' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
expect(data['role']).to eq('administrator')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE /platform/api/v1/accounts/{account_id}/account_users' do
|
||||||
|
let(:account_user) { create(:account_user, account: account, role: 'agent') }
|
||||||
|
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
delete "/platform/api/v1/accounts/#{account.id}/account_users", params: { user_id: account_user.user_id }
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'returns deletes the account user' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: account)
|
||||||
|
|
||||||
|
delete "/platform/api/v1/accounts/#{account.id}/account_users", params: { user_id: account_user.user_id },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(account.account_users.count).to eq 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
107
spec/controllers/platform/api/v1/accounts_controller_spec.rb
Normal file
107
spec/controllers/platform/api/v1/accounts_controller_spec.rb
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Platform Accounts API', type: :request do
|
||||||
|
let!(:account) { create(:account) }
|
||||||
|
|
||||||
|
describe 'POST /platform/api/v1/accounts' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post '/platform/api/v1/accounts'
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an invalid platform app token' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post '/platform/api/v1/accounts', params: { name: 'Test Account' },
|
||||||
|
headers: { api_access_token: 'invalid' }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'creates an account when and its permissible relationship' do
|
||||||
|
post '/platform/api/v1/accounts', params: { name: 'Test Account' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(response.body).to include('Test Account')
|
||||||
|
expect(platform_app.platform_app_permissibles.first.permissible.name).to eq('Test Account')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /platform/api/v1/accounts/{account_id}' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/platform/api/v1/accounts/#{account.id}"
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an invalid platform app token' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/platform/api/v1/accounts/#{account.id}", headers: { api_access_token: 'invalid' }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'returns unauthorized when its not a permissible object' do
|
||||||
|
get "/platform/api/v1/accounts/#{account.id}", headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows an account when its permissible object' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: account)
|
||||||
|
|
||||||
|
get "/platform/api/v1/accounts/#{account.id}",
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(response.body).to include(account.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'PATCH /platform/api/v1/accounts/{account_id}' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
patch "/platform/api/v1/accounts/#{account.id}"
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an invalid platform app token' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
patch "/platform/api/v1/accounts/#{account.id}", params: { name: 'Test Account' },
|
||||||
|
headers: { api_access_token: 'invalid' }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'returns unauthorized when its not a permissible object' do
|
||||||
|
patch "/platform/api/v1/accounts/#{account.id}", params: { name: 'Test Account' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates an account when its permissible object' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: account)
|
||||||
|
|
||||||
|
patch "/platform/api/v1/accounts/#{account.id}", params: { name: 'Test Account' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(account.reload.name).to eq('Test Account')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
154
spec/controllers/platform/api/v1/users_controller_spec.rb
Normal file
154
spec/controllers/platform/api/v1/users_controller_spec.rb
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Platform Users API', type: :request do
|
||||||
|
let!(:user) { create(:user) }
|
||||||
|
|
||||||
|
describe 'GET /platform/api/v1/users/{user_id}' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/platform/api/v1/users/#{user.id}"
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an invalid platform app token' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/platform/api/v1/users/#{user.id}", headers: { api_access_token: 'invalid' }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'returns unauthorized when its not a permissible object' do
|
||||||
|
get "/platform/api/v1/users/#{user.id}", headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows a user when its permissible object' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: user)
|
||||||
|
|
||||||
|
get "/platform/api/v1/users/#{user.id}",
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
expect(data['email']).to eq(user.email)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /platform/api/v1/users/{user_id}/login' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/platform/api/v1/users/#{user.id}/login"
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an invalid platform app token' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/platform/api/v1/users/#{user.id}/login", headers: { api_access_token: 'invalid' }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'returns unauthorized when its not a permissible object' do
|
||||||
|
get "/platform/api/v1/users/#{user.id}/login", headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'return login link for user' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: user)
|
||||||
|
|
||||||
|
get "/platform/api/v1/users/#{user.id}/login",
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
expect(data['url']).to include('sso_auth_token')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /platform/api/v1/users/' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post '/platform/api/v1/users'
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an invalid platform app token' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post '/platform/api/v1/users/', headers: { api_access_token: 'invalid' }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'creates a new user and permissible for the user' do
|
||||||
|
post '/platform/api/v1/users/', params: { name: 'test', email: 'test@test.com', password: 'password123' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
expect(data['email']).to eq('test@test.com')
|
||||||
|
expect(platform_app.platform_app_permissibles.first.permissible_id).to eq data['id']
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fetch existing user and creates permissible for the user' do
|
||||||
|
create(:user, name: 'old test', email: 'test@test.com')
|
||||||
|
post '/platform/api/v1/users/', params: { name: 'test', email: 'test@test.com', password: 'password123' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
expect(data['name']).to eq('old test')
|
||||||
|
expect(platform_app.platform_app_permissibles.first.permissible_id).to eq data['id']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'PATCH /platform/api/v1/users/{user_id}' do
|
||||||
|
context 'when it is an unauthenticated platform app' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
patch "/platform/api/v1/users/#{user.id}"
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an invalid platform app token' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
patch "/platform/api/v1/users/#{user.id}", headers: { api_access_token: 'invalid' }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated platform app' do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
it 'returns unauthorized when its not a permissible object' do
|
||||||
|
patch "/platform/api/v1/users/#{user.id}", params: { name: 'test' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the user' do
|
||||||
|
create(:platform_app_permissible, platform_app: platform_app, permissible: user)
|
||||||
|
patch "/platform/api/v1/users/#{user.id}", params: { name: 'test123' },
|
||||||
|
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = JSON.parse(response.body)
|
||||||
|
expect(data['name']).to eq('test123')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
5
spec/factories/platform_apps.rb
Normal file
5
spec/factories/platform_apps.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
FactoryBot.define do
|
||||||
|
factory :platform_app do
|
||||||
|
name { Faker::Book.name }
|
||||||
|
end
|
||||||
|
end
|
6
spec/factories/platform_apps_permissibles.rb
Normal file
6
spec/factories/platform_apps_permissibles.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
FactoryBot.define do
|
||||||
|
factory :platform_app_permissible do
|
||||||
|
platform_app
|
||||||
|
permissible { create(:user) }
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,8 +1,13 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
require Rails.root.join 'spec/models/concerns/access_tokenable_spec.rb'
|
||||||
|
|
||||||
RSpec.describe AgentBot, type: :model do
|
RSpec.describe AgentBot, type: :model do
|
||||||
describe 'associations' do
|
describe 'associations' do
|
||||||
it { is_expected.to have_many(:agent_bot_inboxes) }
|
it { is_expected.to have_many(:agent_bot_inboxes) }
|
||||||
it { is_expected.to have_many(:inboxes) }
|
it { is_expected.to have_many(:inboxes) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'concerns' do
|
||||||
|
it_behaves_like 'access_tokenable'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
9
spec/models/concerns/access_tokenable_spec.rb
Normal file
9
spec/models/concerns/access_tokenable_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
shared_examples_for 'access_tokenable' do
|
||||||
|
let(:obj) { create(described_class.to_s.underscore) }
|
||||||
|
|
||||||
|
it 'creates access token on create' do
|
||||||
|
expect(obj.access_token).not_to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
20
spec/models/platform_app_permissible_spec.rb
Normal file
20
spec/models/platform_app_permissible_spec.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe PlatformAppPermissible do
|
||||||
|
let!(:platform_app_permissible) { create(:platform_app_permissible) }
|
||||||
|
|
||||||
|
context 'with validations' do
|
||||||
|
it { is_expected.to validate_presence_of(:platform_app) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with associations' do
|
||||||
|
it { is_expected.to belong_to(:platform_app) }
|
||||||
|
it { is_expected.to belong_to(:permissible) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with factories' do
|
||||||
|
it { expect(platform_app_permissible).present? }
|
||||||
|
end
|
||||||
|
end
|
24
spec/models/platform_app_spec.rb
Normal file
24
spec/models/platform_app_spec.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
require Rails.root.join 'spec/models/concerns/access_tokenable_spec.rb'
|
||||||
|
|
||||||
|
RSpec.describe PlatformApp do
|
||||||
|
let(:platform_app) { create(:platform_app) }
|
||||||
|
|
||||||
|
context 'with validations' do
|
||||||
|
it { is_expected.to validate_presence_of(:name) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with associations' do
|
||||||
|
it { is_expected.to have_many(:platform_app_permissibles) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with concerns' do
|
||||||
|
it_behaves_like 'access_tokenable'
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with factories' do
|
||||||
|
it { expect(platform_app).present? }
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
require Rails.root.join 'spec/models/concerns/access_tokenable_spec.rb'
|
||||||
|
|
||||||
RSpec.describe User do
|
RSpec.describe User do
|
||||||
let!(:user) { create(:user) }
|
let!(:user) { create(:user) }
|
||||||
|
@ -20,6 +21,10 @@ RSpec.describe User do
|
||||||
it { is_expected.to have_many(:events) }
|
it { is_expected.to have_many(:events) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'concerns' do
|
||||||
|
it_behaves_like 'access_tokenable'
|
||||||
|
end
|
||||||
|
|
||||||
describe 'pubsub_token' do
|
describe 'pubsub_token' do
|
||||||
before { user.update(name: Faker::Name.name) }
|
before { user.update(name: Faker::Name.name) }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue