feat: view album shared links (#15943)

This commit is contained in:
Jason Rasmussen
2025-02-07 16:38:20 -05:00
committed by GitHub
parent c5360e78c5
commit 61b8eb85b5
13 changed files with 144 additions and 51 deletions

View File

@@ -9,6 +9,7 @@ import {
SharedLinkEditDto,
SharedLinkPasswordDto,
SharedLinkResponseDto,
SharedLinkSearchDto,
} from 'src/dtos/shared-link.dto';
import { ImmichCookie, Permission } from 'src/enum';
import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard';
@@ -24,8 +25,8 @@ export class SharedLinkController {
@Get()
@Authenticated({ permission: Permission.SHARED_LINK_READ })
getAllSharedLinks(@Auth() auth: AuthDto): Promise<SharedLinkResponseDto[]> {
return this.service.getAll(auth);
getAllSharedLinks(@Auth() auth: AuthDto, @Query() dto: SharedLinkSearchDto): Promise<SharedLinkResponseDto[]> {
return this.service.getAll(auth, dto);
}
@Get('me')

View File

@@ -7,6 +7,11 @@ import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { SharedLinkType } from 'src/enum';
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
export class SharedLinkSearchDto {
@ValidateUUID({ optional: true })
albumId?: string;
}
export class SharedLinkCreateDto {
@IsEnum(SharedLinkType)
@ApiProperty({ enum: SharedLinkType, enumName: 'SharedLinkType' })

View File

@@ -4,8 +4,13 @@ import { SharedLinkEntity } from 'src/entities/shared-link.entity';
export const ISharedLinkRepository = 'ISharedLinkRepository';
export type SharedLinkSearchOptions = {
userId: string;
albumId?: string;
};
export interface ISharedLinkRepository {
getAll(userId: string): Promise<SharedLinkEntity[]>;
getAll(options: SharedLinkSearchOptions): Promise<SharedLinkEntity[]>;
get(userId: string, id: string): Promise<SharedLinkEntity | undefined>;
getByKey(key: Buffer): Promise<SharedLinkEntity | undefined>;
create(entity: Insertable<SharedLinks> & { assetIds?: string[] }): Promise<SharedLinkEntity>;

View File

@@ -7,7 +7,7 @@ import { DB, SharedLinks } from 'src/db';
import { DummyValue, GenerateSql } from 'src/decorators';
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { SharedLinkType } from 'src/enum';
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
import { ISharedLinkRepository, SharedLinkSearchOptions } from 'src/interfaces/shared-link.interface';
@Injectable()
export class SharedLinkRepository implements ISharedLinkRepository {
@@ -93,7 +93,7 @@ export class SharedLinkRepository implements ISharedLinkRepository {
}
@GenerateSql({ params: [DummyValue.UUID] })
getAll(userId: string): Promise<SharedLinkEntity[]> {
getAll({ userId, albumId }: SharedLinkSearchOptions): Promise<SharedLinkEntity[]> {
return this.db
.selectFrom('shared_links')
.selectAll('shared_links')
@@ -149,6 +149,7 @@ export class SharedLinkRepository implements ISharedLinkRepository {
)
.select((eb) => eb.fn.toJson('album').as('album'))
.where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)]))
.$if(!!albumId, (eb) => eb.where('shared_links.albumId', '=', albumId!))
.orderBy('shared_links.createdAt', 'desc')
.distinctOn(['shared_links.createdAt'])
.execute() as unknown as Promise<SharedLinkEntity[]>;

View File

@@ -29,11 +29,11 @@ describe(SharedLinkService.name, () => {
describe('getAll', () => {
it('should return all shared links for a user', async () => {
sharedLinkMock.getAll.mockResolvedValue([sharedLinkStub.expired, sharedLinkStub.valid]);
await expect(sut.getAll(authStub.user1)).resolves.toEqual([
await expect(sut.getAll(authStub.user1, {})).resolves.toEqual([
sharedLinkResponseStub.expired,
sharedLinkResponseStub.valid,
]);
expect(sharedLinkMock.getAll).toHaveBeenCalledWith(authStub.user1.user.id);
expect(sharedLinkMock.getAll).toHaveBeenCalledWith({ userId: authStub.user1.user.id });
});
});

View File

@@ -9,6 +9,7 @@ import {
SharedLinkEditDto,
SharedLinkPasswordDto,
SharedLinkResponseDto,
SharedLinkSearchDto,
} from 'src/dtos/shared-link.dto';
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { Permission, SharedLinkType } from 'src/enum';
@@ -17,8 +18,10 @@ import { getExternalDomain, OpenGraphTags } from 'src/utils/misc';
@Injectable()
export class SharedLinkService extends BaseService {
async getAll(auth: AuthDto): Promise<SharedLinkResponseDto[]> {
return this.sharedLinkRepository.getAll(auth.user.id).then((links) => links.map((link) => mapSharedLink(link)));
async getAll(auth: AuthDto, { albumId }: SharedLinkSearchDto): Promise<SharedLinkResponseDto[]> {
return this.sharedLinkRepository
.getAll({ userId: auth.user.id, albumId })
.then((links) => links.map((link) => mapSharedLink(link)));
}
async getMine(auth: AuthDto, dto: SharedLinkPasswordDto): Promise<SharedLinkResponseDto> {