mirror of
https://github.com/immich-app/immich.git
synced 2025-06-01 04:36:19 -04:00
refactor: metadata entity (#17492)
This commit is contained in:
parent
3e372500b0
commit
206545356d
@ -1,6 +1,5 @@
|
|||||||
import { UserMetadataEntity } from 'src/entities/user-metadata.entity';
|
|
||||||
import { AssetStatus, AssetType, MemoryType, Permission, UserStatus } from 'src/enum';
|
import { AssetStatus, AssetType, MemoryType, Permission, UserStatus } from 'src/enum';
|
||||||
import { OnThisDayData } from 'src/types';
|
import { OnThisDayData, UserMetadataItem } from 'src/types';
|
||||||
|
|
||||||
export type AuthUser = {
|
export type AuthUser = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -96,7 +95,7 @@ export type UserAdmin = User & {
|
|||||||
quotaSizeInBytes: number | null;
|
quotaSizeInBytes: number | null;
|
||||||
quotaUsageInBytes: number;
|
quotaUsageInBytes: number;
|
||||||
status: UserStatus;
|
status: UserStatus;
|
||||||
metadata: UserMetadataEntity[];
|
metadata: UserMetadataItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Asset = {
|
export type Asset = {
|
||||||
|
@ -2,7 +2,6 @@ import { ApiProperty } from '@nestjs/swagger';
|
|||||||
import { IsEnum, IsNotEmpty, IsString, ValidateIf } from 'class-validator';
|
import { IsEnum, IsNotEmpty, IsString, ValidateIf } from 'class-validator';
|
||||||
import { Activity } from 'src/database';
|
import { Activity } from 'src/database';
|
||||||
import { mapUser, UserResponseDto } from 'src/dtos/user.dto';
|
import { mapUser, UserResponseDto } from 'src/dtos/user.dto';
|
||||||
import { UserEntity } from 'src/entities/user.entity';
|
|
||||||
import { Optional, ValidateUUID } from 'src/validation';
|
import { Optional, ValidateUUID } from 'src/validation';
|
||||||
|
|
||||||
export enum ReactionType {
|
export enum ReactionType {
|
||||||
@ -75,6 +74,6 @@ export const mapActivity = (activity: Activity): ActivityResponseDto => {
|
|||||||
createdAt: activity.createdAt,
|
createdAt: activity.createdAt,
|
||||||
comment: activity.comment,
|
comment: activity.comment,
|
||||||
type: activity.isLiked ? ReactionType.LIKE : ReactionType.COMMENT,
|
type: activity.isLiked ? ReactionType.LIKE : ReactionType.COMMENT,
|
||||||
user: mapUser(activity.user as unknown as UserEntity),
|
user: mapUser(activity.user),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
import { IsDateString, IsEnum, IsInt, IsPositive, ValidateNested } from 'class-validator';
|
import { IsDateString, IsEnum, IsInt, IsPositive, ValidateNested } from 'class-validator';
|
||||||
import { UserPreferences } from 'src/entities/user-metadata.entity';
|
|
||||||
import { UserAvatarColor } from 'src/enum';
|
import { UserAvatarColor } from 'src/enum';
|
||||||
|
import { UserPreferences } from 'src/types';
|
||||||
import { Optional, ValidateBoolean } from 'src/validation';
|
import { Optional, ValidateBoolean } from 'src/validation';
|
||||||
|
|
||||||
class AvatarUpdate {
|
class AvatarUpdate {
|
||||||
|
@ -2,9 +2,9 @@ import { ApiProperty } from '@nestjs/swagger';
|
|||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import { IsBoolean, IsEmail, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator';
|
import { IsBoolean, IsEmail, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator';
|
||||||
import { User, UserAdmin } from 'src/database';
|
import { User, UserAdmin } from 'src/database';
|
||||||
import { UserMetadataEntity, UserMetadataItem } from 'src/entities/user-metadata.entity';
|
|
||||||
import { UserEntity } from 'src/entities/user.entity';
|
import { UserEntity } from 'src/entities/user.entity';
|
||||||
import { UserAvatarColor, UserMetadataKey, UserStatus } from 'src/enum';
|
import { UserAvatarColor, UserMetadataKey, UserStatus } from 'src/enum';
|
||||||
|
import { UserMetadataItem } from 'src/types';
|
||||||
import { getPreferences } from 'src/utils/preferences';
|
import { getPreferences } from 'src/utils/preferences';
|
||||||
import { Optional, ValidateBoolean, toEmail, toSanitized } from 'src/validation';
|
import { Optional, ValidateBoolean, toEmail, toSanitized } from 'src/validation';
|
||||||
|
|
||||||
@ -143,8 +143,9 @@ export class UserAdminResponseDto extends UserResponseDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function mapUserAdmin(entity: UserEntity | UserAdmin): UserAdminResponseDto {
|
export function mapUserAdmin(entity: UserEntity | UserAdmin): UserAdminResponseDto {
|
||||||
const license = (entity.metadata as UserMetadataItem[])?.find(
|
const metadata = entity.metadata || [];
|
||||||
(item): item is UserMetadataEntity<UserMetadataKey.LICENSE> => item.key === UserMetadataKey.LICENSE,
|
const license = metadata.find(
|
||||||
|
(item): item is UserMetadataItem<UserMetadataKey.LICENSE> => item.key === UserMetadataKey.LICENSE,
|
||||||
)?.value;
|
)?.value;
|
||||||
return {
|
return {
|
||||||
...mapUser(entity),
|
...mapUser(entity),
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
import { UserEntity } from 'src/entities/user.entity';
|
|
||||||
import { UserAvatarColor, UserMetadataKey } from 'src/enum';
|
|
||||||
import { DeepPartial } from 'src/types';
|
|
||||||
import { HumanReadableSize } from 'src/utils/bytes';
|
|
||||||
|
|
||||||
export type UserMetadataItem<T extends keyof UserMetadata = UserMetadataKey> = {
|
|
||||||
key: T;
|
|
||||||
value: UserMetadata[T];
|
|
||||||
};
|
|
||||||
|
|
||||||
export class UserMetadataEntity<T extends keyof UserMetadata = UserMetadataKey> implements UserMetadataItem<T> {
|
|
||||||
userId!: string;
|
|
||||||
user?: UserEntity;
|
|
||||||
key!: T;
|
|
||||||
value!: UserMetadata[T];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserPreferences {
|
|
||||||
folders: {
|
|
||||||
enabled: boolean;
|
|
||||||
sidebarWeb: boolean;
|
|
||||||
};
|
|
||||||
memories: {
|
|
||||||
enabled: boolean;
|
|
||||||
};
|
|
||||||
people: {
|
|
||||||
enabled: boolean;
|
|
||||||
sidebarWeb: boolean;
|
|
||||||
};
|
|
||||||
ratings: {
|
|
||||||
enabled: boolean;
|
|
||||||
};
|
|
||||||
sharedLinks: {
|
|
||||||
enabled: boolean;
|
|
||||||
sidebarWeb: boolean;
|
|
||||||
};
|
|
||||||
tags: {
|
|
||||||
enabled: boolean;
|
|
||||||
sidebarWeb: boolean;
|
|
||||||
};
|
|
||||||
avatar: {
|
|
||||||
color: UserAvatarColor;
|
|
||||||
};
|
|
||||||
emailNotifications: {
|
|
||||||
enabled: boolean;
|
|
||||||
albumInvite: boolean;
|
|
||||||
albumUpdate: boolean;
|
|
||||||
};
|
|
||||||
download: {
|
|
||||||
archiveSize: number;
|
|
||||||
includeEmbeddedVideos: boolean;
|
|
||||||
};
|
|
||||||
purchase: {
|
|
||||||
showSupportBadge: boolean;
|
|
||||||
hideBuyButtonUntil: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getDefaultPreferences = (user: { email: string }): UserPreferences => {
|
|
||||||
const values = Object.values(UserAvatarColor);
|
|
||||||
const randomIndex = Math.floor(
|
|
||||||
[...user.email].map((letter) => letter.codePointAt(0) ?? 0).reduce((a, b) => a + b, 0) % values.length,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
folders: {
|
|
||||||
enabled: false,
|
|
||||||
sidebarWeb: false,
|
|
||||||
},
|
|
||||||
memories: {
|
|
||||||
enabled: true,
|
|
||||||
},
|
|
||||||
people: {
|
|
||||||
enabled: true,
|
|
||||||
sidebarWeb: false,
|
|
||||||
},
|
|
||||||
sharedLinks: {
|
|
||||||
enabled: true,
|
|
||||||
sidebarWeb: false,
|
|
||||||
},
|
|
||||||
ratings: {
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
tags: {
|
|
||||||
enabled: false,
|
|
||||||
sidebarWeb: false,
|
|
||||||
},
|
|
||||||
avatar: {
|
|
||||||
color: values[randomIndex],
|
|
||||||
},
|
|
||||||
emailNotifications: {
|
|
||||||
enabled: true,
|
|
||||||
albumInvite: true,
|
|
||||||
albumUpdate: true,
|
|
||||||
},
|
|
||||||
download: {
|
|
||||||
archiveSize: HumanReadableSize.GiB * 4,
|
|
||||||
includeEmbeddedVideos: false,
|
|
||||||
},
|
|
||||||
purchase: {
|
|
||||||
showSupportBadge: true,
|
|
||||||
hideBuyButtonUntil: new Date(2022, 1, 12).toISOString(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface UserMetadata extends Record<UserMetadataKey, Record<string, any>> {
|
|
||||||
[UserMetadataKey.PREFERENCES]: DeepPartial<UserPreferences>;
|
|
||||||
[UserMetadataKey.LICENSE]: { licenseKey: string; activationKey: string; activatedAt: string };
|
|
||||||
}
|
|
@ -2,8 +2,8 @@ import { ExpressionBuilder } from 'kysely';
|
|||||||
import { jsonArrayFrom } from 'kysely/helpers/postgres';
|
import { jsonArrayFrom } from 'kysely/helpers/postgres';
|
||||||
import { DB } from 'src/db';
|
import { DB } from 'src/db';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { UserMetadataEntity } from 'src/entities/user-metadata.entity';
|
|
||||||
import { UserStatus } from 'src/enum';
|
import { UserStatus } from 'src/enum';
|
||||||
|
import { UserMetadataItem } from 'src/types';
|
||||||
|
|
||||||
export class UserEntity {
|
export class UserEntity {
|
||||||
id!: string;
|
id!: string;
|
||||||
@ -23,7 +23,7 @@ export class UserEntity {
|
|||||||
assets!: AssetEntity[];
|
assets!: AssetEntity[];
|
||||||
quotaSizeInBytes!: number | null;
|
quotaSizeInBytes!: number | null;
|
||||||
quotaUsageInBytes!: number;
|
quotaUsageInBytes!: number;
|
||||||
metadata!: UserMetadataEntity[];
|
metadata!: UserMetadataItem[];
|
||||||
profileChangedAt!: Date;
|
profileChangedAt!: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,10 @@ import { InjectKysely } from 'nestjs-kysely';
|
|||||||
import { columns, UserAdmin } from 'src/database';
|
import { columns, UserAdmin } from 'src/database';
|
||||||
import { DB, UserMetadata as DbUserMetadata } from 'src/db';
|
import { DB, UserMetadata as DbUserMetadata } from 'src/db';
|
||||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||||
import { UserMetadata, UserMetadataItem } from 'src/entities/user-metadata.entity';
|
|
||||||
import { UserEntity, withMetadata } from 'src/entities/user.entity';
|
import { UserEntity, withMetadata } from 'src/entities/user.entity';
|
||||||
import { AssetType, UserStatus } from 'src/enum';
|
import { AssetType, UserStatus } from 'src/enum';
|
||||||
import { UserTable } from 'src/schema/tables/user.table';
|
import { UserTable } from 'src/schema/tables/user.table';
|
||||||
|
import { UserMetadata, UserMetadataItem } from 'src/types';
|
||||||
import { asUuid } from 'src/utils/database';
|
import { asUuid } from 'src/utils/database';
|
||||||
|
|
||||||
type Upsert = Insertable<DbUserMetadata>;
|
type Upsert = Insertable<DbUserMetadata>;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { UserMetadata, UserMetadataItem } from 'src/entities/user-metadata.entity';
|
|
||||||
import { UserMetadataKey } from 'src/enum';
|
import { UserMetadataKey } from 'src/enum';
|
||||||
import { UserTable } from 'src/schema/tables/user.table';
|
import { UserTable } from 'src/schema/tables/user.table';
|
||||||
import { Column, ForeignKeyColumn, PrimaryColumn, Table } from 'src/sql-tools';
|
import { Column, ForeignKeyColumn, PrimaryColumn, Table } from 'src/sql-tools';
|
||||||
|
import { UserMetadata, UserMetadataItem } from 'src/types';
|
||||||
|
|
||||||
@Table('user_metadata')
|
@Table('user_metadata')
|
||||||
export class UserMetadataTable<T extends keyof UserMetadata = UserMetadataKey> implements UserMetadataItem<T> {
|
export class UserMetadataTable<T extends keyof UserMetadata = UserMetadataKey> implements UserMetadataItem<T> {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { BadRequestException, ForbiddenException, UnauthorizedException } from '@nestjs/common';
|
import { BadRequestException, ForbiddenException, UnauthorizedException } from '@nestjs/common';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { AuthDto, SignUpDto } from 'src/dtos/auth.dto';
|
import { AuthDto, SignUpDto } from 'src/dtos/auth.dto';
|
||||||
import { UserMetadataEntity } from 'src/entities/user-metadata.entity';
|
|
||||||
import { UserEntity } from 'src/entities/user.entity';
|
import { UserEntity } from 'src/entities/user.entity';
|
||||||
import { AuthType, Permission } from 'src/enum';
|
import { AuthType, Permission } from 'src/enum';
|
||||||
import { AuthService } from 'src/services/auth.service';
|
import { AuthService } from 'src/services/auth.service';
|
||||||
|
import { UserMetadataItem } from 'src/types';
|
||||||
import { sharedLinkStub } from 'test/fixtures/shared-link.stub';
|
import { sharedLinkStub } from 'test/fixtures/shared-link.stub';
|
||||||
import { systemConfigStub } from 'test/fixtures/system-config.stub';
|
import { systemConfigStub } from 'test/fixtures/system-config.stub';
|
||||||
import { userStub } from 'test/fixtures/user.stub';
|
import { userStub } from 'test/fixtures/user.stub';
|
||||||
@ -230,7 +230,7 @@ describe('AuthService', () => {
|
|||||||
...dto,
|
...dto,
|
||||||
id: 'admin',
|
id: 'admin',
|
||||||
createdAt: new Date('2021-01-01'),
|
createdAt: new Date('2021-01-01'),
|
||||||
metadata: [] as UserMetadataEntity[],
|
metadata: [] as UserMetadataItem[],
|
||||||
} as UserEntity);
|
} as UserEntity);
|
||||||
|
|
||||||
await expect(sut.adminSignUp(dto)).resolves.toMatchObject({
|
await expect(sut.adminSignUp(dto)).resolves.toMatchObject({
|
||||||
|
@ -357,8 +357,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: false, albumInvite: true } },
|
value: { emailNotifications: { enabled: false, albumInvite: true } },
|
||||||
userId: userStub.user1.id,
|
|
||||||
user: userStub.user1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -374,8 +372,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: true, albumInvite: false } },
|
value: { emailNotifications: { enabled: true, albumInvite: false } },
|
||||||
userId: userStub.user1.id,
|
|
||||||
user: userStub.user1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -391,8 +387,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
||||||
userId: userStub.user1.id,
|
|
||||||
user: userStub.user1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -414,8 +408,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
||||||
userId: userStub.user1.id,
|
|
||||||
user: userStub.user1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -443,8 +435,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
||||||
userId: userStub.user1.id,
|
|
||||||
user: userStub.user1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -476,8 +466,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
value: { emailNotifications: { enabled: true, albumInvite: true } },
|
||||||
userId: userStub.user1.id,
|
|
||||||
user: userStub.user1,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -536,8 +524,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: false, albumUpdate: true } },
|
value: { emailNotifications: { enabled: false, albumUpdate: true } },
|
||||||
user: userStub.user1,
|
|
||||||
userId: userStub.user1.id,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -559,8 +545,6 @@ describe(NotificationService.name, () => {
|
|||||||
{
|
{
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { emailNotifications: { enabled: true, albumUpdate: false } },
|
value: { emailNotifications: { enabled: true, albumUpdate: false } },
|
||||||
user: userStub.user1,
|
|
||||||
userId: userStub.user1.id,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -8,12 +8,11 @@ import { LicenseKeyDto, LicenseResponseDto } from 'src/dtos/license.dto';
|
|||||||
import { UserPreferencesResponseDto, UserPreferencesUpdateDto, mapPreferences } from 'src/dtos/user-preferences.dto';
|
import { UserPreferencesResponseDto, UserPreferencesUpdateDto, mapPreferences } from 'src/dtos/user-preferences.dto';
|
||||||
import { CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto';
|
import { CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto';
|
||||||
import { UserAdminResponseDto, UserResponseDto, UserUpdateMeDto, mapUser, mapUserAdmin } from 'src/dtos/user.dto';
|
import { UserAdminResponseDto, UserResponseDto, UserUpdateMeDto, mapUser, mapUserAdmin } from 'src/dtos/user.dto';
|
||||||
import { UserMetadataEntity } from 'src/entities/user-metadata.entity';
|
|
||||||
import { UserEntity } from 'src/entities/user.entity';
|
import { UserEntity } from 'src/entities/user.entity';
|
||||||
import { CacheControl, JobName, JobStatus, QueueName, StorageFolder, UserMetadataKey } from 'src/enum';
|
import { CacheControl, JobName, JobStatus, QueueName, StorageFolder, UserMetadataKey } from 'src/enum';
|
||||||
import { UserFindOptions } from 'src/repositories/user.repository';
|
import { UserFindOptions } from 'src/repositories/user.repository';
|
||||||
import { BaseService } from 'src/services/base.service';
|
import { BaseService } from 'src/services/base.service';
|
||||||
import { JobOf } from 'src/types';
|
import { JobOf, UserMetadataItem } from 'src/types';
|
||||||
import { ImmichFileResponse } from 'src/utils/file';
|
import { ImmichFileResponse } from 'src/utils/file';
|
||||||
import { getPreferences, getPreferencesPartial, mergePreferences } from 'src/utils/preferences';
|
import { getPreferences, getPreferencesPartial, mergePreferences } from 'src/utils/preferences';
|
||||||
|
|
||||||
@ -135,7 +134,7 @@ export class UserService extends BaseService {
|
|||||||
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
const metadata = await this.userRepository.getMetadata(auth.user.id);
|
||||||
|
|
||||||
const license = metadata.find(
|
const license = metadata.find(
|
||||||
(item): item is UserMetadataEntity<UserMetadataKey.LICENSE> => item.key === UserMetadataKey.LICENSE,
|
(item): item is UserMetadataItem<UserMetadataKey.LICENSE> => item.key === UserMetadataKey.LICENSE,
|
||||||
);
|
);
|
||||||
if (!license) {
|
if (!license) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
@ -11,6 +11,8 @@ import {
|
|||||||
SyncEntityType,
|
SyncEntityType,
|
||||||
SystemMetadataKey,
|
SystemMetadataKey,
|
||||||
TranscodeTarget,
|
TranscodeTarget,
|
||||||
|
UserAvatarColor,
|
||||||
|
UserMetadataKey,
|
||||||
VideoCodec,
|
VideoCodec,
|
||||||
} from 'src/enum';
|
} from 'src/enum';
|
||||||
|
|
||||||
@ -455,3 +457,54 @@ export interface SystemMetadata extends Record<SystemMetadataKey, Record<string,
|
|||||||
[SystemMetadataKey.VERSION_CHECK_STATE]: VersionCheckMetadata;
|
[SystemMetadataKey.VERSION_CHECK_STATE]: VersionCheckMetadata;
|
||||||
[SystemMetadataKey.MEMORIES_STATE]: MemoriesState;
|
[SystemMetadataKey.MEMORIES_STATE]: MemoriesState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UserMetadataItem<T extends keyof UserMetadata = UserMetadataKey> = {
|
||||||
|
key: T;
|
||||||
|
value: UserMetadata[T];
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface UserPreferences {
|
||||||
|
folders: {
|
||||||
|
enabled: boolean;
|
||||||
|
sidebarWeb: boolean;
|
||||||
|
};
|
||||||
|
memories: {
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
people: {
|
||||||
|
enabled: boolean;
|
||||||
|
sidebarWeb: boolean;
|
||||||
|
};
|
||||||
|
ratings: {
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
sharedLinks: {
|
||||||
|
enabled: boolean;
|
||||||
|
sidebarWeb: boolean;
|
||||||
|
};
|
||||||
|
tags: {
|
||||||
|
enabled: boolean;
|
||||||
|
sidebarWeb: boolean;
|
||||||
|
};
|
||||||
|
avatar: {
|
||||||
|
color: UserAvatarColor;
|
||||||
|
};
|
||||||
|
emailNotifications: {
|
||||||
|
enabled: boolean;
|
||||||
|
albumInvite: boolean;
|
||||||
|
albumUpdate: boolean;
|
||||||
|
};
|
||||||
|
download: {
|
||||||
|
archiveSize: number;
|
||||||
|
includeEmbeddedVideos: boolean;
|
||||||
|
};
|
||||||
|
purchase: {
|
||||||
|
showSupportBadge: boolean;
|
||||||
|
hideBuyButtonUntil: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserMetadata extends Record<UserMetadataKey, Record<string, any>> {
|
||||||
|
[UserMetadataKey.PREFERENCES]: DeepPartial<UserPreferences>;
|
||||||
|
[UserMetadataKey.LICENSE]: { licenseKey: string; activationKey: string; activatedAt: string };
|
||||||
|
}
|
||||||
|
@ -1,10 +1,58 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { UserPreferencesUpdateDto } from 'src/dtos/user-preferences.dto';
|
import { UserPreferencesUpdateDto } from 'src/dtos/user-preferences.dto';
|
||||||
import { UserMetadataItem, UserPreferences, getDefaultPreferences } from 'src/entities/user-metadata.entity';
|
import { UserAvatarColor, UserMetadataKey } from 'src/enum';
|
||||||
import { UserMetadataKey } from 'src/enum';
|
import { DeepPartial, UserMetadataItem, UserPreferences } from 'src/types';
|
||||||
import { DeepPartial } from 'src/types';
|
import { HumanReadableSize } from 'src/utils/bytes';
|
||||||
import { getKeysDeep } from 'src/utils/misc';
|
import { getKeysDeep } from 'src/utils/misc';
|
||||||
|
|
||||||
|
const getDefaultPreferences = (user: { email: string }): UserPreferences => {
|
||||||
|
const values = Object.values(UserAvatarColor);
|
||||||
|
const randomIndex = Math.floor(
|
||||||
|
[...user.email].map((letter) => letter.codePointAt(0) ?? 0).reduce((a, b) => a + b, 0) % values.length,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
folders: {
|
||||||
|
enabled: false,
|
||||||
|
sidebarWeb: false,
|
||||||
|
},
|
||||||
|
memories: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
people: {
|
||||||
|
enabled: true,
|
||||||
|
sidebarWeb: false,
|
||||||
|
},
|
||||||
|
sharedLinks: {
|
||||||
|
enabled: true,
|
||||||
|
sidebarWeb: false,
|
||||||
|
},
|
||||||
|
ratings: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
enabled: false,
|
||||||
|
sidebarWeb: false,
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
color: values[randomIndex],
|
||||||
|
},
|
||||||
|
emailNotifications: {
|
||||||
|
enabled: true,
|
||||||
|
albumInvite: true,
|
||||||
|
albumUpdate: true,
|
||||||
|
},
|
||||||
|
download: {
|
||||||
|
archiveSize: HumanReadableSize.GiB * 4,
|
||||||
|
includeEmbeddedVideos: false,
|
||||||
|
},
|
||||||
|
purchase: {
|
||||||
|
showSupportBadge: true,
|
||||||
|
hideBuyButtonUntil: new Date(2022, 1, 12).toISOString(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const getPreferences = (email: string, metadata: UserMetadataItem[]): UserPreferences => {
|
export const getPreferences = (email: string, metadata: UserMetadataItem[]): UserPreferences => {
|
||||||
const preferences = getDefaultPreferences({ email });
|
const preferences = getDefaultPreferences({ email });
|
||||||
const item = metadata.find(({ key }) => key === UserMetadataKey.PREFERENCES);
|
const item = metadata.find(({ key }) => key === UserMetadataKey.PREFERENCES);
|
||||||
|
1
server/test/fixtures/user.stub.ts
vendored
1
server/test/fixtures/user.stub.ts
vendored
@ -38,7 +38,6 @@ export const userStub = {
|
|||||||
assets: [],
|
assets: [],
|
||||||
metadata: [
|
metadata: [
|
||||||
{
|
{
|
||||||
userId: authStub.user1.user.id,
|
|
||||||
key: UserMetadataKey.PREFERENCES,
|
key: UserMetadataKey.PREFERENCES,
|
||||||
value: { avatar: { color: UserAvatarColor.PRIMARY } },
|
value: { avatar: { color: UserAvatarColor.PRIMARY } },
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user