feat(web,server): user memory settings (#3628)

* feat(web,server): user preference for time-based memories

* chore: open api

* dev: mobile

* fix: update

* mobile work

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: Alex Tran <Alex.Tran@conductix.com>
This commit is contained in:
Jason Rasmussen 2023-08-09 22:01:16 -04:00 committed by GitHub
parent 343087e2b4
commit a6eb227330
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 519 additions and 25 deletions

View file

@ -176,6 +176,7 @@ describe(AlbumService.name, () => {
deletedAt: null,
updatedAt: new Date('2021-01-01'),
externalPath: null,
memoriesEnabled: true,
},
ownerId: 'admin_id',
shared: false,

View file

@ -1,10 +1,11 @@
import { BadRequestException } from '@nestjs/common';
import { authStub, newPartnerRepositoryMock, partnerStub } from '@test';
import { UserResponseDto } from '../index';
import { IPartnerRepository, PartnerDirection } from './partner.repository';
import { PartnerService } from './partner.service';
const responseDto = {
admin: {
admin: <UserResponseDto>{
email: 'admin@test.com',
firstName: 'admin_first_name',
id: 'admin_id',
@ -18,8 +19,9 @@ const responseDto = {
deletedAt: null,
updatedAt: new Date('2021-01-01'),
externalPath: null,
memoriesEnabled: true,
},
user1: {
user1: <UserResponseDto>{
email: 'immich@test.com',
firstName: 'immich_first_name',
id: 'user-id',
@ -33,6 +35,7 @@ const responseDto = {
deletedAt: null,
updatedAt: new Date('2021-01-01'),
externalPath: null,
memoriesEnabled: true,
},
};

View file

@ -1,5 +1,5 @@
import { Transform } from 'class-transformer';
import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { IsBoolean, IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { toEmail, toSanitized } from '../../domain.util';
export class CreateUserDto {
@ -27,6 +27,10 @@ export class CreateUserDto {
@IsOptional()
@IsString()
externalPath?: string | null;
@IsOptional()
@IsBoolean()
memoriesEnabled?: boolean;
}
export class CreateAdminDto {

View file

@ -45,4 +45,8 @@ export class UpdateUserDto {
@IsOptional()
@IsBoolean()
shouldChangePassword?: boolean;
@IsOptional()
@IsBoolean()
memoriesEnabled?: boolean;
}

View file

@ -14,6 +14,7 @@ export class UserResponseDto {
deletedAt!: Date | null;
updatedAt!: Date;
oauthId!: string;
memoriesEnabled!: boolean;
}
export function mapUser(entity: UserEntity): UserResponseDto {
@ -31,5 +32,6 @@ export function mapUser(entity: UserEntity): UserResponseDto {
deletedAt: entity.deletedAt,
updatedAt: entity.updatedAt,
oauthId: entity.oauthId,
memoriesEnabled: entity.memoriesEnabled,
};
}

View file

@ -60,6 +60,7 @@ export class UserCore {
dto.externalPath = null;
}
console.log(dto.memoriesEnabled);
return this.userRepository.update(id, dto);
} catch (e) {
Logger.error(e, 'Failed to update user info');

View file

@ -16,6 +16,7 @@ import { ICryptoRepository } from '../crypto';
import { IJobRepository, JobName } from '../job';
import { IStorageRepository } from '../storage';
import { UpdateUserDto } from './dto/update-user.dto';
import { UserResponseDto } from './response-dto';
import { IUserRepository } from './user.repository';
import { UserService } from './user.service';
@ -54,6 +55,7 @@ const adminUser: UserEntity = Object.freeze({
assets: [],
storageLabel: 'admin',
externalPath: null,
memoriesEnabled: true,
});
const immichUser: UserEntity = Object.freeze({
@ -73,9 +75,10 @@ const immichUser: UserEntity = Object.freeze({
assets: [],
storageLabel: null,
externalPath: null,
memoriesEnabled: true,
});
const updatedImmichUser: UserEntity = Object.freeze({
const updatedImmichUser = Object.freeze<UserEntity>({
id: immichUserAuth.id,
email: 'immich@test.com',
password: 'immich_password',
@ -92,9 +95,10 @@ const updatedImmichUser: UserEntity = Object.freeze({
assets: [],
storageLabel: null,
externalPath: null,
memoriesEnabled: true,
});
const adminUserResponse = Object.freeze({
const adminUserResponse = Object.freeze<UserResponseDto>({
id: adminUserAuth.id,
email: 'admin@test.com',
firstName: 'admin_first_name',
@ -108,6 +112,7 @@ const adminUserResponse = Object.freeze({
updatedAt: new Date('2021-01-01'),
storageLabel: 'admin',
externalPath: null,
memoriesEnabled: true,
});
describe(UserService.name, () => {
@ -158,6 +163,7 @@ describe(UserService.name, () => {
updatedAt: new Date('2021-01-01'),
storageLabel: 'admin',
externalPath: null,
memoriesEnabled: true,
},
]);
});

View file

@ -54,6 +54,9 @@ export class UserEntity {
@UpdateDateColumn({ type: 'timestamptz' })
updatedAt!: Date;
@Column({ default: true })
memoriesEnabled!: boolean;
@OneToMany(() => TagEntity, (tag) => tag.user)
tags!: TagEntity[];

View file

@ -0,0 +1,13 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UserMemoryPreference1691600216749 implements MigrationInterface {
name = 'UserMemoryPreference1691600216749';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" ADD "memoriesEnabled" boolean NOT NULL DEFAULT true`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "memoriesEnabled"`);
}
}