feat(server): user metadata (#9650)

* feat(server): user metadata

* add missing method to user mock

* update migration to include cascades

* update sql files

* test: fix e2e

* chore: clean up

---------

Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
This commit is contained in:
Jason Rasmussen
2024-05-22 08:13:36 -04:00
committed by GitHub
parent a4887bfa7e
commit 06ce8247cc
24 changed files with 267 additions and 126 deletions
+39 -4
View File
@@ -6,6 +6,7 @@ import { UserCore } from 'src/cores/user.core';
import { AuthDto } from 'src/dtos/auth.dto';
import { CreateProfileImageResponseDto, mapCreateProfileImageResponse } from 'src/dtos/user-profile.dto';
import { CreateUserDto, DeleteUserDto, UpdateUserDto, UserResponseDto, mapUser } from 'src/dtos/user.dto';
import { UserMetadataKey } from 'src/entities/user-metadata.entity';
import { UserEntity, UserStatus } from 'src/entities/user.entity';
import { IAlbumRepository } from 'src/interfaces/album.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
@@ -16,6 +17,7 @@ import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository, UserFindOptions } from 'src/interfaces/user.interface';
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
import { getPreferences, getPreferencesPartial } from 'src/utils/preferences';
@Injectable()
export class UserService {
@@ -61,9 +63,21 @@ export class UserService {
}
async create(dto: CreateUserDto): Promise<UserResponseDto> {
const user = await this.userCore.createUser(dto);
const tempPassword = user.shouldChangePassword ? dto.password : undefined;
if (dto.notify) {
const { memoriesEnabled, notify, ...rest } = dto;
let user = await this.userCore.createUser(rest);
// TODO remove and replace with entire dto.preferences config
if (memoriesEnabled === false) {
await this.userRepository.upsertMetadata(user.id, {
key: UserMetadataKey.PREFERENCES,
value: { memories: { enabled: false } },
});
user = await this.findOrFail(user.id, {});
}
const tempPassword = user.shouldChangePassword ? rest.password : undefined;
if (notify) {
await this.jobRepository.queue({ name: JobName.NOTIFY_SIGNUP, data: { id: user.id, tempPassword } });
}
return mapUser(user);
@@ -76,7 +90,28 @@ export class UserService {
await this.userRepository.syncUsage(dto.id);
}
return this.userCore.updateUser(auth.user, dto.id, dto).then(mapUser);
// TODO replace with entire preferences object
if (dto.memoriesEnabled !== undefined || dto.avatarColor) {
const newPreferences = getPreferences(user);
if (dto.memoriesEnabled !== undefined) {
newPreferences.memories.enabled = dto.memoriesEnabled;
delete dto.memoriesEnabled;
}
if (dto.avatarColor) {
newPreferences.avatar.color = dto.avatarColor;
delete dto.avatarColor;
}
await this.userRepository.upsertMetadata(dto.id, {
key: UserMetadataKey.PREFERENCES,
value: getPreferencesPartial(user, newPreferences),
});
}
const updatedUser = await this.userCore.updateUser(auth.user, dto.id, dto);
return mapUser(updatedUser);
}
async delete(auth: AuthDto, id: string, dto: DeleteUserDto): Promise<UserResponseDto> {