chore!: remove getRandom api endpoint (#27780)

* chore!: remove getRandom api endpoint

* chore: sync openapi

* fix: test

* chore: more cleanup
This commit is contained in:
Brandon Wees
2026-04-14 20:32:12 -05:00
committed by GitHub
parent 41d2d84b21
commit 6da2d3d587
13 changed files with 2 additions and 357 deletions
@@ -245,19 +245,6 @@ describe(AssetController.name, () => {
});
});
describe('GET /assets/random', () => {
it('should be an authenticated route', async () => {
await request(ctx.getHttpServer()).get(`/assets/random`);
expect(ctx.authenticate).toHaveBeenCalled();
});
it('should not allow count to be a string', async () => {
const { status, body } = await request(ctx.getHttpServer()).get('/assets/random?count=ABC');
expect(status).toBe(400);
expect(body).toEqual(factory.responses.badRequest(['[count] Invalid input: expected number, received NaN']));
});
});
describe('GET /assets/:id/metadata', () => {
it('should be an authenticated route', async () => {
await request(ctx.getHttpServer()).get(`/assets/${factory.uuid()}/metadata`);
@@ -16,7 +16,6 @@ import {
AssetStatsDto,
AssetStatsResponseDto,
DeviceIdDto,
RandomAssetsDto,
UpdateAssetDto,
} from 'src/dtos/asset.dto';
import { AuthDto } from 'src/dtos/auth.dto';
@@ -32,17 +31,6 @@ import { UUIDParamDto } from 'src/validation';
export class AssetController {
constructor(private service: AssetService) {}
@Get('random')
@Authenticated({ permission: Permission.AssetRead })
@Endpoint({
summary: 'Get random assets',
description: 'Retrieve a specified number of random assets for the authenticated user.',
history: new HistoryBuilder().added('v1').deprecated('v1', { replacementId: 'searchAssets' }),
})
getRandom(@Auth() auth: AuthDto, @Query() dto: RandomAssetsDto): Promise<AssetResponseDto[]> {
return this.service.getRandom(auth, dto.count ?? 1);
}
@Get('/device/:deviceId')
@Endpoint({
summary: 'Retrieve assets by device ID',
-7
View File
@@ -58,12 +58,6 @@ const UpdateAssetSchema = UpdateAssetBaseSchema.extend({
livePhotoVideoId: z.uuidv4().nullish().describe('Live photo video ID'),
}).meta({ id: 'UpdateAssetDto' });
const RandomAssetsSchema = z
.object({
count: z.coerce.number().min(1).optional().describe('Number of random assets to return'),
})
.meta({ id: 'RandomAssetsDto' });
const AssetBulkDeleteSchema = BulkIdsSchema.extend({
force: z.boolean().optional().describe('Force delete even if in use'),
}).meta({ id: 'AssetBulkDeleteDto' });
@@ -191,7 +185,6 @@ export const mapStats = (stats: AssetStats): AssetStatsResponseDto => {
export class DeviceIdDto extends createZodDto(DeviceIdSchema) {}
export class AssetBulkUpdateDto extends createZodDto(AssetBulkUpdateSchema) {}
export class UpdateAssetDto extends createZodDto(UpdateAssetSchema) {}
export class RandomAssetsDto extends createZodDto(RandomAssetsSchema) {}
export class AssetBulkDeleteDto extends createZodDto(AssetBulkDeleteSchema) {}
export class AssetIdsDto extends createZodDto(AssetIdsSchema) {}
export class AssetJobsDto extends createZodDto(AssetJobsSchema) {}
@@ -681,19 +681,6 @@ export class AssetRepository {
.executeTakeFirstOrThrow();
}
getRandom(userIds: string[], take: number) {
return this.db
.selectFrom('asset')
.selectAll('asset')
.$call(withExif)
.$call(withDefaultVisibility)
.where('ownerId', '=', anyUuid(userIds))
.where('deletedAt', 'is', null)
.orderBy((eb) => eb.fn('random'))
.limit(take)
.execute();
}
@GenerateSql({ params: [{}] })
async getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]> {
return this.db
+1 -37
View File
@@ -7,9 +7,8 @@ import { AssetStats } from 'src/repositories/asset.repository';
import { AssetService } from 'src/services/asset.service';
import { AssetFactory } from 'test/factories/asset.factory';
import { AuthFactory } from 'test/factories/auth.factory';
import { PartnerFactory } from 'test/factories/partner.factory';
import { authStub } from 'test/fixtures/auth.stub';
import { getForAsset, getForAssetDeletion, getForPartner } from 'test/mappers';
import { getForAsset, getForAssetDeletion } from 'test/mappers';
import { factory, newUuid } from 'test/small.factory';
import { makeStream, newTestService, ServiceMocks } from 'test/utils';
@@ -70,41 +69,6 @@ describe(AssetService.name, () => {
});
});
describe('getRandom', () => {
it('should get own random assets', async () => {
mocks.partner.getAll.mockResolvedValue([]);
mocks.asset.getRandom.mockResolvedValue([getForAsset(AssetFactory.create())]);
await sut.getRandom(authStub.admin, 1);
expect(mocks.asset.getRandom).toHaveBeenCalledWith([authStub.admin.user.id], 1);
});
it('should not include partner assets if not in timeline', async () => {
const partner = PartnerFactory.create({ inTimeline: false });
const auth = AuthFactory.create({ id: partner.sharedWithId });
mocks.asset.getRandom.mockResolvedValue([getForAsset(AssetFactory.create())]);
mocks.partner.getAll.mockResolvedValue([getForPartner(partner)]);
await sut.getRandom(auth, 1);
expect(mocks.asset.getRandom).toHaveBeenCalledWith([auth.user.id], 1);
});
it('should include partner assets if in timeline', async () => {
const partner = PartnerFactory.create({ inTimeline: true });
const auth = AuthFactory.create({ id: partner.sharedWithId });
mocks.asset.getRandom.mockResolvedValue([getForAsset(AssetFactory.create())]);
mocks.partner.getAll.mockResolvedValue([getForPartner(partner)]);
await sut.getRandom(auth, 1);
expect(mocks.asset.getRandom).toHaveBeenCalledWith([auth.user.id, partner.sharedById], 1);
});
});
describe('get', () => {
it('should allow owner access', async () => {
const asset = AssetFactory.create();
-11
View File
@@ -39,7 +39,6 @@ import { requireElevatedPermission } from 'src/utils/access';
import {
getAssetFiles,
getDimensions,
getMyPartnerIds,
isPanorama,
onAfterUnlink,
onBeforeLink,
@@ -60,16 +59,6 @@ export class AssetService extends BaseService {
return mapStats(stats);
}
async getRandom(auth: AuthDto, count: number): Promise<AssetResponseDto[]> {
const partnerIds = await getMyPartnerIds({
userId: auth.user.id,
repository: this.partnerRepository,
timelineEnabled: true,
});
const assets = await this.assetRepository.getRandom([auth.user.id, ...partnerIds], count);
return assets.map((a) => mapAsset(a, { auth }));
}
async getUserAssetsByDeviceId(auth: AuthDto, deviceId: string) {
return this.assetRepository.getAllByDeviceId(auth.user.id, deviceId);
}