feat: auditlog for team and inbox member updates (#7516)
- adds an audit log when an agent is added or removed from a team - adds an audit log when an agent is added or removed from an inbox Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
@@ -30,6 +30,10 @@ const translationKeys = {
|
|||||||
'accountuser:create': `AUDIT_LOGS.ACCOUNT_USER.ADD`,
|
'accountuser:create': `AUDIT_LOGS.ACCOUNT_USER.ADD`,
|
||||||
'accountuser:update:self': `AUDIT_LOGS.ACCOUNT_USER.EDIT.SELF`,
|
'accountuser:update:self': `AUDIT_LOGS.ACCOUNT_USER.EDIT.SELF`,
|
||||||
'accountuser:update:other': `AUDIT_LOGS.ACCOUNT_USER.EDIT.OTHER`,
|
'accountuser:update:other': `AUDIT_LOGS.ACCOUNT_USER.EDIT.OTHER`,
|
||||||
|
'inboxmember:create': `AUDIT_LOGS.INBOX_MEMBER.ADD`,
|
||||||
|
'inboxmember:destroy': `AUDIT_LOGS.INBOX_MEMBER.REMOVE`,
|
||||||
|
'teammember:create': `AUDIT_LOGS.TEAM_MEMBER.ADD`,
|
||||||
|
'teammember:destroy': `AUDIT_LOGS.TEAM_MEMBER.REMOVE`,
|
||||||
'account:update': `AUDIT_LOGS.ACCOUNT.EDIT`,
|
'account:update': `AUDIT_LOGS.ACCOUNT.EDIT`,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -102,6 +106,58 @@ function handleAccountUserUpdate(auditLogItem, translationPayload, agentList) {
|
|||||||
return translationPayload;
|
return translationPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setUserInPayload(auditLogItem, translationPayload, agentList) {
|
||||||
|
const userIdChange = auditLogItem.audited_changes.user_id;
|
||||||
|
if (userIdChange && userIdChange !== undefined) {
|
||||||
|
translationPayload.user = getAgentName(userIdChange, agentList);
|
||||||
|
}
|
||||||
|
return translationPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTeamIdInPayload(auditLogItem, translationPayload) {
|
||||||
|
if (auditLogItem.audited_changes.team_id) {
|
||||||
|
translationPayload.team_id = auditLogItem.audited_changes.team_id;
|
||||||
|
}
|
||||||
|
return translationPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setInboxIdInPayload(auditLogItem, translationPayload) {
|
||||||
|
if (auditLogItem.audited_changes.inbox_id) {
|
||||||
|
translationPayload.inbox_id = auditLogItem.audited_changes.inbox_id;
|
||||||
|
}
|
||||||
|
return translationPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInboxTeamMember(auditLogItem, translationPayload, agentList) {
|
||||||
|
if (auditLogItem.audited_changes) {
|
||||||
|
translationPayload = setUserInPayload(
|
||||||
|
auditLogItem,
|
||||||
|
translationPayload,
|
||||||
|
agentList
|
||||||
|
);
|
||||||
|
translationPayload = setTeamIdInPayload(auditLogItem, translationPayload);
|
||||||
|
translationPayload = setInboxIdInPayload(auditLogItem, translationPayload);
|
||||||
|
}
|
||||||
|
return translationPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAccountUser(
|
||||||
|
auditLogItem,
|
||||||
|
translationPayload,
|
||||||
|
agentList,
|
||||||
|
action
|
||||||
|
) {
|
||||||
|
if (action === 'create') {
|
||||||
|
return handleAccountUserCreate(auditLogItem, translationPayload, agentList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'update') {
|
||||||
|
return handleAccountUserUpdate(auditLogItem, translationPayload, agentList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return translationPayload;
|
||||||
|
}
|
||||||
|
|
||||||
export function generateTranslationPayload(auditLogItem, agentList) {
|
export function generateTranslationPayload(auditLogItem, agentList) {
|
||||||
let translationPayload = {
|
let translationPayload = {
|
||||||
agentName: getAgentName(auditLogItem.user_id, agentList),
|
agentName: getAgentName(auditLogItem.user_id, agentList),
|
||||||
@@ -112,21 +168,20 @@ export function generateTranslationPayload(auditLogItem, agentList) {
|
|||||||
const action = auditLogItem.action.toLowerCase();
|
const action = auditLogItem.action.toLowerCase();
|
||||||
|
|
||||||
if (auditableType === 'accountuser') {
|
if (auditableType === 'accountuser') {
|
||||||
if (action === 'create') {
|
translationPayload = handleAccountUser(
|
||||||
translationPayload = handleAccountUserCreate(
|
auditLogItem,
|
||||||
auditLogItem,
|
translationPayload,
|
||||||
translationPayload,
|
agentList,
|
||||||
agentList
|
action
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'update') {
|
if (auditableType === 'inboxmember' || auditableType === 'teammember') {
|
||||||
translationPayload = handleAccountUserUpdate(
|
translationPayload = handleInboxTeamMember(
|
||||||
auditLogItem,
|
auditLogItem,
|
||||||
translationPayload,
|
translationPayload,
|
||||||
agentList
|
agentList
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return translationPayload;
|
return translationPayload;
|
||||||
|
|||||||
@@ -98,6 +98,48 @@ describe('Helper functions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle InboxMember or TeamMember', () => {
|
||||||
|
const auditLogItemInboxMember = {
|
||||||
|
auditable_type: 'InboxMember',
|
||||||
|
action: 'create',
|
||||||
|
audited_changes: {
|
||||||
|
user_id: 2,
|
||||||
|
},
|
||||||
|
user_id: 1,
|
||||||
|
auditable_id: 789,
|
||||||
|
};
|
||||||
|
|
||||||
|
const payloadInboxMember = generateTranslationPayload(
|
||||||
|
auditLogItemInboxMember,
|
||||||
|
agentList
|
||||||
|
);
|
||||||
|
expect(payloadInboxMember).toEqual({
|
||||||
|
agentName: 'Agent 1',
|
||||||
|
id: 789,
|
||||||
|
user: 'Agent 2',
|
||||||
|
});
|
||||||
|
|
||||||
|
const auditLogItemTeamMember = {
|
||||||
|
auditable_type: 'TeamMember',
|
||||||
|
action: 'create',
|
||||||
|
audited_changes: {
|
||||||
|
user_id: 3,
|
||||||
|
},
|
||||||
|
user_id: 1,
|
||||||
|
auditable_id: 789,
|
||||||
|
};
|
||||||
|
|
||||||
|
const payloadTeamMember = generateTranslationPayload(
|
||||||
|
auditLogItemTeamMember,
|
||||||
|
agentList
|
||||||
|
);
|
||||||
|
expect(payloadTeamMember).toEqual({
|
||||||
|
agentName: 'Agent 1',
|
||||||
|
id: 789,
|
||||||
|
user: 'Agent 3',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle generic case like Team create', () => {
|
it('should handle generic case like Team create', () => {
|
||||||
const auditLogItem = {
|
const auditLogItem = {
|
||||||
auditable_type: 'Team',
|
auditable_type: 'Team',
|
||||||
|
|||||||
@@ -56,8 +56,16 @@
|
|||||||
"EDIT": "%{agentName} updated a macro (#%{id})",
|
"EDIT": "%{agentName} updated a macro (#%{id})",
|
||||||
"DELETE": "%{agentName} deleted a macro (#%{id})"
|
"DELETE": "%{agentName} deleted a macro (#%{id})"
|
||||||
},
|
},
|
||||||
|
"INBOX_MEMBER": {
|
||||||
|
"ADD": "%{agentName} added %{user} to the inbox(#%{inbox_id})",
|
||||||
|
"REMOVE": "%{agentName} removed %{user} from the inbox(#%{inbox_id})"
|
||||||
|
},
|
||||||
|
"TEAM_MEMBER": {
|
||||||
|
"ADD": "%{agentName} added %{user} to the team(#%{team_id})",
|
||||||
|
"REMOVE": "%{agentName} removed %{user} from the team(#%{team_id})"
|
||||||
|
},
|
||||||
"ACCOUNT": {
|
"ACCOUNT": {
|
||||||
"EDIT": "%{agentName} updated the account configuration (#%{id})"
|
"EDIT": "%{agentName} updated the account configuration (#%{id})"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,3 +35,5 @@ class InboxMember < ApplicationRecord
|
|||||||
::AutoAssignment::InboxRoundRobinService.new(inbox: inbox).remove_agent_from_queue(user_id) if inbox.present?
|
::AutoAssignment::InboxRoundRobinService.new(inbox: inbox).remove_agent_from_queue(user_id) if inbox.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
InboxMember.include_mod_with('Audit::InboxMember')
|
||||||
|
|||||||
@@ -19,3 +19,5 @@ class TeamMember < ApplicationRecord
|
|||||||
belongs_to :team
|
belongs_to :team
|
||||||
validates :user_id, uniqueness: { scope: :team_id }
|
validates :user_id, uniqueness: { scope: :team_id }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
TeamMember.include_mod_with('Audit::TeamMember')
|
||||||
|
|||||||
31
enterprise/app/models/enterprise/audit/inbox_member.rb
Normal file
31
enterprise/app/models/enterprise/audit/inbox_member.rb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
module Enterprise::Audit::InboxMember
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
after_commit :create_audit_log_entry_on_create, on: :create
|
||||||
|
after_commit :create_audit_log_entry_on_delete, on: :destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def create_audit_log_entry_on_create
|
||||||
|
create_audit_log_entry('create')
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_audit_log_entry_on_delete
|
||||||
|
create_audit_log_entry('destroy')
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_audit_log_entry(action)
|
||||||
|
return if inbox.blank?
|
||||||
|
|
||||||
|
Enterprise::AuditLog.create(
|
||||||
|
auditable_id: id,
|
||||||
|
auditable_type: 'InboxMember',
|
||||||
|
action: action,
|
||||||
|
associated_id: inbox&.account_id,
|
||||||
|
audited_changes: attributes.except('updated_at', 'created_at'),
|
||||||
|
associated_type: 'Account'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
31
enterprise/app/models/enterprise/audit/team_member.rb
Normal file
31
enterprise/app/models/enterprise/audit/team_member.rb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
module Enterprise::Audit::TeamMember
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
after_commit :create_audit_log_entry_on_create, on: :create
|
||||||
|
after_commit :create_audit_log_entry_on_delete, on: :destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def create_audit_log_entry_on_create
|
||||||
|
create_audit_log_entry('create')
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_audit_log_entry_on_delete
|
||||||
|
create_audit_log_entry('destroy')
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_audit_log_entry(action)
|
||||||
|
return if team.blank?
|
||||||
|
|
||||||
|
Enterprise::AuditLog.create(
|
||||||
|
auditable_id: id,
|
||||||
|
auditable_type: 'TeamMember',
|
||||||
|
action: action,
|
||||||
|
associated_id: team&.account_id,
|
||||||
|
audited_changes: attributes.except('updated_at', 'created_at'),
|
||||||
|
associated_type: 'Account'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
31
spec/enterprise/models/inbox_member_spec.rb
Normal file
31
spec/enterprise/models/inbox_member_spec.rb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe InboxMember, type: :model do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:inbox) { create(:inbox) }
|
||||||
|
let!(:inbox_member) { create(:inbox_member, inbox: inbox, user: user) }
|
||||||
|
|
||||||
|
describe 'audit log' do
|
||||||
|
context 'when inbox member is created' do
|
||||||
|
it 'has associated audit log created' do
|
||||||
|
expect(Audited::Audit.where(auditable: inbox_member, action: 'create').count).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'has user_id in audited_changes matching user.id' do
|
||||||
|
audit_log = Audited::Audit.find_by(auditable: inbox_member, action: 'create')
|
||||||
|
expect(audit_log.audited_changes['user_id']).to eq(user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when inbox member is destroyed' do
|
||||||
|
it 'has associated audit log created' do
|
||||||
|
inbox_member.destroy
|
||||||
|
audit_log = Audited::Audit.find_by(auditable: inbox_member, action: 'destroy')
|
||||||
|
expect(audit_log).to be_present
|
||||||
|
expect(audit_log.audited_changes['inbox_id']).to eq(inbox.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
31
spec/enterprise/models/team_member_spec.rb
Normal file
31
spec/enterprise/models/team_member_spec.rb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe TeamMember, type: :model do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:team) { create(:team) }
|
||||||
|
let!(:team_member) { create(:team_member, user: user, team: team) }
|
||||||
|
|
||||||
|
describe 'audit log' do
|
||||||
|
context 'when team member is created' do
|
||||||
|
it 'has associated audit log created' do
|
||||||
|
expect(Audited::Audit.where(auditable: team_member, action: 'create').count).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'has user_id in audited_changes matching user.id' do
|
||||||
|
audit_log = Audited::Audit.find_by(auditable: team_member, action: 'create')
|
||||||
|
expect(audit_log.audited_changes['user_id']).to eq(user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when team member is destroyed' do
|
||||||
|
it 'has associated audit log created' do
|
||||||
|
team_member.destroy
|
||||||
|
audit_log = Audited::Audit.find_by(auditable: team_member, action: 'destroy')
|
||||||
|
expect(audit_log).to be_present
|
||||||
|
expect(audit_log.audited_changes['team_id']).to eq(team.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user