mirror of
https://github.com/immich-app/immich.git
synced 2025-12-17 01:11:13 +03:00
* move markers and style to dedicated map endpoint * chore: open api * chore: clean up repos --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
163 lines
5.7 KiB
TypeScript
163 lines
5.7 KiB
TypeScript
import { AssetFileUploadResponseDto, LoginResponseDto, SharedLinkType } from '@immich/sdk';
|
|
import { readFile } from 'node:fs/promises';
|
|
import { basename, join } from 'node:path';
|
|
import { Socket } from 'socket.io-client';
|
|
import { createUserDto } from 'src/fixtures';
|
|
import { errorDto } from 'src/responses';
|
|
import { app, testAssetDir, utils } from 'src/utils';
|
|
import request from 'supertest';
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
|
|
describe('/map', () => {
|
|
let websocket: Socket;
|
|
let admin: LoginResponseDto;
|
|
let nonAdmin: LoginResponseDto;
|
|
let asset: AssetFileUploadResponseDto;
|
|
|
|
beforeAll(async () => {
|
|
await utils.resetDatabase();
|
|
admin = await utils.adminSetup({ onboarding: false });
|
|
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
|
|
|
|
websocket = await utils.connectWebsocket(admin.accessToken);
|
|
|
|
asset = await utils.createAsset(admin.accessToken);
|
|
|
|
const files = ['formats/heic/IMG_2682.heic', 'metadata/gps-position/thompson-springs.jpg'];
|
|
utils.resetEvents();
|
|
const uploadFile = async (input: string) => {
|
|
const filepath = join(testAssetDir, input);
|
|
const { id } = await utils.createAsset(admin.accessToken, {
|
|
assetData: { bytes: await readFile(filepath), filename: basename(filepath) },
|
|
});
|
|
await utils.waitForWebsocketEvent({ event: 'assetUpload', id });
|
|
};
|
|
await Promise.all(files.map((f) => uploadFile(f)));
|
|
});
|
|
|
|
afterAll(() => {
|
|
utils.disconnectWebsocket(websocket);
|
|
});
|
|
|
|
describe('GET /map/markers', () => {
|
|
it('should require authentication', async () => {
|
|
const { status, body } = await request(app).get('/map/markers');
|
|
expect(status).toBe(401);
|
|
expect(body).toEqual(errorDto.unauthorized);
|
|
});
|
|
|
|
// TODO archive one of these assets
|
|
it('should get map markers for all non-archived assets', async () => {
|
|
const { status, body } = await request(app)
|
|
.get('/map/markers')
|
|
.query({ isArchived: false })
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
|
|
expect(status).toBe(200);
|
|
expect(body).toHaveLength(2);
|
|
expect(body).toEqual([
|
|
{
|
|
city: 'Palisade',
|
|
country: 'United States of America',
|
|
id: expect.any(String),
|
|
lat: expect.closeTo(39.115),
|
|
lon: expect.closeTo(-108.400_968),
|
|
state: 'Colorado',
|
|
},
|
|
{
|
|
city: 'Ralston',
|
|
country: 'United States of America',
|
|
id: expect.any(String),
|
|
lat: expect.closeTo(41.2203),
|
|
lon: expect.closeTo(-96.071_625),
|
|
state: 'Nebraska',
|
|
},
|
|
]);
|
|
});
|
|
|
|
// TODO archive one of these assets
|
|
it('should get all map markers', async () => {
|
|
const { status, body } = await request(app)
|
|
.get('/map/markers')
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual([
|
|
{
|
|
city: 'Palisade',
|
|
country: 'United States of America',
|
|
id: expect.any(String),
|
|
lat: expect.closeTo(39.115),
|
|
lon: expect.closeTo(-108.400_968),
|
|
state: 'Colorado',
|
|
},
|
|
{
|
|
city: 'Ralston',
|
|
country: 'United States of America',
|
|
id: expect.any(String),
|
|
lat: expect.closeTo(41.2203),
|
|
lon: expect.closeTo(-96.071_625),
|
|
state: 'Nebraska',
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('GET /map/style.json', () => {
|
|
it('should require authentication', async () => {
|
|
const { status, body } = await request(app).get('/map/style.json');
|
|
expect(status).toBe(401);
|
|
expect(body).toEqual(errorDto.unauthorized);
|
|
});
|
|
|
|
it('should allow shared link access', async () => {
|
|
const sharedLink = await utils.createSharedLink(admin.accessToken, {
|
|
type: SharedLinkType.Individual,
|
|
assetIds: [asset.id],
|
|
});
|
|
const { status, body } = await request(app).get(`/map/style.json?key=${sharedLink.key}`).query({ theme: 'dark' });
|
|
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual(expect.objectContaining({ id: 'immich-map-dark' }));
|
|
});
|
|
|
|
it('should throw an error if a theme is not light or dark', async () => {
|
|
for (const theme of ['dark1', true, 123, '', null, undefined]) {
|
|
const { status, body } = await request(app)
|
|
.get('/map/style.json')
|
|
.query({ theme })
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(errorDto.badRequest(['theme must be one of the following values: light, dark']));
|
|
}
|
|
});
|
|
|
|
it('should return the light style.json', async () => {
|
|
const { status, body } = await request(app)
|
|
.get('/map/style.json')
|
|
.query({ theme: 'light' })
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual(expect.objectContaining({ id: 'immich-map-light' }));
|
|
});
|
|
|
|
it('should return the dark style.json', async () => {
|
|
const { status, body } = await request(app)
|
|
.get('/map/style.json')
|
|
.query({ theme: 'dark' })
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual(expect.objectContaining({ id: 'immich-map-dark' }));
|
|
});
|
|
|
|
it('should not require admin authentication', async () => {
|
|
const { status, body } = await request(app)
|
|
.get('/map/style.json')
|
|
.query({ theme: 'dark' })
|
|
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual(expect.objectContaining({ id: 'immich-map-dark' }));
|
|
});
|
|
});
|
|
});
|