1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-12 01:17:04 +02:00

feat: store first seen for users

This commit is contained in:
sjaanus 2024-08-28 16:17:57 +03:00
parent 515d49aefe
commit c16bcbd6c5
No known key found for this signature in database
GPG Key ID: 20E007C0248BA7FF
3 changed files with 25 additions and 0 deletions

View File

@ -22,6 +22,7 @@ const USER_COLUMNS_PUBLIC = [
'email', 'email',
'image_url', 'image_url',
'seen_at', 'seen_at',
'first_seen_at',
'is_service', 'is_service',
'scim_id', 'scim_id',
]; ];
@ -58,6 +59,7 @@ const rowToUser = (row) => {
imageUrl: emptify(row.image_url), imageUrl: emptify(row.image_url),
loginAttempts: row.login_attempts, loginAttempts: row.login_attempts,
seenAt: row.seen_at, seenAt: row.seen_at,
firstSeenAt: row.first_seen_at,
createdAt: row.created_at, createdAt: row.created_at,
isService: row.is_service, isService: row.is_service,
scimId: row.scim_id, scimId: row.scim_id,
@ -233,6 +235,9 @@ class UserStore implements IUserStore {
return this.buildSelectUser(user).update({ return this.buildSelectUser(user).update({
login_attempts: 0, login_attempts: 0,
seen_at: new Date(), seen_at: new Date(),
first_seen_at: this.db.raw('COALESCE(first_seen_at, ?)', [
new Date(),
]),
}); });
} }

View File

@ -11,6 +11,7 @@ export interface UserData {
email?: string; email?: string;
imageUrl?: string; imageUrl?: string;
seenAt?: Date; seenAt?: Date;
firstSeenAt?: Date;
loginAttempts?: number; loginAttempts?: number;
createdAt?: Date; createdAt?: Date;
isService?: boolean; isService?: boolean;
@ -24,6 +25,7 @@ export interface IUser {
email?: string; email?: string;
inviteLink?: string; inviteLink?: string;
seenAt?: Date; seenAt?: Date;
firstSeenAt?: Date;
createdAt?: Date; createdAt?: Date;
permissions: string[]; permissions: string[];
loginAttempts?: number; loginAttempts?: number;
@ -75,6 +77,7 @@ export default class User implements IUser {
username, username,
imageUrl, imageUrl,
seenAt, seenAt,
firstSeenAt,
loginAttempts, loginAttempts,
createdAt, createdAt,
isService, isService,
@ -93,6 +96,7 @@ export default class User implements IUser {
this.email = email!; this.email = email!;
this.imageUrl = imageUrl || this.generateImageUrl(); this.imageUrl = imageUrl || this.generateImageUrl();
this.seenAt = seenAt; this.seenAt = seenAt;
this.firstSeenAt = firstSeenAt;
this.loginAttempts = loginAttempts; this.loginAttempts = loginAttempts;
this.createdAt = createdAt; this.createdAt = createdAt;
this.accountType = isService ? 'Service Account' : 'User'; this.accountType = isService ? 'Service Account' : 'User';

View File

@ -108,6 +108,22 @@ test('should reset user after successful login', async () => {
expect(storedUser.seenAt! >= user.seenAt!).toBe(true); expect(storedUser.seenAt! >= user.seenAt!).toBe(true);
}); });
test('should track and keep first login', async () => {
const store = stores.userStore;
const user = await store.insert({ email: 'firstlogin@mail.com' });
await store.successfullyLogin(user);
const storedUser = await store.getByQuery(user);
expect(storedUser.seenAt).toEqual(storedUser.firstSeenAt);
await store.successfullyLogin(user);
const newLoginUser = await store.getByQuery(user);
expect(storedUser.seenAt).toEqual(newLoginUser.firstSeenAt);
});
test('should only update specified fields on user', async () => { test('should only update specified fields on user', async () => {
const store = stores.userStore; const store = stores.userStore;
const email = 'usertobeupdated@mail.com'; const email = 'usertobeupdated@mail.com';