You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-08-09 23:17:29 +02:00
feat(server): visibility column (#17939)
* feat: private view * pr feedback * sql generation * feat: visibility column * fix: set visibility value as the same as the still part after unlinked live photos * fix: test * pr feedback
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
||||
AssetMediaStatus,
|
||||
AssetResponseDto,
|
||||
AssetTypeEnum,
|
||||
AssetVisibility,
|
||||
getAssetInfo,
|
||||
getMyUser,
|
||||
LoginResponseDto,
|
||||
@@ -119,9 +120,9 @@ describe('/asset', () => {
|
||||
// stats
|
||||
utils.createAsset(statsUser.accessToken),
|
||||
utils.createAsset(statsUser.accessToken, { isFavorite: true }),
|
||||
utils.createAsset(statsUser.accessToken, { isArchived: true }),
|
||||
utils.createAsset(statsUser.accessToken, { visibility: AssetVisibility.Archive }),
|
||||
utils.createAsset(statsUser.accessToken, {
|
||||
isArchived: true,
|
||||
visibility: AssetVisibility.Archive,
|
||||
isFavorite: true,
|
||||
assetData: { filename: 'example.mp4' },
|
||||
}),
|
||||
@@ -309,7 +310,7 @@ describe('/asset', () => {
|
||||
});
|
||||
|
||||
it('disallows viewing archived assets', async () => {
|
||||
const asset = await utils.createAsset(user1.accessToken, { isArchived: true });
|
||||
const asset = await utils.createAsset(user1.accessToken, { visibility: AssetVisibility.Archive });
|
||||
|
||||
const { status } = await request(app)
|
||||
.get(`/assets/${asset.id}`)
|
||||
@@ -353,7 +354,7 @@ describe('/asset', () => {
|
||||
const { status, body } = await request(app)
|
||||
.get('/assets/statistics')
|
||||
.set('Authorization', `Bearer ${statsUser.accessToken}`)
|
||||
.query({ isArchived: true });
|
||||
.query({ visibility: AssetVisibility.Archive });
|
||||
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual({ images: 1, videos: 1, total: 2 });
|
||||
@@ -363,7 +364,7 @@ describe('/asset', () => {
|
||||
const { status, body } = await request(app)
|
||||
.get('/assets/statistics')
|
||||
.set('Authorization', `Bearer ${statsUser.accessToken}`)
|
||||
.query({ isFavorite: true, isArchived: true });
|
||||
.query({ isFavorite: true, visibility: AssetVisibility.Archive });
|
||||
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual({ images: 0, videos: 1, total: 1 });
|
||||
@@ -373,7 +374,7 @@ describe('/asset', () => {
|
||||
const { status, body } = await request(app)
|
||||
.get('/assets/statistics')
|
||||
.set('Authorization', `Bearer ${statsUser.accessToken}`)
|
||||
.query({ isFavorite: false, isArchived: false });
|
||||
.query({ isFavorite: false, visibility: AssetVisibility.Timeline });
|
||||
|
||||
expect(status).toBe(200);
|
||||
expect(body).toEqual({ images: 1, videos: 0, total: 1 });
|
||||
@@ -459,7 +460,7 @@ describe('/asset', () => {
|
||||
const { status, body } = await request(app)
|
||||
.put(`/assets/${user1Assets[0].id}`)
|
||||
.set('Authorization', `Bearer ${user1.accessToken}`)
|
||||
.send({ isArchived: true });
|
||||
.send({ visibility: AssetVisibility.Archive });
|
||||
expect(body).toMatchObject({ id: user1Assets[0].id, isArchived: true });
|
||||
expect(status).toEqual(200);
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { LoginResponseDto } from '@immich/sdk';
|
||||
import { AssetVisibility, LoginResponseDto } from '@immich/sdk';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { basename, join } from 'node:path';
|
||||
import { Socket } from 'socket.io-client';
|
||||
@@ -44,7 +44,7 @@ describe('/map', () => {
|
||||
it('should get map markers for all non-archived assets', async () => {
|
||||
const { status, body } = await request(app)
|
||||
.get('/map/markers')
|
||||
.query({ isArchived: false })
|
||||
.query({ visibility: AssetVisibility.Timeline })
|
||||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
|
||||
expect(status).toBe(200);
|
||||
|
@@ -1,4 +1,11 @@
|
||||
import { AssetMediaResponseDto, AssetResponseDto, deleteAssets, LoginResponseDto, updateAsset } from '@immich/sdk';
|
||||
import {
|
||||
AssetMediaResponseDto,
|
||||
AssetResponseDto,
|
||||
AssetVisibility,
|
||||
deleteAssets,
|
||||
LoginResponseDto,
|
||||
updateAsset,
|
||||
} from '@immich/sdk';
|
||||
import { DateTime } from 'luxon';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
@@ -49,7 +56,7 @@ describe('/search', () => {
|
||||
{ filename: '/formats/motionphoto/samsung-one-ui-6.heic' },
|
||||
{ filename: '/formats/motionphoto/samsung-one-ui-5.jpg' },
|
||||
|
||||
{ filename: '/metadata/gps-position/thompson-springs.jpg', dto: { isArchived: true } },
|
||||
{ filename: '/metadata/gps-position/thompson-springs.jpg', dto: { visibility: AssetVisibility.Archive } },
|
||||
|
||||
// used for search suggestions
|
||||
{ filename: '/formats/png/density_plot.png' },
|
||||
@@ -171,12 +178,12 @@ describe('/search', () => {
|
||||
deferred: () => ({ dto: { size: 1, isFavorite: false }, assets: [assetLast] }),
|
||||
},
|
||||
{
|
||||
should: 'should search by isArchived (true)',
|
||||
deferred: () => ({ dto: { isArchived: true }, assets: [assetSprings] }),
|
||||
should: 'should search by visibility (AssetVisibility.Archive)',
|
||||
deferred: () => ({ dto: { visibility: AssetVisibility.Archive }, assets: [assetSprings] }),
|
||||
},
|
||||
{
|
||||
should: 'should search by isArchived (false)',
|
||||
deferred: () => ({ dto: { size: 1, isArchived: false }, assets: [assetLast] }),
|
||||
should: 'should search by visibility (AssetVisibility.Timeline)',
|
||||
deferred: () => ({ dto: { size: 1, visibility: AssetVisibility.Timeline }, assets: [assetLast] }),
|
||||
},
|
||||
{
|
||||
should: 'should search by type (image)',
|
||||
@@ -185,7 +192,7 @@ describe('/search', () => {
|
||||
{
|
||||
should: 'should search by type (video)',
|
||||
deferred: () => ({
|
||||
dto: { type: 'VIDEO' },
|
||||
dto: { type: 'VIDEO', visibility: AssetVisibility.Hidden },
|
||||
assets: [
|
||||
// the three live motion photos
|
||||
{ id: expect.any(String) },
|
||||
@@ -229,13 +236,6 @@ describe('/search', () => {
|
||||
should: 'should search by takenAfter (no results)',
|
||||
deferred: () => ({ dto: { takenAfter: today.plus({ hour: 1 }).toJSDate() }, assets: [] }),
|
||||
},
|
||||
// {
|
||||
// should: 'should search by originalPath',
|
||||
// deferred: () => ({
|
||||
// dto: { originalPath: asset1.originalPath },
|
||||
// assets: [asset1],
|
||||
// }),
|
||||
// },
|
||||
{
|
||||
should: 'should search by originalFilename',
|
||||
deferred: () => ({
|
||||
@@ -265,7 +265,7 @@ describe('/search', () => {
|
||||
deferred: () => ({
|
||||
dto: {
|
||||
city: '',
|
||||
isVisible: true,
|
||||
visibility: AssetVisibility.Timeline,
|
||||
includeNull: true,
|
||||
},
|
||||
assets: [assetLast],
|
||||
@@ -276,7 +276,7 @@ describe('/search', () => {
|
||||
deferred: () => ({
|
||||
dto: {
|
||||
city: null,
|
||||
isVisible: true,
|
||||
visibility: AssetVisibility.Timeline,
|
||||
includeNull: true,
|
||||
},
|
||||
assets: [assetLast],
|
||||
@@ -297,7 +297,7 @@ describe('/search', () => {
|
||||
deferred: () => ({
|
||||
dto: {
|
||||
state: '',
|
||||
isVisible: true,
|
||||
visibility: AssetVisibility.Timeline,
|
||||
withExif: true,
|
||||
includeNull: true,
|
||||
},
|
||||
@@ -309,7 +309,7 @@ describe('/search', () => {
|
||||
deferred: () => ({
|
||||
dto: {
|
||||
state: null,
|
||||
isVisible: true,
|
||||
visibility: AssetVisibility.Timeline,
|
||||
includeNull: true,
|
||||
},
|
||||
assets: [assetLast, assetNotocactus],
|
||||
@@ -330,7 +330,7 @@ describe('/search', () => {
|
||||
deferred: () => ({
|
||||
dto: {
|
||||
country: '',
|
||||
isVisible: true,
|
||||
visibility: AssetVisibility.Timeline,
|
||||
includeNull: true,
|
||||
},
|
||||
assets: [assetLast],
|
||||
@@ -341,7 +341,7 @@ describe('/search', () => {
|
||||
deferred: () => ({
|
||||
dto: {
|
||||
country: null,
|
||||
isVisible: true,
|
||||
visibility: AssetVisibility.Timeline,
|
||||
includeNull: true,
|
||||
},
|
||||
assets: [assetLast],
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { AssetMediaResponseDto, LoginResponseDto, SharedLinkType, TimeBucketSize } from '@immich/sdk';
|
||||
import { AssetMediaResponseDto, AssetVisibility, LoginResponseDto, SharedLinkType, TimeBucketSize } from '@immich/sdk';
|
||||
import { DateTime } from 'luxon';
|
||||
import { createUserDto } from 'src/fixtures';
|
||||
import { errorDto } from 'src/responses';
|
||||
@@ -104,7 +104,7 @@ describe('/timeline', () => {
|
||||
const req1 = await request(app)
|
||||
.get('/timeline/buckets')
|
||||
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
|
||||
.query({ size: TimeBucketSize.Month, withPartners: true, isArchived: true });
|
||||
.query({ size: TimeBucketSize.Month, withPartners: true, visibility: AssetVisibility.Archive });
|
||||
|
||||
expect(req1.status).toBe(400);
|
||||
expect(req1.body).toEqual(errorDto.badRequest());
|
||||
@@ -112,7 +112,7 @@ describe('/timeline', () => {
|
||||
const req2 = await request(app)
|
||||
.get('/timeline/buckets')
|
||||
.set('Authorization', `Bearer ${user.accessToken}`)
|
||||
.query({ size: TimeBucketSize.Month, withPartners: true, isArchived: undefined });
|
||||
.query({ size: TimeBucketSize.Month, withPartners: true, visibility: undefined });
|
||||
|
||||
expect(req2.status).toBe(400);
|
||||
expect(req2.body).toEqual(errorDto.badRequest());
|
||||
|
@@ -3,6 +3,7 @@ import {
|
||||
AssetMediaCreateDto,
|
||||
AssetMediaResponseDto,
|
||||
AssetResponseDto,
|
||||
AssetVisibility,
|
||||
CheckExistingAssetsDto,
|
||||
CreateAlbumDto,
|
||||
CreateLibraryDto,
|
||||
@@ -429,7 +430,10 @@ export const utils = {
|
||||
},
|
||||
|
||||
archiveAssets: (accessToken: string, ids: string[]) =>
|
||||
updateAssets({ assetBulkUpdateDto: { ids, isArchived: true } }, { headers: asBearerAuth(accessToken) }),
|
||||
updateAssets(
|
||||
{ assetBulkUpdateDto: { ids, visibility: AssetVisibility.Archive } },
|
||||
{ headers: asBearerAuth(accessToken) },
|
||||
),
|
||||
|
||||
deleteAssets: (accessToken: string, ids: string[]) =>
|
||||
deleteAssets({ assetBulkDeleteDto: { ids } }, { headers: asBearerAuth(accessToken) }),
|
||||
|
Reference in New Issue
Block a user