Skip to content

Commit

Permalink
feat: added user email to ownership and privilege audit logs (#2459)
Browse files Browse the repository at this point in the history
  • Loading branch information
craigzour authored Aug 8, 2023
1 parent 3122649 commit 5315839
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 30 deletions.
6 changes: 3 additions & 3 deletions __tests__/api/users.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,21 +294,21 @@ describe("Users API endpoint", () => {
"2",
{ id: "1", type: "Privilege" },
"GrantPrivilege",
"Granted privilege : View Users by User forms.admin@cds.ca (userID: 1)"
"Granted privilege : View Users to forms@cds.ca (userID: 2) by forms.admin@cds.ca (userID: 1)"
);
expect(mockedLogEvent).toHaveBeenNthCalledWith(
2,
"2",
{ id: "2", type: "Privilege" },
"GrantPrivilege",
"Granted privilege : Manage Settings by User forms.admin@cds.ca (userID: 1)"
"Granted privilege : Manage Settings to forms@cds.ca (userID: 2) by forms.admin@cds.ca (userID: 1)"
);
expect(mockedLogEvent).toHaveBeenNthCalledWith(
3,
"2",
{ id: "3", type: "Privilege" },
"RevokePrivilege",
"Revoked privilege : Manage Forms by User forms.admin@cds.ca (userID: 1)"
"Revoked privilege : Manage Forms from forms@cds.ca (userID: 2) by forms.admin@cds.ca (userID: 1)"
);
});
});
Expand Down
18 changes: 12 additions & 6 deletions lib/privileges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ export const updatePrivilegesForUser = async (
) => {
try {
checkPrivileges(ability, [{ action: "update", subject: "User" }]);

const addPrivileges: { id: string }[] = [];
const removePrivileges: { id: string }[] = [];

privileges.forEach((privilege) => {
if (privilege.action === "add") {
addPrivileges.push({ id: privilege.id });
Expand Down Expand Up @@ -166,6 +168,8 @@ export const updatePrivilegesForUser = async (
},
},
select: {
id: true,
email: true,
privileges: true,
},
}),
Expand All @@ -185,21 +189,23 @@ export const updatePrivilegesForUser = async (
userID,
{ type: "Privilege", id: privilege.id },
"GrantPrivilege",
`Granted privilege : ${privilegesInfo.find((p) => p.id === privilege.id)?.nameEn} by User ${
privilegedUser?.email
} (userID: ${ability.userID})`
`Granted privilege : ${privilegesInfo.find((p) => p.id === privilege.id)?.nameEn} to ${
user.email
} (userID: ${user.id}) by ${privilegedUser?.email} (userID: ${ability.userID})`
)
);

removePrivileges.forEach((privilege) =>
logEvent(
userID,
{ type: "Privilege", id: privilege.id },
"RevokePrivilege",
`Revoked privilege : ${privilegesInfo.find((p) => p.id === privilege.id)?.nameEn} by User ${
privilegedUser?.email
} (userID: ${ability.userID})`
`Revoked privilege : ${privilegesInfo.find((p) => p.id === privilege.id)?.nameEn} from ${
user.email
} (userID: ${user.id}) by ${privilegedUser?.email} (userID: ${ability.userID})`
)
);

// Remove existing values from Cache
await privilegeDelete(userID);

Expand Down
40 changes: 22 additions & 18 deletions lib/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,14 +747,22 @@ export async function updateAssignedUsersForTemplate(
? updatedTemplate.users.map((u) => u.name)
: [];

toAdd.forEach(async (u) => {
const user = await prisma.user.findFirst({
where: {
id: u.id,
},
});
const getUsersFromUserIds = (userIds: string[]) => {
return Promise.all(
userIds.map((userId) => {
return prisma.user.findUniqueOrThrow({
where: {
id: userId,
},
});
})
);
};

if (user && user.email && user.name) {
const usersToAdd = await getUsersFromUserIds(toAdd.map((u) => u.id));

usersToAdd.forEach((user) => {
if (user.email && user.name) {
addOwnershipEmail({
emailTo: user.email,
formTitleEn: updatedTemplate.name,
Expand All @@ -765,14 +773,10 @@ export async function updateAssignedUsersForTemplate(
}
});

toRemove.forEach(async (u) => {
const user = await prisma.user.findFirst({
where: {
id: u.id,
},
});
const usersToRemove = await getUsersFromUserIds(toRemove.map((u) => u.id));

if (user && user.email && user.name) {
usersToRemove.forEach((user) => {
if (user.email && user.name) {
transferOwnershipEmail({
emailTo: user.email,
formTitleEn: updatedTemplate.name,
Expand All @@ -784,20 +788,20 @@ export async function updateAssignedUsersForTemplate(
}
});

toAdd.length > 0 &&
usersToAdd.length > 0 &&
logEvent(
ability.userID,
{ type: "Form", id: formID },
"GrantFormAccess",
`Access granted to ${toAdd.map((user) => user.id).toString()}`
`Access granted to ${usersToAdd.map((user) => user.email ?? user.id).toString()}`
);

toRemove.length > 0 &&
usersToRemove.length > 0 &&
logEvent(
ability.userID,
{ type: "Form", id: formID },
"RevokeFormAccess",
`Access revoked for ${toRemove.map((user) => user.id).toString()}`
`Access revoked for ${usersToRemove.map((user) => user.email ?? user.id).toString()}`
);

if (formCache.cacheAvailable) formCache.formID.invalidate(formID);
Expand Down
19 changes: 16 additions & 3 deletions lib/tests/templates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,9 @@ describe("Template CRUD functions", () => {
(prismaMock.template.update as jest.MockedFunction<any>).mockResolvedValue(
buildPrismaResponse("formtestID", formConfiguration, true)
);
(prismaMock.user.findUniqueOrThrow as jest.MockedFunction<any>).mockResolvedValueOnce({
email: "user2@test.ca",
});

// We're just adding an additional user (2)
const users: { id: string }[] = [{ id: "1" }, { id: "2" }];
Expand Down Expand Up @@ -656,7 +659,7 @@ describe("Template CRUD functions", () => {
fakeSession.user.id,
{ id: "formTestID", type: "Form" },
"GrantFormAccess",
"Access granted to 2"
"Access granted to user2@test.ca"
);

// Template has three users assigned to it to start
Expand All @@ -669,6 +672,16 @@ describe("Template CRUD functions", () => {
(prismaMock.template.update as jest.MockedFunction<any>).mockResolvedValue(
buildPrismaResponse("formtestID", formConfiguration, true)
);
(prismaMock.user.findUniqueOrThrow as jest.MockedFunction<any>)
.mockResolvedValueOnce({
email: "user1@test.ca",
})
.mockResolvedValueOnce({
email: "user2@test.ca",
})
.mockResolvedValueOnce({
email: "user4@test.ca",
});

// We're removing two (2,4) and adding one (1)
const users2: { id: string }[] = [{ id: "1" }, { id: "3" }];
Expand Down Expand Up @@ -705,7 +718,7 @@ describe("Template CRUD functions", () => {
fakeSession.user.id,
{ id: "formTestID", type: "Form" },
"GrantFormAccess",
"Access granted to 1"
"Access granted to user1@test.ca"
);

// Log two removed
Expand All @@ -714,7 +727,7 @@ describe("Template CRUD functions", () => {
fakeSession.user.id,
{ id: "formTestID", type: "Form" },
"RevokeFormAccess",
"Access revoked for 2,4"
"Access revoked for user2@test.ca,user4@test.ca"
);
});

Expand Down

0 comments on commit 5315839

Please sign in to comment.