Skip to content

Commit

Permalink
feat: store user last accessed attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
shreddedbacon committed Mar 27, 2024
1 parent 1ef8e57 commit 3e7284c
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 0 deletions.
34 changes: 34 additions & 0 deletions services/api/src/models/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface User {
firstName?: string;
lastName?: string;
comment?: string;
lastAccessed?: string;
gitlabId?: string;
attributes?: IUserAttributes;
owner?: boolean;
Expand Down Expand Up @@ -54,6 +55,7 @@ interface UserModel {
updateUser: (userInput: UserEdit) => Promise<User>;
deleteUser: (id: string) => Promise<void>;
resetUserPassword: (id: string) => Promise<void>;
userLastAccessed: (userInput: User) => Promise<Boolean>;
transformKeycloakUsers: (keycloakUsers: UserRepresentation[]) => Promise<User[]>;
}

Expand Down Expand Up @@ -170,8 +172,14 @@ export const User = (clients: {
let usersWithGitlabIdFetch = [];

for (const user of users) {
// set the lastaccessed attribute
let date = null;
if (user['attributes']['last_accessed']) {
date = new Date(user['attributes']['last_accessed']*1000).toISOString()
}
usersWithGitlabIdFetch.push({
...user,
lastAccessed: date,
gitlabId: await fetchGitlabId(user)
});
}
Expand Down Expand Up @@ -510,6 +518,31 @@ export const User = (clients: {
}
};

const userLastAccessed = async (userInput: User): Promise<Boolean> => {
// set the last accessed as a unix timestamp on the user attributes
try {
const lastAccessed = {last_accessed: Math.floor(Date.now() / 1000)}
await keycloakAdminClient.users.update(
{
id: userInput.id
},
{
attributes: {
...userInput.attributes,
...lastAccessed
}
}
);
} catch (err) {
if (err.response.status && err.response.status === 404) {
throw new UserNotFoundError(`User not found: ${userInput.id}`);
} else {
logger.warn(`Error updating Keycloak user: ${err.message}`);
}
}
return true
};

const updateUser = async (userInput: UserEdit): Promise<User> => {
// comments used to be removed when updating a user, now they aren't
let organizations = null;
Expand Down Expand Up @@ -638,6 +671,7 @@ export const User = (clients: {
getUserRolesForProject,
addUser,
updateUser,
userLastAccessed,
deleteUser,
resetUserPassword,
transformKeycloakUsers
Expand Down
1 change: 1 addition & 0 deletions services/api/src/typeDefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ const typeDefs = gql`
# This just returns the group name, id and the role the user has in that group.
# This is a neat way to visualize a users specific access without having to get all members of a group
groupRoles: [GroupRoleInterface]
lastAccessed: String
}
type GroupMembership {
Expand Down
1 change: 1 addition & 0 deletions services/api/src/util/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export const keycloakHasPermission = (grant, requestCache, modelClients, service
currentUser: [currentUser.id]
};

await UserModel.userLastAccessed(currentUser);

const usersAttribute = R.prop('users', attributes);
if (usersAttribute && usersAttribute.length) {
Expand Down

0 comments on commit 3e7284c

Please sign in to comment.