mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
fix(server): incorrect number of assets for a person (#7602)
* fix: incorrect number of assets * fix: tests * pr feedback * fix: e2e test * fix: e2e test * fix: e2e test * feat: more tests
This commit is contained in:
parent
5bc13c49a4
commit
6ab404597c
@ -9,6 +9,7 @@ describe('/activity', () => {
|
|||||||
let admin: LoginResponseDto;
|
let admin: LoginResponseDto;
|
||||||
let visiblePerson: PersonResponseDto;
|
let visiblePerson: PersonResponseDto;
|
||||||
let hiddenPerson: PersonResponseDto;
|
let hiddenPerson: PersonResponseDto;
|
||||||
|
let multipleAssetsPerson: PersonResponseDto;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
apiUtils.setup();
|
apiUtils.setup();
|
||||||
@ -19,7 +20,7 @@ describe('/activity', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await dbUtils.reset(['person']);
|
await dbUtils.reset(['person']);
|
||||||
|
|
||||||
[visiblePerson, hiddenPerson] = await Promise.all([
|
[visiblePerson, hiddenPerson, multipleAssetsPerson] = await Promise.all([
|
||||||
apiUtils.createPerson(admin.accessToken, {
|
apiUtils.createPerson(admin.accessToken, {
|
||||||
name: 'visible_person',
|
name: 'visible_person',
|
||||||
}),
|
}),
|
||||||
@ -27,13 +28,20 @@ describe('/activity', () => {
|
|||||||
name: 'hidden_person',
|
name: 'hidden_person',
|
||||||
isHidden: true,
|
isHidden: true,
|
||||||
}),
|
}),
|
||||||
|
apiUtils.createPerson(admin.accessToken, {
|
||||||
|
name: 'multiple_assets_person',
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const asset = await apiUtils.createAsset(admin.accessToken);
|
const asset1 = await apiUtils.createAsset(admin.accessToken);
|
||||||
|
const asset2 = await apiUtils.createAsset(admin.accessToken);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
dbUtils.createFace({ assetId: asset.id, personId: visiblePerson.id }),
|
dbUtils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
|
||||||
dbUtils.createFace({ assetId: asset.id, personId: hiddenPerson.id }),
|
dbUtils.createFace({ assetId: asset1.id, personId: hiddenPerson.id }),
|
||||||
|
dbUtils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
|
dbUtils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
|
||||||
|
dbUtils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -55,9 +63,10 @@ describe('/activity', () => {
|
|||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
total: 2,
|
total: 3,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [
|
people: [
|
||||||
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
expect.objectContaining({ name: 'visible_person' }),
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
expect.objectContaining({ name: 'hidden_person' }),
|
expect.objectContaining({ name: 'hidden_person' }),
|
||||||
],
|
],
|
||||||
@ -69,9 +78,12 @@ describe('/activity', () => {
|
|||||||
|
|
||||||
expect(status).toBe(200);
|
expect(status).toBe(200);
|
||||||
expect(body).toEqual({
|
expect(body).toEqual({
|
||||||
total: 2,
|
total: 3,
|
||||||
hidden: 1,
|
hidden: 1,
|
||||||
people: [expect.objectContaining({ name: 'visible_person' })],
|
people: [
|
||||||
|
expect.objectContaining({ name: 'multiple_assets_person' }),
|
||||||
|
expect.objectContaining({ name: 'visible_person' }),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -103,6 +115,33 @@ describe('/activity', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET /person/:id/statistics', () => {
|
||||||
|
it('should require authentication', async () => {
|
||||||
|
const { status, body } = await request(app).get(`/person/${multipleAssetsPerson.id}/statistics`);
|
||||||
|
|
||||||
|
expect(status).toBe(401);
|
||||||
|
expect(body).toEqual(errorDto.unauthorized);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw error if person with id does not exist', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get(`/person/${uuidDto.notFound}/statistics`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorDto.badRequest());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the correct number of assets', async () => {
|
||||||
|
const { status, body } = await request(app)
|
||||||
|
.get(`/person/${multipleAssetsPerson.id}/statistics`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||||
|
|
||||||
|
expect(status).toBe(200);
|
||||||
|
expect(body).toEqual(expect.objectContaining({ assets: 2 }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('PUT /person/:id', () => {
|
describe('PUT /person/:id', () => {
|
||||||
it('should require authentication', async () => {
|
it('should require authentication', async () => {
|
||||||
const { status, body } = await request(app).put(`/person/${uuidDto.notFound}`);
|
const { status, body } = await request(app).put(`/person/${uuidDto.notFound}`);
|
||||||
|
@ -171,16 +171,17 @@ export class PersonRepository implements IPersonRepository {
|
|||||||
|
|
||||||
@GenerateSql({ params: [DummyValue.UUID] })
|
@GenerateSql({ params: [DummyValue.UUID] })
|
||||||
async getStatistics(personId: string): Promise<PersonStatistics> {
|
async getStatistics(personId: string): Promise<PersonStatistics> {
|
||||||
return {
|
const items = await this.assetFaceRepository
|
||||||
assets: await this.assetFaceRepository
|
|
||||||
.createQueryBuilder('face')
|
.createQueryBuilder('face')
|
||||||
.leftJoin('face.asset', 'asset')
|
.leftJoin('face.asset', 'asset')
|
||||||
.where('face.personId = :personId', { personId })
|
.where('face.personId = :personId', { personId })
|
||||||
.andWhere('asset.isArchived = false')
|
.andWhere('asset.isArchived = false')
|
||||||
.andWhere('asset.deletedAt IS NULL')
|
.andWhere('asset.deletedAt IS NULL')
|
||||||
.andWhere('asset.livePhotoVideoId IS NULL')
|
.andWhere('asset.livePhotoVideoId IS NULL')
|
||||||
.distinct(true)
|
.select('COUNT(DISTINCT(asset.id))', 'count')
|
||||||
.getCount(),
|
.getRawOne();
|
||||||
|
return {
|
||||||
|
assets: items.count ?? 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,8 +224,8 @@ export class PersonRepository implements IPersonRepository {
|
|||||||
.getRawOne();
|
.getRawOne();
|
||||||
|
|
||||||
const result: PeopleStatistics = {
|
const result: PeopleStatistics = {
|
||||||
total: items ? Number.parseInt(items.total) : 0,
|
total: items.total ?? 0,
|
||||||
hidden: items ? Number.parseInt(items.hidden) : 0,
|
hidden: items.hidden ?? 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -224,8 +224,8 @@ LIMIT
|
|||||||
20
|
20
|
||||||
|
|
||||||
-- PersonRepository.getStatistics
|
-- PersonRepository.getStatistics
|
||||||
SELECT DISTINCT
|
SELECT
|
||||||
COUNT(DISTINCT ("face"."id")) AS "cnt"
|
COUNT(DISTINCT ("asset"."id")) AS "count"
|
||||||
FROM
|
FROM
|
||||||
"asset_faces" "face"
|
"asset_faces" "face"
|
||||||
LEFT JOIN "assets" "asset" ON "asset"."id" = "face"."assetId"
|
LEFT JOIN "assets" "asset" ON "asset"."id" = "face"."assetId"
|
||||||
|
Loading…
Reference in New Issue
Block a user