From f9c3b7f2f18470fb6b2e50be882d35fe918ee07a Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Fri, 29 Jan 2021 12:34:52 +0530 Subject: [PATCH] feat: Bulk add team members in Team APIs (#1695) --- .../api/v1/accounts/team_members_controller.rb | 17 ++++++++++++++--- app/models/team.rb | 14 +++++++++++++- app/models/team_member.rb | 5 +++-- .../accounts/team_members/create.json.jbuilder | 8 +++++++- ...126121313_addunique_index_to_team_members.rb | 6 ++++++ db/schema.rb | 4 +++- .../v1/accounts/team_members_controller_spec.rb | 14 ++++++++------ .../api/v1/accounts/teams_controller_spec.rb | 8 ++++---- 8 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 db/migrate/20210126121313_addunique_index_to_team_members.rb diff --git a/app/controllers/api/v1/accounts/team_members_controller.rb b/app/controllers/api/v1/accounts/team_members_controller.rb index 32a792509..0b1b8eac9 100644 --- a/app/controllers/api/v1/accounts/team_members_controller.rb +++ b/app/controllers/api/v1/accounts/team_members_controller.rb @@ -7,17 +7,28 @@ class Api::V1::Accounts::TeamMembersController < Api::V1::Accounts::BaseControll end def create - record = @team.team_members.find_or_create_by(user_id: params[:user_id]) - @team_member = record.user + ActiveRecord::Base.transaction do + @team_members = params[:user_ids].map { |user_id| create_team_member(user_id) } + end end def destroy - @team.team_members.find_by(user_id: params[:user_id])&.destroy + ActiveRecord::Base.transaction do + params[:user_ids].map { |user_id| remove_team_member(user_id) } + end head :ok end private + def create_team_member(user_id) + @team.team_members.find_or_create_by(user_id: user_id)&.user + end + + def remove_team_member(user_id) + @team.team_members.find_by(user_id: user_id)&.destroy + end + def fetch_team @team = Current.account.teams.find(params[:team_id]) end diff --git a/app/models/team.rb b/app/models/team.rb index afb797f3f..ced73efdc 100644 --- a/app/models/team.rb +++ b/app/models/team.rb @@ -12,14 +12,26 @@ # # Indexes # -# index_teams_on_account_id (account_id) +# index_teams_on_account_id (account_id) +# index_teams_on_name_and_account_id (name,account_id) UNIQUE # # Foreign Keys # # fk_rails_... (account_id => accounts.id) # class Team < ApplicationRecord + include RegexHelper + belongs_to :account has_many :team_members, dependent: :destroy has_many :conversations, dependent: :nullify + + validates :name, + presence: { message: 'must not be blank' }, + format: { with: UNICODE_CHARACTER_NUMBER_HYPHEN_UNDERSCORE }, + uniqueness: { scope: :account_id } + + before_validation do + self.name = name.downcase if attribute_present?('name') + end end diff --git a/app/models/team_member.rb b/app/models/team_member.rb index d621a85a3..0938e9028 100644 --- a/app/models/team_member.rb +++ b/app/models/team_member.rb @@ -10,8 +10,9 @@ # # Indexes # -# index_team_members_on_team_id (team_id) -# index_team_members_on_user_id (user_id) +# index_team_members_on_team_id (team_id) +# index_team_members_on_team_id_and_user_id (team_id,user_id) UNIQUE +# index_team_members_on_user_id (user_id) # # Foreign Keys # diff --git a/app/views/api/v1/accounts/team_members/create.json.jbuilder b/app/views/api/v1/accounts/team_members/create.json.jbuilder index 603a1cc2a..e4924f6a2 100644 --- a/app/views/api/v1/accounts/team_members/create.json.jbuilder +++ b/app/views/api/v1/accounts/team_members/create.json.jbuilder @@ -1 +1,7 @@ -json.partial! 'api/v1/models/agent.json.jbuilder', resource: @team_member +if @team_member + json.partial! 'api/v1/models/agent.json.jbuilder', resource: @team_member +elsif @team_members.present? + json.array! @team_members do |team_member| + json.partial! 'api/v1/models/agent.json.jbuilder', resource: team_member + end +end diff --git a/db/migrate/20210126121313_addunique_index_to_team_members.rb b/db/migrate/20210126121313_addunique_index_to_team_members.rb new file mode 100644 index 000000000..1a1db98eb --- /dev/null +++ b/db/migrate/20210126121313_addunique_index_to_team_members.rb @@ -0,0 +1,6 @@ +class AdduniqueIndexToTeamMembers < ActiveRecord::Migration[6.0] + def change + add_index :teams, [:name, :account_id], unique: true + add_index :team_members, [:team_id, :user_id], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index d5f4e4943..3f84e27c3 100644 --- a/db/schema.rb +++ b/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_01_14_202310) do +ActiveRecord::Schema.define(version: 2021_01_26_121313) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" @@ -498,6 +498,7 @@ ActiveRecord::Schema.define(version: 2021_01_14_202310) do t.bigint "user_id", null: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.index ["team_id", "user_id"], name: "index_team_members_on_team_id_and_user_id", unique: true t.index ["team_id"], name: "index_team_members_on_team_id" t.index ["user_id"], name: "index_team_members_on_user_id" end @@ -510,6 +511,7 @@ ActiveRecord::Schema.define(version: 2021_01_14_202310) do t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.index ["account_id"], name: "index_teams_on_account_id" + t.index ["name", "account_id"], name: "index_teams_on_name_and_account_id", unique: true end create_table "telegram_bots", id: :serial, force: :cascade do |t| diff --git a/spec/controllers/api/v1/accounts/team_members_controller_spec.rb b/spec/controllers/api/v1/accounts/team_members_controller_spec.rb index e45efc6cc..d33b75f7f 100644 --- a/spec/controllers/api/v1/accounts/team_members_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/team_members_controller_spec.rb @@ -52,8 +52,9 @@ RSpec.describe 'Team Members API', type: :request do expect(response).to have_http_status(:unauthorized) end - it 'add a new team member when its administrator' do - params = { user_id: agent.id } + it 'add a new team members when its administrator' do + user_ids = (1..5).map { create(:user, account: account, role: :agent).id } + params = { user_ids: user_ids } post "/api/v1/accounts/#{account.id}/teams/#{team.id}/team_members", params: params, @@ -62,7 +63,7 @@ RSpec.describe 'Team Members API', type: :request do expect(response).to have_http_status(:success) json_response = JSON.parse(response.body) - expect(json_response['id']).to eq(agent.id) + expect(json_response.count).to eq(user_ids.count) end end end @@ -90,9 +91,10 @@ RSpec.describe 'Team Members API', type: :request do expect(response).to have_http_status(:unauthorized) end - it 'destroys the team member when its administrator' do - params = { user_id: agent.id } - create(:team_member, team: team, user: agent) + it 'destroys the team members when its administrator' do + user_ids = (1..5).map { create(:user, account: account, role: :agent).id } + params = { user_ids: user_ids } + delete "/api/v1/accounts/#{account.id}/teams/#{team.id}", params: params, headers: administrator.create_new_auth_token, diff --git a/spec/controllers/api/v1/accounts/teams_controller_spec.rb b/spec/controllers/api/v1/accounts/teams_controller_spec.rb index ae9c64d7e..5c8588867 100644 --- a/spec/controllers/api/v1/accounts/teams_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/teams_controller_spec.rb @@ -75,7 +75,7 @@ RSpec.describe 'Teams API', type: :request do end it 'creates a new team when its administrator' do - params = { name: 'Test Team' } + params = { name: 'test-team' } post "/api/v1/accounts/#{account.id}/teams", params: params, @@ -102,7 +102,7 @@ RSpec.describe 'Teams API', type: :request do let(:administrator) { create(:user, account: account, role: :administrator) } it 'returns unauthorized for agent' do - params = { name: 'New Team' } + params = { name: 'new-team' } put "/api/v1/accounts/#{account.id}/teams/#{team.id}", params: params, @@ -113,7 +113,7 @@ RSpec.describe 'Teams API', type: :request do end it 'updates an existing team when its an administrator' do - params = { name: 'New Team' } + params = { name: 'new-team' } put "/api/v1/accounts/#{account.id}/teams/#{team.id}", params: params, @@ -121,7 +121,7 @@ RSpec.describe 'Teams API', type: :request do as: :json expect(response).to have_http_status(:success) - expect(team.reload.name).to eq('New Team') + expect(team.reload.name).to eq('new-team') end end end