import User from '#models/user' import db from '@adonisjs/lucid/services/db' import { signupValidator } from '#validators/user' import type { HttpContext } from '@adonisjs/core/http' import UserTransformer from '#transformers/user_transformer' import AccessService from '#services/access_service' class InviteGone extends Error {} export default class NewAccountController { async store({ request, response, serialize }: HttpContext) { const { fullName, email, password, invite } = await request.validateUsing(signupValidator) if (AccessService.signup === 'closed') return response.forbidden({ error: 'Signup is closed' }) if (AccessService.signup === 'invite' && !invite) return response.forbidden({ error: 'An invite code is needed to sign up' }) // The user and their invite together: an invite that's gone rolls the signup back. const user = await db .transaction(async (trx) => { const created = await User.create({ fullName, email, password }, { client: trx }) if (AccessService.signup !== 'invite') return created const gives = await AccessService.redeem(invite!, created.id, trx) if (!gives) throw new InviteGone() if (gives.tier) { AccessService.grantTier(created, gives.tier, gives.tier_days) await created.useTransaction(trx).save() } return created }) .catch((error) => { if (error instanceof InviteGone) return null throw error }) if (!user) return response.forbidden({ error: 'Unknown or used invite code' }) const token = await User.accessTokens.create(user) return serialize({ user: UserTransformer.transform(user), token: token.value!.release(), }) } }