Add last logged in to User and delete users who are older than 1 year with no sessions

This commit is contained in:
William Oldham
2023-11-04 11:35:17 +00:00
parent b0af87a6b1
commit 04175fafae
4 changed files with 47 additions and 5 deletions

View File

@@ -22,6 +22,9 @@ export class User {
@Property({ type: 'date' }) @Property({ type: 'date' })
createdAt: Date = new Date(); createdAt: Date = new Date();
@Property({ type: 'date', nullable: true })
lastLoggedIn?: Date;
@Property({ name: 'permissions', type: types.array }) @Property({ name: 'permissions', type: types.array })
roles: string[] = []; roles: string[] = [];

View File

@@ -1,9 +1,9 @@
import { Session } from '@/db/models/Session'; import { Session } from '@/db/models/Session';
import { User } from '@/db/models/User';
import { job } from '@/modules/jobs/job'; import { job } from '@/modules/jobs/job';
// every day at 12:00:00 // every day at 12:00:00
export const sessionExpiryJob = job('0 12 * * *', async ({ em }) => { export const sessionExpiryJob = job('0 12 * * *', async ({ em, log }) => {
await em const deletedSessions = await em
.createQueryBuilder(Session) .createQueryBuilder(Session)
.delete() .delete()
.where({ .where({
@@ -11,5 +11,39 @@ export const sessionExpiryJob = job('0 12 * * *', async ({ em }) => {
$lt: new Date(), $lt: new Date(),
}, },
}) })
.execute(); .execute<{ affectedRows: number }>('run');
log.info(`Removed ${deletedSessions.affectedRows} sessions that had expired`);
const knex = em.getKnex();
// Count all sessions for a user ID
const sessionCountForUser = em
.createQueryBuilder(Session, 'session')
.count()
.where({ user: knex.ref('user.id') })
.getKnexQuery();
const now = new Date();
const oneYearAgo = new Date();
oneYearAgo.setFullYear(now.getFullYear() - 1);
// Delete all users who do not have any sessions AND
// (their login date is null OR they last logged in over 1 year ago)
const deletedUsers = await em
.createQueryBuilder(User, 'user')
.delete()
.withSubQuery(sessionCountForUser, 'session.sessionCount')
.where({
'session.sessionCount': 0,
$or: [
{ lastLoggedIn: { $eq: undefined } },
{ lastLoggedIn: { $lt: oneYearAgo } },
],
})
.execute<{ affectedRows: number }>('run');
log.info(
`Removed ${deletedUsers.affectedRows} users older than 1 year with no sessions`,
);
}); });

View File

@@ -62,13 +62,15 @@ export const loginAuthRouter = makeRouter((app) => {
throw new StatusError('User cannot be found', 401); throw new StatusError('User cannot be found', 401);
} }
user.lastLoggedIn = new Date();
const session = makeSession( const session = makeSession(
user.id, user.id,
body.device, body.device,
req.headers['user-agent'], req.headers['user-agent'],
); );
await em.persistAndFlush(session); await em.persistAndFlush([session, user]);
return { return {
session: formatSession(session), session: formatSession(session),

View File

@@ -64,11 +64,14 @@ export const manageAuthRouter = makeRouter((app) => {
user.namespace = body.namespace; user.namespace = body.namespace;
user.publicKey = body.publicKey; user.publicKey = body.publicKey;
user.profile = body.profile; user.profile = body.profile;
user.lastLoggedIn = new Date();
const session = makeSession( const session = makeSession(
user.id, user.id,
body.device, body.device,
req.headers['user-agent'], req.headers['user-agent'],
); );
await em.persistAndFlush([user, session]); await em.persistAndFlush([user, session]);
getMetrics().user.inc({ namespace: body.namespace }, 1); getMetrics().user.inc({ namespace: body.namespace }, 1);
return { return {