feat: Add APIs for custom attribute definitions (#2689)
This commit is contained in:
parent
7e0937f3ed
commit
6e1493501a
13 changed files with 284 additions and 1 deletions
|
@ -0,0 +1,50 @@
|
|||
class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Accounts::BaseController
|
||||
before_action :fetch_custom_attributes_definitions, except: [:create]
|
||||
before_action :fetch_custom_attribute_definition, only: [:show, :update, :destroy]
|
||||
DEFAULT_ATTRIBUTE_MODEL = 'conversation_attribute'.freeze
|
||||
|
||||
def index; end
|
||||
|
||||
def show; end
|
||||
|
||||
def create
|
||||
@custom_attribute_definition = Current.account.custom_attribute_definitions.create!(
|
||||
permitted_payload
|
||||
)
|
||||
end
|
||||
|
||||
def update
|
||||
@custom_attribute_definition.update!(permitted_payload)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@custom_attribute_definition.destroy
|
||||
head :no_content
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_custom_attributes_definitions
|
||||
@custom_attribute_definitions = Current.account.custom_attribute_definitions.where(
|
||||
attribute_model: permitted_params[:attribute_model] || DEFAULT_ATTRIBUTE_MODEL
|
||||
)
|
||||
end
|
||||
|
||||
def fetch_custom_attribute_definition
|
||||
@custom_attribute_definition = @custom_attribute_definitions.find(permitted_params[:id])
|
||||
end
|
||||
|
||||
def permitted_payload
|
||||
params.require(:custom_attribute_definition).permit(
|
||||
:attribute_display_name,
|
||||
:attribute_display_type,
|
||||
:attribute_key,
|
||||
:attribute_model,
|
||||
:default_value
|
||||
)
|
||||
end
|
||||
|
||||
def permitted_params
|
||||
params.permit(:id, :filter_type)
|
||||
end
|
||||
end
|
|
@ -61,6 +61,8 @@ class Account < ApplicationRecord
|
|||
has_many :kbase_articles, dependent: :destroy, class_name: '::Kbase::Article'
|
||||
has_many :teams, dependent: :destroy
|
||||
has_many :custom_filters, dependent: :destroy
|
||||
has_many :custom_attribute_definitions, dependent: :destroy
|
||||
|
||||
has_flags ACCOUNT_SETTINGS_FLAGS.merge(column: 'settings_flags').merge(DEFAULT_QUERY_SETTING)
|
||||
|
||||
enum locale: LANGUAGES_CONFIG.map { |key, val| [val[:iso_639_1_code], key] }.to_h
|
||||
|
|
34
app/models/custom_attribute_definition.rb
Normal file
34
app/models/custom_attribute_definition.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: custom_attribute_definitions
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# attribute_display_name :string
|
||||
# attribute_display_type :integer default("text")
|
||||
# attribute_key :string
|
||||
# attribute_model :integer default("conversation_attribute")
|
||||
# default_value :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# account_id :bigint
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# attribute_key_model_index (attribute_key,attribute_model) UNIQUE
|
||||
# index_custom_attribute_definitions_on_account_id (account_id)
|
||||
#
|
||||
class CustomAttributeDefinition < ApplicationRecord
|
||||
validates :attribute_display_name, presence: true
|
||||
|
||||
validates :attribute_key,
|
||||
presence: true,
|
||||
uniqueness: { scope: :attribute_model }
|
||||
|
||||
validates :attribute_display_type, presence: true
|
||||
validates :attribute_model, presence: true
|
||||
|
||||
enum attribute_model: { conversation_attribute: 0, contact_attribute: 1 }
|
||||
enum attribute_display_type: { text: 0, number: 1, currency: 2, percent: 3, link: 4 }
|
||||
|
||||
belongs_to :account
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
json.partial! 'api/v1/models/custom_attribute_definition.json.jbuilder', resource: @custom_attribute_definition
|
|
@ -0,0 +1,3 @@
|
|||
json.array! @custom_attribute_definitions do |custom_attribute_definition|
|
||||
json.partial! 'api/v1/models/custom_attribute_definition.json.jbuilder', resource: custom_attribute_definition
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
json.partial! 'api/v1/models/custom_attribute_definition.json.jbuilder', resource: @custom_attribute_definition
|
|
@ -0,0 +1 @@
|
|||
json.partial! 'api/v1/models/custom_attribute_definition.json.jbuilder', resource: @custom_attribute_definition
|
|
@ -0,0 +1,7 @@
|
|||
json.attribute_display_name resource.attribute_display_name
|
||||
json.attribute_display_type resource.attribute_display_type
|
||||
json.attribute_key resource.attribute_key
|
||||
json.attribute_model resource.attribute_model
|
||||
json.default_value resource.default_value
|
||||
json.created_at resource.created_at
|
||||
json.updated_at resource.updated_at
|
|
@ -92,6 +92,7 @@ Rails.application.routes.draw do
|
|||
get :metrics
|
||||
end
|
||||
end
|
||||
resources :custom_attribute_definitions, only: [:index, :show, :create, :update, :destroy]
|
||||
resources :custom_filters, only: [:index, :show, :create, :update, :destroy]
|
||||
resources :inboxes, only: [:index, :create, :update, :destroy] do
|
||||
get :assignable_agents, on: :member
|
||||
|
|
16
db/migrate/20210722095814_add_custom_attribute_definition.rb
Normal file
16
db/migrate/20210722095814_add_custom_attribute_definition.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
class AddCustomAttributeDefinition < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :custom_attribute_definitions do |t|
|
||||
t.string :attribute_display_name
|
||||
t.string :attribute_key
|
||||
t.integer :attribute_display_type, default: 0
|
||||
t.integer :default_value
|
||||
t.integer :attribute_model, default: 0
|
||||
t.references :account, index: true
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :custom_attribute_definitions, [:attribute_key, :attribute_model], unique: true, name: 'attribute_key_model_index'
|
||||
end
|
||||
end
|
15
db/schema.rb
15
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_07_21_182458) do
|
||||
ActiveRecord::Schema.define(version: 2021_07_22_095814) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
|
@ -292,6 +292,19 @@ ActiveRecord::Schema.define(version: 2021_07_21_182458) do
|
|||
t.index ["message_id"], name: "index_csat_survey_responses_on_message_id", unique: true
|
||||
end
|
||||
|
||||
create_table "custom_attribute_definitions", force: :cascade do |t|
|
||||
t.string "attribute_display_name"
|
||||
t.string "attribute_key"
|
||||
t.integer "attribute_display_type", default: 0
|
||||
t.integer "default_value"
|
||||
t.integer "attribute_model", default: 0
|
||||
t.bigint "account_id"
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.index ["account_id"], name: "index_custom_attribute_definitions_on_account_id"
|
||||
t.index ["attribute_key", "attribute_model"], name: "attribute_key_model_index", unique: true
|
||||
end
|
||||
|
||||
create_table "custom_filters", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.integer "filter_type", default: 0, null: false
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Custom Attribute Definitions API', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
|
||||
describe 'GET /api/v1/accounts/{account.id}/custom_attribute_definitions' do
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
get "/api/v1/accounts/#{account.id}/custom_attribute_definitions"
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let!(:custom_attribute_definition) { create(:custom_attribute_definition, account: account) }
|
||||
|
||||
it 'returns all customer attribute definitions related to the account' do
|
||||
create(:custom_attribute_definition, attribute_model: 'contact_attribute', account: account)
|
||||
|
||||
get "/api/v1/accounts/#{account.id}/custom_attribute_definitions",
|
||||
headers: user.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_body = JSON.parse(response.body)
|
||||
|
||||
expect(response_body.count).to eq(1)
|
||||
expect(response_body.first['attribute_key']).to eq(custom_attribute_definition.attribute_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/accounts/{account.id}/custom_attribute_definitions/:id' do
|
||||
let!(:custom_attribute_definition) { create(:custom_attribute_definition, account: account) }
|
||||
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
get "/api/v1/accounts/#{account.id}/custom_attribute_definitions/#{custom_attribute_definition.id}"
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
it 'shows the custom attribute definition' do
|
||||
get "/api/v1/accounts/#{account.id}/custom_attribute_definitions/#{custom_attribute_definition.id}",
|
||||
headers: user.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(response.body).to include(custom_attribute_definition.attribute_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v1/accounts/{account.id}/custom_attribute_definitions' do
|
||||
let(:payload) do
|
||||
{
|
||||
custom_attribute_definition: {
|
||||
attribute_display_name: 'Developer ID',
|
||||
attribute_key: 'developer_id',
|
||||
attribute_model: 'contact_attribute',
|
||||
attribute_display_type: 'text',
|
||||
default_value: ''
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
expect do
|
||||
post "/api/v1/accounts/#{account.id}/custom_attribute_definitions",
|
||||
params: payload
|
||||
end.to change(CustomAttributeDefinition, :count).by(0)
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
it 'creates the filter' do
|
||||
expect do
|
||||
post "/api/v1/accounts/#{account.id}/custom_attribute_definitions", headers: user.create_new_auth_token,
|
||||
params: payload
|
||||
end.to change(CustomAttributeDefinition, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
json_response = JSON.parse(response.body)
|
||||
expect(json_response['attribute_key']).to eq 'developer_id'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH /api/v1/accounts/{account.id}/custom_attribute_definitions/:id' do
|
||||
let(:payload) { { custom_attribute_definition: { attribute_display_name: 'Developer ID', attribute_key: 'developer_id' } } }
|
||||
let!(:custom_attribute_definition) { create(:custom_attribute_definition, account: account) }
|
||||
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
put "/api/v1/accounts/#{account.id}/custom_attribute_definitions/#{custom_attribute_definition.id}",
|
||||
params: payload
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
it 'updates the custom attribute definition' do
|
||||
patch "/api/v1/accounts/#{account.id}/custom_attribute_definitions/#{custom_attribute_definition.id}",
|
||||
headers: user.create_new_auth_token,
|
||||
params: payload,
|
||||
as: :json
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(custom_attribute_definition.reload.attribute_display_name).to eq('Developer ID')
|
||||
expect(custom_attribute_definition.reload.attribute_key).to eq('developer_id')
|
||||
expect(custom_attribute_definition.reload.attribute_model).to eq('conversation_attribute')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /api/v1/accounts/{account.id}/custom_attribute_definitions/:id' do
|
||||
let!(:custom_attribute_definition) { create(:custom_attribute_definition, account: account) }
|
||||
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
delete "/api/v1/accounts/#{account.id}/custom_attribute_definitions/#{custom_attribute_definition.id}"
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated admin user' do
|
||||
it 'deletes custom attribute' do
|
||||
delete "/api/v1/accounts/#{account.id}/custom_attribute_definitions/#{custom_attribute_definition.id}",
|
||||
headers: user.create_new_auth_token,
|
||||
as: :json
|
||||
expect(response).to have_http_status(:no_content)
|
||||
expect(account.custom_attribute_definitions.count).to be 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
12
spec/factories/custom_attribute_definitions.rb
Normal file
12
spec/factories/custom_attribute_definitions.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :custom_attribute_definition do
|
||||
sequence(:attribute_display_name) { |n| "Custom Attribute Definition #{n}" }
|
||||
sequence(:attribute_key) { |n| "custom_attribute_#{n}" }
|
||||
attribute_display_type { 1 }
|
||||
attribute_model { 0 }
|
||||
default_value { nil }
|
||||
account
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue