1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-28 06:32:44 +01:00

refactor(server): user create logic ()

This commit is contained in:
Jason Rasmussen 2024-10-24 17:24:37 -04:00 committed by GitHub
parent fb995816a1
commit 43d18ccc36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 47 additions and 62 deletions

View file

@ -23,7 +23,6 @@ import { OAuthProfile } from 'src/interfaces/oauth.interface';
import { BaseService } from 'src/services/base.service'; import { BaseService } from 'src/services/base.service';
import { isGranted } from 'src/utils/access'; import { isGranted } from 'src/utils/access';
import { HumanReadableSize } from 'src/utils/bytes'; import { HumanReadableSize } from 'src/utils/bytes';
import { createUser } from 'src/utils/user';
export interface LoginDetails { export interface LoginDetails {
isSecure: boolean; isSecure: boolean;
@ -115,16 +114,13 @@ export class AuthService extends BaseService {
throw new BadRequestException('The server already has an admin'); throw new BadRequestException('The server already has an admin');
} }
const admin = await createUser( const admin = await this.createUser({
{ userRepo: this.userRepository, cryptoRepo: this.cryptoRepository }, isAdmin: true,
{ email: dto.email,
isAdmin: true, name: dto.name,
email: dto.email, password: dto.password,
name: dto.name, storageLabel: 'admin',
password: dto.password, });
storageLabel: 'admin',
},
);
return mapUserAdmin(admin); return mapUserAdmin(admin);
} }
@ -234,16 +230,13 @@ export class AuthService extends BaseService {
}); });
const userName = profile.name ?? `${profile.given_name || ''} ${profile.family_name || ''}`; const userName = profile.name ?? `${profile.given_name || ''} ${profile.family_name || ''}`;
user = await createUser( user = await this.createUser({
{ userRepo: this.userRepository, cryptoRepo: this.cryptoRepository }, name: userName,
{ email: profile.email,
name: userName, oauthId: profile.sub,
email: profile.email, quotaSizeInBytes: storageQuota * HumanReadableSize.GiB || null,
oauthId: profile.sub, storageLabel: storageLabel || null,
quotaSizeInBytes: storageQuota * HumanReadableSize.GiB || null, });
storageLabel: storageLabel || null,
},
);
} }
return this.createLoginResponse(user, loginDetails); return this.createLoginResponse(user, loginDetails);

View file

@ -1,6 +1,9 @@
import { Inject } from '@nestjs/common'; import { BadRequestException, Inject } from '@nestjs/common';
import sanitize from 'sanitize-filename';
import { SystemConfig } from 'src/config'; import { SystemConfig } from 'src/config';
import { SALT_ROUNDS } from 'src/constants';
import { StorageCore } from 'src/cores/storage.core'; import { StorageCore } from 'src/cores/storage.core';
import { UserEntity } from 'src/entities/user.entity';
import { IAccessRepository } from 'src/interfaces/access.interface'; import { IAccessRepository } from 'src/interfaces/access.interface';
import { IActivityRepository } from 'src/interfaces/activity.interface'; import { IActivityRepository } from 'src/interfaces/activity.interface';
import { IAlbumUserRepository } from 'src/interfaces/album-user.interface'; import { IAlbumUserRepository } from 'src/interfaces/album-user.interface';
@ -119,4 +122,28 @@ export class BaseService {
checkAccess(request: AccessRequest) { checkAccess(request: AccessRequest) {
return checkAccess(this.accessRepository, request); return checkAccess(this.accessRepository, request);
} }
async createUser(dto: Partial<UserEntity> & { email: string }): Promise<UserEntity> {
const user = await this.userRepository.getByEmail(dto.email);
if (user) {
throw new BadRequestException('User exists');
}
if (!dto.isAdmin) {
const localAdmin = await this.userRepository.getAdmin();
if (!localAdmin) {
throw new BadRequestException('The first registered account must the administrator.');
}
}
const payload: Partial<UserEntity> = { ...dto };
if (payload.password) {
payload.password = await this.cryptoRepository.hashBcrypt(payload.password, SALT_ROUNDS);
}
if (payload.storageLabel) {
payload.storageLabel = sanitize(payload.storageLabel.replaceAll('.', ''));
}
return this.userRepository.create(payload);
}
} }

View file

@ -15,7 +15,6 @@ import { JobName } from 'src/interfaces/job.interface';
import { UserFindOptions } from 'src/interfaces/user.interface'; import { UserFindOptions } from 'src/interfaces/user.interface';
import { BaseService } from 'src/services/base.service'; import { BaseService } from 'src/services/base.service';
import { getPreferences, getPreferencesPartial, mergePreferences } from 'src/utils/preferences'; import { getPreferences, getPreferencesPartial, mergePreferences } from 'src/utils/preferences';
import { createUser } from 'src/utils/user';
@Injectable() @Injectable()
export class UserAdminService extends BaseService { export class UserAdminService extends BaseService {
@ -25,17 +24,18 @@ export class UserAdminService extends BaseService {
} }
async create(dto: UserAdminCreateDto): Promise<UserAdminResponseDto> { async create(dto: UserAdminCreateDto): Promise<UserAdminResponseDto> {
const { notify, ...rest } = dto; const { notify, ...userDto } = dto;
const config = await this.getConfig({ withCache: false }); const config = await this.getConfig({ withCache: false });
if (!config.oauth.enabled && !rest.password) { if (!config.oauth.enabled && !userDto.password) {
throw new BadRequestException('password is required'); throw new BadRequestException('password is required');
} }
const user = await createUser({ userRepo: this.userRepository, cryptoRepo: this.cryptoRepository }, rest);
const user = await this.createUser(userDto);
await this.eventRepository.emit('user.signup', { await this.eventRepository.emit('user.signup', {
notify: !!notify, notify: !!notify,
id: user.id, id: user.id,
tempPassword: user.shouldChangePassword ? rest.password : undefined, tempPassword: user.shouldChangePassword ? userDto.password : undefined,
}); });
return mapUserAdmin(user); return mapUserAdmin(user);

View file

@ -1,35 +0,0 @@
import { BadRequestException } from '@nestjs/common';
import sanitize from 'sanitize-filename';
import { SALT_ROUNDS } from 'src/constants';
import { UserEntity } from 'src/entities/user.entity';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
type RepoDeps = { userRepo: IUserRepository; cryptoRepo: ICryptoRepository };
export const createUser = async (
{ userRepo, cryptoRepo }: RepoDeps,
dto: Partial<UserEntity> & { email: string },
): Promise<UserEntity> => {
const user = await userRepo.getByEmail(dto.email);
if (user) {
throw new BadRequestException('User exists');
}
if (!dto.isAdmin) {
const localAdmin = await userRepo.getAdmin();
if (!localAdmin) {
throw new BadRequestException('The first registered account must the administrator.');
}
}
const payload: Partial<UserEntity> = { ...dto };
if (payload.password) {
payload.password = await cryptoRepo.hashBcrypt(payload.password, SALT_ROUNDS);
}
if (payload.storageLabel) {
payload.storageLabel = sanitize(payload.storageLabel.replaceAll('.', ''));
}
return userRepo.create(payload);
};