boredgame/src/lib/server/api/services/users.service.ts

149 lines
5.1 KiB
TypeScript

import type { SignupUsernameEmailDto } from '$lib/server/api/dtos/signup-username-email.dto'
import { CredentialsRepository } from '$lib/server/api/repositories/credentials.repository'
import { FederatedIdentityRepository } from '$lib/server/api/repositories/federated_identity.repository'
import { WishlistsRepository } from '$lib/server/api/repositories/wishlists.repository'
import { TokensService } from '$lib/server/api/services/tokens.service'
import { UserRolesService } from '$lib/server/api/services/user_roles.service'
import { inject, injectable } from 'tsyringe'
import {CredentialsType, RoleName} from '../databases/tables'
import { type UpdateUser, UsersRepository } from '../repositories/users.repository'
import { CollectionsService } from './collections.service'
import { DrizzleService } from './drizzle.service'
import { WishlistsService } from './wishlists.service'
import type {OAuthUser} from "$lib/server/api/common/types/oauth-user";
@injectable()
export class UsersService {
constructor(
@inject(CollectionsService) private readonly collectionsService: CollectionsService,
@inject(CredentialsRepository) private readonly credentialsRepository: CredentialsRepository,
@inject(DrizzleService) private readonly drizzleService: DrizzleService,
@inject(FederatedIdentityRepository) private readonly federatedIdentityRepository: FederatedIdentityRepository,
@inject(TokensService) private readonly tokenService: TokensService,
@inject(UsersRepository) private readonly usersRepository: UsersRepository,
@inject(UserRolesService) private readonly userRolesService: UserRolesService,
@inject(WishlistsRepository) private readonly wishlistsRepository: WishlistsRepository,
@inject(WishlistsService) private readonly wishlistsService: WishlistsService,
) {}
async create(data: SignupUsernameEmailDto) {
const { firstName, lastName, email, username, password } = data
const hashedPassword = await this.tokenService.createHashedToken(password)
return await this.drizzleService.db.transaction(async (trx) => {
const createdUser = await this.usersRepository.create(
{
first_name: firstName,
last_name: lastName,
email,
username,
},
trx,
)
if (!createdUser) {
return null
}
const credentials = await this.credentialsRepository.create(
{
user_id: createdUser.id,
type: CredentialsType.PASSWORD,
secret_data: hashedPassword,
},
trx,
)
if (!credentials) {
await this.usersRepository.delete(createdUser.id)
return null
}
await this.userRolesService.addRoleToUser(createdUser.id, RoleName.USER, true, trx)
await this.wishlistsService.createEmptyNoName(createdUser.id, trx)
await this.collectionsService.createEmptyNoName(createdUser.id, trx)
})
}
async createOAuthUser(oAuthUser: OAuthUser, oauthProvider: string) {
return await this.drizzleService.db.transaction(async (trx) => {
const createdUser = await this.usersRepository.create(
{
username: oAuthUser.username || oAuthUser.username,
email: oAuthUser.email || null,
first_name: oAuthUser.given_name || null,
last_name: oAuthUser.family_name || null,
picture: oAuthUser.picture || null,
email_verified: oAuthUser.email_verified || false,
},
trx,
)
if (!createdUser) {
return null
}
await this.federatedIdentityRepository.create(
{
identity_provider: oauthProvider,
user_id: createdUser.id,
federated_user_id: oAuthUser.sub,
federated_username: oAuthUser.email || oAuthUser.username,
},
trx,
)
await this.userRolesService.addRoleToUser(createdUser.id, RoleName.USER, true, trx)
await this.wishlistsService.createEmptyNoName(createdUser.id, trx)
await this.collectionsService.createEmptyNoName(createdUser.id, trx)
return createdUser
})
}
async updateUser(userId: string, data: UpdateUser) {
return this.usersRepository.update(userId, data)
}
async findOneByUsername(username: string) {
return this.usersRepository.findOneByUsername(username)
}
async findOneByEmail(email: string) {
return this.usersRepository.findOneByEmail(email)
}
async findOneById(id: string) {
return this.usersRepository.findOneById(id)
}
async updatePassword(userId: string, password: string) {
const hashedPassword = await this.tokenService.createHashedToken(password)
const currentCredentials = await this.credentialsRepository.findPasswordCredentialsByUserId(userId)
if (!currentCredentials) {
await this.credentialsRepository.create({
user_id: userId,
type: CredentialsType.PASSWORD,
secret_data: hashedPassword,
})
} else {
await this.credentialsRepository.update(currentCredentials.id, {
secret_data: hashedPassword,
})
}
}
async verifyPassword(userId: string, data: { password: string }) {
const user = await this.usersRepository.findOneById(userId)
if (!user) {
throw new Error('User not found')
}
const credential = await this.credentialsRepository.findOneByUserIdAndType(userId, CredentialsType.PASSWORD)
if (!credential) {
throw new Error('Password credentials not found')
}
const { password } = data
return this.tokenService.verifyHashedToken(credential.secret_data, password)
}
}