diff --git a/src/lib/auth/getUserFromToken.ts b/src/lib/auth/getUserFromToken.ts index d888b4f2..4293c194 100644 --- a/src/lib/auth/getUserFromToken.ts +++ b/src/lib/auth/getUserFromToken.ts @@ -14,8 +14,14 @@ async function getUserFromToken(ctx: Context) { const userId: number = ctx.state.user.sub const user = await em.repo(User).findOneOrFail( userId, - getResultCacheOptions(`user-from-token-${userId}-${ctx.state.user.iat}`) + getResultCacheOptions(`user-from-token-${userId}-${ctx.state.user.iat}`, 600_000) ) + + // populate after so the cache doesn't include from circular structures + if (!user.organisation.games.isInitialized()) { + await em.populate(user, ['organisation.games']) + } + return user } diff --git a/src/policies/policy.ts b/src/policies/policy.ts index 6470280c..87c3888a 100644 --- a/src/policies/policy.ts +++ b/src/policies/policy.ts @@ -41,7 +41,7 @@ export default class Policy extends ServicePolicy { async canAccessGame(gameId: number): Promise { const game = await this.em.repo(Game).findOne(gameId, { - ...getResultCacheOptions(`can-access-game-${gameId}`), + ...getResultCacheOptions(`can-access-game-${gameId}`, 600_000), populate: ['organisation.id'] }) diff --git a/src/services/public/user-public.service.ts b/src/services/public/user-public.service.ts index 6aac053a..73188d1d 100644 --- a/src/services/public/user-public.service.ts +++ b/src/services/public/user-public.service.ts @@ -92,7 +92,12 @@ export default class UserPublicService extends Service { user.emailConfirmed = process.env.AUTO_CONFIRM_EMAIL === 'true' if (inviteToken) { - const invite = await em.getRepository(Invite).findOne({ token: inviteToken }) + const invite = await em.getRepository(Invite).findOne({ + token: inviteToken + }, { + populate: ['organisation.games'] + }) + if (!invite || invite.email !== email) req.ctx.throw(404, 'Invite not found') user.organisation = invite.organisation @@ -319,7 +324,9 @@ export default class UserPublicService extends Service { const { code, userId } = req.body const em: EntityManager = req.ctx.em - const user = await em.getRepository(User).findOneOrFail(userId, { populate: ['recoveryCodes'] }) + const user = await em.getRepository(User).findOneOrFail(userId, { + populate: ['recoveryCodes', 'organisation.games'] + }) const redis: Redis = req.ctx.redis const hasSession = (await redis.get(`2fa:${user.id}`)) === 'true' diff --git a/src/services/user.service.ts b/src/services/user.service.ts index aa6a620e..41d0e40e 100644 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -89,10 +89,7 @@ export default class UserService extends Service { path: '/me' }) async me(req: Request): Promise { - const em: EntityManager = req.ctx.em const user = await getUserFromToken(req.ctx) - // cache doesn't include the full organisation - await em.populate(user, ['organisation.games']) return { status: 200, diff --git a/tests/services/_public/user-public/login.test.ts b/tests/services/_public/user-public/login.test.ts index 1de19da7..ccf953a4 100644 --- a/tests/services/_public/user-public/login.test.ts +++ b/tests/services/_public/user-public/login.test.ts @@ -16,7 +16,8 @@ describe('User public service - login', () => { expect(res.body.accessToken).toBeTruthy() expect(res.body.user).toBeTruthy() expect(res.body.user.organisation).toBeTruthy() - expect(new Date(res.body.user.lastSeenAt).getDay()).toBe(new Date().getDay()) + expect(res.body.user.organisation.games).toEqual([]) + expect(new Date(res.body.user.lastSeenAt).getDay()).toEqual(new Date().getDay()) }) it('should not let a user login with the wrong password', async () => { diff --git a/tests/services/_public/user-public/refresh.test.ts b/tests/services/_public/user-public/refresh.test.ts index 2327facb..d4b7c865 100644 --- a/tests/services/_public/user-public/refresh.test.ts +++ b/tests/services/_public/user-public/refresh.test.ts @@ -16,7 +16,10 @@ describe('User public service - refresh', () => { expect(res.body.accessToken).toBeTruthy() expect(res.body.user).toBeTruthy() - expect(new Date(res.body.user.lastSeenAt).getDay()).toBe(new Date().getDay()) + expect(res.body.user.organisation).toBeTruthy() + expect(res.body.user.organisation.games).toEqual([]) + + expect(new Date(res.body.user.lastSeenAt).getDay()).toEqual(new Date().getDay()) }) it('should not let a user refresh their session if they don\'t have one', async () => { diff --git a/tests/services/_public/user-public/register.test.ts b/tests/services/_public/user-public/register.test.ts index 039dc5fe..bd1991e9 100644 --- a/tests/services/_public/user-public/register.test.ts +++ b/tests/services/_public/user-public/register.test.ts @@ -6,6 +6,7 @@ import InviteFactory from '../../../fixtures/InviteFactory' import GameActivity, { GameActivityType } from '../../../../src/entities/game-activity' import PricingPlanFactory from '../../../fixtures/PricingPlanFactory' import { randEmail, randUserName } from '@ngneat/falso' +import createOrganisationAndGame from '../../../utils/createOrganisationAndGame' describe('User public service - register', () => { beforeAll(async () => { @@ -27,6 +28,7 @@ describe('User public service - register', () => { expect(res.body.user.username).toBe(username) expect(res.body.user.password).not.toBeDefined() expect(res.body.user.organisation.name).toBe('Talo') + expect(res.body.user.organisation.games).toEqual([]) }) it('should not let a user register if the email already exists', async () => { @@ -60,7 +62,7 @@ describe('User public service - register', () => { }) it('should let a user register with an invite', async () => { - const organisation = await new OrganisationFactory().one() + const [organisation] = await createOrganisationAndGame() const invite = await new InviteFactory().construct(organisation).one() await em.persistAndFlush(invite) @@ -77,6 +79,7 @@ describe('User public service - register', () => { expect(res.body.user.username).toBe(username) expect(res.body.user.password).not.toBeDefined() expect(res.body.user.organisation.id).toBe(organisation.id) + expect(res.body.user.organisation.games).toHaveLength(1) const activity = await em.getRepository(GameActivity).findOne({ type: GameActivityType.INVITE_ACCEPTED diff --git a/tests/services/_public/user-public/use-recovery-code.test.ts b/tests/services/_public/user-public/use-recovery-code.test.ts index 53311015..b595edfc 100644 --- a/tests/services/_public/user-public/use-recovery-code.test.ts +++ b/tests/services/_public/user-public/use-recovery-code.test.ts @@ -38,6 +38,9 @@ describe('User public service - use recovery code', () => { .expect(200) expect(res.body.user).toBeTruthy() + expect(res.body.user.organisation).toBeTruthy() + expect(res.body.user.organisation.games).toEqual([]) + expect(res.body.accessToken).toBeTruthy() expect(res.body.newRecoveryCodes).toBeUndefined() diff --git a/tests/services/_public/user-public/verify-2fa.test.ts b/tests/services/_public/user-public/verify-2fa.test.ts index 6f5ad126..74c8c5fb 100644 --- a/tests/services/_public/user-public/verify-2fa.test.ts +++ b/tests/services/_public/user-public/verify-2fa.test.ts @@ -20,6 +20,9 @@ describe('User public service - verify 2fa', () => { .expect(200) expect(res.body.user).toBeTruthy() + expect(res.body.user.organisation).toBeTruthy() + expect(res.body.user.organisation.games).toEqual([]) + expect(res.body.accessToken).toBeTruthy() const hasSession = await redis.get(`2fa:${user.id}`) diff --git a/tests/services/user/confirm-2fa.test.ts b/tests/services/user/confirm-2fa.test.ts index 797d4e9c..cb3e0afc 100644 --- a/tests/services/user/confirm-2fa.test.ts +++ b/tests/services/user/confirm-2fa.test.ts @@ -19,6 +19,9 @@ describe('User service - confirm 2fa', () => { .expect(200) expect(res.body.user).toBeTruthy() + expect(res.body.user.organisation).toBeTruthy() + expect(res.body.user.organisation.games).toEqual([]) + expect(res.body.recoveryCodes).toHaveLength(8) await wrap(user.twoFactorAuth!).init() diff --git a/tests/services/user/confirm-email.test.ts b/tests/services/user/confirm-email.test.ts index 4187afec..3b1e2287 100644 --- a/tests/services/user/confirm-email.test.ts +++ b/tests/services/user/confirm-email.test.ts @@ -18,6 +18,8 @@ describe('User service - confirm email', () => { .expect(200) expect(res.body.user.emailConfirmed).toBe(true) + expect(res.body.user.organisation).toBeTruthy() + expect(res.body.user.organisation.games).toEqual([]) const updatedAccessCode = await em.getRepository(UserAccessCode).findOne({ code: accessCode.code }) expect(updatedAccessCode).toBeNull() diff --git a/tests/services/user/disable-2fa.test.ts b/tests/services/user/disable-2fa.test.ts index ab1c53e8..a12985bd 100644 --- a/tests/services/user/disable-2fa.test.ts +++ b/tests/services/user/disable-2fa.test.ts @@ -16,6 +16,8 @@ describe('User service - disable 2fa', () => { .expect(200) expect(res.body.user.has2fa).toBe(false) + expect(res.body.user.organisation).toBeTruthy() + expect(res.body.user.organisation.games).toEqual([]) const recoveryCodes = await em.getRepository(UserRecoveryCode).find({ user }) expect(recoveryCodes).toHaveLength(0)