Compare commits

..

2 Commits

Author SHA1 Message Date
Marty Fuhry
6a156b813e background 2024-05-21 16:00:46 -04:00
Lukas
4907916345 fix(web): emit updated date when pressing enter (#9640)
wip uploading

format

wip first working version
2024-05-21 16:00:46 -04:00
340 changed files with 5808 additions and 7986 deletions

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: PR Conventional Commit Validation
uses: ytanikin/PRConventionalCommits@1.2.0
uses: ytanikin/PRConventionalCommits@1.1.0
with:
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]'
add_label: 'false'

View File

@@ -260,18 +260,9 @@ jobs:
name: OpenAPI Clients
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install server dependencies
run: npm --prefix=server ci
- name: Build the app
run: npm --prefix=server run build
- uses: actions/checkout@v4
- name: Run API generation
run: make open-api
- name: Find file changes
uses: tj-actions/verify-changed-files@v20
id: verify-changed-files
@@ -279,8 +270,6 @@ jobs:
files: |
mobile/openapi
open-api/typescript-sdk
open-api/immich-openapi-specs.json
- name: Verify files have not changed
if: steps.verify-changed-files.outputs.files_changed == 'true'
run: |
@@ -343,7 +332,7 @@ jobs:
exit 1
- name: Run SQL generation
run: npm run sync:sql
run: npm run sql:generate
env:
DB_URL: postgres://postgres:postgres@localhost:5432/immich

View File

@@ -37,7 +37,7 @@ open-api-typescript:
cd ./open-api && bash ./bin/generate-open-api.sh typescript
sql:
npm --prefix server run sync:sql
npm --prefix server run sql:generate
attach-server:
docker exec -it docker_immich-server_1 sh

View File

@@ -1,4 +1,4 @@
import { getMyUser } from '@immich/sdk';
import { getMyUserInfo } from '@immich/sdk';
import { existsSync } from 'node:fs';
import { mkdir, unlink } from 'node:fs/promises';
import { BaseOptions, connect, getAuthFilePath, logError, withError, writeAuthFile } from 'src/utils';
@@ -10,13 +10,13 @@ export const login = async (url: string, key: string, options: BaseOptions) => {
await connect(url, key);
const [error, user] = await withError(getMyUser());
const [error, userInfo] = await withError(getMyUserInfo());
if (error) {
logError(error, 'Failed to load user info');
process.exit(1);
}
console.log(`Logged in as ${user.email}`);
console.log(`Logged in as ${userInfo.email}`);
if (!existsSync(configDir)) {
// Create config folder if it doesn't exist

View File

@@ -1,4 +1,4 @@
import { getAssetStatistics, getMyUser, getServerVersion, getSupportedMediaTypes } from '@immich/sdk';
import { getAssetStatistics, getMyUserInfo, getServerVersion, getSupportedMediaTypes } from '@immich/sdk';
import { BaseOptions, authenticate } from 'src/utils';
export const serverInfo = async (options: BaseOptions) => {
@@ -8,7 +8,7 @@ export const serverInfo = async (options: BaseOptions) => {
getServerVersion(),
getSupportedMediaTypes(),
getAssetStatistics({}),
getMyUser(),
getMyUserInfo(),
]);
console.log(`Server Info (via ${userInfo.email})`);

View File

@@ -1,4 +1,4 @@
import { getMyUser, init, isHttpError } from '@immich/sdk';
import { getMyUserInfo, init, isHttpError } from '@immich/sdk';
import { glob } from 'fast-glob';
import { createHash } from 'node:crypto';
import { createReadStream } from 'node:fs';
@@ -48,7 +48,7 @@ export const connect = async (url: string, key: string) => {
init({ baseUrl: url, apiKey: key });
const [error] = await withError(getMyUser());
const [error] = await withError(getMyUserInfo());
if (isHttpError(error)) {
logError(error, 'Failed to connect to server');
process.exit(1);

View File

@@ -9,9 +9,6 @@ services:
container_name: immich_server
command: ['/usr/src/app/bin/immich-dev']
image: immich-server-dev:latest
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
build:
context: ../
dockerfile: server/Dockerfile
@@ -84,9 +81,7 @@ services:
redis:
container_name: immich_redis
image: redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93
healthcheck:
test: redis-cli ping || exit 1
image: redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
database:
container_name: immich_postgres
@@ -102,11 +97,6 @@ services:
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
ports:
- 5432:5432
healthcheck:
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
# set IMMICH_METRICS=true in .env to enable metrics

View File

@@ -4,9 +4,6 @@ services:
immich-server:
container_name: immich_server
image: immich-server:latest
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
build:
context: ../
dockerfile: server/Dockerfile
@@ -15,12 +12,12 @@ services:
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
restart: always
ports:
- 2283:3001
depends_on:
- redis
- database
restart: always
immich-machine-learning:
container_name: immich_machine_learning
@@ -41,9 +38,7 @@ services:
redis:
container_name: immich_redis
image: redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93
healthcheck:
test: redis-cli ping || exit 1
image: redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
restart: always
database:
@@ -60,13 +55,7 @@ services:
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
ports:
- 5432:5432
healthcheck:
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
restart: always
# set IMMICH_METRICS=true in .env to enable metrics
immich-prometheus:

View File

@@ -12,9 +12,6 @@ services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
@@ -43,9 +40,7 @@ services:
redis:
container_name: immich_redis
image: docker.io/redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93
healthcheck:
test: redis-cli ping || exit 1
image: docker.io/redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
restart: always
database:
@@ -58,13 +53,8 @@ services:
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
healthcheck:
test: pg_isready --dbname='${DB_DATABASE_NAME}' || exit 1; Chksum="$$(psql --dbname='${DB_DATABASE_NAME}' --username='${DB_USERNAME}' --tuples-only --no-align --command='SELECT SUM(checksum_failures) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
restart: always
command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
volumes:
model-cache:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

View File

@@ -110,44 +110,8 @@ Immich has a route (`/api/oauth/mobile-redirect`) that is already configured to
## Example Configuration
<details>
<summary>Authentik Example</summary>
### Authentik Example
Here's an example of OAuth configured for Authentik:
<img src={require('./img/oauth-settings.png').default} title="OAuth settings" />
</details>
<details>
<summary>Google Example</summary>
### Google Example
Configuration of Authorised redirect URIs (Google Console)
<img src={require('./img/google-example.webp').default} width='50%' title="Authorised redirect URIs" />
Configuration of OAuth in System Settings
| Setting | Value |
| ---------------------------- | ------------------------------------------------------------------------------------------------------ |
| Issuer URL | [https://accounts.google.com](https://accounts.google.com) |
| Client ID | 7\***\*\*\*\*\*\*\***\*\*\***\*\*\*\*\*\*\***vuls.apps.googleusercontent.com |
| Client Secret | G\***\*\*\*\*\*\*\***\*\*\***\*\*\*\*\*\*\***OO |
| Scope | openid email profile |
| Signing Algorithm | RS256 |
| Storage Label Claim | preferred_username |
| Storage Quota Claim | immich_quota |
| Default Storage Quota (GiB) | 0 (0 for unlimited quota) |
| Button Text | Sign in with Google (optional) |
| Auto Register | Enabled (optional) |
| Auto Launch | Enabled |
| Mobile Redirect URI Override | Enabled (required) |
| Mobile Redirect URI | [https://demo.immich.app/api/oauth/mobile-redirect](https://demo.immich.app/api/oauth/mobile-redirect) |
</details>
![OAuth Settings](./img/oauth-settings.png)
[oidc]: https://openid.net/connect/

View File

@@ -15,7 +15,7 @@ The [hwaccel.ml.yml](https://github.com/immich-app/immich/releases/latest/downlo
:::
```yaml
name: immich_remote_ml
version: '3.8'
services:
immich-machine-learning:

View File

@@ -157,6 +157,9 @@ The default configuration looks like this:
"server": {
"externalDomain": "",
"loginPageMessage": ""
},
"user": {
"deleteDelay": 7
}
}
```

View File

@@ -27,7 +27,7 @@ services:
- 2283:3001
redis:
image: redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93
image: redis:6.2-alpine@sha256:c0634a08e74a4bb576d02d1ee993dc05dba10e8b7b9492dfa28a7af100d46c01
database:
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0

26
e2e/package-lock.json generated
View File

@@ -11,7 +11,7 @@
"devDependencies": {
"@immich/cli": "file:../cli",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@playwright/test": "^1.44.1",
"@playwright/test": "^1.41.2",
"@types/luxon": "^3.4.2",
"@types/node": "^20.11.17",
"@types/pg": "^8.11.0",
@@ -88,7 +88,7 @@
"@oazapfts/runtime": "^1.0.2"
},
"devDependencies": {
"@types/node": "^20.11.0",
"@types/node": "^20.12.12",
"typescript": "^5.3.3"
}
},
@@ -971,12 +971,12 @@
}
},
"node_modules/@playwright/test": {
"version": "1.44.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz",
"integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==",
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.0.tgz",
"integrity": "sha512-rNX5lbNidamSUorBhB4XZ9SQTjAqfe5M+p37Z8ic0jPFBMo5iCtQz1kRWkEMg+rYOKSlVycpQmpqjSFq7LXOfg==",
"dev": true,
"dependencies": {
"playwright": "1.44.1"
"playwright": "1.44.0"
},
"bin": {
"playwright": "cli.js"
@@ -4252,12 +4252,12 @@
}
},
"node_modules/playwright": {
"version": "1.44.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz",
"integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==",
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.0.tgz",
"integrity": "sha512-F9b3GUCLQ3Nffrfb6dunPOkE5Mh68tR7zN32L4jCk4FjQamgesGay7/dAAe1WaMEGV04DkdJfcJzjoCKygUaRQ==",
"dev": true,
"dependencies": {
"playwright-core": "1.44.1"
"playwright-core": "1.44.0"
},
"bin": {
"playwright": "cli.js"
@@ -4270,9 +4270,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.44.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz",
"integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==",
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.0.tgz",
"integrity": "sha512-ZTbkNpFfYcGWohvTTl+xewITm7EOuqIqex0c7dNZ+aXsbrLj0qI8XlGKfPpipjm0Wny/4Lt4CJsWJk1stVS5qQ==",
"dev": true,
"bin": {
"playwright-core": "cli.js"

View File

@@ -21,7 +21,7 @@
"devDependencies": {
"@immich/cli": "file:../cli",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@playwright/test": "^1.44.1",
"@playwright/test": "^1.41.2",
"@types/luxon": "^3.4.2",
"@types/node": "^20.11.17",
"@types/pg": "^8.11.0",

View File

@@ -14,7 +14,7 @@ import { app, asBearerAuth, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
describe('/activities', () => {
describe('/activity', () => {
let admin: LoginResponseDto;
let nonOwner: LoginResponseDto;
let asset: AssetFileUploadResponseDto;
@@ -45,24 +45,22 @@ describe('/activities', () => {
await utils.resetDatabase(['activity']);
});
describe('GET /activities', () => {
describe('GET /activity', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/activities');
const { status, body } = await request(app).get('/activity');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require an albumId', async () => {
const { status, body } = await request(app)
.get('/activities')
.set('Authorization', `Bearer ${admin.accessToken}`);
const { status, body } = await request(app).get('/activity').set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(400);
expect(body).toEqual(errorDto.badRequest(expect.arrayContaining(['albumId must be a UUID'])));
});
it('should reject an invalid albumId', async () => {
const { status, body } = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: uuidDto.invalid })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(400);
@@ -71,7 +69,7 @@ describe('/activities', () => {
it('should reject an invalid assetId', async () => {
const { status, body } = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: uuidDto.notFound, assetId: uuidDto.invalid })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(400);
@@ -80,7 +78,7 @@ describe('/activities', () => {
it('should start off empty', async () => {
const { status, body } = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: album.id })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toEqual([]);
@@ -104,7 +102,7 @@ describe('/activities', () => {
]);
const { status, body } = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: album.id })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(200);
@@ -123,7 +121,7 @@ describe('/activities', () => {
]);
const { status, body } = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: album.id, type: 'comment' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(200);
@@ -142,7 +140,7 @@ describe('/activities', () => {
]);
const { status, body } = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: album.id, type: 'like' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(200);
@@ -154,7 +152,7 @@ describe('/activities', () => {
const reaction = await createActivity({ albumId: album.id, type: ReactionType.Like });
const response1 = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: album.id, userId: uuidDto.notFound })
.set('Authorization', `Bearer ${admin.accessToken}`);
@@ -162,7 +160,7 @@ describe('/activities', () => {
expect(response1.body.length).toBe(0);
const response2 = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: album.id, userId: admin.userId })
.set('Authorization', `Bearer ${admin.accessToken}`);
@@ -182,7 +180,7 @@ describe('/activities', () => {
]);
const { status, body } = await request(app)
.get('/activities')
.get('/activity')
.query({ albumId: album.id, assetId: asset.id })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(200);
@@ -191,16 +189,16 @@ describe('/activities', () => {
});
});
describe('POST /activities', () => {
describe('POST /activity', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post('/activities');
const { status, body } = await request(app).post('/activity');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require an albumId', async () => {
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ albumId: uuidDto.invalid });
expect(status).toEqual(400);
@@ -209,7 +207,7 @@ describe('/activities', () => {
it('should require a comment when type is comment', async () => {
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ albumId: uuidDto.notFound, type: 'comment', comment: null });
expect(status).toEqual(400);
@@ -218,7 +216,7 @@ describe('/activities', () => {
it('should add a comment to an album', async () => {
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
albumId: album.id,
@@ -238,7 +236,7 @@ describe('/activities', () => {
it('should add a like to an album', async () => {
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ albumId: album.id, type: 'like' });
expect(status).toEqual(201);
@@ -255,7 +253,7 @@ describe('/activities', () => {
it('should return a 200 for a duplicate like on the album', async () => {
const reaction = await createActivity({ albumId: album.id, type: ReactionType.Like });
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ albumId: album.id, type: 'like' });
expect(status).toEqual(200);
@@ -269,7 +267,7 @@ describe('/activities', () => {
type: ReactionType.Like,
});
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ albumId: album.id, type: 'like' });
expect(status).toEqual(201);
@@ -278,7 +276,7 @@ describe('/activities', () => {
it('should add a comment to an asset', async () => {
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
albumId: album.id,
@@ -299,7 +297,7 @@ describe('/activities', () => {
it('should add a like to an asset', async () => {
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ albumId: album.id, assetId: asset.id, type: 'like' });
expect(status).toEqual(201);
@@ -321,7 +319,7 @@ describe('/activities', () => {
});
const { status, body } = await request(app)
.post('/activities')
.post('/activity')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ albumId: album.id, assetId: asset.id, type: 'like' });
expect(status).toEqual(200);
@@ -329,16 +327,16 @@ describe('/activities', () => {
});
});
describe('DELETE /activities/:id', () => {
describe('DELETE /activity/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete(`/activities/${uuidDto.notFound}`);
const { status, body } = await request(app).delete(`/activity/${uuidDto.notFound}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid uuid', async () => {
const { status, body } = await request(app)
.delete(`/activities/${uuidDto.invalid}`)
.delete(`/activity/${uuidDto.invalid}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
@@ -351,7 +349,7 @@ describe('/activities', () => {
comment: 'This is a test comment',
});
const { status } = await request(app)
.delete(`/activities/${reaction.id}`)
.delete(`/activity/${reaction.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(204);
});
@@ -362,7 +360,7 @@ describe('/activities', () => {
type: ReactionType.Like,
});
const { status } = await request(app)
.delete(`/activities/${reaction.id}`)
.delete(`/activity/${reaction.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(204);
});
@@ -375,7 +373,7 @@ describe('/activities', () => {
});
const { status } = await request(app)
.delete(`/activities/${reaction.id}`)
.delete(`/activity/${reaction.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(204);
@@ -389,7 +387,7 @@ describe('/activities', () => {
});
const { status, body } = await request(app)
.delete(`/activities/${reaction.id}`)
.delete(`/activity/${reaction.id}`)
.set('Authorization', `Bearer ${nonOwner.accessToken}`);
expect(status).toBe(400);
@@ -407,7 +405,7 @@ describe('/activities', () => {
);
const { status } = await request(app)
.delete(`/activities/${reaction.id}`)
.delete(`/activity/${reaction.id}`)
.set('Authorization', `Bearer ${nonOwner.accessToken}`);
expect(status).toBe(204);

View File

@@ -4,7 +4,7 @@ import {
AlbumUserRole,
AssetFileUploadResponseDto,
AssetOrder,
deleteUserAdmin,
deleteUser,
getAlbumInfo,
LoginResponseDto,
SharedLinkType,
@@ -23,7 +23,7 @@ const user2SharedUser = 'user2SharedUser';
const user2SharedLink = 'user2SharedLink';
const user2NotShared = 'user2NotShared';
describe('/albums', () => {
describe('/album', () => {
let admin: LoginResponseDto;
let user1: LoginResponseDto;
let user1Asset1: AssetFileUploadResponseDto;
@@ -107,19 +107,19 @@ describe('/albums', () => {
}),
]);
await deleteUserAdmin({ id: user3.userId, userAdminDeleteDto: {} }, { headers: asBearerAuth(admin.accessToken) });
await deleteUser({ id: user3.userId, deleteUserDto: {} }, { headers: asBearerAuth(admin.accessToken) });
});
describe('GET /albums', () => {
describe('GET /album', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/albums');
const { status, body } = await request(app).get('/album');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should reject an invalid shared param', async () => {
const { status, body } = await request(app)
.get('/albums?shared=invalid')
.get('/album?shared=invalid')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toEqual(400);
expect(body).toEqual(errorDto.badRequest(['shared must be a boolean value']));
@@ -127,7 +127,7 @@ describe('/albums', () => {
it('should reject an invalid assetId param', async () => {
const { status, body } = await request(app)
.get('/albums?assetId=invalid')
.get('/album?assetId=invalid')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toEqual(400);
expect(body).toEqual(errorDto.badRequest(['assetId must be a UUID']));
@@ -135,7 +135,7 @@ describe('/albums', () => {
it("should not show other users' favorites", async () => {
const { status, body } = await request(app)
.get(`/albums/${user1Albums[0].id}?withoutAssets=false`)
.get(`/album/${user1Albums[0].id}?withoutAssets=false`)
.set('Authorization', `Bearer ${user2.accessToken}`);
expect(status).toEqual(200);
expect(body).toEqual({
@@ -146,7 +146,7 @@ describe('/albums', () => {
it('should not return shared albums with a deleted owner', async () => {
const { status, body } = await request(app)
.get('/albums?shared=true')
.get('/album?shared=true')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -178,7 +178,7 @@ describe('/albums', () => {
});
it('should return the album collection including owned and shared', async () => {
const { status, body } = await request(app).get('/albums').set('Authorization', `Bearer ${user1.accessToken}`);
const { status, body } = await request(app).get('/album').set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(4);
expect(body).toEqual(
@@ -209,7 +209,7 @@ describe('/albums', () => {
it('should return the album collection filtered by shared', async () => {
const { status, body } = await request(app)
.get('/albums?shared=true')
.get('/album?shared=true')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(4);
@@ -241,7 +241,7 @@ describe('/albums', () => {
it('should return the album collection filtered by NOT shared', async () => {
const { status, body } = await request(app)
.get('/albums?shared=false')
.get('/album?shared=false')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(1);
@@ -258,7 +258,7 @@ describe('/albums', () => {
it('should return the album collection filtered by assetId', async () => {
const { status, body } = await request(app)
.get(`/albums?assetId=${user1Asset2.id}`)
.get(`/album?assetId=${user1Asset2.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(1);
@@ -266,7 +266,7 @@ describe('/albums', () => {
it('should return the album collection filtered by assetId and ignores shared=true', async () => {
const { status, body } = await request(app)
.get(`/albums?shared=true&assetId=${user1Asset1.id}`)
.get(`/album?shared=true&assetId=${user1Asset1.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(5);
@@ -274,23 +274,23 @@ describe('/albums', () => {
it('should return the album collection filtered by assetId and ignores shared=false', async () => {
const { status, body } = await request(app)
.get(`/albums?shared=false&assetId=${user1Asset1.id}`)
.get(`/album?shared=false&assetId=${user1Asset1.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(5);
});
});
describe('GET /albums/:id', () => {
describe('GET /album/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/albums/${user1Albums[0].id}`);
const { status, body } = await request(app).get(`/album/${user1Albums[0].id}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should return album info for own album', async () => {
const { status, body } = await request(app)
.get(`/albums/${user1Albums[0].id}?withoutAssets=false`)
.get(`/album/${user1Albums[0].id}?withoutAssets=false`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -302,7 +302,7 @@ describe('/albums', () => {
it('should return album info for shared album (editor)', async () => {
const { status, body } = await request(app)
.get(`/albums/${user2Albums[0].id}?withoutAssets=false`)
.get(`/album/${user2Albums[0].id}?withoutAssets=false`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -311,7 +311,7 @@ describe('/albums', () => {
it('should return album info for shared album (viewer)', async () => {
const { status, body } = await request(app)
.get(`/albums/${user1Albums[3].id}?withoutAssets=false`)
.get(`/album/${user1Albums[3].id}?withoutAssets=false`)
.set('Authorization', `Bearer ${user2.accessToken}`);
expect(status).toBe(200);
@@ -320,7 +320,7 @@ describe('/albums', () => {
it('should return album info with assets when withoutAssets is undefined', async () => {
const { status, body } = await request(app)
.get(`/albums/${user1Albums[0].id}`)
.get(`/album/${user1Albums[0].id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -332,7 +332,7 @@ describe('/albums', () => {
it('should return album info without assets when withoutAssets is true', async () => {
const { status, body } = await request(app)
.get(`/albums/${user1Albums[0].id}?withoutAssets=true`)
.get(`/album/${user1Albums[0].id}?withoutAssets=true`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -344,16 +344,16 @@ describe('/albums', () => {
});
});
describe('GET /albums/count', () => {
describe('GET /album/count', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/albums/count');
const { status, body } = await request(app).get('/album/count');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should return total count of albums the user has access to', async () => {
const { status, body } = await request(app)
.get('/albums/count')
.get('/album/count')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -361,16 +361,16 @@ describe('/albums', () => {
});
});
describe('POST /albums', () => {
describe('POST /album', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post('/albums').send({ albumName: 'New album' });
const { status, body } = await request(app).post('/album').send({ albumName: 'New album' });
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should create an album', async () => {
const { status, body } = await request(app)
.post('/albums')
.post('/album')
.send({ albumName: 'New album' })
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(201);
@@ -383,6 +383,7 @@ describe('/albums', () => {
description: '',
albumThumbnailAssetId: null,
shared: false,
sharedUsers: [],
albumUsers: [],
hasSharedLink: false,
assets: [],
@@ -394,9 +395,9 @@ describe('/albums', () => {
});
});
describe('PUT /albums/:id/assets', () => {
describe('PUT /album/:id/assets', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/albums/${user1Albums[0].id}/assets`);
const { status, body } = await request(app).put(`/album/${user1Albums[0].id}/assets`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
@@ -404,7 +405,7 @@ describe('/albums', () => {
it('should be able to add own asset to own album', async () => {
const asset = await utils.createAsset(user1.accessToken);
const { status, body } = await request(app)
.put(`/albums/${user1Albums[0].id}/assets`)
.put(`/album/${user1Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ ids: [asset.id] });
@@ -415,7 +416,7 @@ describe('/albums', () => {
it('should be able to add own asset to shared album', async () => {
const asset = await utils.createAsset(user1.accessToken);
const { status, body } = await request(app)
.put(`/albums/${user2Albums[0].id}/assets`)
.put(`/album/${user2Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ ids: [asset.id] });
@@ -426,7 +427,7 @@ describe('/albums', () => {
it('should not be able to add assets to album as a viewer', async () => {
const asset = await utils.createAsset(user2.accessToken);
const { status, body } = await request(app)
.put(`/albums/${user1Albums[3].id}/assets`)
.put(`/album/${user1Albums[3].id}/assets`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ ids: [asset.id] });
@@ -437,7 +438,7 @@ describe('/albums', () => {
it('should add duplicate assets only once', async () => {
const asset = await utils.createAsset(user1.accessToken);
const { status, body } = await request(app)
.put(`/albums/${user1Albums[0].id}/assets`)
.put(`/album/${user1Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ ids: [asset.id, asset.id] });
@@ -449,10 +450,10 @@ describe('/albums', () => {
});
});
describe('PATCH /albums/:id', () => {
describe('PATCH /album/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app)
.patch(`/albums/${uuidDto.notFound}`)
.patch(`/album/${uuidDto.notFound}`)
.send({ albumName: 'New album name' });
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -463,7 +464,7 @@ describe('/albums', () => {
albumName: 'New album',
});
const { status, body } = await request(app)
.patch(`/albums/${album.id}`)
.patch(`/album/${album.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({
albumName: 'New album name',
@@ -480,7 +481,7 @@ describe('/albums', () => {
it('should not be able to update as a viewer', async () => {
const { status, body } = await request(app)
.patch(`/albums/${user1Albums[3].id}`)
.patch(`/album/${user1Albums[3].id}`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ albumName: 'New album name' });
@@ -490,7 +491,7 @@ describe('/albums', () => {
it('should not be able to update as an editor', async () => {
const { status, body } = await request(app)
.patch(`/albums/${user1Albums[0].id}`)
.patch(`/album/${user1Albums[0].id}`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ albumName: 'New album name' });
@@ -499,10 +500,10 @@ describe('/albums', () => {
});
});
describe('DELETE /albums/:id/assets', () => {
describe('DELETE /album/:id/assets', () => {
it('should require authentication', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user1Albums[0].id}/assets`)
.delete(`/album/${user1Albums[0].id}/assets`)
.send({ ids: [user1Asset1.id] });
expect(status).toBe(401);
@@ -511,7 +512,7 @@ describe('/albums', () => {
it('should not be able to remove foreign asset from own album', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user2Albums[0].id}/assets`)
.delete(`/album/${user2Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ ids: [user1Asset1.id] });
@@ -527,7 +528,7 @@ describe('/albums', () => {
it('should not be able to remove foreign asset from foreign album', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user1Albums[0].id}/assets`)
.delete(`/album/${user1Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ ids: [user1Asset1.id] });
@@ -543,7 +544,7 @@ describe('/albums', () => {
it('should be able to remove own asset from own album', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user1Albums[0].id}/assets`)
.delete(`/album/${user1Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ ids: [user1Asset1.id] });
@@ -553,7 +554,7 @@ describe('/albums', () => {
it('should be able to remove own asset from shared album', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user2Albums[0].id}/assets`)
.delete(`/album/${user2Albums[0].id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ ids: [user1Asset1.id] });
@@ -563,7 +564,7 @@ describe('/albums', () => {
it('should not be able to remove assets from album as a viewer', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user1Albums[3].id}/assets`)
.delete(`/album/${user1Albums[3].id}/assets`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ ids: [user1Asset1.id] });
@@ -573,7 +574,7 @@ describe('/albums', () => {
it('should remove duplicate assets only once', async () => {
const { status, body } = await request(app)
.delete(`/albums/${user1Albums[1].id}/assets`)
.delete(`/album/${user1Albums[1].id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ ids: [user1Asset1.id, user1Asset1.id] });
@@ -595,7 +596,7 @@ describe('/albums', () => {
});
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/albums/${user1Albums[0].id}/users`).send({ sharedUserIds: [] });
const { status, body } = await request(app).put(`/album/${user1Albums[0].id}/users`).send({ sharedUserIds: [] });
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -603,25 +604,21 @@ describe('/albums', () => {
it('should be able to add user to own album', async () => {
const { status, body } = await request(app)
.put(`/albums/${album.id}/users`)
.put(`/album/${album.id}/users`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Editor }] });
expect(status).toBe(200);
expect(body).toEqual(
expect.objectContaining({
albumUsers: [
expect.objectContaining({
user: expect.objectContaining({ id: user2.userId }),
}),
],
sharedUsers: [expect.objectContaining({ id: user2.userId })],
}),
);
});
it('should not be able to share album with owner', async () => {
const { status, body } = await request(app)
.put(`/albums/${album.id}/users`)
.put(`/album/${album.id}/users`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ albumUsers: [{ userId: user1.userId, role: AlbumUserRole.Editor }] });
@@ -631,12 +628,12 @@ describe('/albums', () => {
it('should not be able to add existing user to shared album', async () => {
await request(app)
.put(`/albums/${album.id}/users`)
.put(`/album/${album.id}/users`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Editor }] });
const { status, body } = await request(app)
.put(`/albums/${album.id}/users`)
.put(`/album/${album.id}/users`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Editor }] });
@@ -655,16 +652,14 @@ describe('/albums', () => {
expect(album.albumUsers[0].role).toEqual(AlbumUserRole.Viewer);
const { status } = await request(app)
.put(`/albums/${album.id}/user/${user2.userId}`)
.put(`/album/${album.id}/user/${user2.userId}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ role: AlbumUserRole.Editor });
expect(status).toBe(200);
// Get album to verify the role change
const { body } = await request(app)
.get(`/albums/${album.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
const { body } = await request(app).get(`/album/${album.id}`).set('Authorization', `Bearer ${user1.accessToken}`);
expect(body).toEqual(
expect.objectContaining({
albumUsers: [expect.objectContaining({ role: AlbumUserRole.Editor })],
@@ -681,7 +676,7 @@ describe('/albums', () => {
expect(album.albumUsers[0].role).toEqual(AlbumUserRole.Viewer);
const { status, body } = await request(app)
.put(`/albums/${album.id}/user/${user2.userId}`)
.put(`/album/${album.id}/user/${user2.userId}`)
.set('Authorization', `Bearer ${user2.accessToken}`)
.send({ role: AlbumUserRole.Editor });

View File

@@ -5,7 +5,6 @@ import {
LoginResponseDto,
SharedLinkType,
getAssetInfo,
getMyUser,
updateAssets,
} from '@immich/sdk';
import { exiftool } from 'exiftool-vendored';
@@ -72,7 +71,7 @@ describe('/asset', () => {
let stackAssets: AssetFileUploadResponseDto[];
let locationAsset: AssetFileUploadResponseDto;
const setupTests = async () => {
beforeAll(async () => {
await utils.resetDatabase();
admin = await utils.adminSetup({ onboarding: false });
@@ -86,8 +85,6 @@ describe('/asset', () => {
utils.userSetup(admin.accessToken, createUserDto.create('stack')),
]);
await utils.createPartner(user1.accessToken, user2.userId);
// asset location
locationAsset = await utils.createAsset(admin.accessToken, {
assetData: {
@@ -157,8 +154,7 @@ describe('/asset', () => {
assetId: user1Assets[0].id,
personId: person1.id,
});
};
beforeAll(setupTests, 30_000);
}, 30_000);
afterAll(() => {
utils.disconnectWebsocket(websocket);
@@ -235,35 +231,6 @@ describe('/asset', () => {
expect(data.status).toBe(200);
expect(data.body).toMatchObject({ people: [] });
});
describe('partner assets', () => {
it('should get the asset info', async () => {
const { status, body } = await request(app)
.get(`/asset/${user1Assets[0].id}`)
.set('Authorization', `Bearer ${user2.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({ id: user1Assets[0].id });
});
it('disallows viewing archived assets', async () => {
const asset = await utils.createAsset(user1.accessToken, { isArchived: true });
const { status } = await request(app)
.get(`/asset/${asset.id}`)
.set('Authorization', `Bearer ${user2.accessToken}`);
expect(status).toBe(400);
});
it('disallows viewing trashed assets', async () => {
const asset = await utils.createAsset(user1.accessToken);
await utils.deleteAssets(user1.accessToken, [asset.id]);
const { status } = await request(app)
.get(`/asset/${asset.id}`)
.set('Authorization', `Bearer ${user2.accessToken}`);
expect(status).toBe(400);
});
});
});
describe('GET /asset/statistics', () => {
@@ -571,321 +538,14 @@ describe('/asset', () => {
});
});
describe('GET /asset/thumbnail/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/asset/thumbnail/${locationAsset.id}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should not include gps data for webp thumbnails', async () => {
await utils.waitForWebsocketEvent({
event: 'assetUpload',
id: locationAsset.id,
});
const { status, body, type } = await request(app)
.get(`/asset/thumbnail/${locationAsset.id}?format=WEBP`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toBeDefined();
expect(type).toBe('image/webp');
const exifData = await readTags(body, 'thumbnail.webp');
expect(exifData).not.toHaveProperty('GPSLongitude');
expect(exifData).not.toHaveProperty('GPSLatitude');
});
it('should not include gps data for jpeg thumbnails', async () => {
const { status, body, type } = await request(app)
.get(`/asset/thumbnail/${locationAsset.id}?format=JPEG`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toBeDefined();
expect(type).toBe('image/jpeg');
const exifData = await readTags(body, 'thumbnail.jpg');
expect(exifData).not.toHaveProperty('GPSLongitude');
expect(exifData).not.toHaveProperty('GPSLatitude');
});
});
describe('GET /asset/file/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/asset/thumbnail/${locationAsset.id}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should download the original', async () => {
const { status, body, type } = await request(app)
.get(`/asset/file/${locationAsset.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toBeDefined();
expect(type).toBe('image/jpeg');
const asset = await utils.getAssetInfo(admin.accessToken, locationAsset.id);
const original = await readFile(locationAssetFilepath);
const originalChecksum = utils.sha1(original);
const downloadChecksum = utils.sha1(body);
expect(originalChecksum).toBe(downloadChecksum);
expect(downloadChecksum).toBe(asset.checksum);
});
});
describe('GET /asset/map-marker', () => {
beforeAll(async () => {
const files = [
'formats/avif/8bit-sRGB.avif',
'formats/jpg/el_torcal_rocks.jpg',
'formats/jxl/8bit-sRGB.jxl',
'formats/heic/IMG_2682.heic',
'formats/png/density_plot.png',
'formats/raw/Nikon/D80/glarus.nef',
'formats/raw/Nikon/D700/philadelphia.nef',
'formats/raw/Panasonic/DMC-GH4/4_3.rw2',
'formats/raw/Sony/ILCE-6300/12bit-compressed-(3_2).arw',
'formats/raw/Sony/ILCE-7M2/14bit-uncompressed-(3_2).arw',
];
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 });
};
const uploads = files.map((f) => uploadFile(f));
await Promise.all(uploads);
}, 30_000);
it('should require authentication', async () => {
const { status, body } = await request(app).get('/asset/map-marker');
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('/asset/map-marker')
.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('/asset/map-marker')
.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('PUT /asset', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put('/asset');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid parent id', async () => {
const { status, body } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ stackParentId: uuidDto.invalid, ids: [stackAssets[0].id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['stackParentId must be a UUID']));
});
it('should require access to the parent', async () => {
const { status, body } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ stackParentId: stackAssets[3].id, ids: [user1Assets[0].id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.noPermission);
});
it('should add stack children', async () => {
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ stackParentId: stackAssets[0].id, ids: [stackAssets[3].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(expect.arrayContaining([expect.objectContaining({ id: stackAssets[3].id })]));
});
it('should remove stack children', async () => {
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ removeParent: true, ids: [stackAssets[1].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: stackAssets[2].id }),
expect.objectContaining({ id: stackAssets[3].id }),
]),
);
});
it('should remove all stack children', async () => {
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ removeParent: true, ids: [stackAssets[2].id, stackAssets[3].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).toBeUndefined();
});
it('should merge stack children', async () => {
// create stack after previous test removed stack children
await updateAssets(
{ assetBulkUpdateDto: { stackParentId: stackAssets[0].id, ids: [stackAssets[1].id, stackAssets[2].id] } },
{ headers: asBearerAuth(stackUser.accessToken) },
);
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ stackParentId: stackAssets[3].id, ids: [stackAssets[0].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[3].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: stackAssets[0].id }),
expect.objectContaining({ id: stackAssets[1].id }),
expect.objectContaining({ id: stackAssets[2].id }),
]),
);
});
});
describe('PUT /asset/stack/parent', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put('/asset/stack/parent');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid id', async () => {
const { status, body } = await request(app)
.put('/asset/stack/parent')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ oldParentId: uuidDto.invalid, newParentId: uuidDto.invalid });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
it('should require access', async () => {
const { status, body } = await request(app)
.put('/asset/stack/parent')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ oldParentId: stackAssets[3].id, newParentId: stackAssets[0].id });
expect(status).toBe(400);
expect(body).toEqual(errorDto.noPermission);
});
it('should make old parent child of new parent', async () => {
const { status } = await request(app)
.put('/asset/stack/parent')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ oldParentId: stackAssets[3].id, newParentId: stackAssets[0].id });
expect(status).toBe(200);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
// new parent
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: stackAssets[1].id }),
expect.objectContaining({ id: stackAssets[2].id }),
expect.objectContaining({ id: stackAssets[3].id }),
]),
);
});
});
describe('POST /asset/upload', () => {
beforeAll(setupTests, 30_000);
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/asset/upload`);
expect(body).toEqual(errorDto.unauthorized);
expect(status).toBe(401);
});
it.each([
const invalid = [
{ should: 'require `deviceAssetId`', dto: { ...makeUploadDto({ omit: 'deviceAssetId' }) } },
{ should: 'require `deviceId`', dto: { ...makeUploadDto({ omit: 'deviceId' }) } },
{ should: 'require `fileCreatedAt`', dto: { ...makeUploadDto({ omit: 'fileCreatedAt' }) } },
@@ -894,17 +554,21 @@ describe('/asset', () => {
{ should: 'throw if `isFavorite` is not a boolean', dto: { ...makeUploadDto(), isFavorite: 'not-a-boolean' } },
{ should: 'throw if `isVisible` is not a boolean', dto: { ...makeUploadDto(), isVisible: 'not-a-boolean' } },
{ should: 'throw if `isArchived` is not a boolean', dto: { ...makeUploadDto(), isArchived: 'not-a-boolean' } },
])('should $should', async ({ dto }) => {
const { status, body } = await request(app)
.post('/asset/upload')
.set('Authorization', `Bearer ${user1.accessToken}`)
.attach('assetData', makeRandomImage(), 'example.png')
.field(dto);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
];
it.each([
for (const { should, dto } of invalid) {
it(`should ${should}`, async () => {
const { status, body } = await request(app)
.post('/asset/upload')
.set('Authorization', `Bearer ${user1.accessToken}`)
.attach('assetData', makeRandomImage(), 'example.png')
.field(dto);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
}
const tests = [
{
input: 'formats/avif/8bit-sRGB.avif',
expected: {
@@ -1120,22 +784,26 @@ describe('/asset', () => {
},
},
},
])(`should upload and generate a thumbnail for $input`, async ({ input, expected }) => {
const filepath = join(testAssetDir, input);
const { id, duplicate } = await utils.createAsset(admin.accessToken, {
assetData: { bytes: await readFile(filepath), filename: basename(filepath) },
];
for (const { input, expected } of tests) {
it(`should upload and generate a thumbnail for ${input}`, async () => {
const filepath = join(testAssetDir, input);
const { id, duplicate } = await utils.createAsset(admin.accessToken, {
assetData: { bytes: await readFile(filepath), filename: basename(filepath) },
});
expect(duplicate).toBe(false);
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: id });
const asset = await utils.getAssetInfo(admin.accessToken, id);
expect(asset.exifInfo).toBeDefined();
expect(asset.exifInfo).toMatchObject(expected.exifInfo);
expect(asset).toMatchObject(expected);
});
expect(duplicate).toBe(false);
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: id });
const asset = await utils.getAssetInfo(admin.accessToken, id);
expect(asset.exifInfo).toBeDefined();
expect(asset.exifInfo).toMatchObject(expected.exifInfo);
expect(asset).toMatchObject(expected);
});
}
it('should handle a duplicate', async () => {
const filepath = 'formats/jpeg/el_torcal_rocks.jpeg';
@@ -1162,7 +830,7 @@ describe('/asset', () => {
expect(body).toEqual({ id: expect.any(String), duplicate: false });
expect(status).toBe(201);
const user = await getMyUser({ headers: asBearerAuth(quotaUser.accessToken) });
const { body: user } = await request(app).get('/user/me').set('Authorization', `Bearer ${quotaUser.accessToken}`);
expect(user).toEqual(expect.objectContaining({ quotaUsageInBytes: 70 }));
});
@@ -1186,7 +854,7 @@ describe('/asset', () => {
// This ensures that immich+exiftool are extracting the videos the same way Samsung does.
// DO NOT assume immich+exiftool are doing things correctly and just copy whatever hash it gives
// into the test here.
it.each([
const motionTests = [
{
filepath: 'formats/motionphoto/Samsung One UI 5.jpg',
checksum: 'fr14niqCq6N20HB8rJYEvpsUVtI=',
@@ -1199,23 +867,329 @@ describe('/asset', () => {
filepath: 'formats/motionphoto/Samsung One UI 6.heic',
checksum: '/ejgzywvgvzvVhUYVfvkLzFBAF0=',
},
])(`should extract motionphoto video from $filepath`, async ({ filepath, checksum }) => {
const response = await utils.createAsset(admin.accessToken, {
assetData: {
bytes: await readFile(join(testAssetDir, filepath)),
filename: basename(filepath),
},
];
for (const { filepath, checksum } of motionTests) {
it(`should extract motionphoto video from ${filepath}`, async () => {
const response = await utils.createAsset(admin.accessToken, {
assetData: {
bytes: await readFile(join(testAssetDir, filepath)),
filename: basename(filepath),
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: response.id });
expect(response.duplicate).toBe(false);
const asset = await utils.getAssetInfo(admin.accessToken, response.id);
expect(asset.livePhotoVideoId).toBeDefined();
const video = await utils.getAssetInfo(admin.accessToken, asset.livePhotoVideoId as string);
expect(video.checksum).toStrictEqual(checksum);
});
}
});
describe('GET /asset/thumbnail/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/asset/thumbnail/${locationAsset.id}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should not include gps data for webp thumbnails', async () => {
await utils.waitForWebsocketEvent({
event: 'assetUpload',
id: locationAsset.id,
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: response.id });
const { status, body, type } = await request(app)
.get(`/asset/thumbnail/${locationAsset.id}?format=WEBP`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(response.duplicate).toBe(false);
expect(status).toBe(200);
expect(body).toBeDefined();
expect(type).toBe('image/webp');
const asset = await utils.getAssetInfo(admin.accessToken, response.id);
expect(asset.livePhotoVideoId).toBeDefined();
const exifData = await readTags(body, 'thumbnail.webp');
expect(exifData).not.toHaveProperty('GPSLongitude');
expect(exifData).not.toHaveProperty('GPSLatitude');
});
const video = await utils.getAssetInfo(admin.accessToken, asset.livePhotoVideoId as string);
expect(video.checksum).toStrictEqual(checksum);
it('should not include gps data for jpeg thumbnails', async () => {
const { status, body, type } = await request(app)
.get(`/asset/thumbnail/${locationAsset.id}?format=JPEG`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toBeDefined();
expect(type).toBe('image/jpeg');
const exifData = await readTags(body, 'thumbnail.jpg');
expect(exifData).not.toHaveProperty('GPSLongitude');
expect(exifData).not.toHaveProperty('GPSLatitude');
});
});
describe('GET /asset/file/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/asset/thumbnail/${locationAsset.id}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should download the original', async () => {
const { status, body, type } = await request(app)
.get(`/asset/file/${locationAsset.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toBeDefined();
expect(type).toBe('image/jpeg');
const asset = await utils.getAssetInfo(admin.accessToken, locationAsset.id);
const original = await readFile(locationAssetFilepath);
const originalChecksum = utils.sha1(original);
const downloadChecksum = utils.sha1(body);
expect(originalChecksum).toBe(downloadChecksum);
expect(downloadChecksum).toBe(asset.checksum);
});
});
describe('GET /asset/map-marker', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/asset/map-marker');
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('/asset/map-marker')
.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('/asset/map-marker')
.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 /asset', () => {
it('should return stack data', async () => {
const { status, body } = await request(app).get('/asset').set('Authorization', `Bearer ${stackUser.accessToken}`);
const stack = body.find((asset: AssetResponseDto) => asset.id === stackAssets[0].id);
expect(status).toBe(200);
expect(stack).toEqual(
expect.objectContaining({
stackCount: 3,
stack:
// Response includes children at the root level
expect.arrayContaining([
expect.objectContaining({ id: stackAssets[1].id }),
expect.objectContaining({ id: stackAssets[2].id }),
]),
}),
);
});
});
describe('PUT /asset', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put('/asset');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid parent id', async () => {
const { status, body } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ stackParentId: uuidDto.invalid, ids: [stackAssets[0].id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['stackParentId must be a UUID']));
});
it('should require access to the parent', async () => {
const { status, body } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ stackParentId: stackAssets[3].id, ids: [user1Assets[0].id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.noPermission);
});
it('should add stack children', async () => {
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ stackParentId: stackAssets[0].id, ids: [stackAssets[3].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(expect.arrayContaining([expect.objectContaining({ id: stackAssets[3].id })]));
});
it('should remove stack children', async () => {
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ removeParent: true, ids: [stackAssets[1].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: stackAssets[2].id }),
expect.objectContaining({ id: stackAssets[3].id }),
]),
);
});
it('should remove all stack children', async () => {
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ removeParent: true, ids: [stackAssets[2].id, stackAssets[3].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).toBeUndefined();
});
it('should merge stack children', async () => {
// create stack after previous test removed stack children
await updateAssets(
{ assetBulkUpdateDto: { stackParentId: stackAssets[0].id, ids: [stackAssets[1].id, stackAssets[2].id] } },
{ headers: asBearerAuth(stackUser.accessToken) },
);
const { status } = await request(app)
.put('/asset')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ stackParentId: stackAssets[3].id, ids: [stackAssets[0].id] });
expect(status).toBe(204);
const asset = await getAssetInfo({ id: stackAssets[3].id }, { headers: asBearerAuth(stackUser.accessToken) });
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: stackAssets[0].id }),
expect.objectContaining({ id: stackAssets[1].id }),
expect.objectContaining({ id: stackAssets[2].id }),
]),
);
});
});
describe('PUT /asset/stack/parent', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put('/asset/stack/parent');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid id', async () => {
const { status, body } = await request(app)
.put('/asset/stack/parent')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ oldParentId: uuidDto.invalid, newParentId: uuidDto.invalid });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
it('should require access', async () => {
const { status, body } = await request(app)
.put('/asset/stack/parent')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ oldParentId: stackAssets[3].id, newParentId: stackAssets[0].id });
expect(status).toBe(400);
expect(body).toEqual(errorDto.noPermission);
});
it('should make old parent child of new parent', async () => {
const { status } = await request(app)
.put('/asset/stack/parent')
.set('Authorization', `Bearer ${stackUser.accessToken}`)
.send({ oldParentId: stackAssets[3].id, newParentId: stackAssets[0].id });
expect(status).toBe(200);
const asset = await getAssetInfo({ id: stackAssets[0].id }, { headers: asBearerAuth(stackUser.accessToken) });
// new parent
expect(asset.stack).not.toBeUndefined();
expect(asset.stack).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: stackAssets[1].id }),
expect.objectContaining({ id: stackAssets[2].id }),
expect.objectContaining({ id: stackAssets[3].id }),
]),
);
});
});
});

View File

@@ -2,7 +2,7 @@ import { deleteAssets, getAuditFiles, updateAsset, type LoginResponseDto } from
import { asBearerAuth, utils } from 'src/utils';
import { beforeAll, describe, expect, it } from 'vitest';
describe('/audits', () => {
describe('/audit', () => {
let admin: LoginResponseDto;
beforeAll(async () => {

View File

@@ -11,7 +11,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest';
const scan = async (accessToken: string, id: string, dto: ScanLibraryDto = {}) =>
scanLibrary({ id, scanLibraryDto: dto }, { headers: asBearerAuth(accessToken) });
describe('/libraries', () => {
describe('/library', () => {
let admin: LoginResponseDto;
let user: LoginResponseDto;
let library: LibraryResponseDto;
@@ -37,24 +37,24 @@ describe('/libraries', () => {
utils.resetEvents();
});
describe('GET /libraries', () => {
describe('GET /library', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/libraries');
const { status, body } = await request(app).get('/library');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
});
describe('POST /libraries', () => {
describe('POST /library', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post('/libraries').send({});
const { status, body } = await request(app).post('/library').send({});
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require admin authentication', async () => {
const { status, body } = await request(app)
.post('/libraries')
.post('/library')
.set('Authorization', `Bearer ${user.accessToken}`)
.send({ ownerId: admin.userId });
@@ -64,7 +64,7 @@ describe('/libraries', () => {
it('should create an external library with defaults', async () => {
const { status, body } = await request(app)
.post('/libraries')
.post('/library')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ ownerId: admin.userId });
@@ -83,7 +83,7 @@ describe('/libraries', () => {
it('should create an external library with options', async () => {
const { status, body } = await request(app)
.post('/libraries')
.post('/library')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
ownerId: admin.userId,
@@ -103,7 +103,7 @@ describe('/libraries', () => {
it('should not create an external library with duplicate import paths', async () => {
const { status, body } = await request(app)
.post('/libraries')
.post('/library')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
ownerId: admin.userId,
@@ -118,7 +118,7 @@ describe('/libraries', () => {
it('should not create an external library with duplicate exclusion patterns', async () => {
const { status, body } = await request(app)
.post('/libraries')
.post('/library')
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
ownerId: admin.userId,
@@ -132,16 +132,16 @@ describe('/libraries', () => {
});
});
describe('PUT /libraries/:id', () => {
describe('PUT /library/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/libraries/${uuidDto.notFound}`).send({});
const { status, body } = await request(app).put(`/library/${uuidDto.notFound}`).send({});
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should change the library name', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ name: 'New Library Name' });
@@ -155,7 +155,7 @@ describe('/libraries', () => {
it('should not set an empty name', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ name: '' });
@@ -165,7 +165,7 @@ describe('/libraries', () => {
it('should change the import paths', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ importPaths: [testAssetDirInternal] });
@@ -179,7 +179,7 @@ describe('/libraries', () => {
it('should reject an empty import path', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ importPaths: [''] });
@@ -189,7 +189,7 @@ describe('/libraries', () => {
it('should reject duplicate import paths', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ importPaths: ['/path', '/path'] });
@@ -199,7 +199,7 @@ describe('/libraries', () => {
it('should change the exclusion pattern', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ exclusionPatterns: ['**/Raw/**'] });
@@ -213,7 +213,7 @@ describe('/libraries', () => {
it('should reject duplicate exclusion patterns', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ exclusionPatterns: ['**/*.jpg', '**/*.jpg'] });
@@ -223,7 +223,7 @@ describe('/libraries', () => {
it('should reject an empty exclusion pattern', async () => {
const { status, body } = await request(app)
.put(`/libraries/${library.id}`)
.put(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ exclusionPatterns: [''] });
@@ -232,9 +232,9 @@ describe('/libraries', () => {
});
});
describe('GET /libraries/:id', () => {
describe('GET /library/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/libraries/${uuidDto.notFound}`);
const { status, body } = await request(app).get(`/library/${uuidDto.notFound}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -242,7 +242,7 @@ describe('/libraries', () => {
it('should require admin access', async () => {
const { status, body } = await request(app)
.get(`/libraries/${uuidDto.notFound}`)
.get(`/library/${uuidDto.notFound}`)
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
@@ -252,7 +252,7 @@ describe('/libraries', () => {
const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId });
const { status, body } = await request(app)
.get(`/libraries/${library.id}`)
.get(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
@@ -269,18 +269,18 @@ describe('/libraries', () => {
});
});
describe('GET /libraries/:id/statistics', () => {
describe('GET /library/:id/statistics', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/libraries/${uuidDto.notFound}/statistics`);
const { status, body } = await request(app).get(`/library/${uuidDto.notFound}/statistics`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
});
describe('POST /libraries/:id/scan', () => {
describe('POST /library/:id/scan', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/libraries/${uuidDto.notFound}/scan`).send({});
const { status, body } = await request(app).post(`/library/${uuidDto.notFound}/scan`).send({});
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -496,9 +496,9 @@ describe('/libraries', () => {
});
});
describe('POST /libraries/:id/removeOffline', () => {
describe('POST /library/:id/removeOffline', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/libraries/${uuidDto.notFound}/removeOffline`).send({});
const { status, body } = await request(app).post(`/library/${uuidDto.notFound}/removeOffline`).send({});
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -532,7 +532,7 @@ describe('/libraries', () => {
expect(offlineAssets.count).toBe(1);
const { status } = await request(app)
.post(`/libraries/${library.id}/removeOffline`)
.post(`/library/${library.id}/removeOffline`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send();
expect(status).toBe(204);
@@ -557,7 +557,7 @@ describe('/libraries', () => {
expect(assetsBefore.count).toBeGreaterThan(1);
const { status } = await request(app)
.post(`/libraries/${library.id}/removeOffline`)
.post(`/library/${library.id}/removeOffline`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send();
expect(status).toBe(204);
@@ -569,9 +569,9 @@ describe('/libraries', () => {
});
});
describe('POST /libraries/:id/validate', () => {
describe('POST /library/:id/validate', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/libraries/${uuidDto.notFound}/validate`).send({});
const { status, body } = await request(app).post(`/library/${uuidDto.notFound}/validate`).send({});
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -617,9 +617,9 @@ describe('/libraries', () => {
});
});
describe('DELETE /libraries/:id', () => {
describe('DELETE /library/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete(`/libraries/${uuidDto.notFound}`);
const { status, body } = await request(app).delete(`/library/${uuidDto.notFound}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -629,7 +629,7 @@ describe('/libraries', () => {
const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId });
const { status, body } = await request(app)
.delete(`/libraries/${library.id}`)
.delete(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(204);
@@ -655,7 +655,7 @@ describe('/libraries', () => {
await utils.waitForWebsocketEvent({ event: 'assetUpload', total: 2 });
const { status, body } = await request(app)
.delete(`/libraries/${library.id}`)
.delete(`/library/${library.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(204);

View File

@@ -5,7 +5,7 @@ import { app, asBearerAuth, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
describe('/partners', () => {
describe('/partner', () => {
let admin: LoginResponseDto;
let user1: LoginResponseDto;
let user2: LoginResponseDto;
@@ -28,9 +28,9 @@ describe('/partners', () => {
]);
});
describe('GET /partners', () => {
describe('GET /partner', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/partners');
const { status, body } = await request(app).get('/partner');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -38,7 +38,7 @@ describe('/partners', () => {
it('should get all partners shared by user', async () => {
const { status, body } = await request(app)
.get('/partners')
.get('/partner')
.set('Authorization', `Bearer ${user1.accessToken}`)
.query({ direction: 'shared-by' });
@@ -48,7 +48,7 @@ describe('/partners', () => {
it('should get all partners that share with user', async () => {
const { status, body } = await request(app)
.get('/partners')
.get('/partner')
.set('Authorization', `Bearer ${user1.accessToken}`)
.query({ direction: 'shared-with' });
@@ -57,9 +57,9 @@ describe('/partners', () => {
});
});
describe('POST /partners/:id', () => {
describe('POST /partner/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/partners/${user3.userId}`);
const { status, body } = await request(app).post(`/partner/${user3.userId}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -67,7 +67,7 @@ describe('/partners', () => {
it('should share with new partner', async () => {
const { status, body } = await request(app)
.post(`/partners/${user3.userId}`)
.post(`/partner/${user3.userId}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(201);
@@ -76,7 +76,7 @@ describe('/partners', () => {
it('should not share with new partner if already sharing with this partner', async () => {
const { status, body } = await request(app)
.post(`/partners/${user2.userId}`)
.post(`/partner/${user2.userId}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(400);
@@ -84,9 +84,9 @@ describe('/partners', () => {
});
});
describe('PUT /partners/:id', () => {
describe('PUT /partner/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/partners/${user2.userId}`);
const { status, body } = await request(app).put(`/partner/${user2.userId}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -94,7 +94,7 @@ describe('/partners', () => {
it('should update partner', async () => {
const { status, body } = await request(app)
.put(`/partners/${user2.userId}`)
.put(`/partner/${user2.userId}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ inTimeline: false });
@@ -103,9 +103,9 @@ describe('/partners', () => {
});
});
describe('DELETE /partners/:id', () => {
describe('DELETE /partner/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete(`/partners/${user3.userId}`);
const { status, body } = await request(app).delete(`/partner/${user3.userId}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -113,7 +113,7 @@ describe('/partners', () => {
it('should delete partner', async () => {
const { status } = await request(app)
.delete(`/partners/${user3.userId}`)
.delete(`/partner/${user3.userId}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -121,7 +121,7 @@ describe('/partners', () => {
it('should throw a bad request if partner not found', async () => {
const { status, body } = await request(app)
.delete(`/partners/${user3.userId}`)
.delete(`/partner/${user3.userId}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(400);

View File

@@ -12,7 +12,7 @@ const invalidBirthday = [
{ birthDate: new Date(9999, 0, 0).toISOString(), response: ['Birth date cannot be in the future'] },
];
describe('/people', () => {
describe('/person', () => {
let admin: LoginResponseDto;
let visiblePerson: PersonResponseDto;
let hiddenPerson: PersonResponseDto;
@@ -47,11 +47,11 @@ describe('/people', () => {
]);
});
describe('GET /people', () => {
describe('GET /person', () => {
beforeEach(async () => {});
it('should require authentication', async () => {
const { status, body } = await request(app).get('/people');
const { status, body } = await request(app).get('/person');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -59,7 +59,7 @@ describe('/people', () => {
it('should return all people (including hidden)', async () => {
const { status, body } = await request(app)
.get('/people')
.get('/person')
.set('Authorization', `Bearer ${admin.accessToken}`)
.query({ withHidden: true });
@@ -76,7 +76,7 @@ describe('/people', () => {
});
it('should return only visible people', async () => {
const { status, body } = await request(app).get('/people').set('Authorization', `Bearer ${admin.accessToken}`);
const { status, body } = await request(app).get('/person').set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
@@ -90,9 +90,9 @@ describe('/people', () => {
});
});
describe('GET /people/:id', () => {
describe('GET /person/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/people/${uuidDto.notFound}`);
const { status, body } = await request(app).get(`/person/${uuidDto.notFound}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -100,7 +100,7 @@ describe('/people', () => {
it('should throw error if person with id does not exist', async () => {
const { status, body } = await request(app)
.get(`/people/${uuidDto.notFound}`)
.get(`/person/${uuidDto.notFound}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
@@ -109,7 +109,7 @@ describe('/people', () => {
it('should return person information', async () => {
const { status, body } = await request(app)
.get(`/people/${visiblePerson.id}`)
.get(`/person/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
@@ -117,9 +117,9 @@ describe('/people', () => {
});
});
describe('GET /people/:id/statistics', () => {
describe('GET /person/:id/statistics', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/people/${multipleAssetsPerson.id}/statistics`);
const { status, body } = await request(app).get(`/person/${multipleAssetsPerson.id}/statistics`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -127,7 +127,7 @@ describe('/people', () => {
it('should throw error if person with id does not exist', async () => {
const { status, body } = await request(app)
.get(`/people/${uuidDto.notFound}/statistics`)
.get(`/person/${uuidDto.notFound}/statistics`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
@@ -136,7 +136,7 @@ describe('/people', () => {
it('should return the correct number of assets', async () => {
const { status, body } = await request(app)
.get(`/people/${multipleAssetsPerson.id}/statistics`)
.get(`/person/${multipleAssetsPerson.id}/statistics`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
@@ -144,9 +144,9 @@ describe('/people', () => {
});
});
describe('POST /people', () => {
describe('POST /person', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/people`);
const { status, body } = await request(app).post(`/person`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
@@ -154,7 +154,7 @@ describe('/people', () => {
for (const { birthDate, response } of invalidBirthday) {
it(`should not accept an invalid birth date [${birthDate}]`, async () => {
const { status, body } = await request(app)
.post(`/people`)
.post(`/person`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ birthDate });
expect(status).toBe(400);
@@ -164,7 +164,7 @@ describe('/people', () => {
it('should create a person', async () => {
const { status, body } = await request(app)
.post(`/people`)
.post(`/person`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({
name: 'New Person',
@@ -179,9 +179,9 @@ describe('/people', () => {
});
});
describe('PUT /people/:id', () => {
describe('PUT /person/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/people/${uuidDto.notFound}`);
const { status, body } = await request(app).put(`/person/${uuidDto.notFound}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
@@ -193,7 +193,7 @@ describe('/people', () => {
]) {
it(`should not allow null ${key}`, async () => {
const { status, body } = await request(app)
.put(`/people/${visiblePerson.id}`)
.put(`/person/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ [key]: null });
expect(status).toBe(400);
@@ -204,7 +204,7 @@ describe('/people', () => {
for (const { birthDate, response } of invalidBirthday) {
it(`should not accept an invalid birth date [${birthDate}]`, async () => {
const { status, body } = await request(app)
.put(`/people/${visiblePerson.id}`)
.put(`/person/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ birthDate });
expect(status).toBe(400);
@@ -214,7 +214,7 @@ describe('/people', () => {
it('should update a date of birth', async () => {
const { status, body } = await request(app)
.put(`/people/${visiblePerson.id}`)
.put(`/person/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ birthDate: '1990-01-01T05:00:00.000Z' });
expect(status).toBe(200);
@@ -223,7 +223,7 @@ describe('/people', () => {
it('should clear a date of birth', async () => {
const { status, body } = await request(app)
.put(`/people/${visiblePerson.id}`)
.put(`/person/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ birthDate: null });
expect(status).toBe(200);

View File

@@ -15,16 +15,16 @@ describe('/server-info', () => {
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1);
});
describe('GET /server-info/storage', () => {
describe('GET /server-info', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/server-info/storage');
const { status, body } = await request(app).get('/server-info');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should return the disk information', async () => {
const { status, body } = await request(app)
.get('/server-info/storage')
.get('/server-info')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({

View File

@@ -5,7 +5,7 @@ import {
SharedLinkResponseDto,
SharedLinkType,
createAlbum,
deleteUserAdmin,
deleteUser,
} from '@immich/sdk';
import { createUserDto, uuidDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
@@ -13,7 +13,7 @@ import { app, asBearerAuth, shareUrl, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
describe('/shared-links', () => {
describe('/shared-link', () => {
let admin: LoginResponseDto;
let asset1: AssetFileUploadResponseDto;
let asset2: AssetFileUploadResponseDto;
@@ -86,7 +86,7 @@ describe('/shared-links', () => {
}),
]);
await deleteUserAdmin({ id: user2.userId, userAdminDeleteDto: {} }, { headers: asBearerAuth(admin.accessToken) });
await deleteUser({ id: user2.userId, deleteUserDto: {} }, { headers: asBearerAuth(admin.accessToken) });
});
describe('GET /share/${key}', () => {
@@ -114,9 +114,9 @@ describe('/shared-links', () => {
});
});
describe('GET /shared-links', () => {
describe('GET /shared-link', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/shared-links');
const { status, body } = await request(app).get('/shared-link');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -124,7 +124,7 @@ describe('/shared-links', () => {
it('should get all shared links created by user', async () => {
const { status, body } = await request(app)
.get('/shared-links')
.get('/shared-link')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -142,7 +142,7 @@ describe('/shared-links', () => {
it('should not get shared links created by other users', async () => {
const { status, body } = await request(app)
.get('/shared-links')
.get('/shared-link')
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
@@ -150,15 +150,15 @@ describe('/shared-links', () => {
});
});
describe('GET /shared-links/me', () => {
describe('GET /shared-link/me', () => {
it('should not require admin authentication', async () => {
const { status } = await request(app).get('/shared-links/me').set('Authorization', `Bearer ${admin.accessToken}`);
const { status } = await request(app).get('/shared-link/me').set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(403);
});
it('should get data for correct shared link', async () => {
const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithAlbum.key });
const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithAlbum.key });
expect(status).toBe(200);
expect(body).toEqual(
@@ -172,7 +172,7 @@ describe('/shared-links', () => {
it('should return unauthorized for incorrect shared link', async () => {
const { status, body } = await request(app)
.get('/shared-links/me')
.get('/shared-link/me')
.query({ key: linkWithAlbum.key + 'foo' });
expect(status).toBe(401);
@@ -180,14 +180,14 @@ describe('/shared-links', () => {
});
it('should return unauthorized if target has been soft deleted', async () => {
const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithDeletedAlbum.key });
const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithDeletedAlbum.key });
expect(status).toBe(401);
expect(body).toEqual(errorDto.invalidShareKey);
});
it('should return unauthorized for password protected link', async () => {
const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithPassword.key });
const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithPassword.key });
expect(status).toBe(401);
expect(body).toEqual(errorDto.invalidSharePassword);
@@ -195,7 +195,7 @@ describe('/shared-links', () => {
it('should get data for correct password protected link', async () => {
const { status, body } = await request(app)
.get('/shared-links/me')
.get('/shared-link/me')
.query({ key: linkWithPassword.key, password: 'foo' });
expect(status).toBe(200);
@@ -209,7 +209,7 @@ describe('/shared-links', () => {
});
it('should return metadata for album shared link', async () => {
const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithMetadata.key });
const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithMetadata.key });
expect(status).toBe(200);
expect(body.assets).toHaveLength(1);
@@ -225,7 +225,7 @@ describe('/shared-links', () => {
});
it('should not return metadata for album shared link without metadata', async () => {
const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithoutMetadata.key });
const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithoutMetadata.key });
expect(status).toBe(200);
expect(body.assets).toHaveLength(1);
@@ -239,9 +239,9 @@ describe('/shared-links', () => {
});
});
describe('GET /shared-links/:id', () => {
describe('GET /shared-link/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/shared-links/${linkWithAlbum.id}`);
const { status, body } = await request(app).get(`/shared-link/${linkWithAlbum.id}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -249,7 +249,7 @@ describe('/shared-links', () => {
it('should get shared link by id', async () => {
const { status, body } = await request(app)
.get(`/shared-links/${linkWithAlbum.id}`)
.get(`/shared-link/${linkWithAlbum.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
@@ -264,7 +264,7 @@ describe('/shared-links', () => {
it('should not get shared link by id if user has not created the link or it does not exist', async () => {
const { status, body } = await request(app)
.get(`/shared-links/${linkWithAlbum.id}`)
.get(`/shared-link/${linkWithAlbum.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
@@ -272,10 +272,10 @@ describe('/shared-links', () => {
});
});
describe('POST /shared-links', () => {
describe('POST /shared-link', () => {
it('should require authentication', async () => {
const { status, body } = await request(app)
.post('/shared-links')
.post('/shared-link')
.send({ type: SharedLinkType.Album, albumId: uuidDto.notFound });
expect(status).toBe(401);
@@ -284,7 +284,7 @@ describe('/shared-links', () => {
it('should require a type and the correspondent asset/album id', async () => {
const { status, body } = await request(app)
.post('/shared-links')
.post('/shared-link')
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(400);
@@ -293,7 +293,7 @@ describe('/shared-links', () => {
it('should require an asset/album id', async () => {
const { status, body } = await request(app)
.post('/shared-links')
.post('/shared-link')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ type: SharedLinkType.Album });
@@ -303,7 +303,7 @@ describe('/shared-links', () => {
it('should require a valid asset id', async () => {
const { status, body } = await request(app)
.post('/shared-links')
.post('/shared-link')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ type: SharedLinkType.Individual, assetId: uuidDto.notFound });
@@ -313,7 +313,7 @@ describe('/shared-links', () => {
it('should create a shared link', async () => {
const { status, body } = await request(app)
.post('/shared-links')
.post('/shared-link')
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ type: SharedLinkType.Album, albumId: album.id });
@@ -327,10 +327,10 @@ describe('/shared-links', () => {
});
});
describe('PATCH /shared-links/:id', () => {
describe('PATCH /shared-link/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app)
.patch(`/shared-links/${linkWithAlbum.id}`)
.patch(`/shared-link/${linkWithAlbum.id}`)
.send({ description: 'foo' });
expect(status).toBe(401);
@@ -339,7 +339,7 @@ describe('/shared-links', () => {
it('should fail if invalid link', async () => {
const { status, body } = await request(app)
.patch(`/shared-links/${uuidDto.notFound}`)
.patch(`/shared-link/${uuidDto.notFound}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ description: 'foo' });
@@ -349,7 +349,7 @@ describe('/shared-links', () => {
it('should update shared link', async () => {
const { status, body } = await request(app)
.patch(`/shared-links/${linkWithAlbum.id}`)
.patch(`/shared-link/${linkWithAlbum.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ description: 'foo' });
@@ -364,10 +364,10 @@ describe('/shared-links', () => {
});
});
describe('PUT /shared-links/:id/assets', () => {
describe('PUT /shared-link/:id/assets', () => {
it('should not add assets to shared link (album)', async () => {
const { status, body } = await request(app)
.put(`/shared-links/${linkWithAlbum.id}/assets`)
.put(`/shared-link/${linkWithAlbum.id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ assetIds: [asset2.id] });
@@ -377,7 +377,7 @@ describe('/shared-links', () => {
it('should add an assets to a shared link (individual)', async () => {
const { status, body } = await request(app)
.put(`/shared-links/${linkWithAssets.id}/assets`)
.put(`/shared-link/${linkWithAssets.id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ assetIds: [asset2.id] });
@@ -386,10 +386,10 @@ describe('/shared-links', () => {
});
});
describe('DELETE /shared-links/:id/assets', () => {
describe('DELETE /shared-link/:id/assets', () => {
it('should not remove assets from a shared link (album)', async () => {
const { status, body } = await request(app)
.delete(`/shared-links/${linkWithAlbum.id}/assets`)
.delete(`/shared-link/${linkWithAlbum.id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ assetIds: [asset2.id] });
@@ -399,7 +399,7 @@ describe('/shared-links', () => {
it('should remove assets from a shared link (individual)', async () => {
const { status, body } = await request(app)
.delete(`/shared-links/${linkWithAssets.id}/assets`)
.delete(`/shared-link/${linkWithAssets.id}/assets`)
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ assetIds: [asset2.id] });
@@ -408,9 +408,9 @@ describe('/shared-links', () => {
});
});
describe('DELETE /shared-links/:id', () => {
describe('DELETE /shared-link/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete(`/shared-links/${linkWithAlbum.id}`);
const { status, body } = await request(app).delete(`/shared-link/${linkWithAlbum.id}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
@@ -418,7 +418,7 @@ describe('/shared-links', () => {
it('should fail if invalid link', async () => {
const { status, body } = await request(app)
.delete(`/shared-links/${uuidDto.notFound}`)
.delete(`/shared-link/${uuidDto.notFound}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(400);
@@ -427,7 +427,7 @@ describe('/shared-links', () => {
it('should delete a shared link', async () => {
const { status } = await request(app)
.delete(`/shared-links/${linkWithAlbum.id}`)
.delete(`/shared-link/${linkWithAlbum.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);

View File

@@ -1,4 +1,4 @@
import { LoginResponseDto, getAssetInfo, getAssetStatistics } from '@immich/sdk';
import { LoginResponseDto, getAllAssets } from '@immich/sdk';
import { Socket } from 'socket.io-client';
import { errorDto } from 'src/responses';
import { app, asBearerAuth, utils } from 'src/utils';
@@ -31,16 +31,16 @@ describe('/trash', () => {
const { id: assetId } = await utils.createAsset(admin.accessToken);
await utils.deleteAssets(admin.accessToken, [assetId]);
const before = await getAssetInfo({ id: assetId }, { headers: asBearerAuth(admin.accessToken) });
expect(before).toStrictEqual(expect.objectContaining({ id: assetId, isTrashed: true }));
const before = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
expect(before).toStrictEqual([expect.objectContaining({ id: assetId, isTrashed: true })]);
const { status } = await request(app).post('/trash/empty').set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(204);
await utils.waitForWebsocketEvent({ event: 'assetDelete', id: assetId });
const after = await getAssetStatistics({ isTrashed: true }, { headers: asBearerAuth(admin.accessToken) });
expect(after.total).toBe(0);
const after = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
expect(after.length).toBe(0);
});
});
@@ -56,14 +56,14 @@ describe('/trash', () => {
const { id: assetId } = await utils.createAsset(admin.accessToken);
await utils.deleteAssets(admin.accessToken, [assetId]);
const before = await getAssetInfo({ id: assetId }, { headers: asBearerAuth(admin.accessToken) });
expect(before).toStrictEqual(expect.objectContaining({ id: assetId, isTrashed: true }));
const before = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
expect(before).toStrictEqual([expect.objectContaining({ id: assetId, isTrashed: true })]);
const { status } = await request(app).post('/trash/restore').set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(204);
const after = await getAssetInfo({ id: assetId }, { headers: asBearerAuth(admin.accessToken) });
expect(after).toStrictEqual(expect.objectContaining({ id: assetId, isTrashed: false }));
const after = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) });
expect(after).toStrictEqual([expect.objectContaining({ id: assetId, isTrashed: false })]);
});
});

View File

@@ -1,317 +0,0 @@
import { LoginResponseDto, deleteUserAdmin, getMyUser, getUserAdmin, login } from '@immich/sdk';
import { Socket } from 'socket.io-client';
import { createUserDto, uuidDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
import { app, asBearerAuth, utils } from 'src/utils';
import request from 'supertest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
describe('/admin/users', () => {
let websocket: Socket;
let admin: LoginResponseDto;
let nonAdmin: LoginResponseDto;
let deletedUser: LoginResponseDto;
let userToDelete: LoginResponseDto;
let userToHardDelete: LoginResponseDto;
beforeAll(async () => {
await utils.resetDatabase();
admin = await utils.adminSetup({ onboarding: false });
[websocket, nonAdmin, deletedUser, userToDelete, userToHardDelete] = await Promise.all([
utils.connectWebsocket(admin.accessToken),
utils.userSetup(admin.accessToken, createUserDto.user1),
utils.userSetup(admin.accessToken, createUserDto.user2),
utils.userSetup(admin.accessToken, createUserDto.user3),
utils.userSetup(admin.accessToken, createUserDto.user4),
]);
await deleteUserAdmin(
{ id: deletedUser.userId, userAdminDeleteDto: {} },
{ headers: asBearerAuth(admin.accessToken) },
);
});
afterAll(() => {
utils.disconnectWebsocket(websocket);
});
describe('GET /admin/users', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/admin/users`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require authorization', async () => {
const { status, body } = await request(app)
.get(`/admin/users`)
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
it('should hide deleted users by default', async () => {
const { status, body } = await request(app)
.get(`/admin/users`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(4);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: admin.userEmail }),
expect.objectContaining({ email: nonAdmin.userEmail }),
expect.objectContaining({ email: userToDelete.userEmail }),
expect.objectContaining({ email: userToHardDelete.userEmail }),
]),
);
});
it('should include deleted users', async () => {
const { status, body } = await request(app)
.get(`/admin/users?withDeleted=true`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(5);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: admin.userEmail }),
expect.objectContaining({ email: nonAdmin.userEmail }),
expect.objectContaining({ email: userToDelete.userEmail }),
expect.objectContaining({ email: userToHardDelete.userEmail }),
expect.objectContaining({ email: deletedUser.userEmail }),
]),
);
});
});
describe('POST /admin/users', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/admin/users`).send(createUserDto.user1);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require authorization', async () => {
const { status, body } = await request(app)
.post(`/admin/users`)
.set('Authorization', `Bearer ${nonAdmin.accessToken}`)
.send(createUserDto.user1);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
for (const key of [
'password',
'email',
'name',
'quotaSizeInBytes',
'shouldChangePassword',
'memoriesEnabled',
'notify',
]) {
it(`should not allow null ${key}`, async () => {
const { status, body } = await request(app)
.post(`/admin/users`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ ...createUserDto.user1, [key]: null });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
}
it('should ignore `isAdmin`', async () => {
const { status, body } = await request(app)
.post(`/admin/users`)
.send({
isAdmin: true,
email: 'user5@immich.cloud',
password: 'password123',
name: 'Immich',
})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toMatchObject({
email: 'user5@immich.cloud',
isAdmin: false,
shouldChangePassword: true,
});
expect(status).toBe(201);
});
it('should create a user without memories enabled', async () => {
const { status, body } = await request(app)
.post(`/admin/users`)
.send({
email: 'no-memories@immich.cloud',
password: 'Password123',
name: 'No Memories',
memoriesEnabled: false,
})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toMatchObject({
email: 'no-memories@immich.cloud',
memoriesEnabled: false,
});
expect(status).toBe(201);
});
});
describe('PUT /admin/users/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/admin/users/${uuidDto.notFound}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require authorization', async () => {
const { status, body } = await request(app)
.put(`/admin/users/${uuidDto.notFound}`)
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
for (const key of ['password', 'email', 'name', 'shouldChangePassword', 'memoriesEnabled']) {
it(`should not allow null ${key}`, async () => {
const { status, body } = await request(app)
.put(`/admin/users/${uuidDto.notFound}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ [key]: null });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
}
it('should not allow a non-admin to become an admin', async () => {
const { status, body } = await request(app)
.put(`/admin/users/${nonAdmin.userId}`)
.send({ isAdmin: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({ isAdmin: false });
});
it('ignores updates to profileImagePath', async () => {
const { status, body } = await request(app)
.put(`/admin/users/${admin.userId}`)
.send({ profileImagePath: 'invalid.jpg' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({ id: admin.userId, profileImagePath: '' });
});
it('should update first and last name', async () => {
const before = await getUserAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
const { status, body } = await request(app)
.put(`/admin/users/${admin.userId}`)
.send({ name: 'Name' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
...before,
updatedAt: expect.any(String),
name: 'Name',
});
expect(before.updatedAt).not.toEqual(body.updatedAt);
});
it('should update memories enabled', async () => {
const before = await getUserAdmin({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
const { status, body } = await request(app)
.put(`/admin/users/${admin.userId}`)
.send({ memoriesEnabled: false })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
...before,
updatedAt: expect.anything(),
memoriesEnabled: false,
});
expect(before.updatedAt).not.toEqual(body.updatedAt);
});
it('should update password', async () => {
const { status, body } = await request(app)
.put(`/admin/users/${nonAdmin.userId}`)
.send({ password: 'super-secret' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({ email: nonAdmin.userEmail });
const token = await login({ loginCredentialDto: { email: nonAdmin.userEmail, password: 'super-secret' } });
expect(token.accessToken).toBeDefined();
const user = await getMyUser({ headers: asBearerAuth(token.accessToken) });
expect(user).toMatchObject({ email: nonAdmin.userEmail });
});
});
describe('DELETE /admin/users/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete(`/admin/users/${userToDelete.userId}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require authorization', async () => {
const { status, body } = await request(app)
.delete(`/admin/users/${userToDelete.userId}`)
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
it('should delete user', async () => {
const { status, body } = await request(app)
.delete(`/admin/users/${userToDelete.userId}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: userToDelete.userId,
updatedAt: expect.any(String),
deletedAt: expect.any(String),
});
});
it('should hard delete a user', async () => {
const { status, body } = await request(app)
.delete(`/admin/users/${userToHardDelete.userId}`)
.send({ force: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: userToHardDelete.userId,
updatedAt: expect.any(String),
deletedAt: expect.any(String),
});
await utils.waitForWebsocketEvent({ event: 'userDelete', id: userToHardDelete.userId, timeout: 5000 });
});
});
describe('POST /admin/users/:id/restore', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/admin/users/${userToDelete.userId}/restore`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require authorization', async () => {
const { status, body } = await request(app)
.post(`/admin/users/${userToDelete.userId}/restore`)
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
});
});

View File

@@ -1,105 +1,288 @@
import { LoginResponseDto, SharedLinkType, deleteUserAdmin, getMyUser, login } from '@immich/sdk';
import { createUserDto } from 'src/fixtures';
import { LoginResponseDto, deleteUser, getUserById } from '@immich/sdk';
import { Socket } from 'socket.io-client';
import { createUserDto, userDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
import { app, asBearerAuth, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
describe('/user', () => {
let websocket: Socket;
describe('/users', () => {
let admin: LoginResponseDto;
let deletedUser: LoginResponseDto;
let userToDelete: LoginResponseDto;
let userToHardDelete: LoginResponseDto;
let nonAdmin: LoginResponseDto;
beforeAll(async () => {
await utils.resetDatabase();
admin = await utils.adminSetup({ onboarding: false });
[deletedUser, nonAdmin] = await Promise.all([
[websocket, deletedUser, nonAdmin, userToDelete, userToHardDelete] = await Promise.all([
utils.connectWebsocket(admin.accessToken),
utils.userSetup(admin.accessToken, createUserDto.user1),
utils.userSetup(admin.accessToken, createUserDto.user2),
utils.userSetup(admin.accessToken, createUserDto.user3),
utils.userSetup(admin.accessToken, createUserDto.user4),
]);
await deleteUserAdmin(
{ id: deletedUser.userId, userAdminDeleteDto: {} },
{ headers: asBearerAuth(admin.accessToken) },
);
await deleteUser({ id: deletedUser.userId, deleteUserDto: {} }, { headers: asBearerAuth(admin.accessToken) });
});
describe('GET /users', () => {
afterAll(() => {
utils.disconnectWebsocket(websocket);
});
describe('GET /user', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/users');
const { status, body } = await request(app).get('/user');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should get users', async () => {
const { status, body } = await request(app).get('/users').set('Authorization', `Bearer ${admin.accessToken}`);
const { status, body } = await request(app).get('/user').set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(200);
expect(body).toHaveLength(2);
expect(body).toHaveLength(5);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: 'admin@immich.cloud' }),
expect.objectContaining({ email: 'user1@immich.cloud' }),
expect.objectContaining({ email: 'user2@immich.cloud' }),
expect.objectContaining({ email: 'user3@immich.cloud' }),
expect.objectContaining({ email: 'user4@immich.cloud' }),
]),
);
});
it('should hide deleted users', async () => {
const { status, body } = await request(app)
.get(`/user`)
.query({ isAll: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(4);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: 'admin@immich.cloud' }),
expect.objectContaining({ email: 'user2@immich.cloud' }),
expect.objectContaining({ email: 'user3@immich.cloud' }),
expect.objectContaining({ email: 'user4@immich.cloud' }),
]),
);
});
it('should include deleted users', async () => {
const { status, body } = await request(app)
.get(`/user`)
.query({ isAll: false })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(5);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ email: 'admin@immich.cloud' }),
expect.objectContaining({ email: 'user1@immich.cloud' }),
expect.objectContaining({ email: 'user2@immich.cloud' }),
expect.objectContaining({ email: 'user3@immich.cloud' }),
expect.objectContaining({ email: 'user4@immich.cloud' }),
]),
);
});
});
describe('GET /users/me', () => {
describe('GET /user/info/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/users/me`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
const { status } = await request(app).get(`/user/info/${admin.userId}`);
expect(status).toEqual(401);
});
it('should not work for shared links', async () => {
const album = await utils.createAlbum(admin.accessToken, { albumName: 'Album' });
const sharedLink = await utils.createSharedLink(admin.accessToken, {
type: SharedLinkType.Album,
albumId: album.id,
});
const { status, body } = await request(app).get(`/users/me?key=${sharedLink.key}`);
expect(status).toBe(403);
expect(body).toEqual(errorDto.forbidden);
});
it('should get my user', async () => {
const { status, body } = await request(app).get(`/users/me`).set('Authorization', `Bearer ${admin.accessToken}`);
it('should get the user info', async () => {
const { status, body } = await request(app)
.get(`/user/info/${admin.userId}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: admin.userId,
email: 'admin@immich.cloud',
memoriesEnabled: true,
quotaUsageInBytes: 0,
});
});
});
describe('PUT /users/me', () => {
describe('GET /user/me', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/users/me`);
const { status, body } = await request(app).get(`/user/me`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
for (const key of ['email', 'name', 'memoriesEnabled', 'avatarColor']) {
it('should get my info', async () => {
const { status, body } = await request(app).get(`/user/me`).set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: admin.userId,
email: 'admin@immich.cloud',
});
});
});
describe('POST /user', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/user`).send(createUserDto.user1);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
for (const key of Object.keys(createUserDto.user1)) {
it(`should not allow null ${key}`, async () => {
const dto = { [key]: null };
const { status, body } = await request(app)
.put(`/users/me`)
.post(`/user`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send(dto);
.send({ ...createUserDto.user1, [key]: null });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
}
it('should update first and last name', async () => {
const before = await getMyUser({ headers: asBearerAuth(admin.accessToken) });
it('should ignore `isAdmin`', async () => {
const { status, body } = await request(app)
.post(`/user`)
.send({
isAdmin: true,
email: 'user5@immich.cloud',
password: 'password123',
name: 'Immich',
})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toMatchObject({
email: 'user5@immich.cloud',
isAdmin: false,
shouldChangePassword: true,
});
expect(status).toBe(201);
});
it('should create a user without memories enabled', async () => {
const { status, body } = await request(app)
.post(`/user`)
.send({
email: 'no-memories@immich.cloud',
password: 'Password123',
name: 'No Memories',
memoriesEnabled: false,
})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(body).toMatchObject({
email: 'no-memories@immich.cloud',
memoriesEnabled: false,
});
expect(status).toBe(201);
});
});
describe('DELETE /user/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete(`/user/${userToDelete.userId}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should delete user', async () => {
const { status, body } = await request(app)
.delete(`/user/${userToDelete.userId}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: userToDelete.userId,
updatedAt: expect.any(String),
deletedAt: expect.any(String),
});
});
it('should hard delete user', async () => {
const { status, body } = await request(app)
.delete(`/user/${userToHardDelete.userId}`)
.send({ force: true })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: userToHardDelete.userId,
updatedAt: expect.any(String),
deletedAt: expect.any(String),
});
await utils.waitForWebsocketEvent({ event: 'userDelete', id: userToHardDelete.userId, timeout: 5000 });
});
});
describe('PUT /user', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/user`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
for (const key of Object.keys(userDto.admin)) {
it(`should not allow null ${key}`, async () => {
const { status, body } = await request(app)
.put(`/user`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ ...userDto.admin, [key]: null });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest());
});
}
it('should not allow a non-admin to become an admin', async () => {
const { status, body } = await request(app)
.put(`/user`)
.send({ isAdmin: true, id: nonAdmin.userId })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.alreadyHasAdmin);
});
it('ignores updates to profileImagePath', async () => {
const { status, body } = await request(app)
.put(`/user`)
.send({ id: admin.userId, profileImagePath: 'invalid.jpg' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({ id: admin.userId, profileImagePath: '' });
});
it('should ignore updates to createdAt, updatedAt and deletedAt', async () => {
const before = await getUserById({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
const { status, body } = await request(app)
.put(`/users/me`)
.send({ name: 'Name' })
.put(`/user`)
.send({
id: admin.userId,
createdAt: '2023-01-01T00:00:00.000Z',
updatedAt: '2023-01-01T00:00:00.000Z',
deletedAt: '2023-01-01T00:00:00.000Z',
})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toStrictEqual(before);
});
it('should update first and last name', async () => {
const before = await getUserById({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
const { status, body } = await request(app)
.put(`/user`)
.send({
id: admin.userId,
name: 'Name',
})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
@@ -108,13 +291,17 @@ describe('/users', () => {
updatedAt: expect.any(String),
name: 'Name',
});
expect(before.updatedAt).not.toEqual(body.updatedAt);
});
it('should update memories enabled', async () => {
const before = await getMyUser({ headers: asBearerAuth(admin.accessToken) });
const before = await getUserById({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) });
const { status, body } = await request(app)
.put(`/users/me`)
.send({ memoriesEnabled: false })
.put(`/user`)
.send({
id: admin.userId,
memoriesEnabled: false,
})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
@@ -123,80 +310,7 @@ describe('/users', () => {
updatedAt: expect.anything(),
memoriesEnabled: false,
});
const after = await getMyUser({ headers: asBearerAuth(admin.accessToken) });
expect(after.memoriesEnabled).toBe(false);
});
/** @deprecated */
it('should allow a user to change their password (deprecated)', async () => {
const user = await getMyUser({ headers: asBearerAuth(nonAdmin.accessToken) });
expect(user.shouldChangePassword).toBe(true);
const { status, body } = await request(app)
.put(`/users/me`)
.send({ password: 'super-secret' })
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
email: nonAdmin.userEmail,
shouldChangePassword: false,
});
const token = await login({ loginCredentialDto: { email: nonAdmin.userEmail, password: 'super-secret' } });
expect(token.accessToken).toBeDefined();
});
it('should not allow user to change to a taken email', async () => {
const { status, body } = await request(app)
.put(`/users/me`)
.send({ email: 'admin@immich.cloud' })
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(400);
expect(body).toMatchObject(errorDto.badRequest('Email already in use by another account'));
});
it('should update my email', async () => {
const before = await getMyUser({ headers: asBearerAuth(nonAdmin.accessToken) });
const { status, body } = await request(app)
.put(`/users/me`)
.send({ email: 'non-admin@immich.cloud' })
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
...before,
email: 'non-admin@immich.cloud',
updatedAt: expect.anything(),
});
});
});
describe('GET /users/:id', () => {
it('should require authentication', async () => {
const { status } = await request(app).get(`/users/${admin.userId}`);
expect(status).toEqual(401);
});
it('should get the user', async () => {
const { status, body } = await request(app)
.get(`/users/${admin.userId}`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toMatchObject({
id: admin.userId,
email: 'admin@immich.cloud',
});
expect(body).not.toMatchObject({
shouldChangePassword: expect.anything(),
memoriesEnabled: expect.anything(),
storageLabel: expect.anything(),
});
expect(before.updatedAt).not.toEqual(body.updatedAt);
});
});
});

View File

@@ -1,4 +1,4 @@
import { LoginResponseDto, getAllAlbums, getAssetStatistics } from '@immich/sdk';
import { LoginResponseDto, getAllAlbums, getAllAssets } from '@immich/sdk';
import { readFileSync } from 'node:fs';
import { mkdir, readdir, rm, symlink } from 'node:fs/promises';
import { asKeyAuth, immichCli, testAssetDir, utils } from 'src/utils';
@@ -28,8 +28,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(1);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(1);
});
it('should skip a duplicate file', async () => {
@@ -40,8 +40,8 @@ describe(`immich upload`, () => {
);
expect(first.exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(1);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(1);
const second = await immichCli(['upload', `${testAssetDir}/albums/nature/silver_fir.jpg`]);
expect(second.stderr).toBe('');
@@ -60,8 +60,8 @@ describe(`immich upload`, () => {
expect(stdout.split('\n')).toEqual(expect.arrayContaining([expect.stringContaining('No files found, exiting')]));
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(0);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(0);
});
it('should have accurate dry run', async () => {
@@ -76,8 +76,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(0);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(0);
});
it('dry run should handle duplicates', async () => {
@@ -88,8 +88,8 @@ describe(`immich upload`, () => {
);
expect(first.exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(1);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(1);
const second = await immichCli(['upload', `${testAssetDir}/albums/nature/`, '--dry-run']);
expect(second.stderr).toBe('');
@@ -112,8 +112,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(9);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(9);
});
});
@@ -135,8 +135,8 @@ describe(`immich upload`, () => {
expect(stderr).toBe('');
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(9);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(9);
const albums = await getAllAlbums({}, { headers: asKeyAuth(key) });
expect(albums.length).toBe(1);
@@ -151,8 +151,8 @@ describe(`immich upload`, () => {
expect(response1.stderr).toBe('');
expect(response1.exitCode).toBe(0);
const assets1 = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets1.total).toBe(9);
const assets1 = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets1.length).toBe(9);
const albums1 = await getAllAlbums({}, { headers: asKeyAuth(key) });
expect(albums1.length).toBe(0);
@@ -167,8 +167,8 @@ describe(`immich upload`, () => {
expect(response2.stderr).toBe('');
expect(response2.exitCode).toBe(0);
const assets2 = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets2.total).toBe(9);
const assets2 = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets2.length).toBe(9);
const albums2 = await getAllAlbums({}, { headers: asKeyAuth(key) });
expect(albums2.length).toBe(1);
@@ -193,8 +193,8 @@ describe(`immich upload`, () => {
expect(stderr).toBe('');
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(0);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(0);
const albums = await getAllAlbums({}, { headers: asKeyAuth(key) });
expect(albums.length).toBe(0);
@@ -219,8 +219,8 @@ describe(`immich upload`, () => {
expect(stderr).toBe('');
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(9);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(9);
const albums = await getAllAlbums({}, { headers: asKeyAuth(key) });
expect(albums.length).toBe(1);
@@ -245,8 +245,8 @@ describe(`immich upload`, () => {
expect(stderr).toBe('');
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(0);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(0);
const albums = await getAllAlbums({}, { headers: asKeyAuth(key) });
expect(albums.length).toBe(0);
@@ -276,8 +276,8 @@ describe(`immich upload`, () => {
expect(stderr).toBe('');
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(9);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(9);
});
it('should have accurate dry run', async () => {
@@ -302,8 +302,8 @@ describe(`immich upload`, () => {
expect(stderr).toBe('');
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(0);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(0);
});
});
@@ -328,8 +328,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(1);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(1);
});
it('should throw an error if attempting dry run', async () => {
@@ -344,8 +344,8 @@ describe(`immich upload`, () => {
expect(stderr).toEqual(`error: option '-n, --dry-run' cannot be used with option '-h, --skip-hash'`);
expect(exitCode).not.toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(0);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(0);
});
});
@@ -367,8 +367,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(9);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(9);
});
it('should reject string argument', async () => {
@@ -408,8 +408,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(8);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(8);
});
it('should ignore assets matching glob pattern', async () => {
@@ -429,8 +429,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(1);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(1);
});
it('should have accurate dry run', async () => {
@@ -451,8 +451,8 @@ describe(`immich upload`, () => {
);
expect(exitCode).toBe(0);
const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) });
expect(assets.total).toBe(0);
const assets = await getAllAssets({}, { headers: asKeyAuth(key) });
expect(assets.length).toBe(0);
});
});
});

View File

@@ -5,19 +5,19 @@ import {
CreateAlbumDto,
CreateAssetDto,
CreateLibraryDto,
CreateUserDto,
MetadataSearchDto,
PersonCreateDto,
SharedLinkCreateDto,
UserAdminCreateDto,
ValidateLibraryDto,
createAlbum,
createApiKey,
createLibrary,
createPartner,
createPerson,
createSharedLink,
createUserAdmin,
createUser,
deleteAssets,
getAllAssets,
getAllJobsStatus,
getAssetInfo,
getConfigDefaults,
@@ -273,8 +273,8 @@ export const utils = {
return response;
},
userSetup: async (accessToken: string, dto: UserAdminCreateDto) => {
await createUserAdmin({ userAdminCreateDto: dto }, { headers: asBearerAuth(accessToken) });
userSetup: async (accessToken: string, dto: CreateUserDto) => {
await createUser({ createUserDto: dto }, { headers: asBearerAuth(accessToken) });
return login({
loginCredentialDto: { email: dto.email, password: dto.password },
});
@@ -340,6 +340,8 @@ export const utils = {
getAssetInfo: (accessToken: string, id: string) => getAssetInfo({ id }, { headers: asBearerAuth(accessToken) }),
getAllAssets: (accessToken: string) => getAllAssets({}, { headers: asBearerAuth(accessToken) }),
metadataSearch: async (accessToken: string, dto: MetadataSearchDto) => {
return searchMetadata({ metadataSearchDto: dto }, { headers: asBearerAuth(accessToken) });
},
@@ -386,8 +388,6 @@ export const utils = {
validateLibrary: (accessToken: string, id: string, dto: ValidateLibraryDto) =>
validate({ id, validateLibraryDto: dto }, { headers: asBearerAuth(accessToken) }),
createPartner: (accessToken: string, id: string) => createPartner({ id }, { headers: asBearerAuth(accessToken) }),
setAuthCookies: async (context: BrowserContext, accessToken: string) =>
await context.addCookies([
{

View File

@@ -1,60 +0,0 @@
import { AssetFileUploadResponseDto, LoginResponseDto, SharedLinkType } from '@immich/sdk';
import { expect, test } from '@playwright/test';
import { utils } from 'src/utils';
test.describe('Detail Panel', () => {
let admin: LoginResponseDto;
let asset: AssetFileUploadResponseDto;
test.beforeAll(async () => {
utils.initSdk();
await utils.resetDatabase();
admin = await utils.adminSetup();
asset = await utils.createAsset(admin.accessToken);
});
test('can be opened for shared links', async ({ page }) => {
const sharedLink = await utils.createSharedLink(admin.accessToken, {
type: SharedLinkType.Individual,
assetIds: [asset.id],
});
await page.goto(`/share/${sharedLink.key}/photos/${asset.id}`);
await page.waitForSelector('#immich-asset-viewer');
await expect(page.getByRole('button', { name: 'Info' })).toBeVisible();
await page.keyboard.press('i');
await expect(page.locator('#detail-panel')).toBeVisible();
await page.keyboard.press('i');
await expect(page.locator('#detail-panel')).toHaveCount(0);
});
test('cannot be opened for shared links with hidden metadata', async ({ page }) => {
const sharedLink = await utils.createSharedLink(admin.accessToken, {
type: SharedLinkType.Individual,
assetIds: [asset.id],
showMetadata: false,
});
await page.goto(`/share/${sharedLink.key}/photos/${asset.id}`);
await page.waitForSelector('#immich-asset-viewer');
await expect(page.getByRole('button', { name: 'Info' })).toHaveCount(0);
await page.keyboard.press('i');
await expect(page.locator('#detail-panel')).toHaveCount(0);
await page.keyboard.press('i');
await expect(page.locator('#detail-panel')).toHaveCount(0);
});
test('description is visible for owner on shared links', async ({ context, page }) => {
const sharedLink = await utils.createSharedLink(admin.accessToken, {
type: SharedLinkType.Individual,
assetIds: [asset.id],
});
await utils.setAuthCookies(context, admin.accessToken);
await page.goto(`/share/${sharedLink.key}/photos/${asset.id}`);
const textarea = page.getByRole('textbox', { name: 'Add a description' });
await page.getByRole('button', { name: 'Info' }).click();
await expect(textarea).toBeVisible();
await expect(textarea).not.toBeDisabled();
});
});

View File

@@ -1,52 +0,0 @@
import { AssetFileUploadResponseDto, LoginResponseDto, SharedLinkType } from '@immich/sdk';
import { expect, test } from '@playwright/test';
import { utils } from 'src/utils';
test.describe('Asset Viewer Navbar', () => {
let admin: LoginResponseDto;
let asset: AssetFileUploadResponseDto;
test.beforeAll(async () => {
utils.initSdk();
await utils.resetDatabase();
admin = await utils.adminSetup();
asset = await utils.createAsset(admin.accessToken);
});
test.describe('shared link without metadata', () => {
test('visible guest actions', async ({ page }) => {
const sharedLink = await utils.createSharedLink(admin.accessToken, {
type: SharedLinkType.Individual,
assetIds: [asset.id],
showMetadata: false,
});
await page.goto(`/share/${sharedLink.key}/photos/${asset.id}`);
await page.waitForSelector('#immich-asset-viewer');
const expected = ['Zoom Image', 'Copy Image', 'Download'];
const buttons = await page.getByTestId('asset-viewer-navbar-actions').getByRole('button').all();
for (const [i, button] of buttons.entries()) {
await expect(button).toHaveAccessibleName(expected[i]);
}
});
test('visible owner actions', async ({ context, page }) => {
const sharedLink = await utils.createSharedLink(admin.accessToken, {
type: SharedLinkType.Individual,
assetIds: [asset.id],
showMetadata: false,
});
await utils.setAuthCookies(context, admin.accessToken);
await page.goto(`/share/${sharedLink.key}/photos/${asset.id}`);
await page.waitForSelector('#immich-asset-viewer');
const expected = ['Share', 'Zoom Image', 'Copy Image', 'Download'];
const buttons = await page.getByTestId('asset-viewer-navbar-actions').getByRole('button').all();
for (const [i, button] of buttons.entries()) {
await expect(button).toHaveAccessibleName(expected[i]);
}
});
});
});

View File

@@ -95,5 +95,3 @@ COPY start.sh log_conf.json ./
COPY app .
ENTRYPOINT ["tini", "--"]
CMD ["./start.sh"]
HEALTHCHECK CMD python3 healthcheck.py

View File

@@ -1,14 +0,0 @@
import os
import sys
import requests
port = os.getenv("IMMICH_PORT", 3003)
try:
response = requests.get(f"http://localhost:{port}/ping", timeout=2)
if response.status_code == 200:
sys.exit(0)
sys.exit(1)
except requests.RequestException:
sys.exit(1)

View File

@@ -62,8 +62,6 @@ fi
if [ "$CURRENT_SERVER" != "$NEXT_SERVER" ]; then
echo "Pumping Server: $CURRENT_SERVER => $NEXT_SERVER"
npm --prefix server version "$SERVER_PUMP"
npm --prefix server ci
npm --prefix server run build
make open-api
npm --prefix open-api/typescript-sdk version "$SERVER_PUMP"
npm --prefix web version "$SERVER_PUMP"

View File

@@ -10,7 +10,7 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.932.0)
aws-partitions (1.931.0)
aws-sdk-core (3.196.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)

Binary file not shown.

View File

@@ -10,7 +10,7 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.932.0)
aws-partitions (1.931.0)
aws-sdk-core (3.196.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)

View File

@@ -145,10 +145,9 @@ class Album {
.remoteIdEqualTo(dto.albumThumbnailAssetId)
.findFirst();
}
if (dto.albumUsers.isNotEmpty) {
final users = await db.users.getAllById(
dto.albumUsers.map((e) => e.user.id).toList(growable: false),
);
if (dto.sharedUsers.isNotEmpty) {
final users = await db.users
.getAllById(dto.sharedUsers.map((e) => e.id).toList(growable: false));
a.sharedUsers.addAll(users.cast());
}
if (dto.assets.isNotEmpty) {

View File

@@ -27,7 +27,7 @@ class User {
Id get isarId => fastHash(id);
User.fromUserDto(UserAdminResponseDto dto)
User.fromUserDto(UserResponseDto dto)
: id = dto.id,
updatedAt = dto.updatedAt,
email = dto.email,
@@ -44,21 +44,21 @@ class User {
User.fromPartnerDto(PartnerResponseDto dto)
: id = dto.id,
updatedAt = DateTime.now(),
updatedAt = dto.updatedAt,
email = dto.email,
name = dto.name,
isPartnerSharedBy = false,
isPartnerSharedWith = false,
profileImagePath = dto.profileImagePath,
isAdmin = false,
memoryEnabled = false,
isAdmin = dto.isAdmin,
memoryEnabled = dto.memoriesEnabled ?? false,
avatarColor = dto.avatarColor.toAvatarColor(),
inTimeline = dto.inTimeline ?? false,
quotaUsageInBytes = 0,
quotaSizeInBytes = 0;
quotaUsageInBytes = dto.quotaUsageInBytes ?? 0,
quotaSizeInBytes = dto.quotaSizeInBytes ?? 0;
/// Base user dto used where the complete user object is not required
User.fromSimpleUserDto(UserResponseDto dto)
User.fromSimpleUserDto(UserDto dto)
: id = dto.id,
email = dto.email,
name = dto.name,

View File

@@ -32,7 +32,7 @@ class ServerDiskInfo {
return 'ServerDiskInfo(diskAvailable: $diskAvailable, diskSize: $diskSize, diskUse: $diskUse, diskUsagePercentage: $diskUsagePercentage)';
}
ServerDiskInfo.fromDto(ServerStorageResponseDto dto)
ServerDiskInfo.fromDto(ServerInfoResponseDto dto)
: diskAvailable = dto.diskAvailable,
diskSize = dto.diskSize,
diskUse = dto.diskUse,

View File

@@ -133,7 +133,7 @@ class AlbumViewerPage extends HookConsumerWidget {
Widget buildTitle(Album album) {
return Padding(
padding: const EdgeInsets.only(left: 8, right: 8),
padding: const EdgeInsets.only(left: 8, right: 8, top: 24),
child: userId == album.ownerId && album.isRemote
? AlbumViewerEditableTitle(
album: album,
@@ -228,30 +228,9 @@ class AlbumViewerPage extends HookConsumerWidget {
}
return Scaffold(
body: Stack(
children: [
album.widgetWhen(
onData: (data) => MultiselectGrid(
renderListProvider: albumRenderlistProvider(albumId),
topWidget: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildHeader(data),
if (data.isRemote) buildControlButton(data),
],
),
onRemoveFromAlbum: onRemoveFromAlbumPressed,
editEnabled: data.ownerId == userId,
),
),
AnimatedPositioned(
duration: const Duration(milliseconds: 300),
top: ref.watch(multiselectProvider)
? -(kToolbarHeight + MediaQuery.of(context).padding.top)
: 0,
left: 0,
right: 0,
child: album.when(
appBar: ref.watch(multiselectProvider)
? null
: album.when(
data: (data) => AlbumViewerAppbar(
titleFocusNode: titleFocusNode,
album: data,
@@ -263,8 +242,19 @@ class AlbumViewerPage extends HookConsumerWidget {
error: (error, stackTrace) => AppBar(title: const Text("Error")),
loading: () => AppBar(),
),
body: album.widgetWhen(
onData: (data) => MultiselectGrid(
renderListProvider: albumRenderlistProvider(albumId),
topWidget: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildHeader(data),
if (data.isRemote) buildControlButton(data),
],
),
],
onRemoveFromAlbum: onRemoveFromAlbumPressed,
editEnabled: data.ownerId == userId,
),
),
);
}

View File

@@ -138,9 +138,11 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
Future<bool> changePassword(String newPassword) async {
try {
await _apiService.userApi.updateMyUser(
UserUpdateMeDto(
await _apiService.userApi.updateUser(
UpdateUserDto(
id: state.userId,
password: newPassword,
shouldChangePassword: false,
),
);
@@ -176,9 +178,9 @@ class AuthenticationNotifier extends StateNotifier<AuthenticationState> {
user = offlineUser;
retResult = false;
} else {
UserAdminResponseDto? userResponseDto;
UserResponseDto? userResponseDto;
try {
userResponseDto = await _apiService.userApi.getMyUser();
userResponseDto = await _apiService.userApi.getMyUserInfo();
} on ApiException catch (error, stackTrace) {
_log.severe(
"Error getting user information from the server [API EXCEPTION]",

View File

@@ -374,7 +374,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
if (state.backupProgress != BackUpProgressEnum.inBackground) {
await _getBackupAlbumsInfo();
await updateDiskInfo();
await updateServerInfo();
await _updateBackupAssetCount();
} else {
log.warning("cannot get backup info - background backup is in progress!");
@@ -542,7 +542,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
_updatePersistentAlbumsSelection();
}
updateDiskInfo();
updateServerInfo();
}
void _onUploadProgress(int sent, int total) {
@@ -579,13 +579,13 @@ class BackupNotifier extends StateNotifier<BackUpState> {
);
}
Future<void> updateDiskInfo() async {
final diskInfo = await _serverInfoService.getDiskInfo();
Future<void> updateServerInfo() async {
final serverInfo = await _serverInfoService.getServerInfo();
// Update server info
if (diskInfo != null) {
if (serverInfo != null) {
state = state.copyWith(
serverInfo: diskInfo,
serverInfo: serverInfo,
);
}
}

View File

@@ -121,7 +121,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
bool isDuplicated,
) {
state = state.copyWith(successfulUploads: state.successfulUploads + 1);
_backupProvider.updateDiskInfo();
_backupProvider.updateServerInfo();
}
void _onAssetUploadError(ErrorUploadAsset errorAssetInfo) {

View File

@@ -20,7 +20,7 @@ class CurrentUserProvider extends StateNotifier<User?> {
refresh() async {
try {
final user = await _apiService.userApi.getMyUser();
final user = await _apiService.userApi.getMyUserInfo();
if (user != null) {
Store.put(
StoreKey.currentUser,

View File

@@ -57,7 +57,7 @@ class TabNavigationObserver extends AutoRouterObserver {
// Update user info
try {
final userResponseDto =
await ref.read(apiServiceProvider).userApi.getMyUser();
await ref.read(apiServiceProvider).userApi.getMyUserInfo();
if (userResponseDto == null) {
return;

View File

@@ -180,14 +180,7 @@ class AlbumService {
CreateAlbumDto(
albumName: albumName,
assetIds: assets.map((asset) => asset.remoteId!).toList(),
albumUsers: sharedUsers
.map(
(e) => AlbumUserCreateDto(
userId: e.id,
role: AlbumUserRole.editor,
),
)
.toList(),
sharedWithUserIds: sharedUsers.map((e) => e.id).toList(),
),
);
if (remote != null) {

View File

@@ -20,7 +20,6 @@ import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/utils/backup_progress.dart';
import 'package:immich_mobile/utils/diff.dart';
import 'package:immich_mobile/utils/http_ssl_cert_override.dart';
import 'package:isar/isar.dart';
import 'package:path_provider_ios/path_provider_ios.dart';
import 'package:photo_manager/photo_manager.dart';
@@ -591,7 +590,6 @@ enum IosBackgroundTask { fetch, processing }
/// entry point called by Kotlin/Java code; needs to be a top-level function
@pragma('vm:entry-point')
void _nativeEntry() {
HttpOverrides.global = HttpSSLCertOverride();
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
BackgroundService backgroundService = BackgroundService();

View File

@@ -1,7 +1,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:background_downloader/background_downloader.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -21,7 +21,6 @@ import 'package:openapi/api.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:cancellation_token_http/http.dart' as http;
import 'package:path/path.dart' as p;
final backupServiceProvider = Provider(
(ref) => BackupService(
@@ -33,6 +32,7 @@ final backupServiceProvider = Provider(
class BackupService {
final httpClient = http.Client();
final _fileDownloader = FileDownloader();
final ApiService _apiService;
final Isar _db;
final Logger _log = Logger("BackupService");
@@ -242,121 +242,127 @@ class BackupService {
)
: assetList.toList();
final tasks = <UploadTask>[];
for (var entity in assetsToUpload) {
File? file;
File? livePhotoFile;
final isAvailableLocally =
await entity.isLocallyAvailable(isOrigin: true);
try {
final isAvailableLocally =
await entity.isLocallyAvailable(isOrigin: true);
// Handle getting files from iCloud
if (!isAvailableLocally && Platform.isIOS) {
// Skip iCloud assets if the user has disabled this feature
if (isIgnoreIcloudAssets) {
continue;
}
setCurrentUploadAssetCb(
CurrentUploadAsset(
id: entity.id,
fileCreatedAt: entity.createDateTime.year == 1970
? entity.modifiedDateTime
: entity.createDateTime,
fileName: await entity.titleAsync,
fileType: _getAssetType(entity.type),
iCloudAsset: true,
),
);
file = await entity.loadFile(progressHandler: pmProgressHandler);
livePhotoFile = await entity.loadFile(
withSubtype: true,
progressHandler: pmProgressHandler,
);
} else {
if (entity.type == AssetType.video) {
file = await entity.originFile;
} else {
file = await entity.originFile.timeout(const Duration(seconds: 5));
if (entity.isLivePhoto) {
livePhotoFile = await entity.originFileWithSubtype
.timeout(const Duration(seconds: 5));
}
}
// Handle getting files from iCloud
if (!isAvailableLocally && Platform.isIOS) {
// Skip iCloud assets if the user has disabled this feature
if (isIgnoreIcloudAssets) {
continue;
}
if (file != null) {
String originalFileName = await entity.titleAsync;
var fileStream = file.openRead();
var assetRawUploadData = http.MultipartFile(
"assetData",
fileStream,
file.lengthSync(),
filename: originalFileName,
);
setCurrentUploadAssetCb(
CurrentUploadAsset(
id: entity.id,
fileCreatedAt: entity.createDateTime.year == 1970
? entity.modifiedDateTime
: entity.createDateTime,
fileName: await entity.titleAsync,
fileType: _getAssetType(entity.type),
iCloudAsset: true,
),
);
}
var req = MultipartRequest(
'POST',
Uri.parse('$savedEndpoint/asset/upload'),
onProgress: ((bytes, totalBytes) =>
uploadProgressCb(bytes, totalBytes)),
);
req.headers["x-immich-user-token"] = Store.get(StoreKey.accessToken);
req.headers["Transfer-Encoding"] = "chunked";
final files = [];
// TODO: This is silly to have to load the file just to access the path
// But there doesn't seem to be any other way to do it
final fileName = (await entity.originFile)?.path;
files.add(fileName);
req.fields['deviceAssetId'] = entity.id;
req.fields['deviceId'] = deviceId;
req.fields['fileCreatedAt'] =
entity.createDateTime.toUtc().toIso8601String();
req.fields['fileModifiedAt'] =
entity.modifiedDateTime.toUtc().toIso8601String();
req.fields['isFavorite'] = entity.isFavorite.toString();
req.fields['duration'] = entity.videoDuration.toString();
if (entity.isLivePhoto) {
final livePhotoFileName = (await entity.originFileWithSubtype)?.path;
if (livePhotoFileName != null) {
files.add(livePhotoFileName);
}
}
req.files.add(assetRawUploadData);
final url = '$savedEndpoint/asset/upload';
final headers = {
'x-immich-user-token': Store.get(StoreKey.accessToken),
'Transfer-Encoding': 'chunked',
};
var fileSize = file.lengthSync();
final fields = {
'deviceAssetId': entity.id,
'deviceId': deviceId,
'fileCreatedAt': entity.createDateTime.toUtc().toIso8601String(),
'fileModifiedAt': entity.modifiedDateTime.toUtc().toIso8601String(),
'isFavorite': entity.isFavorite.toString(),
'duration': entity.videoDuration.toString(),
};
if (entity.isLivePhoto) {
if (livePhotoFile != null) {
final livePhotoTitle = p.setExtension(
originalFileName,
p.extension(livePhotoFile.path),
);
final fileStream = livePhotoFile.openRead();
final livePhotoRawUploadData = http.MultipartFile(
"livePhotoData",
fileStream,
livePhotoFile.lengthSync(),
filename: livePhotoTitle,
);
req.files.add(livePhotoRawUploadData);
fileSize += livePhotoFile.lengthSync();
} else {
_log.warning(
"Failed to obtain motion part of the livePhoto - $originalFileName",
);
}
}
for (final file in files) {
final split = file.split('/');
final name = split.last;
final directory = split.take(split.length - 1).join('/');
setCurrentUploadAssetCb(
CurrentUploadAsset(
id: entity.id,
fileCreatedAt: entity.createDateTime.year == 1970
? entity.modifiedDateTime
: entity.createDateTime,
fileName: originalFileName,
fileType: _getAssetType(entity.type),
fileSize: fileSize,
iCloudAsset: false,
),
);
final task = UploadTask(
url: url,
group: 'backup',
fileField: 'assetData',
taskId: entity.id,
fields: fields,
headers: headers,
updates: Updates.statusAndProgress,
retries: 0,
httpRequestMethod: 'POST',
displayName: 'Immich',
filename: name,
directory: directory,
baseDirectory: BaseDirectory.root,
);
tasks.add(task);
}
}
var response =
await httpClient.send(req, cancellationToken: cancelToken);
final permission = await _fileDownloader.permissions
.status(PermissionType.androidSharedStorage);
print('has permission $permission');
if (response.statusCode == 200) {
if (tasks.length == 1) {
final result = await _fileDownloader.upload(
tasks.first,
onProgress: (percent) => print('${percent * 100} done'),
onStatus: (status) => print('status $status'),
onElapsedTime: (t) => print('time is $t'),
elapsedTimeInterval: const Duration(seconds: 1),
);
print('$result is done with ${result.status}');
print('result ${result.responseBody}');
print('result ${result.responseHeaders}');
} else {
final result = await _fileDownloader.uploadBatch(
tasks,
batchProgressCallback: (succeeded, failed) =>
print('$succeeded succeeded, $failed failed'),
taskStatusCallback: (status) => print('status $status'),
taskProgressCallback: (update) => print('update $update'),
onElapsedTime: (t) => print('time is $t'),
elapsedTimeInterval: const Duration(seconds: 1),
);
print(
'$result is done with ${result.succeeded.length} succeeded and ${result.failed.length} failed',
);
for (final task in result.succeeded) {
final r = result.results[task];
print('successful task $task with result $r');
}
for (final task in result.failed) {
final r = result.results[task];
print('failed task $task with result $r');
}
}
/*
if (result.status == 200) {
// asset is a duplicate (already exists on the server)
duplicatedAssetIds.add(entity.id);
uploadSuccessCb(entity.id, deviceId, true);
@@ -409,6 +415,7 @@ class BackupService {
}
}
}
*/
if (duplicatedAssetIds.isNotEmpty) {
await _saveDuplicatedAssetIds(duplicatedAssetIds);
}

View File

@@ -8,8 +8,6 @@ import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
import '../utils/string_helper.dart';
final memoryServiceProvider = StateProvider<MemoryService>((ref) {
return MemoryService(
ref.watch(apiServiceProvider),
@@ -38,13 +36,13 @@ class MemoryService {
}
List<Memory> memories = [];
for (final MemoryLaneResponseDto(:yearsAgo, :assets) in data) {
for (final MemoryLaneResponseDto(:title, :assets) in data) {
final dbAssets =
await _db.assets.getAllByRemoteId(assets.map((e) => e.id));
if (dbAssets.isNotEmpty) {
memories.add(
Memory(
title: '$yearsAgo year${s(yearsAgo)} ago',
title: title,
assets: dbAssets,
),
);

View File

@@ -18,14 +18,14 @@ class ServerInfoService {
ServerInfoService(this._apiService);
Future<ServerDiskInfo?> getDiskInfo() async {
Future<ServerDiskInfo?> getServerInfo() async {
try {
final dto = await _apiService.serverInfoApi.getStorage();
final dto = await _apiService.serverInfoApi.getServerInfo();
if (dto != null) {
return ServerDiskInfo.fromDto(dto);
}
} catch (e) {
debugPrint("Error [getDiskInfo] ${e.toString()}");
debugPrint("Error [getServerInfo] ${e.toString()}");
}
return null;
}

View File

@@ -362,15 +362,15 @@ class SyncService {
// update shared users
final List<User> sharedUsers = album.sharedUsers.toList(growable: false);
sharedUsers.sort((a, b) => a.id.compareTo(b.id));
dto.albumUsers.sort((a, b) => a.user.id.compareTo(b.user.id));
dto.sharedUsers.sort((a, b) => a.id.compareTo(b.id));
final List<String> userIdsToAdd = [];
final List<User> usersToUnlink = [];
diffSortedListsSync(
dto.albumUsers,
dto.sharedUsers,
sharedUsers,
compare: (AlbumUserResponseDto a, User b) => a.user.id.compareTo(b.id),
compare: (UserResponseDto a, User b) => a.id.compareTo(b.id),
both: (a, b) => false,
onlyFirst: (AlbumUserResponseDto a) => userIdsToAdd.add(a.user.id),
onlyFirst: (UserResponseDto a) => userIdsToAdd.add(a.id),
onlySecond: (User a) => usersToUnlink.add(a),
);
@@ -905,7 +905,7 @@ bool _hasAlbumResponseDtoChanged(AlbumResponseDto dto, Album a) {
dto.albumName != a.name ||
dto.albumThumbnailAssetId != a.thumbnail.value?.remoteId ||
dto.shared != a.shared ||
dto.albumUsers.length != a.sharedUsers.length ||
dto.sharedUsers.length != a.sharedUsers.length ||
!dto.updatedAt.isAtSameMomentAs(a.modifiedAt) ||
!isAtSameMomentAs(dto.startDate, a.startDate) ||
!isAtSameMomentAs(dto.endDate, a.endDate) ||

View File

@@ -37,10 +37,10 @@ class UserService {
this._partnerService,
);
Future<List<User>?> _getAllUsers() async {
Future<List<User>?> _getAllUsers({required bool isAll}) async {
try {
final dto = await _apiService.userApi.searchUsers();
return dto?.map(User.fromSimpleUserDto).toList();
final dto = await _apiService.userApi.getAllUsers(isAll);
return dto?.map(User.fromUserDto).toList();
} catch (e) {
_log.warning("Failed get all users", e);
return null;
@@ -71,7 +71,7 @@ class UserService {
}
Future<List<User>?> getUsersFromServer() async {
final List<User>? users = await _getAllUsers();
final List<User>? users = await _getAllUsers(isAll: true);
final List<User>? sharedBy =
await _partnerService.getPartners(PartnerDirection.sharedBy);
final List<User>? sharedWith =

View File

@@ -3,5 +3,3 @@ extension StringExtension on String {
return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
}
}
String s(num count) => (count == 1 ? '' : 's');

View File

@@ -77,5 +77,5 @@ String getThumbnailUrlForRemoteId(
}
String getFaceThumbnailUrl(final String personId) {
return '${Store.get(StoreKey.serverEndpoint)}/people/$personId/thumbnail';
return '${Store.get(StoreKey.serverEndpoint)}/person/$personId/thumbnail';
}

View File

@@ -36,62 +36,58 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
[],
);
return Material(
color: Colors.transparent,
child: TextField(
onChanged: (value) {
if (value.isEmpty) {
} else {
ref.watch(albumViewerProvider.notifier).setEditTitleText(value);
}
},
focusNode: titleFocusNode,
style: context.textTheme.headlineMedium,
controller: titleTextEditController,
onTap: () {
FocusScope.of(context).requestFocus(titleFocusNode);
return TextField(
onChanged: (value) {
if (value.isEmpty) {
} else {
ref.watch(albumViewerProvider.notifier).setEditTitleText(value);
}
},
focusNode: titleFocusNode,
style: context.textTheme.headlineMedium,
controller: titleTextEditController,
onTap: () {
FocusScope.of(context).requestFocus(titleFocusNode);
ref.watch(albumViewerProvider.notifier).setEditTitleText(album.name);
ref.watch(albumViewerProvider.notifier).enableEditAlbum();
ref.watch(albumViewerProvider.notifier).setEditTitleText(album.name);
ref.watch(albumViewerProvider.notifier).enableEditAlbum();
if (titleTextEditController.text == 'Untitled') {
titleTextEditController.clear();
}
},
decoration: InputDecoration(
contentPadding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
suffixIcon: titleFocusNode.hasFocus
? IconButton(
onPressed: () {
titleTextEditController.clear();
},
icon: Icon(
Icons.cancel_rounded,
color: context.primaryColor,
),
splashRadius: 10,
)
: null,
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.circular(10),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.circular(10),
),
focusColor: Colors.grey[300],
fillColor: context.isDarkTheme
? const Color.fromARGB(255, 32, 33, 35)
: Colors.grey[200],
filled: titleFocusNode.hasFocus,
hintText: 'share_add_title'.tr(),
hintStyle: TextStyle(
fontSize: 28,
color: context.isDarkTheme ? Colors.grey[300] : Colors.grey[700],
fontWeight: FontWeight.bold,
),
if (titleTextEditController.text == 'Untitled') {
titleTextEditController.clear();
}
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
suffixIcon: titleFocusNode.hasFocus
? IconButton(
onPressed: () {
titleTextEditController.clear();
},
icon: Icon(
Icons.cancel_rounded,
color: context.primaryColor,
),
splashRadius: 10,
)
: null,
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.circular(10),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.circular(10),
),
focusColor: Colors.grey[300],
fillColor: context.isDarkTheme
? const Color.fromARGB(255, 32, 33, 35)
: Colors.grey[200],
filled: titleFocusNode.hasFocus,
hintText: 'share_add_title'.tr(),
hintStyle: TextStyle(
fontSize: 28,
color: context.isDarkTheme ? Colors.grey[300] : Colors.grey[700],
fontWeight: FontWeight.bold,
),
),
);

View File

@@ -238,10 +238,8 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
}
bool appBarOffset() {
return (ref.watch(tabProvider).index == 0 &&
ModalRoute.of(context)?.settings.name ==
TabControllerRoute.name) ||
(ModalRoute.of(context)?.settings.name == AlbumViewerRoute.name);
return ref.watch(tabProvider).index == 0 &&
ModalRoute.of(context)?.settings.name == TabControllerRoute.name;
}
final listWidget = ScrollablePositionedList.builder(

View File

@@ -31,7 +31,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
useEffect(
() {
ref.read(backupProvider.notifier).updateDiskInfo();
ref.read(backupProvider.notifier).updateServerInfo();
ref.read(currentUserProvider.notifier).refresh();
return null;
},

View File

@@ -215,7 +215,7 @@ class _ManualPicker extends HookWidget {
decorationText: "location_picker_longitude",
hintText: "location_picker_longitude_hint",
errorText: "location_picker_longitude_error",
focusNode: longitudeFocusNode,
focusNode: latitiudeFocusNode,
validator: _validateLong,
onUpdated: onLongitudeEditingCompleted,
),

View File

@@ -6,7 +6,7 @@ import 'package:immich_mobile/entities/user.entity.dart';
Widget userAvatar(BuildContext context, User u, {double? radius}) {
final url =
"${Store.get(StoreKey.serverEndpoint)}/users/${u.id}/profile-image";
"${Store.get(StoreKey.serverEndpoint)}/user/profile-image/${u.id}";
final nameFirstLetter = u.name.isNotEmpty ? u.name[0] : "";
return CircleAvatar(
radius: radius,

View File

@@ -24,7 +24,7 @@ class UserCircleAvatar extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
bool isDarkTheme = Theme.of(context).brightness == Brightness.dark;
final profileImageUrl =
'${Store.get(StoreKey.serverEndpoint)}/users/${user.id}/profile-image?d=${Random().nextInt(1024)}';
'${Store.get(StoreKey.serverEndpoint)}/user/profile-image/${user.id}?d=${Random().nextInt(1024)}';
final textIcon = Text(
user.name[0].toUpperCase(),

168
mobile/openapi/README.md generated
View File

@@ -73,29 +73,30 @@ All URIs are relative to */api*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*APIKeyApi* | [**createApiKey**](doc//APIKeyApi.md#createapikey) | **POST** /api-keys |
*APIKeyApi* | [**deleteApiKey**](doc//APIKeyApi.md#deleteapikey) | **DELETE** /api-keys/{id} |
*APIKeyApi* | [**getApiKey**](doc//APIKeyApi.md#getapikey) | **GET** /api-keys/{id} |
*APIKeyApi* | [**getApiKeys**](doc//APIKeyApi.md#getapikeys) | **GET** /api-keys |
*APIKeyApi* | [**updateApiKey**](doc//APIKeyApi.md#updateapikey) | **PUT** /api-keys/{id} |
*ActivityApi* | [**createActivity**](doc//ActivityApi.md#createactivity) | **POST** /activities |
*ActivityApi* | [**deleteActivity**](doc//ActivityApi.md#deleteactivity) | **DELETE** /activities/{id} |
*ActivityApi* | [**getActivities**](doc//ActivityApi.md#getactivities) | **GET** /activities |
*ActivityApi* | [**getActivityStatistics**](doc//ActivityApi.md#getactivitystatistics) | **GET** /activities/statistics |
*AlbumApi* | [**addAssetsToAlbum**](doc//AlbumApi.md#addassetstoalbum) | **PUT** /albums/{id}/assets |
*AlbumApi* | [**addUsersToAlbum**](doc//AlbumApi.md#adduserstoalbum) | **PUT** /albums/{id}/users |
*AlbumApi* | [**createAlbum**](doc//AlbumApi.md#createalbum) | **POST** /albums |
*AlbumApi* | [**deleteAlbum**](doc//AlbumApi.md#deletealbum) | **DELETE** /albums/{id} |
*AlbumApi* | [**getAlbumCount**](doc//AlbumApi.md#getalbumcount) | **GET** /albums/count |
*AlbumApi* | [**getAlbumInfo**](doc//AlbumApi.md#getalbuminfo) | **GET** /albums/{id} |
*AlbumApi* | [**getAllAlbums**](doc//AlbumApi.md#getallalbums) | **GET** /albums |
*AlbumApi* | [**removeAssetFromAlbum**](doc//AlbumApi.md#removeassetfromalbum) | **DELETE** /albums/{id}/assets |
*AlbumApi* | [**removeUserFromAlbum**](doc//AlbumApi.md#removeuserfromalbum) | **DELETE** /albums/{id}/user/{userId} |
*AlbumApi* | [**updateAlbumInfo**](doc//AlbumApi.md#updatealbuminfo) | **PATCH** /albums/{id} |
*AlbumApi* | [**updateAlbumUser**](doc//AlbumApi.md#updatealbumuser) | **PUT** /albums/{id}/user/{userId} |
*APIKeyApi* | [**createApiKey**](doc//APIKeyApi.md#createapikey) | **POST** /api-key |
*APIKeyApi* | [**deleteApiKey**](doc//APIKeyApi.md#deleteapikey) | **DELETE** /api-key/{id} |
*APIKeyApi* | [**getApiKey**](doc//APIKeyApi.md#getapikey) | **GET** /api-key/{id} |
*APIKeyApi* | [**getApiKeys**](doc//APIKeyApi.md#getapikeys) | **GET** /api-key |
*APIKeyApi* | [**updateApiKey**](doc//APIKeyApi.md#updateapikey) | **PUT** /api-key/{id} |
*ActivityApi* | [**createActivity**](doc//ActivityApi.md#createactivity) | **POST** /activity |
*ActivityApi* | [**deleteActivity**](doc//ActivityApi.md#deleteactivity) | **DELETE** /activity/{id} |
*ActivityApi* | [**getActivities**](doc//ActivityApi.md#getactivities) | **GET** /activity |
*ActivityApi* | [**getActivityStatistics**](doc//ActivityApi.md#getactivitystatistics) | **GET** /activity/statistics |
*AlbumApi* | [**addAssetsToAlbum**](doc//AlbumApi.md#addassetstoalbum) | **PUT** /album/{id}/assets |
*AlbumApi* | [**addUsersToAlbum**](doc//AlbumApi.md#adduserstoalbum) | **PUT** /album/{id}/users |
*AlbumApi* | [**createAlbum**](doc//AlbumApi.md#createalbum) | **POST** /album |
*AlbumApi* | [**deleteAlbum**](doc//AlbumApi.md#deletealbum) | **DELETE** /album/{id} |
*AlbumApi* | [**getAlbumCount**](doc//AlbumApi.md#getalbumcount) | **GET** /album/count |
*AlbumApi* | [**getAlbumInfo**](doc//AlbumApi.md#getalbuminfo) | **GET** /album/{id} |
*AlbumApi* | [**getAllAlbums**](doc//AlbumApi.md#getallalbums) | **GET** /album |
*AlbumApi* | [**removeAssetFromAlbum**](doc//AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets |
*AlbumApi* | [**removeUserFromAlbum**](doc//AlbumApi.md#removeuserfromalbum) | **DELETE** /album/{id}/user/{userId} |
*AlbumApi* | [**updateAlbumInfo**](doc//AlbumApi.md#updatealbuminfo) | **PATCH** /album/{id} |
*AlbumApi* | [**updateAlbumUser**](doc//AlbumApi.md#updatealbumuser) | **PUT** /album/{id}/user/{userId} |
*AssetApi* | [**checkBulkUpload**](doc//AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check |
*AssetApi* | [**checkExistingAssets**](doc//AssetApi.md#checkexistingassets) | **POST** /asset/exist |
*AssetApi* | [**deleteAssets**](doc//AssetApi.md#deleteassets) | **DELETE** /asset |
*AssetApi* | [**getAllAssets**](doc//AssetApi.md#getallassets) | **GET** /asset |
*AssetApi* | [**getAllUserAssetsByDeviceId**](doc//AssetApi.md#getalluserassetsbydeviceid) | **GET** /asset/device/{deviceId} |
*AssetApi* | [**getAssetInfo**](doc//AssetApi.md#getassetinfo) | **GET** /asset/{id} |
*AssetApi* | [**getAssetStatistics**](doc//AssetApi.md#getassetstatistics) | **GET** /asset/statistics |
@@ -103,7 +104,6 @@ Class | Method | HTTP request | Description
*AssetApi* | [**getMapMarkers**](doc//AssetApi.md#getmapmarkers) | **GET** /asset/map-marker |
*AssetApi* | [**getMemoryLane**](doc//AssetApi.md#getmemorylane) | **GET** /asset/memory-lane |
*AssetApi* | [**getRandom**](doc//AssetApi.md#getrandom) | **GET** /asset/random |
*AssetApi* | [**replaceAsset**](doc//AssetApi.md#replaceasset) | **PUT** /asset/{id}/file |
*AssetApi* | [**runAssetJobs**](doc//AssetApi.md#runassetjobs) | **POST** /asset/jobs |
*AssetApi* | [**serveFile**](doc//AssetApi.md#servefile) | **GET** /asset/file/{id} |
*AssetApi* | [**updateAsset**](doc//AssetApi.md#updateasset) | **PUT** /asset/{id} |
@@ -120,22 +120,22 @@ Class | Method | HTTP request | Description
*DownloadApi* | [**downloadFile**](doc//DownloadApi.md#downloadfile) | **POST** /download/asset/{id} |
*DownloadApi* | [**getDownloadInfo**](doc//DownloadApi.md#getdownloadinfo) | **POST** /download/info |
*DuplicateApi* | [**getAssetDuplicates**](doc//DuplicateApi.md#getassetduplicates) | **GET** /duplicates |
*FaceApi* | [**getFaces**](doc//FaceApi.md#getfaces) | **GET** /faces |
*FaceApi* | [**reassignFacesById**](doc//FaceApi.md#reassignfacesbyid) | **PUT** /faces/{id} |
*FileReportApi* | [**fixAuditFiles**](doc//FileReportApi.md#fixauditfiles) | **POST** /reports/fix |
*FileReportApi* | [**getAuditFiles**](doc//FileReportApi.md#getauditfiles) | **GET** /reports |
*FileReportApi* | [**getFileChecksums**](doc//FileReportApi.md#getfilechecksums) | **POST** /reports/checksum |
*FaceApi* | [**getFaces**](doc//FaceApi.md#getfaces) | **GET** /face |
*FaceApi* | [**reassignFacesById**](doc//FaceApi.md#reassignfacesbyid) | **PUT** /face/{id} |
*FileReportApi* | [**fixAuditFiles**](doc//FileReportApi.md#fixauditfiles) | **POST** /report/fix |
*FileReportApi* | [**getAuditFiles**](doc//FileReportApi.md#getauditfiles) | **GET** /report |
*FileReportApi* | [**getFileChecksums**](doc//FileReportApi.md#getfilechecksums) | **POST** /report/checksum |
*JobApi* | [**getAllJobsStatus**](doc//JobApi.md#getalljobsstatus) | **GET** /jobs |
*JobApi* | [**sendJobCommand**](doc//JobApi.md#sendjobcommand) | **PUT** /jobs/{id} |
*LibraryApi* | [**createLibrary**](doc//LibraryApi.md#createlibrary) | **POST** /libraries |
*LibraryApi* | [**deleteLibrary**](doc//LibraryApi.md#deletelibrary) | **DELETE** /libraries/{id} |
*LibraryApi* | [**getAllLibraries**](doc//LibraryApi.md#getalllibraries) | **GET** /libraries |
*LibraryApi* | [**getLibrary**](doc//LibraryApi.md#getlibrary) | **GET** /libraries/{id} |
*LibraryApi* | [**getLibraryStatistics**](doc//LibraryApi.md#getlibrarystatistics) | **GET** /libraries/{id}/statistics |
*LibraryApi* | [**removeOfflineFiles**](doc//LibraryApi.md#removeofflinefiles) | **POST** /libraries/{id}/removeOffline |
*LibraryApi* | [**scanLibrary**](doc//LibraryApi.md#scanlibrary) | **POST** /libraries/{id}/scan |
*LibraryApi* | [**updateLibrary**](doc//LibraryApi.md#updatelibrary) | **PUT** /libraries/{id} |
*LibraryApi* | [**validate**](doc//LibraryApi.md#validate) | **POST** /libraries/{id}/validate |
*LibraryApi* | [**createLibrary**](doc//LibraryApi.md#createlibrary) | **POST** /library |
*LibraryApi* | [**deleteLibrary**](doc//LibraryApi.md#deletelibrary) | **DELETE** /library/{id} |
*LibraryApi* | [**getAllLibraries**](doc//LibraryApi.md#getalllibraries) | **GET** /library |
*LibraryApi* | [**getLibrary**](doc//LibraryApi.md#getlibrary) | **GET** /library/{id} |
*LibraryApi* | [**getLibraryStatistics**](doc//LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics |
*LibraryApi* | [**removeOfflineFiles**](doc//LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline |
*LibraryApi* | [**scanLibrary**](doc//LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan |
*LibraryApi* | [**updateLibrary**](doc//LibraryApi.md#updatelibrary) | **PUT** /library/{id} |
*LibraryApi* | [**validate**](doc//LibraryApi.md#validate) | **POST** /library/{id}/validate |
*MemoryApi* | [**addMemoryAssets**](doc//MemoryApi.md#addmemoryassets) | **PUT** /memories/{id}/assets |
*MemoryApi* | [**createMemory**](doc//MemoryApi.md#creatememory) | **POST** /memories |
*MemoryApi* | [**deleteMemory**](doc//MemoryApi.md#deletememory) | **DELETE** /memories/{id} |
@@ -148,20 +148,20 @@ Class | Method | HTTP request | Description
*OAuthApi* | [**redirectOAuthToMobile**](doc//OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect |
*OAuthApi* | [**startOAuth**](doc//OAuthApi.md#startoauth) | **POST** /oauth/authorize |
*OAuthApi* | [**unlinkOAuthAccount**](doc//OAuthApi.md#unlinkoauthaccount) | **POST** /oauth/unlink |
*PartnerApi* | [**createPartner**](doc//PartnerApi.md#createpartner) | **POST** /partners/{id} |
*PartnerApi* | [**getPartners**](doc//PartnerApi.md#getpartners) | **GET** /partners |
*PartnerApi* | [**removePartner**](doc//PartnerApi.md#removepartner) | **DELETE** /partners/{id} |
*PartnerApi* | [**updatePartner**](doc//PartnerApi.md#updatepartner) | **PUT** /partners/{id} |
*PersonApi* | [**createPerson**](doc//PersonApi.md#createperson) | **POST** /people |
*PersonApi* | [**getAllPeople**](doc//PersonApi.md#getallpeople) | **GET** /people |
*PersonApi* | [**getPerson**](doc//PersonApi.md#getperson) | **GET** /people/{id} |
*PersonApi* | [**getPersonAssets**](doc//PersonApi.md#getpersonassets) | **GET** /people/{id}/assets |
*PersonApi* | [**getPersonStatistics**](doc//PersonApi.md#getpersonstatistics) | **GET** /people/{id}/statistics |
*PersonApi* | [**getPersonThumbnail**](doc//PersonApi.md#getpersonthumbnail) | **GET** /people/{id}/thumbnail |
*PersonApi* | [**mergePerson**](doc//PersonApi.md#mergeperson) | **POST** /people/{id}/merge |
*PersonApi* | [**reassignFaces**](doc//PersonApi.md#reassignfaces) | **PUT** /people/{id}/reassign |
*PersonApi* | [**updatePeople**](doc//PersonApi.md#updatepeople) | **PUT** /people |
*PersonApi* | [**updatePerson**](doc//PersonApi.md#updateperson) | **PUT** /people/{id} |
*PartnerApi* | [**createPartner**](doc//PartnerApi.md#createpartner) | **POST** /partner/{id} |
*PartnerApi* | [**getPartners**](doc//PartnerApi.md#getpartners) | **GET** /partner |
*PartnerApi* | [**removePartner**](doc//PartnerApi.md#removepartner) | **DELETE** /partner/{id} |
*PartnerApi* | [**updatePartner**](doc//PartnerApi.md#updatepartner) | **PUT** /partner/{id} |
*PersonApi* | [**createPerson**](doc//PersonApi.md#createperson) | **POST** /person |
*PersonApi* | [**getAllPeople**](doc//PersonApi.md#getallpeople) | **GET** /person |
*PersonApi* | [**getPerson**](doc//PersonApi.md#getperson) | **GET** /person/{id} |
*PersonApi* | [**getPersonAssets**](doc//PersonApi.md#getpersonassets) | **GET** /person/{id}/assets |
*PersonApi* | [**getPersonStatistics**](doc//PersonApi.md#getpersonstatistics) | **GET** /person/{id}/statistics |
*PersonApi* | [**getPersonThumbnail**](doc//PersonApi.md#getpersonthumbnail) | **GET** /person/{id}/thumbnail |
*PersonApi* | [**mergePerson**](doc//PersonApi.md#mergeperson) | **POST** /person/{id}/merge |
*PersonApi* | [**reassignFaces**](doc//PersonApi.md#reassignfaces) | **PUT** /person/{id}/reassign |
*PersonApi* | [**updatePeople**](doc//PersonApi.md#updatepeople) | **PUT** /person |
*PersonApi* | [**updatePerson**](doc//PersonApi.md#updateperson) | **PUT** /person/{id} |
*SearchApi* | [**getAssetsByCity**](doc//SearchApi.md#getassetsbycity) | **GET** /search/cities |
*SearchApi* | [**getExploreData**](doc//SearchApi.md#getexploredata) | **GET** /search/explore |
*SearchApi* | [**getSearchSuggestions**](doc//SearchApi.md#getsearchsuggestions) | **GET** /search/suggestions |
@@ -171,23 +171,23 @@ Class | Method | HTTP request | Description
*SearchApi* | [**searchSmart**](doc//SearchApi.md#searchsmart) | **POST** /search/smart |
*ServerInfoApi* | [**getServerConfig**](doc//ServerInfoApi.md#getserverconfig) | **GET** /server-info/config |
*ServerInfoApi* | [**getServerFeatures**](doc//ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features |
*ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info |
*ServerInfoApi* | [**getServerStatistics**](doc//ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics |
*ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version |
*ServerInfoApi* | [**getStorage**](doc//ServerInfoApi.md#getstorage) | **GET** /server-info/storage |
*ServerInfoApi* | [**getSupportedMediaTypes**](doc//ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types |
*ServerInfoApi* | [**getTheme**](doc//ServerInfoApi.md#gettheme) | **GET** /server-info/theme |
*ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping |
*SessionsApi* | [**deleteAllSessions**](doc//SessionsApi.md#deleteallsessions) | **DELETE** /sessions |
*SessionsApi* | [**deleteSession**](doc//SessionsApi.md#deletesession) | **DELETE** /sessions/{id} |
*SessionsApi* | [**getSessions**](doc//SessionsApi.md#getsessions) | **GET** /sessions |
*SharedLinkApi* | [**addSharedLinkAssets**](doc//SharedLinkApi.md#addsharedlinkassets) | **PUT** /shared-links/{id}/assets |
*SharedLinkApi* | [**createSharedLink**](doc//SharedLinkApi.md#createsharedlink) | **POST** /shared-links |
*SharedLinkApi* | [**getAllSharedLinks**](doc//SharedLinkApi.md#getallsharedlinks) | **GET** /shared-links |
*SharedLinkApi* | [**getMySharedLink**](doc//SharedLinkApi.md#getmysharedlink) | **GET** /shared-links/me |
*SharedLinkApi* | [**getSharedLinkById**](doc//SharedLinkApi.md#getsharedlinkbyid) | **GET** /shared-links/{id} |
*SharedLinkApi* | [**removeSharedLink**](doc//SharedLinkApi.md#removesharedlink) | **DELETE** /shared-links/{id} |
*SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-links/{id}/assets |
*SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-links/{id} |
*SharedLinkApi* | [**addSharedLinkAssets**](doc//SharedLinkApi.md#addsharedlinkassets) | **PUT** /shared-link/{id}/assets |
*SharedLinkApi* | [**createSharedLink**](doc//SharedLinkApi.md#createsharedlink) | **POST** /shared-link |
*SharedLinkApi* | [**getAllSharedLinks**](doc//SharedLinkApi.md#getallsharedlinks) | **GET** /shared-link |
*SharedLinkApi* | [**getMySharedLink**](doc//SharedLinkApi.md#getmysharedlink) | **GET** /shared-link/me |
*SharedLinkApi* | [**getSharedLinkById**](doc//SharedLinkApi.md#getsharedlinkbyid) | **GET** /shared-link/{id} |
*SharedLinkApi* | [**removeSharedLink**](doc//SharedLinkApi.md#removesharedlink) | **DELETE** /shared-link/{id} |
*SharedLinkApi* | [**removeSharedLinkAssets**](doc//SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets |
*SharedLinkApi* | [**updateSharedLink**](doc//SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} |
*SyncApi* | [**getDeltaSync**](doc//SyncApi.md#getdeltasync) | **POST** /sync/delta-sync |
*SyncApi* | [**getFullSyncForUser**](doc//SyncApi.md#getfullsyncforuser) | **POST** /sync/full-sync |
*SystemConfigApi* | [**getConfig**](doc//SystemConfigApi.md#getconfig) | **GET** /system-config |
@@ -198,32 +198,29 @@ Class | Method | HTTP request | Description
*SystemMetadataApi* | [**getAdminOnboarding**](doc//SystemMetadataApi.md#getadminonboarding) | **GET** /system-metadata/admin-onboarding |
*SystemMetadataApi* | [**getReverseGeocodingState**](doc//SystemMetadataApi.md#getreversegeocodingstate) | **GET** /system-metadata/reverse-geocoding-state |
*SystemMetadataApi* | [**updateAdminOnboarding**](doc//SystemMetadataApi.md#updateadminonboarding) | **POST** /system-metadata/admin-onboarding |
*TagApi* | [**createTag**](doc//TagApi.md#createtag) | **POST** /tags |
*TagApi* | [**deleteTag**](doc//TagApi.md#deletetag) | **DELETE** /tags/{id} |
*TagApi* | [**getAllTags**](doc//TagApi.md#getalltags) | **GET** /tags |
*TagApi* | [**getTagAssets**](doc//TagApi.md#gettagassets) | **GET** /tags/{id}/assets |
*TagApi* | [**getTagById**](doc//TagApi.md#gettagbyid) | **GET** /tags/{id} |
*TagApi* | [**tagAssets**](doc//TagApi.md#tagassets) | **PUT** /tags/{id}/assets |
*TagApi* | [**untagAssets**](doc//TagApi.md#untagassets) | **DELETE** /tags/{id}/assets |
*TagApi* | [**updateTag**](doc//TagApi.md#updatetag) | **PATCH** /tags/{id} |
*TagApi* | [**createTag**](doc//TagApi.md#createtag) | **POST** /tag |
*TagApi* | [**deleteTag**](doc//TagApi.md#deletetag) | **DELETE** /tag/{id} |
*TagApi* | [**getAllTags**](doc//TagApi.md#getalltags) | **GET** /tag |
*TagApi* | [**getTagAssets**](doc//TagApi.md#gettagassets) | **GET** /tag/{id}/assets |
*TagApi* | [**getTagById**](doc//TagApi.md#gettagbyid) | **GET** /tag/{id} |
*TagApi* | [**tagAssets**](doc//TagApi.md#tagassets) | **PUT** /tag/{id}/assets |
*TagApi* | [**untagAssets**](doc//TagApi.md#untagassets) | **DELETE** /tag/{id}/assets |
*TagApi* | [**updateTag**](doc//TagApi.md#updatetag) | **PATCH** /tag/{id} |
*TimelineApi* | [**getTimeBucket**](doc//TimelineApi.md#gettimebucket) | **GET** /timeline/bucket |
*TimelineApi* | [**getTimeBuckets**](doc//TimelineApi.md#gettimebuckets) | **GET** /timeline/buckets |
*TrashApi* | [**emptyTrash**](doc//TrashApi.md#emptytrash) | **POST** /trash/empty |
*TrashApi* | [**restoreAssets**](doc//TrashApi.md#restoreassets) | **POST** /trash/restore/assets |
*TrashApi* | [**restoreTrash**](doc//TrashApi.md#restoretrash) | **POST** /trash/restore |
*UserApi* | [**createProfileImage**](doc//UserApi.md#createprofileimage) | **POST** /users/profile-image |
*UserApi* | [**createUserAdmin**](doc//UserApi.md#createuseradmin) | **POST** /admin/users |
*UserApi* | [**deleteProfileImage**](doc//UserApi.md#deleteprofileimage) | **DELETE** /users/profile-image |
*UserApi* | [**deleteUserAdmin**](doc//UserApi.md#deleteuseradmin) | **DELETE** /admin/users/{id} |
*UserApi* | [**getMyUser**](doc//UserApi.md#getmyuser) | **GET** /users/me |
*UserApi* | [**getProfileImage**](doc//UserApi.md#getprofileimage) | **GET** /users/{id}/profile-image |
*UserApi* | [**getUser**](doc//UserApi.md#getuser) | **GET** /users/{id} |
*UserApi* | [**getUserAdmin**](doc//UserApi.md#getuseradmin) | **GET** /admin/users/{id} |
*UserApi* | [**restoreUserAdmin**](doc//UserApi.md#restoreuseradmin) | **POST** /admin/users/{id}/restore |
*UserApi* | [**searchUsers**](doc//UserApi.md#searchusers) | **GET** /users |
*UserApi* | [**searchUsersAdmin**](doc//UserApi.md#searchusersadmin) | **GET** /admin/users |
*UserApi* | [**updateMyUser**](doc//UserApi.md#updatemyuser) | **PUT** /users/me |
*UserApi* | [**updateUserAdmin**](doc//UserApi.md#updateuseradmin) | **PUT** /admin/users/{id} |
*UserApi* | [**createProfileImage**](doc//UserApi.md#createprofileimage) | **POST** /user/profile-image |
*UserApi* | [**createUser**](doc//UserApi.md#createuser) | **POST** /user |
*UserApi* | [**deleteProfileImage**](doc//UserApi.md#deleteprofileimage) | **DELETE** /user/profile-image |
*UserApi* | [**deleteUser**](doc//UserApi.md#deleteuser) | **DELETE** /user/{id} |
*UserApi* | [**getAllUsers**](doc//UserApi.md#getallusers) | **GET** /user |
*UserApi* | [**getMyUserInfo**](doc//UserApi.md#getmyuserinfo) | **GET** /user/me |
*UserApi* | [**getProfileImage**](doc//UserApi.md#getprofileimage) | **GET** /user/profile-image/{id} |
*UserApi* | [**getUserById**](doc//UserApi.md#getuserbyid) | **GET** /user/info/{id} |
*UserApi* | [**restoreUser**](doc//UserApi.md#restoreuser) | **POST** /user/{id}/restore |
*UserApi* | [**updateUser**](doc//UserApi.md#updateuser) | **PUT** /user |
## Documentation For Models
@@ -262,8 +259,6 @@ Class | Method | HTTP request | Description
- [AssetIdsResponseDto](doc//AssetIdsResponseDto.md)
- [AssetJobName](doc//AssetJobName.md)
- [AssetJobsDto](doc//AssetJobsDto.md)
- [AssetMediaResponseDto](doc//AssetMediaResponseDto.md)
- [AssetMediaStatus](doc//AssetMediaStatus.md)
- [AssetOrder](doc//AssetOrder.md)
- [AssetResponseDto](doc//AssetResponseDto.md)
- [AssetStatsResponseDto](doc//AssetStatsResponseDto.md)
@@ -283,6 +278,8 @@ Class | Method | HTTP request | Description
- [CreateLibraryDto](doc//CreateLibraryDto.md)
- [CreateProfileImageResponseDto](doc//CreateProfileImageResponseDto.md)
- [CreateTagDto](doc//CreateTagDto.md)
- [CreateUserDto](doc//CreateUserDto.md)
- [DeleteUserDto](doc//DeleteUserDto.md)
- [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
- [DownloadInfoDto](doc//DownloadInfoDto.md)
- [DownloadResponseDto](doc//DownloadResponseDto.md)
@@ -351,10 +348,10 @@ Class | Method | HTTP request | Description
- [SearchSuggestionType](doc//SearchSuggestionType.md)
- [ServerConfigDto](doc//ServerConfigDto.md)
- [ServerFeaturesDto](doc//ServerFeaturesDto.md)
- [ServerInfoResponseDto](doc//ServerInfoResponseDto.md)
- [ServerMediaTypesResponseDto](doc//ServerMediaTypesResponseDto.md)
- [ServerPingResponse](doc//ServerPingResponse.md)
- [ServerStatsResponseDto](doc//ServerStatsResponseDto.md)
- [ServerStorageResponseDto](doc//ServerStorageResponseDto.md)
- [ServerThemeDto](doc//ServerThemeDto.md)
- [ServerVersionResponseDto](doc//ServerVersionResponseDto.md)
- [SessionResponseDto](doc//SessionResponseDto.md)
@@ -403,15 +400,12 @@ Class | Method | HTTP request | Description
- [UpdatePartnerDto](doc//UpdatePartnerDto.md)
- [UpdateStackParentDto](doc//UpdateStackParentDto.md)
- [UpdateTagDto](doc//UpdateTagDto.md)
- [UpdateUserDto](doc//UpdateUserDto.md)
- [UsageByUserDto](doc//UsageByUserDto.md)
- [UserAdminCreateDto](doc//UserAdminCreateDto.md)
- [UserAdminDeleteDto](doc//UserAdminDeleteDto.md)
- [UserAdminResponseDto](doc//UserAdminResponseDto.md)
- [UserAdminUpdateDto](doc//UserAdminUpdateDto.md)
- [UserAvatarColor](doc//UserAvatarColor.md)
- [UserDto](doc//UserDto.md)
- [UserResponseDto](doc//UserResponseDto.md)
- [UserStatus](doc//UserStatus.md)
- [UserUpdateMeDto](doc//UserUpdateMeDto.md)
- [ValidateAccessTokenResponseDto](doc//ValidateAccessTokenResponseDto.md)
- [ValidateLibraryDto](doc//ValidateLibraryDto.md)
- [ValidateLibraryImportPathResponseDto](doc//ValidateLibraryImportPathResponseDto.md)

View File

@@ -91,8 +91,6 @@ part 'model/asset_ids_dto.dart';
part 'model/asset_ids_response_dto.dart';
part 'model/asset_job_name.dart';
part 'model/asset_jobs_dto.dart';
part 'model/asset_media_response_dto.dart';
part 'model/asset_media_status.dart';
part 'model/asset_order.dart';
part 'model/asset_response_dto.dart';
part 'model/asset_stats_response_dto.dart';
@@ -112,6 +110,8 @@ part 'model/create_album_dto.dart';
part 'model/create_library_dto.dart';
part 'model/create_profile_image_response_dto.dart';
part 'model/create_tag_dto.dart';
part 'model/create_user_dto.dart';
part 'model/delete_user_dto.dart';
part 'model/download_archive_info.dart';
part 'model/download_info_dto.dart';
part 'model/download_response_dto.dart';
@@ -180,10 +180,10 @@ part 'model/search_response_dto.dart';
part 'model/search_suggestion_type.dart';
part 'model/server_config_dto.dart';
part 'model/server_features_dto.dart';
part 'model/server_info_response_dto.dart';
part 'model/server_media_types_response_dto.dart';
part 'model/server_ping_response.dart';
part 'model/server_stats_response_dto.dart';
part 'model/server_storage_response_dto.dart';
part 'model/server_theme_dto.dart';
part 'model/server_version_response_dto.dart';
part 'model/session_response_dto.dart';
@@ -232,15 +232,12 @@ part 'model/update_library_dto.dart';
part 'model/update_partner_dto.dart';
part 'model/update_stack_parent_dto.dart';
part 'model/update_tag_dto.dart';
part 'model/update_user_dto.dart';
part 'model/usage_by_user_dto.dart';
part 'model/user_admin_create_dto.dart';
part 'model/user_admin_delete_dto.dart';
part 'model/user_admin_response_dto.dart';
part 'model/user_admin_update_dto.dart';
part 'model/user_avatar_color.dart';
part 'model/user_dto.dart';
part 'model/user_response_dto.dart';
part 'model/user_status.dart';
part 'model/user_update_me_dto.dart';
part 'model/validate_access_token_response_dto.dart';
part 'model/validate_library_dto.dart';
part 'model/validate_library_import_path_response_dto.dart';

View File

@@ -16,13 +16,13 @@ class ActivityApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /activities' operation and returns the [Response].
/// Performs an HTTP 'POST /activity' operation and returns the [Response].
/// Parameters:
///
/// * [ActivityCreateDto] activityCreateDto (required):
Future<Response> createActivityWithHttpInfo(ActivityCreateDto activityCreateDto,) async {
// ignore: prefer_const_declarations
final path = r'/activities';
final path = r'/activity';
// ignore: prefer_final_locals
Object? postBody = activityCreateDto;
@@ -63,13 +63,13 @@ class ActivityApi {
return null;
}
/// Performs an HTTP 'DELETE /activities/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /activity/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> deleteActivityWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/activities/{id}'
final path = r'/activity/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -103,7 +103,7 @@ class ActivityApi {
}
}
/// Performs an HTTP 'GET /activities' operation and returns the [Response].
/// Performs an HTTP 'GET /activity' operation and returns the [Response].
/// Parameters:
///
/// * [String] albumId (required):
@@ -117,7 +117,7 @@ class ActivityApi {
/// * [String] userId:
Future<Response> getActivitiesWithHttpInfo(String albumId, { String? assetId, ReactionLevel? level, ReactionType? type, String? userId, }) async {
// ignore: prefer_const_declarations
final path = r'/activities';
final path = r'/activity';
// ignore: prefer_final_locals
Object? postBody;
@@ -183,7 +183,7 @@ class ActivityApi {
return null;
}
/// Performs an HTTP 'GET /activities/statistics' operation and returns the [Response].
/// Performs an HTTP 'GET /activity/statistics' operation and returns the [Response].
/// Parameters:
///
/// * [String] albumId (required):
@@ -191,7 +191,7 @@ class ActivityApi {
/// * [String] assetId:
Future<Response> getActivityStatisticsWithHttpInfo(String albumId, { String? assetId, }) async {
// ignore: prefer_const_declarations
final path = r'/activities/statistics';
final path = r'/activity/statistics';
// ignore: prefer_final_locals
Object? postBody;

View File

@@ -16,7 +16,7 @@ class AlbumApi {
final ApiClient apiClient;
/// Performs an HTTP 'PUT /albums/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'PUT /album/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -26,7 +26,7 @@ class AlbumApi {
/// * [String] key:
Future<Response> addAssetsToAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto, { String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}/assets'
final path = r'/album/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -79,7 +79,7 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'PUT /albums/{id}/users' operation and returns the [Response].
/// Performs an HTTP 'PUT /album/{id}/users' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -87,7 +87,7 @@ class AlbumApi {
/// * [AddUsersDto] addUsersDto (required):
Future<Response> addUsersToAlbumWithHttpInfo(String id, AddUsersDto addUsersDto,) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}/users'
final path = r'/album/{id}/users'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -131,13 +131,13 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'POST /albums' operation and returns the [Response].
/// Performs an HTTP 'POST /album' operation and returns the [Response].
/// Parameters:
///
/// * [CreateAlbumDto] createAlbumDto (required):
Future<Response> createAlbumWithHttpInfo(CreateAlbumDto createAlbumDto,) async {
// ignore: prefer_const_declarations
final path = r'/albums';
final path = r'/album';
// ignore: prefer_final_locals
Object? postBody = createAlbumDto;
@@ -178,13 +178,13 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'DELETE /albums/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /album/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> deleteAlbumWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}'
final path = r'/album/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -218,10 +218,10 @@ class AlbumApi {
}
}
/// Performs an HTTP 'GET /albums/count' operation and returns the [Response].
/// Performs an HTTP 'GET /album/count' operation and returns the [Response].
Future<Response> getAlbumCountWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/albums/count';
final path = r'/album/count';
// ignore: prefer_final_locals
Object? postBody;
@@ -259,7 +259,7 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'GET /albums/{id}' operation and returns the [Response].
/// Performs an HTTP 'GET /album/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -269,7 +269,7 @@ class AlbumApi {
/// * [bool] withoutAssets:
Future<Response> getAlbumInfoWithHttpInfo(String id, { String? key, bool? withoutAssets, }) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}'
final path = r'/album/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -322,7 +322,7 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'GET /albums' operation and returns the [Response].
/// Performs an HTTP 'GET /album' operation and returns the [Response].
/// Parameters:
///
/// * [String] assetId:
@@ -331,7 +331,7 @@ class AlbumApi {
/// * [bool] shared:
Future<Response> getAllAlbumsWithHttpInfo({ String? assetId, bool? shared, }) async {
// ignore: prefer_const_declarations
final path = r'/albums';
final path = r'/album';
// ignore: prefer_final_locals
Object? postBody;
@@ -385,7 +385,7 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'DELETE /albums/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'DELETE /album/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -393,7 +393,7 @@ class AlbumApi {
/// * [BulkIdsDto] bulkIdsDto (required):
Future<Response> removeAssetFromAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto,) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}/assets'
final path = r'/album/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -440,7 +440,7 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'DELETE /albums/{id}/user/{userId}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /album/{id}/user/{userId}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -448,7 +448,7 @@ class AlbumApi {
/// * [String] userId (required):
Future<Response> removeUserFromAlbumWithHttpInfo(String id, String userId,) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}/user/{userId}'
final path = r'/album/{id}/user/{userId}'
.replaceAll('{id}', id)
.replaceAll('{userId}', userId);
@@ -485,7 +485,7 @@ class AlbumApi {
}
}
/// Performs an HTTP 'PATCH /albums/{id}' operation and returns the [Response].
/// Performs an HTTP 'PATCH /album/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -493,7 +493,7 @@ class AlbumApi {
/// * [UpdateAlbumDto] updateAlbumDto (required):
Future<Response> updateAlbumInfoWithHttpInfo(String id, UpdateAlbumDto updateAlbumDto,) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}'
final path = r'/album/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -537,7 +537,7 @@ class AlbumApi {
return null;
}
/// Performs an HTTP 'PUT /albums/{id}/user/{userId}' operation and returns the [Response].
/// Performs an HTTP 'PUT /album/{id}/user/{userId}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -547,7 +547,7 @@ class AlbumApi {
/// * [UpdateAlbumUserDto] updateAlbumUserDto (required):
Future<Response> updateAlbumUserWithHttpInfo(String id, String userId, UpdateAlbumUserDto updateAlbumUserDto,) async {
// ignore: prefer_const_declarations
final path = r'/albums/{id}/user/{userId}'
final path = r'/album/{id}/user/{userId}'
.replaceAll('{id}', id)
.replaceAll('{userId}', userId);

View File

@@ -16,13 +16,13 @@ class APIKeyApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /api-keys' operation and returns the [Response].
/// Performs an HTTP 'POST /api-key' operation and returns the [Response].
/// Parameters:
///
/// * [APIKeyCreateDto] aPIKeyCreateDto (required):
Future<Response> createApiKeyWithHttpInfo(APIKeyCreateDto aPIKeyCreateDto,) async {
// ignore: prefer_const_declarations
final path = r'/api-keys';
final path = r'/api-key';
// ignore: prefer_final_locals
Object? postBody = aPIKeyCreateDto;
@@ -63,13 +63,13 @@ class APIKeyApi {
return null;
}
/// Performs an HTTP 'DELETE /api-keys/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /api-key/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> deleteApiKeyWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/api-keys/{id}'
final path = r'/api-key/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -103,13 +103,13 @@ class APIKeyApi {
}
}
/// Performs an HTTP 'GET /api-keys/{id}' operation and returns the [Response].
/// Performs an HTTP 'GET /api-key/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getApiKeyWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/api-keys/{id}'
final path = r'/api-key/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -151,10 +151,10 @@ class APIKeyApi {
return null;
}
/// Performs an HTTP 'GET /api-keys' operation and returns the [Response].
/// Performs an HTTP 'GET /api-key' operation and returns the [Response].
Future<Response> getApiKeysWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/api-keys';
final path = r'/api-key';
// ignore: prefer_final_locals
Object? postBody;
@@ -195,7 +195,7 @@ class APIKeyApi {
return null;
}
/// Performs an HTTP 'PUT /api-keys/{id}' operation and returns the [Response].
/// Performs an HTTP 'PUT /api-key/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -203,7 +203,7 @@ class APIKeyApi {
/// * [APIKeyUpdateDto] aPIKeyUpdateDto (required):
Future<Response> updateApiKeyWithHttpInfo(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async {
// ignore: prefer_const_declarations
final path = r'/api-keys/{id}'
final path = r'/api-key/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals

View File

@@ -159,6 +159,117 @@ class AssetApi {
}
}
/// Get all AssetEntity belong to the user
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [String] ifNoneMatch:
/// ETag of data already cached on the client
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
///
/// * [int] skip:
///
/// * [int] take:
///
/// * [DateTime] updatedAfter:
///
/// * [DateTime] updatedBefore:
///
/// * [String] userId:
Future<Response> getAllAssetsWithHttpInfo({ String? ifNoneMatch, bool? isArchived, bool? isFavorite, int? skip, int? take, DateTime? updatedAfter, DateTime? updatedBefore, String? userId, }) async {
// ignore: prefer_const_declarations
final path = r'/asset';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (isArchived != null) {
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
}
if (isFavorite != null) {
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
}
if (skip != null) {
queryParams.addAll(_queryParams('', 'skip', skip));
}
if (take != null) {
queryParams.addAll(_queryParams('', 'take', take));
}
if (updatedAfter != null) {
queryParams.addAll(_queryParams('', 'updatedAfter', updatedAfter));
}
if (updatedBefore != null) {
queryParams.addAll(_queryParams('', 'updatedBefore', updatedBefore));
}
if (userId != null) {
queryParams.addAll(_queryParams('', 'userId', userId));
}
if (ifNoneMatch != null) {
headerParams[r'if-none-match'] = parameterToString(ifNoneMatch);
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Get all AssetEntity belong to the user
///
/// Parameters:
///
/// * [String] ifNoneMatch:
/// ETag of data already cached on the client
///
/// * [bool] isArchived:
///
/// * [bool] isFavorite:
///
/// * [int] skip:
///
/// * [int] take:
///
/// * [DateTime] updatedAfter:
///
/// * [DateTime] updatedBefore:
///
/// * [String] userId:
Future<List<AssetResponseDto>?> getAllAssets({ String? ifNoneMatch, bool? isArchived, bool? isFavorite, int? skip, int? take, DateTime? updatedAfter, DateTime? updatedBefore, String? userId, }) async {
final response = await getAllAssetsWithHttpInfo( ifNoneMatch: ifNoneMatch, isArchived: isArchived, isFavorite: isFavorite, skip: skip, take: take, updatedAfter: updatedAfter, updatedBefore: updatedBefore, userId: userId, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<AssetResponseDto>') as List)
.cast<AssetResponseDto>()
.toList(growable: false);
}
return null;
}
/// Get all asset of a device that are in the database, ID only.
///
/// Note: This method returns the HTTP [Response].
@@ -599,121 +710,6 @@ class AssetApi {
return null;
}
/// Replace the asset with new file, without changing its id
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
///
/// * [String] deviceAssetId (required):
///
/// * [String] deviceId (required):
///
/// * [DateTime] fileCreatedAt (required):
///
/// * [DateTime] fileModifiedAt (required):
///
/// * [String] key:
///
/// * [String] duration:
Future<Response> replaceAssetWithHttpInfo(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, }) async {
// ignore: prefer_const_declarations
final path = r'/asset/{id}/file'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
const contentTypes = <String>['multipart/form-data'];
bool hasFields = false;
final mp = MultipartRequest('PUT', Uri.parse(path));
if (assetData != null) {
hasFields = true;
mp.fields[r'assetData'] = assetData.field;
mp.files.add(assetData);
}
if (deviceAssetId != null) {
hasFields = true;
mp.fields[r'deviceAssetId'] = parameterToString(deviceAssetId);
}
if (deviceId != null) {
hasFields = true;
mp.fields[r'deviceId'] = parameterToString(deviceId);
}
if (duration != null) {
hasFields = true;
mp.fields[r'duration'] = parameterToString(duration);
}
if (fileCreatedAt != null) {
hasFields = true;
mp.fields[r'fileCreatedAt'] = parameterToString(fileCreatedAt);
}
if (fileModifiedAt != null) {
hasFields = true;
mp.fields[r'fileModifiedAt'] = parameterToString(fileModifiedAt);
}
if (hasFields) {
postBody = mp;
}
return apiClient.invokeAPI(
path,
'PUT',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Replace the asset with new file, without changing its id
///
/// Parameters:
///
/// * [String] id (required):
///
/// * [MultipartFile] assetData (required):
///
/// * [String] deviceAssetId (required):
///
/// * [String] deviceId (required):
///
/// * [DateTime] fileCreatedAt (required):
///
/// * [DateTime] fileModifiedAt (required):
///
/// * [String] key:
///
/// * [String] duration:
Future<AssetMediaResponseDto?> replaceAsset(String id, MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? duration, }) async {
final response = await replaceAssetWithHttpInfo(id, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, duration: duration, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'AssetMediaResponseDto',) as AssetMediaResponseDto;
}
return null;
}
/// Performs an HTTP 'POST /asset/jobs' operation and returns the [Response].
/// Parameters:
///

View File

@@ -48,7 +48,7 @@ class AuthenticationApi {
/// Parameters:
///
/// * [ChangePasswordDto] changePasswordDto (required):
Future<UserAdminResponseDto?> changePassword(ChangePasswordDto changePasswordDto,) async {
Future<UserResponseDto?> changePassword(ChangePasswordDto changePasswordDto,) async {
final response = await changePasswordWithHttpInfo(changePasswordDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -57,7 +57,7 @@ class AuthenticationApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;
@@ -183,7 +183,7 @@ class AuthenticationApi {
/// Parameters:
///
/// * [SignUpDto] signUpDto (required):
Future<UserAdminResponseDto?> signUpAdmin(SignUpDto signUpDto,) async {
Future<UserResponseDto?> signUpAdmin(SignUpDto signUpDto,) async {
final response = await signUpAdminWithHttpInfo(signUpDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -192,7 +192,7 @@ class AuthenticationApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;

View File

@@ -16,13 +16,13 @@ class FaceApi {
final ApiClient apiClient;
/// Performs an HTTP 'GET /faces' operation and returns the [Response].
/// Performs an HTTP 'GET /face' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getFacesWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/faces';
final path = r'/face';
// ignore: prefer_final_locals
Object? postBody;
@@ -68,7 +68,7 @@ class FaceApi {
return null;
}
/// Performs an HTTP 'PUT /faces/{id}' operation and returns the [Response].
/// Performs an HTTP 'PUT /face/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -76,7 +76,7 @@ class FaceApi {
/// * [FaceDto] faceDto (required):
Future<Response> reassignFacesByIdWithHttpInfo(String id, FaceDto faceDto,) async {
// ignore: prefer_const_declarations
final path = r'/faces/{id}'
final path = r'/face/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals

View File

@@ -16,13 +16,13 @@ class FileReportApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /reports/fix' operation and returns the [Response].
/// Performs an HTTP 'POST /report/fix' operation and returns the [Response].
/// Parameters:
///
/// * [FileReportFixDto] fileReportFixDto (required):
Future<Response> fixAuditFilesWithHttpInfo(FileReportFixDto fileReportFixDto,) async {
// ignore: prefer_const_declarations
final path = r'/reports/fix';
final path = r'/report/fix';
// ignore: prefer_final_locals
Object? postBody = fileReportFixDto;
@@ -55,10 +55,10 @@ class FileReportApi {
}
}
/// Performs an HTTP 'GET /reports' operation and returns the [Response].
/// Performs an HTTP 'GET /report' operation and returns the [Response].
Future<Response> getAuditFilesWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/reports';
final path = r'/report';
// ignore: prefer_final_locals
Object? postBody;
@@ -96,13 +96,13 @@ class FileReportApi {
return null;
}
/// Performs an HTTP 'POST /reports/checksum' operation and returns the [Response].
/// Performs an HTTP 'POST /report/checksum' operation and returns the [Response].
/// Parameters:
///
/// * [FileChecksumDto] fileChecksumDto (required):
Future<Response> getFileChecksumsWithHttpInfo(FileChecksumDto fileChecksumDto,) async {
// ignore: prefer_const_declarations
final path = r'/reports/checksum';
final path = r'/report/checksum';
// ignore: prefer_final_locals
Object? postBody = fileChecksumDto;

View File

@@ -16,13 +16,13 @@ class LibraryApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /libraries' operation and returns the [Response].
/// Performs an HTTP 'POST /library' operation and returns the [Response].
/// Parameters:
///
/// * [CreateLibraryDto] createLibraryDto (required):
Future<Response> createLibraryWithHttpInfo(CreateLibraryDto createLibraryDto,) async {
// ignore: prefer_const_declarations
final path = r'/libraries';
final path = r'/library';
// ignore: prefer_final_locals
Object? postBody = createLibraryDto;
@@ -63,13 +63,13 @@ class LibraryApi {
return null;
}
/// Performs an HTTP 'DELETE /libraries/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /library/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> deleteLibraryWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/libraries/{id}'
final path = r'/library/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -103,10 +103,10 @@ class LibraryApi {
}
}
/// Performs an HTTP 'GET /libraries' operation and returns the [Response].
/// Performs an HTTP 'GET /library' operation and returns the [Response].
Future<Response> getAllLibrariesWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/libraries';
final path = r'/library';
// ignore: prefer_final_locals
Object? postBody;
@@ -147,13 +147,13 @@ class LibraryApi {
return null;
}
/// Performs an HTTP 'GET /libraries/{id}' operation and returns the [Response].
/// Performs an HTTP 'GET /library/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getLibraryWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/libraries/{id}'
final path = r'/library/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -195,13 +195,13 @@ class LibraryApi {
return null;
}
/// Performs an HTTP 'GET /libraries/{id}/statistics' operation and returns the [Response].
/// Performs an HTTP 'GET /library/{id}/statistics' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getLibraryStatisticsWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/libraries/{id}/statistics'
final path = r'/library/{id}/statistics'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -243,13 +243,13 @@ class LibraryApi {
return null;
}
/// Performs an HTTP 'POST /libraries/{id}/removeOffline' operation and returns the [Response].
/// Performs an HTTP 'POST /library/{id}/removeOffline' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> removeOfflineFilesWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/libraries/{id}/removeOffline'
final path = r'/library/{id}/removeOffline'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -283,7 +283,7 @@ class LibraryApi {
}
}
/// Performs an HTTP 'POST /libraries/{id}/scan' operation and returns the [Response].
/// Performs an HTTP 'POST /library/{id}/scan' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -291,7 +291,7 @@ class LibraryApi {
/// * [ScanLibraryDto] scanLibraryDto (required):
Future<Response> scanLibraryWithHttpInfo(String id, ScanLibraryDto scanLibraryDto,) async {
// ignore: prefer_const_declarations
final path = r'/libraries/{id}/scan'
final path = r'/library/{id}/scan'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -327,7 +327,7 @@ class LibraryApi {
}
}
/// Performs an HTTP 'PUT /libraries/{id}' operation and returns the [Response].
/// Performs an HTTP 'PUT /library/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -335,7 +335,7 @@ class LibraryApi {
/// * [UpdateLibraryDto] updateLibraryDto (required):
Future<Response> updateLibraryWithHttpInfo(String id, UpdateLibraryDto updateLibraryDto,) async {
// ignore: prefer_const_declarations
final path = r'/libraries/{id}'
final path = r'/library/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -379,7 +379,7 @@ class LibraryApi {
return null;
}
/// Performs an HTTP 'POST /libraries/{id}/validate' operation and returns the [Response].
/// Performs an HTTP 'POST /library/{id}/validate' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -387,7 +387,7 @@ class LibraryApi {
/// * [ValidateLibraryDto] validateLibraryDto (required):
Future<Response> validateWithHttpInfo(String id, ValidateLibraryDto validateLibraryDto,) async {
// ignore: prefer_const_declarations
final path = r'/libraries/{id}/validate'
final path = r'/library/{id}/validate'
.replaceAll('{id}', id);
// ignore: prefer_final_locals

View File

@@ -95,7 +95,7 @@ class OAuthApi {
/// Parameters:
///
/// * [OAuthCallbackDto] oAuthCallbackDto (required):
Future<UserAdminResponseDto?> linkOAuthAccount(OAuthCallbackDto oAuthCallbackDto,) async {
Future<UserResponseDto?> linkOAuthAccount(OAuthCallbackDto oAuthCallbackDto,) async {
final response = await linkOAuthAccountWithHttpInfo(oAuthCallbackDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -104,7 +104,7 @@ class OAuthApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;
@@ -216,7 +216,7 @@ class OAuthApi {
);
}
Future<UserAdminResponseDto?> unlinkOAuthAccount() async {
Future<UserResponseDto?> unlinkOAuthAccount() async {
final response = await unlinkOAuthAccountWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@@ -225,7 +225,7 @@ class OAuthApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;

View File

@@ -16,13 +16,13 @@ class PartnerApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /partners/{id}' operation and returns the [Response].
/// Performs an HTTP 'POST /partner/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> createPartnerWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/partners/{id}'
final path = r'/partner/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -64,13 +64,13 @@ class PartnerApi {
return null;
}
/// Performs an HTTP 'GET /partners' operation and returns the [Response].
/// Performs an HTTP 'GET /partner' operation and returns the [Response].
/// Parameters:
///
/// * [String] direction (required):
Future<Response> getPartnersWithHttpInfo(String direction,) async {
// ignore: prefer_const_declarations
final path = r'/partners';
final path = r'/partner';
// ignore: prefer_final_locals
Object? postBody;
@@ -116,13 +116,13 @@ class PartnerApi {
return null;
}
/// Performs an HTTP 'DELETE /partners/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /partner/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> removePartnerWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/partners/{id}'
final path = r'/partner/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -156,7 +156,7 @@ class PartnerApi {
}
}
/// Performs an HTTP 'PUT /partners/{id}' operation and returns the [Response].
/// Performs an HTTP 'PUT /partner/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -164,7 +164,7 @@ class PartnerApi {
/// * [UpdatePartnerDto] updatePartnerDto (required):
Future<Response> updatePartnerWithHttpInfo(String id, UpdatePartnerDto updatePartnerDto,) async {
// ignore: prefer_const_declarations
final path = r'/partners/{id}'
final path = r'/partner/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals

View File

@@ -16,13 +16,13 @@ class PersonApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /people' operation and returns the [Response].
/// Performs an HTTP 'POST /person' operation and returns the [Response].
/// Parameters:
///
/// * [PersonCreateDto] personCreateDto (required):
Future<Response> createPersonWithHttpInfo(PersonCreateDto personCreateDto,) async {
// ignore: prefer_const_declarations
final path = r'/people';
final path = r'/person';
// ignore: prefer_final_locals
Object? postBody = personCreateDto;
@@ -63,13 +63,13 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'GET /people' operation and returns the [Response].
/// Performs an HTTP 'GET /person' operation and returns the [Response].
/// Parameters:
///
/// * [bool] withHidden:
Future<Response> getAllPeopleWithHttpInfo({ bool? withHidden, }) async {
// ignore: prefer_const_declarations
final path = r'/people';
final path = r'/person';
// ignore: prefer_final_locals
Object? postBody;
@@ -114,13 +114,13 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'GET /people/{id}' operation and returns the [Response].
/// Performs an HTTP 'GET /person/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getPersonWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/people/{id}'
final path = r'/person/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -162,13 +162,13 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'GET /people/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'GET /person/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getPersonAssetsWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/people/{id}/assets'
final path = r'/person/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -213,13 +213,13 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'GET /people/{id}/statistics' operation and returns the [Response].
/// Performs an HTTP 'GET /person/{id}/statistics' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getPersonStatisticsWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/people/{id}/statistics'
final path = r'/person/{id}/statistics'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -261,13 +261,13 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'GET /people/{id}/thumbnail' operation and returns the [Response].
/// Performs an HTTP 'GET /person/{id}/thumbnail' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getPersonThumbnailWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/people/{id}/thumbnail'
final path = r'/person/{id}/thumbnail'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -309,7 +309,7 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'POST /people/{id}/merge' operation and returns the [Response].
/// Performs an HTTP 'POST /person/{id}/merge' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -317,7 +317,7 @@ class PersonApi {
/// * [MergePersonDto] mergePersonDto (required):
Future<Response> mergePersonWithHttpInfo(String id, MergePersonDto mergePersonDto,) async {
// ignore: prefer_const_declarations
final path = r'/people/{id}/merge'
final path = r'/person/{id}/merge'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -364,7 +364,7 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'PUT /people/{id}/reassign' operation and returns the [Response].
/// Performs an HTTP 'PUT /person/{id}/reassign' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -372,7 +372,7 @@ class PersonApi {
/// * [AssetFaceUpdateDto] assetFaceUpdateDto (required):
Future<Response> reassignFacesWithHttpInfo(String id, AssetFaceUpdateDto assetFaceUpdateDto,) async {
// ignore: prefer_const_declarations
final path = r'/people/{id}/reassign'
final path = r'/person/{id}/reassign'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -419,13 +419,13 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'PUT /people' operation and returns the [Response].
/// Performs an HTTP 'PUT /person' operation and returns the [Response].
/// Parameters:
///
/// * [PeopleUpdateDto] peopleUpdateDto (required):
Future<Response> updatePeopleWithHttpInfo(PeopleUpdateDto peopleUpdateDto,) async {
// ignore: prefer_const_declarations
final path = r'/people';
final path = r'/person';
// ignore: prefer_final_locals
Object? postBody = peopleUpdateDto;
@@ -469,7 +469,7 @@ class PersonApi {
return null;
}
/// Performs an HTTP 'PUT /people/{id}' operation and returns the [Response].
/// Performs an HTTP 'PUT /person/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -477,7 +477,7 @@ class PersonApi {
/// * [PersonUpdateDto] personUpdateDto (required):
Future<Response> updatePersonWithHttpInfo(String id, PersonUpdateDto personUpdateDto,) async {
// ignore: prefer_const_declarations
final path = r'/people/{id}'
final path = r'/person/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals

View File

@@ -98,6 +98,47 @@ class ServerInfoApi {
return null;
}
/// Performs an HTTP 'GET /server-info' operation and returns the [Response].
Future<Response> getServerInfoWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/server-info';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<ServerInfoResponseDto?> getServerInfo() async {
final response = await getServerInfoWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerInfoResponseDto',) as ServerInfoResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /server-info/statistics' operation and returns the [Response].
Future<Response> getServerStatisticsWithHttpInfo() async {
// ignore: prefer_const_declarations
@@ -180,47 +221,6 @@ class ServerInfoApi {
return null;
}
/// Performs an HTTP 'GET /server-info/storage' operation and returns the [Response].
Future<Response> getStorageWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/server-info/storage';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<ServerStorageResponseDto?> getStorage() async {
final response = await getStorageWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerStorageResponseDto',) as ServerStorageResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /server-info/media-types' operation and returns the [Response].
Future<Response> getSupportedMediaTypesWithHttpInfo() async {
// ignore: prefer_const_declarations

View File

@@ -16,7 +16,7 @@ class SharedLinkApi {
final ApiClient apiClient;
/// Performs an HTTP 'PUT /shared-links/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'PUT /shared-link/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -26,7 +26,7 @@ class SharedLinkApi {
/// * [String] key:
Future<Response> addSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/shared-links/{id}/assets'
final path = r'/shared-link/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -79,13 +79,13 @@ class SharedLinkApi {
return null;
}
/// Performs an HTTP 'POST /shared-links' operation and returns the [Response].
/// Performs an HTTP 'POST /shared-link' operation and returns the [Response].
/// Parameters:
///
/// * [SharedLinkCreateDto] sharedLinkCreateDto (required):
Future<Response> createSharedLinkWithHttpInfo(SharedLinkCreateDto sharedLinkCreateDto,) async {
// ignore: prefer_const_declarations
final path = r'/shared-links';
final path = r'/shared-link';
// ignore: prefer_final_locals
Object? postBody = sharedLinkCreateDto;
@@ -126,10 +126,10 @@ class SharedLinkApi {
return null;
}
/// Performs an HTTP 'GET /shared-links' operation and returns the [Response].
/// Performs an HTTP 'GET /shared-link' operation and returns the [Response].
Future<Response> getAllSharedLinksWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/shared-links';
final path = r'/shared-link';
// ignore: prefer_final_locals
Object? postBody;
@@ -170,7 +170,7 @@ class SharedLinkApi {
return null;
}
/// Performs an HTTP 'GET /shared-links/me' operation and returns the [Response].
/// Performs an HTTP 'GET /shared-link/me' operation and returns the [Response].
/// Parameters:
///
/// * [String] key:
@@ -180,7 +180,7 @@ class SharedLinkApi {
/// * [String] token:
Future<Response> getMySharedLinkWithHttpInfo({ String? key, String? password, String? token, }) async {
// ignore: prefer_const_declarations
final path = r'/shared-links/me';
final path = r'/shared-link/me';
// ignore: prefer_final_locals
Object? postBody;
@@ -235,13 +235,13 @@ class SharedLinkApi {
return null;
}
/// Performs an HTTP 'GET /shared-links/{id}' operation and returns the [Response].
/// Performs an HTTP 'GET /shared-link/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getSharedLinkByIdWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/shared-links/{id}'
final path = r'/shared-link/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -283,13 +283,13 @@ class SharedLinkApi {
return null;
}
/// Performs an HTTP 'DELETE /shared-links/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /shared-link/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> removeSharedLinkWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/shared-links/{id}'
final path = r'/shared-link/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -323,7 +323,7 @@ class SharedLinkApi {
}
}
/// Performs an HTTP 'DELETE /shared-links/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'DELETE /shared-link/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -333,7 +333,7 @@ class SharedLinkApi {
/// * [String] key:
Future<Response> removeSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, }) async {
// ignore: prefer_const_declarations
final path = r'/shared-links/{id}/assets'
final path = r'/shared-link/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -386,7 +386,7 @@ class SharedLinkApi {
return null;
}
/// Performs an HTTP 'PATCH /shared-links/{id}' operation and returns the [Response].
/// Performs an HTTP 'PATCH /shared-link/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -394,7 +394,7 @@ class SharedLinkApi {
/// * [SharedLinkEditDto] sharedLinkEditDto (required):
Future<Response> updateSharedLinkWithHttpInfo(String id, SharedLinkEditDto sharedLinkEditDto,) async {
// ignore: prefer_const_declarations
final path = r'/shared-links/{id}'
final path = r'/shared-link/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals

View File

@@ -16,13 +16,13 @@ class TagApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /tags' operation and returns the [Response].
/// Performs an HTTP 'POST /tag' operation and returns the [Response].
/// Parameters:
///
/// * [CreateTagDto] createTagDto (required):
Future<Response> createTagWithHttpInfo(CreateTagDto createTagDto,) async {
// ignore: prefer_const_declarations
final path = r'/tags';
final path = r'/tag';
// ignore: prefer_final_locals
Object? postBody = createTagDto;
@@ -63,13 +63,13 @@ class TagApi {
return null;
}
/// Performs an HTTP 'DELETE /tags/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /tag/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> deleteTagWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/tags/{id}'
final path = r'/tag/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -103,10 +103,10 @@ class TagApi {
}
}
/// Performs an HTTP 'GET /tags' operation and returns the [Response].
/// Performs an HTTP 'GET /tag' operation and returns the [Response].
Future<Response> getAllTagsWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/tags';
final path = r'/tag';
// ignore: prefer_final_locals
Object? postBody;
@@ -147,13 +147,13 @@ class TagApi {
return null;
}
/// Performs an HTTP 'GET /tags/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'GET /tag/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getTagAssetsWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/tags/{id}/assets'
final path = r'/tag/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -198,13 +198,13 @@ class TagApi {
return null;
}
/// Performs an HTTP 'GET /tags/{id}' operation and returns the [Response].
/// Performs an HTTP 'GET /tag/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getTagByIdWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/tags/{id}'
final path = r'/tag/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -246,7 +246,7 @@ class TagApi {
return null;
}
/// Performs an HTTP 'PUT /tags/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'PUT /tag/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -254,7 +254,7 @@ class TagApi {
/// * [AssetIdsDto] assetIdsDto (required):
Future<Response> tagAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto,) async {
// ignore: prefer_const_declarations
final path = r'/tags/{id}/assets'
final path = r'/tag/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -301,7 +301,7 @@ class TagApi {
return null;
}
/// Performs an HTTP 'DELETE /tags/{id}/assets' operation and returns the [Response].
/// Performs an HTTP 'DELETE /tag/{id}/assets' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -309,7 +309,7 @@ class TagApi {
/// * [AssetIdsDto] assetIdsDto (required):
Future<Response> untagAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto,) async {
// ignore: prefer_const_declarations
final path = r'/tags/{id}/assets'
final path = r'/tag/{id}/assets'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -356,7 +356,7 @@ class TagApi {
return null;
}
/// Performs an HTTP 'PATCH /tags/{id}' operation and returns the [Response].
/// Performs an HTTP 'PATCH /tag/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
@@ -364,7 +364,7 @@ class TagApi {
/// * [UpdateTagDto] updateTagDto (required):
Future<Response> updateTagWithHttpInfo(String id, UpdateTagDto updateTagDto,) async {
// ignore: prefer_const_declarations
final path = r'/tags/{id}'
final path = r'/tag/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals

View File

@@ -16,13 +16,13 @@ class UserApi {
final ApiClient apiClient;
/// Performs an HTTP 'POST /users/profile-image' operation and returns the [Response].
/// Performs an HTTP 'POST /user/profile-image' operation and returns the [Response].
/// Parameters:
///
/// * [MultipartFile] file (required):
Future<Response> createProfileImageWithHttpInfo(MultipartFile file,) async {
// ignore: prefer_const_declarations
final path = r'/users/profile-image';
final path = r'/user/profile-image';
// ignore: prefer_final_locals
Object? postBody;
@@ -73,16 +73,16 @@ class UserApi {
return null;
}
/// Performs an HTTP 'POST /admin/users' operation and returns the [Response].
/// Performs an HTTP 'POST /user' operation and returns the [Response].
/// Parameters:
///
/// * [UserAdminCreateDto] userAdminCreateDto (required):
Future<Response> createUserAdminWithHttpInfo(UserAdminCreateDto userAdminCreateDto,) async {
/// * [CreateUserDto] createUserDto (required):
Future<Response> createUserWithHttpInfo(CreateUserDto createUserDto,) async {
// ignore: prefer_const_declarations
final path = r'/admin/users';
final path = r'/user';
// ignore: prefer_final_locals
Object? postBody = userAdminCreateDto;
Object? postBody = createUserDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
@@ -104,9 +104,9 @@ class UserApi {
/// Parameters:
///
/// * [UserAdminCreateDto] userAdminCreateDto (required):
Future<UserAdminResponseDto?> createUserAdmin(UserAdminCreateDto userAdminCreateDto,) async {
final response = await createUserAdminWithHttpInfo(userAdminCreateDto,);
/// * [CreateUserDto] createUserDto (required):
Future<UserResponseDto?> createUser(CreateUserDto createUserDto,) async {
final response = await createUserWithHttpInfo(createUserDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -114,16 +114,16 @@ class UserApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;
}
/// Performs an HTTP 'DELETE /users/profile-image' operation and returns the [Response].
/// Performs an HTTP 'DELETE /user/profile-image' operation and returns the [Response].
Future<Response> deleteProfileImageWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/users/profile-image';
final path = r'/user/profile-image';
// ignore: prefer_final_locals
Object? postBody;
@@ -153,19 +153,19 @@ class UserApi {
}
}
/// Performs an HTTP 'DELETE /admin/users/{id}' operation and returns the [Response].
/// Performs an HTTP 'DELETE /user/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
///
/// * [UserAdminDeleteDto] userAdminDeleteDto (required):
Future<Response> deleteUserAdminWithHttpInfo(String id, UserAdminDeleteDto userAdminDeleteDto,) async {
/// * [DeleteUserDto] deleteUserDto (required):
Future<Response> deleteUserWithHttpInfo(String id, DeleteUserDto deleteUserDto,) async {
// ignore: prefer_const_declarations
final path = r'/admin/users/{id}'
final path = r'/user/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody = userAdminDeleteDto;
Object? postBody = deleteUserDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
@@ -189,9 +189,9 @@ class UserApi {
///
/// * [String] id (required):
///
/// * [UserAdminDeleteDto] userAdminDeleteDto (required):
Future<UserAdminResponseDto?> deleteUserAdmin(String id, UserAdminDeleteDto userAdminDeleteDto,) async {
final response = await deleteUserAdminWithHttpInfo(id, userAdminDeleteDto,);
/// * [DeleteUserDto] deleteUserDto (required):
Future<UserResponseDto?> deleteUser(String id, DeleteUserDto deleteUserDto,) async {
final response = await deleteUserWithHttpInfo(id, deleteUserDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -199,16 +199,68 @@ class UserApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /users/me' operation and returns the [Response].
Future<Response> getMyUserWithHttpInfo() async {
/// Performs an HTTP 'GET /user' operation and returns the [Response].
/// Parameters:
///
/// * [bool] isAll (required):
Future<Response> getAllUsersWithHttpInfo(bool isAll,) async {
// ignore: prefer_const_declarations
final path = r'/users/me';
final path = r'/user';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
queryParams.addAll(_queryParams('', 'isAll', isAll));
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [bool] isAll (required):
Future<List<UserResponseDto>?> getAllUsers(bool isAll,) async {
final response = await getAllUsersWithHttpInfo(isAll,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<UserResponseDto>') as List)
.cast<UserResponseDto>()
.toList(growable: false);
}
return null;
}
/// Performs an HTTP 'GET /user/me' operation and returns the [Response].
Future<Response> getMyUserInfoWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/user/me';
// ignore: prefer_final_locals
Object? postBody;
@@ -231,8 +283,8 @@ class UserApi {
);
}
Future<UserAdminResponseDto?> getMyUser() async {
final response = await getMyUserWithHttpInfo();
Future<UserResponseDto?> getMyUserInfo() async {
final response = await getMyUserInfoWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -240,19 +292,19 @@ class UserApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /users/{id}/profile-image' operation and returns the [Response].
/// Performs an HTTP 'GET /user/profile-image/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getProfileImageWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/users/{id}/profile-image'
final path = r'/user/profile-image/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -294,13 +346,13 @@ class UserApi {
return null;
}
/// Performs an HTTP 'GET /users/{id}' operation and returns the [Response].
/// Performs an HTTP 'GET /user/info/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getUserWithHttpInfo(String id,) async {
Future<Response> getUserByIdWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/users/{id}'
final path = r'/user/info/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -327,8 +379,8 @@ class UserApi {
/// Parameters:
///
/// * [String] id (required):
Future<UserResponseDto?> getUser(String id,) async {
final response = await getUserWithHttpInfo(id,);
Future<UserResponseDto?> getUserById(String id,) async {
final response = await getUserByIdWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -342,61 +394,13 @@ class UserApi {
return null;
}
/// Performs an HTTP 'GET /admin/users/{id}' operation and returns the [Response].
/// Performs an HTTP 'POST /user/{id}/restore' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> getUserAdminWithHttpInfo(String id,) async {
Future<Response> restoreUserWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/admin/users/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [String] id (required):
Future<UserAdminResponseDto?> getUserAdmin(String id,) async {
final response = await getUserAdminWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
}
return null;
}
/// Performs an HTTP 'POST /admin/users/{id}/restore' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
Future<Response> restoreUserAdminWithHttpInfo(String id,) async {
// ignore: prefer_const_declarations
final path = r'/admin/users/{id}/restore'
final path = r'/user/{id}/restore'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
@@ -423,8 +427,8 @@ class UserApi {
/// Parameters:
///
/// * [String] id (required):
Future<UserAdminResponseDto?> restoreUserAdmin(String id,) async {
final response = await restoreUserAdminWithHttpInfo(id,);
Future<UserResponseDto?> restoreUser(String id,) async {
final response = await restoreUserWithHttpInfo(id,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -432,120 +436,22 @@ class UserApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /users' operation and returns the [Response].
Future<Response> searchUsersWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/users';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<List<UserResponseDto>?> searchUsers() async {
final response = await searchUsersWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<UserResponseDto>') as List)
.cast<UserResponseDto>()
.toList(growable: false);
}
return null;
}
/// Performs an HTTP 'GET /admin/users' operation and returns the [Response].
/// Performs an HTTP 'PUT /user' operation and returns the [Response].
/// Parameters:
///
/// * [bool] withDeleted:
Future<Response> searchUsersAdminWithHttpInfo({ bool? withDeleted, }) async {
/// * [UpdateUserDto] updateUserDto (required):
Future<Response> updateUserWithHttpInfo(UpdateUserDto updateUserDto,) async {
// ignore: prefer_const_declarations
final path = r'/admin/users';
final path = r'/user';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (withDeleted != null) {
queryParams.addAll(_queryParams('', 'withDeleted', withDeleted));
}
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [bool] withDeleted:
Future<List<UserAdminResponseDto>?> searchUsersAdmin({ bool? withDeleted, }) async {
final response = await searchUsersAdminWithHttpInfo( withDeleted: withDeleted, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
final responseBody = await _decodeBodyBytes(response);
return (await apiClient.deserializeAsync(responseBody, 'List<UserAdminResponseDto>') as List)
.cast<UserAdminResponseDto>()
.toList(growable: false);
}
return null;
}
/// Performs an HTTP 'PUT /users/me' operation and returns the [Response].
/// Parameters:
///
/// * [UserUpdateMeDto] userUpdateMeDto (required):
Future<Response> updateMyUserWithHttpInfo(UserUpdateMeDto userUpdateMeDto,) async {
// ignore: prefer_const_declarations
final path = r'/users/me';
// ignore: prefer_final_locals
Object? postBody = userUpdateMeDto;
Object? postBody = updateUserDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
@@ -567,9 +473,9 @@ class UserApi {
/// Parameters:
///
/// * [UserUpdateMeDto] userUpdateMeDto (required):
Future<UserAdminResponseDto?> updateMyUser(UserUpdateMeDto userUpdateMeDto,) async {
final response = await updateMyUserWithHttpInfo(userUpdateMeDto,);
/// * [UpdateUserDto] updateUserDto (required):
Future<UserResponseDto?> updateUser(UpdateUserDto updateUserDto,) async {
final response = await updateUserWithHttpInfo(updateUserDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -577,59 +483,7 @@ class UserApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
}
return null;
}
/// Performs an HTTP 'PUT /admin/users/{id}' operation and returns the [Response].
/// Parameters:
///
/// * [String] id (required):
///
/// * [UserAdminUpdateDto] userAdminUpdateDto (required):
Future<Response> updateUserAdminWithHttpInfo(String id, UserAdminUpdateDto userAdminUpdateDto,) async {
// ignore: prefer_const_declarations
final path = r'/admin/users/{id}'
.replaceAll('{id}', id);
// ignore: prefer_final_locals
Object? postBody = userAdminUpdateDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
path,
'PUT',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Parameters:
///
/// * [String] id (required):
///
/// * [UserAdminUpdateDto] userAdminUpdateDto (required):
Future<UserAdminResponseDto?> updateUserAdmin(String id, UserAdminUpdateDto userAdminUpdateDto,) async {
final response = await updateUserAdminWithHttpInfo(id, userAdminUpdateDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserAdminResponseDto',) as UserAdminResponseDto;
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'UserResponseDto',) as UserResponseDto;
}
return null;

View File

@@ -250,10 +250,6 @@ class ApiClient {
return AssetJobNameTypeTransformer().decode(value);
case 'AssetJobsDto':
return AssetJobsDto.fromJson(value);
case 'AssetMediaResponseDto':
return AssetMediaResponseDto.fromJson(value);
case 'AssetMediaStatus':
return AssetMediaStatusTypeTransformer().decode(value);
case 'AssetOrder':
return AssetOrderTypeTransformer().decode(value);
case 'AssetResponseDto':
@@ -292,6 +288,10 @@ class ApiClient {
return CreateProfileImageResponseDto.fromJson(value);
case 'CreateTagDto':
return CreateTagDto.fromJson(value);
case 'CreateUserDto':
return CreateUserDto.fromJson(value);
case 'DeleteUserDto':
return DeleteUserDto.fromJson(value);
case 'DownloadArchiveInfo':
return DownloadArchiveInfo.fromJson(value);
case 'DownloadInfoDto':
@@ -428,14 +428,14 @@ class ApiClient {
return ServerConfigDto.fromJson(value);
case 'ServerFeaturesDto':
return ServerFeaturesDto.fromJson(value);
case 'ServerInfoResponseDto':
return ServerInfoResponseDto.fromJson(value);
case 'ServerMediaTypesResponseDto':
return ServerMediaTypesResponseDto.fromJson(value);
case 'ServerPingResponse':
return ServerPingResponse.fromJson(value);
case 'ServerStatsResponseDto':
return ServerStatsResponseDto.fromJson(value);
case 'ServerStorageResponseDto':
return ServerStorageResponseDto.fromJson(value);
case 'ServerThemeDto':
return ServerThemeDto.fromJson(value);
case 'ServerVersionResponseDto':
@@ -532,24 +532,18 @@ class ApiClient {
return UpdateStackParentDto.fromJson(value);
case 'UpdateTagDto':
return UpdateTagDto.fromJson(value);
case 'UpdateUserDto':
return UpdateUserDto.fromJson(value);
case 'UsageByUserDto':
return UsageByUserDto.fromJson(value);
case 'UserAdminCreateDto':
return UserAdminCreateDto.fromJson(value);
case 'UserAdminDeleteDto':
return UserAdminDeleteDto.fromJson(value);
case 'UserAdminResponseDto':
return UserAdminResponseDto.fromJson(value);
case 'UserAdminUpdateDto':
return UserAdminUpdateDto.fromJson(value);
case 'UserAvatarColor':
return UserAvatarColorTypeTransformer().decode(value);
case 'UserDto':
return UserDto.fromJson(value);
case 'UserResponseDto':
return UserResponseDto.fromJson(value);
case 'UserStatus':
return UserStatusTypeTransformer().decode(value);
case 'UserUpdateMeDto':
return UserUpdateMeDto.fromJson(value);
case 'ValidateAccessTokenResponseDto':
return ValidateAccessTokenResponseDto.fromJson(value);
case 'ValidateLibraryDto':

View File

@@ -61,9 +61,6 @@ String parameterToString(dynamic value) {
if (value is AssetJobName) {
return AssetJobNameTypeTransformer().encode(value).toString();
}
if (value is AssetMediaStatus) {
return AssetMediaStatusTypeTransformer().encode(value).toString();
}
if (value is AssetOrder) {
return AssetOrderTypeTransformer().encode(value).toString();
}

View File

@@ -31,7 +31,7 @@ class ActivityResponseDto {
ActivityResponseDtoTypeEnum type;
UserResponseDto user;
UserDto user;
@override
bool operator ==(Object other) => identical(this, other) || other is ActivityResponseDto &&
@@ -87,7 +87,7 @@ class ActivityResponseDto {
createdAt: mapDateTime(json, r'createdAt', r'')!,
id: mapValueOfType<String>(json, r'id')!,
type: ActivityResponseDtoTypeEnum.fromJson(json[r'type'])!,
user: UserResponseDto.fromJson(json[r'user'])!,
user: UserDto.fromJson(json[r'user'])!,
);
}
return null;

View File

@@ -14,25 +14,32 @@ class AddUsersDto {
/// Returns a new [AddUsersDto] instance.
AddUsersDto({
this.albumUsers = const [],
this.sharedUserIds = const [],
});
List<AlbumUserAddDto> albumUsers;
/// This property was deprecated in v1.102.0
List<String> sharedUserIds;
@override
bool operator ==(Object other) => identical(this, other) || other is AddUsersDto &&
_deepEquality.equals(other.albumUsers, albumUsers);
_deepEquality.equals(other.albumUsers, albumUsers) &&
_deepEquality.equals(other.sharedUserIds, sharedUserIds);
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(albumUsers.hashCode);
(albumUsers.hashCode) +
(sharedUserIds.hashCode);
@override
String toString() => 'AddUsersDto[albumUsers=$albumUsers]';
String toString() => 'AddUsersDto[albumUsers=$albumUsers, sharedUserIds=$sharedUserIds]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'albumUsers'] = this.albumUsers;
json[r'sharedUserIds'] = this.sharedUserIds;
return json;
}
@@ -45,6 +52,9 @@ class AddUsersDto {
return AddUsersDto(
albumUsers: AlbumUserAddDto.listFromJson(json[r'albumUsers']),
sharedUserIds: json[r'sharedUserIds'] is Iterable
? (json[r'sharedUserIds'] as Iterable).cast<String>().toList(growable: false)
: const [],
);
}
return null;

View File

@@ -29,6 +29,7 @@ class AlbumResponseDto {
required this.owner,
required this.ownerId,
required this.shared,
this.sharedUsers = const [],
this.startDate,
required this.updatedAt,
});
@@ -83,6 +84,9 @@ class AlbumResponseDto {
bool shared;
/// This property was deprecated in v1.102.0
List<UserResponseDto> sharedUsers;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -111,6 +115,7 @@ class AlbumResponseDto {
other.owner == owner &&
other.ownerId == ownerId &&
other.shared == shared &&
_deepEquality.equals(other.sharedUsers, sharedUsers) &&
other.startDate == startDate &&
other.updatedAt == updatedAt;
@@ -133,11 +138,12 @@ class AlbumResponseDto {
(owner.hashCode) +
(ownerId.hashCode) +
(shared.hashCode) +
(sharedUsers.hashCode) +
(startDate == null ? 0 : startDate!.hashCode) +
(updatedAt.hashCode);
@override
String toString() => 'AlbumResponseDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, albumUsers=$albumUsers, assetCount=$assetCount, assets=$assets, createdAt=$createdAt, description=$description, endDate=$endDate, hasSharedLink=$hasSharedLink, id=$id, isActivityEnabled=$isActivityEnabled, lastModifiedAssetTimestamp=$lastModifiedAssetTimestamp, order=$order, owner=$owner, ownerId=$ownerId, shared=$shared, startDate=$startDate, updatedAt=$updatedAt]';
String toString() => 'AlbumResponseDto[albumName=$albumName, albumThumbnailAssetId=$albumThumbnailAssetId, albumUsers=$albumUsers, assetCount=$assetCount, assets=$assets, createdAt=$createdAt, description=$description, endDate=$endDate, hasSharedLink=$hasSharedLink, id=$id, isActivityEnabled=$isActivityEnabled, lastModifiedAssetTimestamp=$lastModifiedAssetTimestamp, order=$order, owner=$owner, ownerId=$ownerId, shared=$shared, sharedUsers=$sharedUsers, startDate=$startDate, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -173,6 +179,7 @@ class AlbumResponseDto {
json[r'owner'] = this.owner;
json[r'ownerId'] = this.ownerId;
json[r'shared'] = this.shared;
json[r'sharedUsers'] = this.sharedUsers;
if (this.startDate != null) {
json[r'startDate'] = this.startDate!.toUtc().toIso8601String();
} else {
@@ -206,6 +213,7 @@ class AlbumResponseDto {
owner: UserResponseDto.fromJson(json[r'owner'])!,
ownerId: mapValueOfType<String>(json, r'ownerId')!,
shared: mapValueOfType<bool>(json, r'shared')!,
sharedUsers: UserResponseDto.listFromJson(json[r'sharedUsers']),
startDate: mapDateTime(json, r'startDate', r''),
updatedAt: mapDateTime(json, r'updatedAt', r'')!,
);
@@ -268,6 +276,7 @@ class AlbumResponseDto {
'owner',
'ownerId',
'shared',
'sharedUsers',
'updatedAt',
};
}

View File

@@ -14,7 +14,6 @@ class AssetBulkUpdateDto {
/// Returns a new [AssetBulkUpdateDto] instance.
AssetBulkUpdateDto({
this.dateTimeOriginal,
this.duplicateId,
this.ids = const [],
this.isArchived,
this.isFavorite,
@@ -32,8 +31,6 @@ class AssetBulkUpdateDto {
///
String? dateTimeOriginal;
String? duplicateId;
List<String> ids;
///
@@ -87,7 +84,6 @@ class AssetBulkUpdateDto {
@override
bool operator ==(Object other) => identical(this, other) || other is AssetBulkUpdateDto &&
other.dateTimeOriginal == dateTimeOriginal &&
other.duplicateId == duplicateId &&
_deepEquality.equals(other.ids, ids) &&
other.isArchived == isArchived &&
other.isFavorite == isFavorite &&
@@ -100,7 +96,6 @@ class AssetBulkUpdateDto {
int get hashCode =>
// ignore: unnecessary_parenthesis
(dateTimeOriginal == null ? 0 : dateTimeOriginal!.hashCode) +
(duplicateId == null ? 0 : duplicateId!.hashCode) +
(ids.hashCode) +
(isArchived == null ? 0 : isArchived!.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode) +
@@ -110,7 +105,7 @@ class AssetBulkUpdateDto {
(stackParentId == null ? 0 : stackParentId!.hashCode);
@override
String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, duplicateId=$duplicateId, ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, removeParent=$removeParent, stackParentId=$stackParentId]';
String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, removeParent=$removeParent, stackParentId=$stackParentId]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -118,11 +113,6 @@ class AssetBulkUpdateDto {
json[r'dateTimeOriginal'] = this.dateTimeOriginal;
} else {
// json[r'dateTimeOriginal'] = null;
}
if (this.duplicateId != null) {
json[r'duplicateId'] = this.duplicateId;
} else {
// json[r'duplicateId'] = null;
}
json[r'ids'] = this.ids;
if (this.isArchived != null) {
@@ -167,7 +157,6 @@ class AssetBulkUpdateDto {
return AssetBulkUpdateDto(
dateTimeOriginal: mapValueOfType<String>(json, r'dateTimeOriginal'),
duplicateId: mapValueOfType<String>(json, r'duplicateId'),
ids: json[r'ids'] is Iterable
? (json[r'ids'] as Iterable).cast<String>().toList(growable: false)
: const [],

View File

@@ -1,106 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class AssetMediaResponseDto {
/// Returns a new [AssetMediaResponseDto] instance.
AssetMediaResponseDto({
required this.id,
required this.status,
});
String id;
AssetMediaStatus status;
@override
bool operator ==(Object other) => identical(this, other) || other is AssetMediaResponseDto &&
other.id == id &&
other.status == status;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(id.hashCode) +
(status.hashCode);
@override
String toString() => 'AssetMediaResponseDto[id=$id, status=$status]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'id'] = this.id;
json[r'status'] = this.status;
return json;
}
/// Returns a new [AssetMediaResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static AssetMediaResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return AssetMediaResponseDto(
id: mapValueOfType<String>(json, r'id')!,
status: AssetMediaStatus.fromJson(json[r'status'])!,
);
}
return null;
}
static List<AssetMediaResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetMediaResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetMediaResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, AssetMediaResponseDto> mapFromJson(dynamic json) {
final map = <String, AssetMediaResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = AssetMediaResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of AssetMediaResponseDto-objects as value to a dart map
static Map<String, List<AssetMediaResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<AssetMediaResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = AssetMediaResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
'status',
};
}

View File

@@ -1,85 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class AssetMediaStatus {
/// Instantiate a new enum with the provided [value].
const AssetMediaStatus._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const replaced = AssetMediaStatus._(r'replaced');
static const duplicate = AssetMediaStatus._(r'duplicate');
/// List of all possible values in this [enum][AssetMediaStatus].
static const values = <AssetMediaStatus>[
replaced,
duplicate,
];
static AssetMediaStatus? fromJson(dynamic value) => AssetMediaStatusTypeTransformer().decode(value);
static List<AssetMediaStatus> listFromJson(dynamic json, {bool growable = false,}) {
final result = <AssetMediaStatus>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = AssetMediaStatus.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [AssetMediaStatus] to String,
/// and [decode] dynamic data back to [AssetMediaStatus].
class AssetMediaStatusTypeTransformer {
factory AssetMediaStatusTypeTransformer() => _instance ??= const AssetMediaStatusTypeTransformer._();
const AssetMediaStatusTypeTransformer._();
String encode(AssetMediaStatus data) => data.value;
/// Decodes a [dynamic value][data] to a AssetMediaStatus.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
AssetMediaStatus? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'replaced': return AssetMediaStatus.replaced;
case r'duplicate': return AssetMediaStatus.duplicate;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [AssetMediaStatusTypeTransformer] instance.
static AssetMediaStatusTypeTransformer? _instance;
}

View File

@@ -24,8 +24,10 @@ class AssetResponseDto {
required this.hasMetadata,
required this.id,
required this.isArchived,
this.isExternal,
required this.isFavorite,
required this.isOffline,
this.isReadOnly,
required this.isTrashed,
this.libraryId,
this.livePhotoVideoId,
@@ -75,10 +77,28 @@ class AssetResponseDto {
bool isArchived;
/// This property was deprecated in v1.104.0
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? isExternal;
bool isFavorite;
bool isOffline;
/// This property was deprecated in v1.104.0
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? isReadOnly;
bool isTrashed;
/// This property was deprecated in v1.106.0
@@ -141,8 +161,10 @@ class AssetResponseDto {
other.hasMetadata == hasMetadata &&
other.id == id &&
other.isArchived == isArchived &&
other.isExternal == isExternal &&
other.isFavorite == isFavorite &&
other.isOffline == isOffline &&
other.isReadOnly == isReadOnly &&
other.isTrashed == isTrashed &&
other.libraryId == libraryId &&
other.livePhotoVideoId == livePhotoVideoId &&
@@ -176,8 +198,10 @@ class AssetResponseDto {
(hasMetadata.hashCode) +
(id.hashCode) +
(isArchived.hashCode) +
(isExternal == null ? 0 : isExternal!.hashCode) +
(isFavorite.hashCode) +
(isOffline.hashCode) +
(isReadOnly == null ? 0 : isReadOnly!.hashCode) +
(isTrashed.hashCode) +
(libraryId == null ? 0 : libraryId!.hashCode) +
(livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
@@ -198,7 +222,7 @@ class AssetResponseDto {
(updatedAt.hashCode);
@override
String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duplicateId=$duplicateId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isFavorite=$isFavorite, isOffline=$isOffline, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, stack=$stack, stackCount=$stackCount, stackParentId=$stackParentId, tags=$tags, thumbhash=$thumbhash, type=$type, updatedAt=$updatedAt]';
String toString() => 'AssetResponseDto[checksum=$checksum, deviceAssetId=$deviceAssetId, deviceId=$deviceId, duplicateId=$duplicateId, duration=$duration, exifInfo=$exifInfo, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, hasMetadata=$hasMetadata, id=$id, isArchived=$isArchived, isExternal=$isExternal, isFavorite=$isFavorite, isOffline=$isOffline, isReadOnly=$isReadOnly, isTrashed=$isTrashed, libraryId=$libraryId, livePhotoVideoId=$livePhotoVideoId, localDateTime=$localDateTime, originalFileName=$originalFileName, originalPath=$originalPath, owner=$owner, ownerId=$ownerId, people=$people, resized=$resized, smartInfo=$smartInfo, stack=$stack, stackCount=$stackCount, stackParentId=$stackParentId, tags=$tags, thumbhash=$thumbhash, type=$type, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -221,8 +245,18 @@ class AssetResponseDto {
json[r'hasMetadata'] = this.hasMetadata;
json[r'id'] = this.id;
json[r'isArchived'] = this.isArchived;
if (this.isExternal != null) {
json[r'isExternal'] = this.isExternal;
} else {
// json[r'isExternal'] = null;
}
json[r'isFavorite'] = this.isFavorite;
json[r'isOffline'] = this.isOffline;
if (this.isReadOnly != null) {
json[r'isReadOnly'] = this.isReadOnly;
} else {
// json[r'isReadOnly'] = null;
}
json[r'isTrashed'] = this.isTrashed;
if (this.libraryId != null) {
json[r'libraryId'] = this.libraryId;
@@ -291,8 +325,10 @@ class AssetResponseDto {
hasMetadata: mapValueOfType<bool>(json, r'hasMetadata')!,
id: mapValueOfType<String>(json, r'id')!,
isArchived: mapValueOfType<bool>(json, r'isArchived')!,
isExternal: mapValueOfType<bool>(json, r'isExternal'),
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
isOffline: mapValueOfType<bool>(json, r'isOffline')!,
isReadOnly: mapValueOfType<bool>(json, r'isReadOnly'),
isTrashed: mapValueOfType<bool>(json, r'isTrashed')!,
libraryId: mapValueOfType<String>(json, r'libraryId'),
livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),

View File

@@ -17,10 +17,12 @@ class CreateAlbumDto {
this.albumUsers = const [],
this.assetIds = const [],
this.description,
this.sharedWithUserIds = const [],
});
String albumName;
/// This property was added in v1.104.0
List<AlbumUserCreateDto> albumUsers;
List<String> assetIds;
@@ -33,12 +35,16 @@ class CreateAlbumDto {
///
String? description;
/// This property was deprecated in v1.104.0
List<String> sharedWithUserIds;
@override
bool operator ==(Object other) => identical(this, other) || other is CreateAlbumDto &&
other.albumName == albumName &&
_deepEquality.equals(other.albumUsers, albumUsers) &&
_deepEquality.equals(other.assetIds, assetIds) &&
other.description == description;
other.description == description &&
_deepEquality.equals(other.sharedWithUserIds, sharedWithUserIds);
@override
int get hashCode =>
@@ -46,10 +52,11 @@ class CreateAlbumDto {
(albumName.hashCode) +
(albumUsers.hashCode) +
(assetIds.hashCode) +
(description == null ? 0 : description!.hashCode);
(description == null ? 0 : description!.hashCode) +
(sharedWithUserIds.hashCode);
@override
String toString() => 'CreateAlbumDto[albumName=$albumName, albumUsers=$albumUsers, assetIds=$assetIds, description=$description]';
String toString() => 'CreateAlbumDto[albumName=$albumName, albumUsers=$albumUsers, assetIds=$assetIds, description=$description, sharedWithUserIds=$sharedWithUserIds]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -61,6 +68,7 @@ class CreateAlbumDto {
} else {
// json[r'description'] = null;
}
json[r'sharedWithUserIds'] = this.sharedWithUserIds;
return json;
}
@@ -78,6 +86,9 @@ class CreateAlbumDto {
? (json[r'assetIds'] as Iterable).cast<String>().toList(growable: false)
: const [],
description: mapValueOfType<String>(json, r'description'),
sharedWithUserIds: json[r'sharedWithUserIds'] is Iterable
? (json[r'sharedWithUserIds'] as Iterable).cast<String>().toList(growable: false)
: const [],
);
}
return null;

View File

@@ -10,9 +10,9 @@
part of openapi.api;
class UserAdminCreateDto {
/// Returns a new [UserAdminCreateDto] instance.
UserAdminCreateDto({
class CreateUserDto {
/// Returns a new [CreateUserDto] instance.
CreateUserDto({
required this.email,
this.memoriesEnabled,
required this.name,
@@ -59,7 +59,7 @@ class UserAdminCreateDto {
String? storageLabel;
@override
bool operator ==(Object other) => identical(this, other) || other is UserAdminCreateDto &&
bool operator ==(Object other) => identical(this, other) || other is CreateUserDto &&
other.email == email &&
other.memoriesEnabled == memoriesEnabled &&
other.name == name &&
@@ -82,7 +82,7 @@ class UserAdminCreateDto {
(storageLabel == null ? 0 : storageLabel!.hashCode);
@override
String toString() => 'UserAdminCreateDto[email=$email, memoriesEnabled=$memoriesEnabled, name=$name, notify=$notify, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
String toString() => 'CreateUserDto[email=$email, memoriesEnabled=$memoriesEnabled, name=$name, notify=$notify, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -117,14 +117,14 @@ class UserAdminCreateDto {
return json;
}
/// Returns a new [UserAdminCreateDto] instance and imports its values from
/// Returns a new [CreateUserDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UserAdminCreateDto? fromJson(dynamic value) {
static CreateUserDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return UserAdminCreateDto(
return CreateUserDto(
email: mapValueOfType<String>(json, r'email')!,
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
name: mapValueOfType<String>(json, r'name')!,
@@ -138,11 +138,11 @@ class UserAdminCreateDto {
return null;
}
static List<UserAdminCreateDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserAdminCreateDto>[];
static List<CreateUserDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <CreateUserDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserAdminCreateDto.fromJson(row);
final value = CreateUserDto.fromJson(row);
if (value != null) {
result.add(value);
}
@@ -151,12 +151,12 @@ class UserAdminCreateDto {
return result.toList(growable: growable);
}
static Map<String, UserAdminCreateDto> mapFromJson(dynamic json) {
final map = <String, UserAdminCreateDto>{};
static Map<String, CreateUserDto> mapFromJson(dynamic json) {
final map = <String, CreateUserDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UserAdminCreateDto.fromJson(entry.value);
final value = CreateUserDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
@@ -165,14 +165,14 @@ class UserAdminCreateDto {
return map;
}
// maps a json object with a list of UserAdminCreateDto-objects as value to a dart map
static Map<String, List<UserAdminCreateDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UserAdminCreateDto>>{};
// maps a json object with a list of CreateUserDto-objects as value to a dart map
static Map<String, List<CreateUserDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<CreateUserDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = UserAdminCreateDto.listFromJson(entry.value, growable: growable,);
map[entry.key] = CreateUserDto.listFromJson(entry.value, growable: growable,);
}
}
return map;

View File

@@ -10,9 +10,9 @@
part of openapi.api;
class UserAdminDeleteDto {
/// Returns a new [UserAdminDeleteDto] instance.
UserAdminDeleteDto({
class DeleteUserDto {
/// Returns a new [DeleteUserDto] instance.
DeleteUserDto({
this.force,
});
@@ -25,7 +25,7 @@ class UserAdminDeleteDto {
bool? force;
@override
bool operator ==(Object other) => identical(this, other) || other is UserAdminDeleteDto &&
bool operator ==(Object other) => identical(this, other) || other is DeleteUserDto &&
other.force == force;
@override
@@ -34,7 +34,7 @@ class UserAdminDeleteDto {
(force == null ? 0 : force!.hashCode);
@override
String toString() => 'UserAdminDeleteDto[force=$force]';
String toString() => 'DeleteUserDto[force=$force]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -46,25 +46,25 @@ class UserAdminDeleteDto {
return json;
}
/// Returns a new [UserAdminDeleteDto] instance and imports its values from
/// Returns a new [DeleteUserDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UserAdminDeleteDto? fromJson(dynamic value) {
static DeleteUserDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return UserAdminDeleteDto(
return DeleteUserDto(
force: mapValueOfType<bool>(json, r'force'),
);
}
return null;
}
static List<UserAdminDeleteDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserAdminDeleteDto>[];
static List<DeleteUserDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <DeleteUserDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserAdminDeleteDto.fromJson(row);
final value = DeleteUserDto.fromJson(row);
if (value != null) {
result.add(value);
}
@@ -73,12 +73,12 @@ class UserAdminDeleteDto {
return result.toList(growable: growable);
}
static Map<String, UserAdminDeleteDto> mapFromJson(dynamic json) {
final map = <String, UserAdminDeleteDto>{};
static Map<String, DeleteUserDto> mapFromJson(dynamic json) {
final map = <String, DeleteUserDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UserAdminDeleteDto.fromJson(entry.value);
final value = DeleteUserDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
@@ -87,14 +87,14 @@ class UserAdminDeleteDto {
return map;
}
// maps a json object with a list of UserAdminDeleteDto-objects as value to a dart map
static Map<String, List<UserAdminDeleteDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UserAdminDeleteDto>>{};
// maps a json object with a list of DeleteUserDto-objects as value to a dart map
static Map<String, List<DeleteUserDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<DeleteUserDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = UserAdminDeleteDto.listFromJson(entry.value, growable: growable,);
map[entry.key] = DeleteUserDto.listFromJson(entry.value, growable: growable,);
}
}
return map;

View File

@@ -14,30 +14,37 @@ class MemoryLaneResponseDto {
/// Returns a new [MemoryLaneResponseDto] instance.
MemoryLaneResponseDto({
this.assets = const [],
required this.title,
required this.yearsAgo,
});
List<AssetResponseDto> assets;
/// This property was deprecated in v1.100.0
String title;
int yearsAgo;
@override
bool operator ==(Object other) => identical(this, other) || other is MemoryLaneResponseDto &&
_deepEquality.equals(other.assets, assets) &&
other.title == title &&
other.yearsAgo == yearsAgo;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(assets.hashCode) +
(title.hashCode) +
(yearsAgo.hashCode);
@override
String toString() => 'MemoryLaneResponseDto[assets=$assets, yearsAgo=$yearsAgo]';
String toString() => 'MemoryLaneResponseDto[assets=$assets, title=$title, yearsAgo=$yearsAgo]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'assets'] = this.assets;
json[r'title'] = this.title;
json[r'yearsAgo'] = this.yearsAgo;
return json;
}
@@ -51,6 +58,7 @@ class MemoryLaneResponseDto {
return MemoryLaneResponseDto(
assets: AssetResponseDto.listFromJson(json[r'assets']),
title: mapValueOfType<String>(json, r'title')!,
yearsAgo: mapValueOfType<int>(json, r'yearsAgo')!,
);
}
@@ -100,6 +108,7 @@ class MemoryLaneResponseDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'assets',
'title',
'yearsAgo',
};
}

View File

@@ -39,6 +39,7 @@ class MetadataSearchDto {
this.page,
this.personIds = const [],
this.previewPath,
this.resizePath,
this.size,
this.state,
this.takenAfter,
@@ -49,6 +50,7 @@ class MetadataSearchDto {
this.type,
this.updatedAfter,
this.updatedBefore,
this.webpPath,
this.withArchived = false,
this.withDeleted,
this.withExif,
@@ -259,6 +261,15 @@ class MetadataSearchDto {
///
String? previewPath;
/// This property was deprecated in v1.100.0
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? resizePath;
/// Minimum value: 1
/// Maximum value: 1000
///
@@ -341,6 +352,15 @@ class MetadataSearchDto {
///
DateTime? updatedBefore;
/// This property was deprecated in v1.100.0
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? webpPath;
bool withArchived;
///
@@ -403,6 +423,7 @@ class MetadataSearchDto {
other.page == page &&
_deepEquality.equals(other.personIds, personIds) &&
other.previewPath == previewPath &&
other.resizePath == resizePath &&
other.size == size &&
other.state == state &&
other.takenAfter == takenAfter &&
@@ -413,6 +434,7 @@ class MetadataSearchDto {
other.type == type &&
other.updatedAfter == updatedAfter &&
other.updatedBefore == updatedBefore &&
other.webpPath == webpPath &&
other.withArchived == withArchived &&
other.withDeleted == withDeleted &&
other.withExif == withExif &&
@@ -448,6 +470,7 @@ class MetadataSearchDto {
(page == null ? 0 : page!.hashCode) +
(personIds.hashCode) +
(previewPath == null ? 0 : previewPath!.hashCode) +
(resizePath == null ? 0 : resizePath!.hashCode) +
(size == null ? 0 : size!.hashCode) +
(state == null ? 0 : state!.hashCode) +
(takenAfter == null ? 0 : takenAfter!.hashCode) +
@@ -458,6 +481,7 @@ class MetadataSearchDto {
(type == null ? 0 : type!.hashCode) +
(updatedAfter == null ? 0 : updatedAfter!.hashCode) +
(updatedBefore == null ? 0 : updatedBefore!.hashCode) +
(webpPath == null ? 0 : webpPath!.hashCode) +
(withArchived.hashCode) +
(withDeleted == null ? 0 : withDeleted!.hashCode) +
(withExif == null ? 0 : withExif!.hashCode) +
@@ -465,7 +489,7 @@ class MetadataSearchDto {
(withStacked == null ? 0 : withStacked!.hashCode);
@override
String toString() => 'MetadataSearchDto[checksum=$checksum, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, deviceAssetId=$deviceAssetId, deviceId=$deviceId, encodedVideoPath=$encodedVideoPath, id=$id, isArchived=$isArchived, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, isVisible=$isVisible, lensModel=$lensModel, libraryId=$libraryId, make=$make, model=$model, order=$order, originalFileName=$originalFileName, originalPath=$originalPath, page=$page, personIds=$personIds, previewPath=$previewPath, size=$size, state=$state, takenAfter=$takenAfter, takenBefore=$takenBefore, thumbnailPath=$thumbnailPath, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, withArchived=$withArchived, withDeleted=$withDeleted, withExif=$withExif, withPeople=$withPeople, withStacked=$withStacked]';
String toString() => 'MetadataSearchDto[checksum=$checksum, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, deviceAssetId=$deviceAssetId, deviceId=$deviceId, encodedVideoPath=$encodedVideoPath, id=$id, isArchived=$isArchived, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, isVisible=$isVisible, lensModel=$lensModel, libraryId=$libraryId, make=$make, model=$model, order=$order, originalFileName=$originalFileName, originalPath=$originalPath, page=$page, personIds=$personIds, previewPath=$previewPath, resizePath=$resizePath, size=$size, state=$state, takenAfter=$takenAfter, takenBefore=$takenBefore, thumbnailPath=$thumbnailPath, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, webpPath=$webpPath, withArchived=$withArchived, withDeleted=$withDeleted, withExif=$withExif, withPeople=$withPeople, withStacked=$withStacked]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -595,6 +619,11 @@ class MetadataSearchDto {
} else {
// json[r'previewPath'] = null;
}
if (this.resizePath != null) {
json[r'resizePath'] = this.resizePath;
} else {
// json[r'resizePath'] = null;
}
if (this.size != null) {
json[r'size'] = this.size;
} else {
@@ -644,6 +673,11 @@ class MetadataSearchDto {
json[r'updatedBefore'] = this.updatedBefore!.toUtc().toIso8601String();
} else {
// json[r'updatedBefore'] = null;
}
if (this.webpPath != null) {
json[r'webpPath'] = this.webpPath;
} else {
// json[r'webpPath'] = null;
}
json[r'withArchived'] = this.withArchived;
if (this.withDeleted != null) {
@@ -705,6 +739,7 @@ class MetadataSearchDto {
? (json[r'personIds'] as Iterable).cast<String>().toList(growable: false)
: const [],
previewPath: mapValueOfType<String>(json, r'previewPath'),
resizePath: mapValueOfType<String>(json, r'resizePath'),
size: num.parse('${json[r'size']}'),
state: mapValueOfType<String>(json, r'state'),
takenAfter: mapDateTime(json, r'takenAfter', r''),
@@ -715,6 +750,7 @@ class MetadataSearchDto {
type: AssetTypeEnum.fromJson(json[r'type']),
updatedAfter: mapDateTime(json, r'updatedAfter', r''),
updatedBefore: mapDateTime(json, r'updatedBefore', r''),
webpPath: mapValueOfType<String>(json, r'webpPath'),
withArchived: mapValueOfType<bool>(json, r'withArchived') ?? false,
withDeleted: mapValueOfType<bool>(json, r'withDeleted'),
withExif: mapValueOfType<bool>(json, r'withExif'),

View File

@@ -14,15 +14,30 @@ class PartnerResponseDto {
/// Returns a new [PartnerResponseDto] instance.
PartnerResponseDto({
required this.avatarColor,
required this.createdAt,
required this.deletedAt,
required this.email,
required this.id,
this.inTimeline,
required this.isAdmin,
this.memoriesEnabled,
required this.name,
required this.oauthId,
required this.profileImagePath,
required this.quotaSizeInBytes,
required this.quotaUsageInBytes,
required this.shouldChangePassword,
required this.status,
required this.storageLabel,
required this.updatedAt,
});
UserAvatarColor avatarColor;
DateTime createdAt;
DateTime? deletedAt;
String email;
String id;
@@ -35,44 +50,121 @@ class PartnerResponseDto {
///
bool? inTimeline;
bool isAdmin;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? memoriesEnabled;
String name;
String oauthId;
String profileImagePath;
int? quotaSizeInBytes;
int? quotaUsageInBytes;
bool shouldChangePassword;
UserStatus status;
String? storageLabel;
DateTime updatedAt;
@override
bool operator ==(Object other) => identical(this, other) || other is PartnerResponseDto &&
other.avatarColor == avatarColor &&
other.createdAt == createdAt &&
other.deletedAt == deletedAt &&
other.email == email &&
other.id == id &&
other.inTimeline == inTimeline &&
other.isAdmin == isAdmin &&
other.memoriesEnabled == memoriesEnabled &&
other.name == name &&
other.profileImagePath == profileImagePath;
other.oauthId == oauthId &&
other.profileImagePath == profileImagePath &&
other.quotaSizeInBytes == quotaSizeInBytes &&
other.quotaUsageInBytes == quotaUsageInBytes &&
other.shouldChangePassword == shouldChangePassword &&
other.status == status &&
other.storageLabel == storageLabel &&
other.updatedAt == updatedAt;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(avatarColor.hashCode) +
(createdAt.hashCode) +
(deletedAt == null ? 0 : deletedAt!.hashCode) +
(email.hashCode) +
(id.hashCode) +
(inTimeline == null ? 0 : inTimeline!.hashCode) +
(isAdmin.hashCode) +
(memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
(name.hashCode) +
(profileImagePath.hashCode);
(oauthId.hashCode) +
(profileImagePath.hashCode) +
(quotaSizeInBytes == null ? 0 : quotaSizeInBytes!.hashCode) +
(quotaUsageInBytes == null ? 0 : quotaUsageInBytes!.hashCode) +
(shouldChangePassword.hashCode) +
(status.hashCode) +
(storageLabel == null ? 0 : storageLabel!.hashCode) +
(updatedAt.hashCode);
@override
String toString() => 'PartnerResponseDto[avatarColor=$avatarColor, email=$email, id=$id, inTimeline=$inTimeline, name=$name, profileImagePath=$profileImagePath]';
String toString() => 'PartnerResponseDto[avatarColor=$avatarColor, createdAt=$createdAt, deletedAt=$deletedAt, email=$email, id=$id, inTimeline=$inTimeline, isAdmin=$isAdmin, memoriesEnabled=$memoriesEnabled, name=$name, oauthId=$oauthId, profileImagePath=$profileImagePath, quotaSizeInBytes=$quotaSizeInBytes, quotaUsageInBytes=$quotaUsageInBytes, shouldChangePassword=$shouldChangePassword, status=$status, storageLabel=$storageLabel, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'avatarColor'] = this.avatarColor;
json[r'createdAt'] = this.createdAt.toUtc().toIso8601String();
if (this.deletedAt != null) {
json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String();
} else {
// json[r'deletedAt'] = null;
}
json[r'email'] = this.email;
json[r'id'] = this.id;
if (this.inTimeline != null) {
json[r'inTimeline'] = this.inTimeline;
} else {
// json[r'inTimeline'] = null;
}
json[r'isAdmin'] = this.isAdmin;
if (this.memoriesEnabled != null) {
json[r'memoriesEnabled'] = this.memoriesEnabled;
} else {
// json[r'memoriesEnabled'] = null;
}
json[r'name'] = this.name;
json[r'oauthId'] = this.oauthId;
json[r'profileImagePath'] = this.profileImagePath;
if (this.quotaSizeInBytes != null) {
json[r'quotaSizeInBytes'] = this.quotaSizeInBytes;
} else {
// json[r'quotaSizeInBytes'] = null;
}
if (this.quotaUsageInBytes != null) {
json[r'quotaUsageInBytes'] = this.quotaUsageInBytes;
} else {
// json[r'quotaUsageInBytes'] = null;
}
json[r'shouldChangePassword'] = this.shouldChangePassword;
json[r'status'] = this.status;
if (this.storageLabel != null) {
json[r'storageLabel'] = this.storageLabel;
} else {
// json[r'storageLabel'] = null;
}
json[r'updatedAt'] = this.updatedAt.toUtc().toIso8601String();
return json;
}
@@ -85,11 +177,22 @@ class PartnerResponseDto {
return PartnerResponseDto(
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor'])!,
createdAt: mapDateTime(json, r'createdAt', r'')!,
deletedAt: mapDateTime(json, r'deletedAt', r''),
email: mapValueOfType<String>(json, r'email')!,
id: mapValueOfType<String>(json, r'id')!,
inTimeline: mapValueOfType<bool>(json, r'inTimeline'),
isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
name: mapValueOfType<String>(json, r'name')!,
oauthId: mapValueOfType<String>(json, r'oauthId')!,
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
quotaSizeInBytes: mapValueOfType<int>(json, r'quotaSizeInBytes'),
quotaUsageInBytes: mapValueOfType<int>(json, r'quotaUsageInBytes'),
shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
status: UserStatus.fromJson(json[r'status'])!,
storageLabel: mapValueOfType<String>(json, r'storageLabel'),
updatedAt: mapDateTime(json, r'updatedAt', r'')!,
);
}
return null;
@@ -138,10 +241,20 @@ class PartnerResponseDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'avatarColor',
'createdAt',
'deletedAt',
'email',
'id',
'isAdmin',
'name',
'oauthId',
'profileImagePath',
'quotaSizeInBytes',
'quotaUsageInBytes',
'shouldChangePassword',
'status',
'storageLabel',
'updatedAt',
};
}

View File

@@ -10,9 +10,9 @@
part of openapi.api;
class ServerStorageResponseDto {
/// Returns a new [ServerStorageResponseDto] instance.
ServerStorageResponseDto({
class ServerInfoResponseDto {
/// Returns a new [ServerInfoResponseDto] instance.
ServerInfoResponseDto({
required this.diskAvailable,
required this.diskAvailableRaw,
required this.diskSize,
@@ -37,7 +37,7 @@ class ServerStorageResponseDto {
int diskUseRaw;
@override
bool operator ==(Object other) => identical(this, other) || other is ServerStorageResponseDto &&
bool operator ==(Object other) => identical(this, other) || other is ServerInfoResponseDto &&
other.diskAvailable == diskAvailable &&
other.diskAvailableRaw == diskAvailableRaw &&
other.diskSize == diskSize &&
@@ -58,7 +58,7 @@ class ServerStorageResponseDto {
(diskUseRaw.hashCode);
@override
String toString() => 'ServerStorageResponseDto[diskAvailable=$diskAvailable, diskAvailableRaw=$diskAvailableRaw, diskSize=$diskSize, diskSizeRaw=$diskSizeRaw, diskUsagePercentage=$diskUsagePercentage, diskUse=$diskUse, diskUseRaw=$diskUseRaw]';
String toString() => 'ServerInfoResponseDto[diskAvailable=$diskAvailable, diskAvailableRaw=$diskAvailableRaw, diskSize=$diskSize, diskSizeRaw=$diskSizeRaw, diskUsagePercentage=$diskUsagePercentage, diskUse=$diskUse, diskUseRaw=$diskUseRaw]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -72,14 +72,14 @@ class ServerStorageResponseDto {
return json;
}
/// Returns a new [ServerStorageResponseDto] instance and imports its values from
/// Returns a new [ServerInfoResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static ServerStorageResponseDto? fromJson(dynamic value) {
static ServerInfoResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return ServerStorageResponseDto(
return ServerInfoResponseDto(
diskAvailable: mapValueOfType<String>(json, r'diskAvailable')!,
diskAvailableRaw: mapValueOfType<int>(json, r'diskAvailableRaw')!,
diskSize: mapValueOfType<String>(json, r'diskSize')!,
@@ -92,11 +92,11 @@ class ServerStorageResponseDto {
return null;
}
static List<ServerStorageResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ServerStorageResponseDto>[];
static List<ServerInfoResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ServerInfoResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = ServerStorageResponseDto.fromJson(row);
final value = ServerInfoResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
@@ -105,12 +105,12 @@ class ServerStorageResponseDto {
return result.toList(growable: growable);
}
static Map<String, ServerStorageResponseDto> mapFromJson(dynamic json) {
final map = <String, ServerStorageResponseDto>{};
static Map<String, ServerInfoResponseDto> mapFromJson(dynamic json) {
final map = <String, ServerInfoResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ServerStorageResponseDto.fromJson(entry.value);
final value = ServerInfoResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
@@ -119,14 +119,14 @@ class ServerStorageResponseDto {
return map;
}
// maps a json object with a list of ServerStorageResponseDto-objects as value to a dart map
static Map<String, List<ServerStorageResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<ServerStorageResponseDto>>{};
// maps a json object with a list of ServerInfoResponseDto-objects as value to a dart map
static Map<String, List<ServerInfoResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<ServerInfoResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = ServerStorageResponseDto.listFromJson(entry.value, growable: growable,);
map[entry.key] = ServerInfoResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;

View File

@@ -10,11 +10,13 @@
part of openapi.api;
class UserAdminUpdateDto {
/// Returns a new [UserAdminUpdateDto] instance.
UserAdminUpdateDto({
class UpdateUserDto {
/// Returns a new [UpdateUserDto] instance.
UpdateUserDto({
this.avatarColor,
this.email,
required this.id,
this.isAdmin,
this.memoriesEnabled,
this.name,
this.password,
@@ -39,6 +41,16 @@ class UserAdminUpdateDto {
///
String? email;
String id;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? isAdmin;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
@@ -74,12 +86,20 @@ class UserAdminUpdateDto {
///
bool? shouldChangePassword;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? storageLabel;
@override
bool operator ==(Object other) => identical(this, other) || other is UserAdminUpdateDto &&
bool operator ==(Object other) => identical(this, other) || other is UpdateUserDto &&
other.avatarColor == avatarColor &&
other.email == email &&
other.id == id &&
other.isAdmin == isAdmin &&
other.memoriesEnabled == memoriesEnabled &&
other.name == name &&
other.password == password &&
@@ -92,6 +112,8 @@ class UserAdminUpdateDto {
// ignore: unnecessary_parenthesis
(avatarColor == null ? 0 : avatarColor!.hashCode) +
(email == null ? 0 : email!.hashCode) +
(id.hashCode) +
(isAdmin == null ? 0 : isAdmin!.hashCode) +
(memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
(name == null ? 0 : name!.hashCode) +
(password == null ? 0 : password!.hashCode) +
@@ -100,7 +122,7 @@ class UserAdminUpdateDto {
(storageLabel == null ? 0 : storageLabel!.hashCode);
@override
String toString() => 'UserAdminUpdateDto[avatarColor=$avatarColor, email=$email, memoriesEnabled=$memoriesEnabled, name=$name, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
String toString() => 'UpdateUserDto[avatarColor=$avatarColor, email=$email, id=$id, isAdmin=$isAdmin, memoriesEnabled=$memoriesEnabled, name=$name, password=$password, quotaSizeInBytes=$quotaSizeInBytes, shouldChangePassword=$shouldChangePassword, storageLabel=$storageLabel]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@@ -113,6 +135,12 @@ class UserAdminUpdateDto {
json[r'email'] = this.email;
} else {
// json[r'email'] = null;
}
json[r'id'] = this.id;
if (this.isAdmin != null) {
json[r'isAdmin'] = this.isAdmin;
} else {
// json[r'isAdmin'] = null;
}
if (this.memoriesEnabled != null) {
json[r'memoriesEnabled'] = this.memoriesEnabled;
@@ -147,16 +175,18 @@ class UserAdminUpdateDto {
return json;
}
/// Returns a new [UserAdminUpdateDto] instance and imports its values from
/// Returns a new [UpdateUserDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UserAdminUpdateDto? fromJson(dynamic value) {
static UpdateUserDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return UserAdminUpdateDto(
return UpdateUserDto(
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor']),
email: mapValueOfType<String>(json, r'email'),
id: mapValueOfType<String>(json, r'id')!,
isAdmin: mapValueOfType<bool>(json, r'isAdmin'),
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
name: mapValueOfType<String>(json, r'name'),
password: mapValueOfType<String>(json, r'password'),
@@ -168,11 +198,11 @@ class UserAdminUpdateDto {
return null;
}
static List<UserAdminUpdateDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserAdminUpdateDto>[];
static List<UpdateUserDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UpdateUserDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserAdminUpdateDto.fromJson(row);
final value = UpdateUserDto.fromJson(row);
if (value != null) {
result.add(value);
}
@@ -181,12 +211,12 @@ class UserAdminUpdateDto {
return result.toList(growable: growable);
}
static Map<String, UserAdminUpdateDto> mapFromJson(dynamic json) {
final map = <String, UserAdminUpdateDto>{};
static Map<String, UpdateUserDto> mapFromJson(dynamic json) {
final map = <String, UpdateUserDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UserAdminUpdateDto.fromJson(entry.value);
final value = UpdateUserDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
@@ -195,14 +225,14 @@ class UserAdminUpdateDto {
return map;
}
// maps a json object with a list of UserAdminUpdateDto-objects as value to a dart map
static Map<String, List<UserAdminUpdateDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UserAdminUpdateDto>>{};
// maps a json object with a list of UpdateUserDto-objects as value to a dart map
static Map<String, List<UpdateUserDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UpdateUserDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = UserAdminUpdateDto.listFromJson(entry.value, growable: growable,);
map[entry.key] = UpdateUserDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
@@ -210,6 +240,7 @@ class UserAdminUpdateDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'id',
};
}

View File

@@ -1,243 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class UserAdminResponseDto {
/// Returns a new [UserAdminResponseDto] instance.
UserAdminResponseDto({
required this.avatarColor,
required this.createdAt,
required this.deletedAt,
required this.email,
required this.id,
required this.isAdmin,
this.memoriesEnabled,
required this.name,
required this.oauthId,
required this.profileImagePath,
required this.quotaSizeInBytes,
required this.quotaUsageInBytes,
required this.shouldChangePassword,
required this.status,
required this.storageLabel,
required this.updatedAt,
});
UserAvatarColor avatarColor;
DateTime createdAt;
DateTime? deletedAt;
String email;
String id;
bool isAdmin;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? memoriesEnabled;
String name;
String oauthId;
String profileImagePath;
int? quotaSizeInBytes;
int? quotaUsageInBytes;
bool shouldChangePassword;
UserStatus status;
String? storageLabel;
DateTime updatedAt;
@override
bool operator ==(Object other) => identical(this, other) || other is UserAdminResponseDto &&
other.avatarColor == avatarColor &&
other.createdAt == createdAt &&
other.deletedAt == deletedAt &&
other.email == email &&
other.id == id &&
other.isAdmin == isAdmin &&
other.memoriesEnabled == memoriesEnabled &&
other.name == name &&
other.oauthId == oauthId &&
other.profileImagePath == profileImagePath &&
other.quotaSizeInBytes == quotaSizeInBytes &&
other.quotaUsageInBytes == quotaUsageInBytes &&
other.shouldChangePassword == shouldChangePassword &&
other.status == status &&
other.storageLabel == storageLabel &&
other.updatedAt == updatedAt;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(avatarColor.hashCode) +
(createdAt.hashCode) +
(deletedAt == null ? 0 : deletedAt!.hashCode) +
(email.hashCode) +
(id.hashCode) +
(isAdmin.hashCode) +
(memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
(name.hashCode) +
(oauthId.hashCode) +
(profileImagePath.hashCode) +
(quotaSizeInBytes == null ? 0 : quotaSizeInBytes!.hashCode) +
(quotaUsageInBytes == null ? 0 : quotaUsageInBytes!.hashCode) +
(shouldChangePassword.hashCode) +
(status.hashCode) +
(storageLabel == null ? 0 : storageLabel!.hashCode) +
(updatedAt.hashCode);
@override
String toString() => 'UserAdminResponseDto[avatarColor=$avatarColor, createdAt=$createdAt, deletedAt=$deletedAt, email=$email, id=$id, isAdmin=$isAdmin, memoriesEnabled=$memoriesEnabled, name=$name, oauthId=$oauthId, profileImagePath=$profileImagePath, quotaSizeInBytes=$quotaSizeInBytes, quotaUsageInBytes=$quotaUsageInBytes, shouldChangePassword=$shouldChangePassword, status=$status, storageLabel=$storageLabel, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'avatarColor'] = this.avatarColor;
json[r'createdAt'] = this.createdAt.toUtc().toIso8601String();
if (this.deletedAt != null) {
json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String();
} else {
// json[r'deletedAt'] = null;
}
json[r'email'] = this.email;
json[r'id'] = this.id;
json[r'isAdmin'] = this.isAdmin;
if (this.memoriesEnabled != null) {
json[r'memoriesEnabled'] = this.memoriesEnabled;
} else {
// json[r'memoriesEnabled'] = null;
}
json[r'name'] = this.name;
json[r'oauthId'] = this.oauthId;
json[r'profileImagePath'] = this.profileImagePath;
if (this.quotaSizeInBytes != null) {
json[r'quotaSizeInBytes'] = this.quotaSizeInBytes;
} else {
// json[r'quotaSizeInBytes'] = null;
}
if (this.quotaUsageInBytes != null) {
json[r'quotaUsageInBytes'] = this.quotaUsageInBytes;
} else {
// json[r'quotaUsageInBytes'] = null;
}
json[r'shouldChangePassword'] = this.shouldChangePassword;
json[r'status'] = this.status;
if (this.storageLabel != null) {
json[r'storageLabel'] = this.storageLabel;
} else {
// json[r'storageLabel'] = null;
}
json[r'updatedAt'] = this.updatedAt.toUtc().toIso8601String();
return json;
}
/// Returns a new [UserAdminResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UserAdminResponseDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return UserAdminResponseDto(
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor'])!,
createdAt: mapDateTime(json, r'createdAt', r'')!,
deletedAt: mapDateTime(json, r'deletedAt', r''),
email: mapValueOfType<String>(json, r'email')!,
id: mapValueOfType<String>(json, r'id')!,
isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
name: mapValueOfType<String>(json, r'name')!,
oauthId: mapValueOfType<String>(json, r'oauthId')!,
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
quotaSizeInBytes: mapValueOfType<int>(json, r'quotaSizeInBytes'),
quotaUsageInBytes: mapValueOfType<int>(json, r'quotaUsageInBytes'),
shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
status: UserStatus.fromJson(json[r'status'])!,
storageLabel: mapValueOfType<String>(json, r'storageLabel'),
updatedAt: mapDateTime(json, r'updatedAt', r'')!,
);
}
return null;
}
static List<UserAdminResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserAdminResponseDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserAdminResponseDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, UserAdminResponseDto> mapFromJson(dynamic json) {
final map = <String, UserAdminResponseDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UserAdminResponseDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of UserAdminResponseDto-objects as value to a dart map
static Map<String, List<UserAdminResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UserAdminResponseDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = UserAdminResponseDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'avatarColor',
'createdAt',
'deletedAt',
'email',
'id',
'isAdmin',
'name',
'oauthId',
'profileImagePath',
'quotaSizeInBytes',
'quotaUsageInBytes',
'shouldChangePassword',
'status',
'storageLabel',
'updatedAt',
};
}

130
mobile/openapi/lib/model/user_dto.dart generated Normal file
View File

@@ -0,0 +1,130 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class UserDto {
/// Returns a new [UserDto] instance.
UserDto({
required this.avatarColor,
required this.email,
required this.id,
required this.name,
required this.profileImagePath,
});
UserAvatarColor avatarColor;
String email;
String id;
String name;
String profileImagePath;
@override
bool operator ==(Object other) => identical(this, other) || other is UserDto &&
other.avatarColor == avatarColor &&
other.email == email &&
other.id == id &&
other.name == name &&
other.profileImagePath == profileImagePath;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(avatarColor.hashCode) +
(email.hashCode) +
(id.hashCode) +
(name.hashCode) +
(profileImagePath.hashCode);
@override
String toString() => 'UserDto[avatarColor=$avatarColor, email=$email, id=$id, name=$name, profileImagePath=$profileImagePath]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'avatarColor'] = this.avatarColor;
json[r'email'] = this.email;
json[r'id'] = this.id;
json[r'name'] = this.name;
json[r'profileImagePath'] = this.profileImagePath;
return json;
}
/// Returns a new [UserDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static UserDto? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return UserDto(
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor'])!,
email: mapValueOfType<String>(json, r'email')!,
id: mapValueOfType<String>(json, r'id')!,
name: mapValueOfType<String>(json, r'name')!,
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
);
}
return null;
}
static List<UserDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, UserDto> mapFromJson(dynamic json) {
final map = <String, UserDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = UserDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of UserDto-objects as value to a dart map
static Map<String, List<UserDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<UserDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = UserDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'avatarColor',
'email',
'id',
'name',
'profileImagePath',
};
}

View File

@@ -14,49 +14,141 @@ class UserResponseDto {
/// Returns a new [UserResponseDto] instance.
UserResponseDto({
required this.avatarColor,
required this.createdAt,
required this.deletedAt,
required this.email,
required this.id,
required this.isAdmin,
this.memoriesEnabled,
required this.name,
required this.oauthId,
required this.profileImagePath,
required this.quotaSizeInBytes,
required this.quotaUsageInBytes,
required this.shouldChangePassword,
required this.status,
required this.storageLabel,
required this.updatedAt,
});
UserAvatarColor avatarColor;
DateTime createdAt;
DateTime? deletedAt;
String email;
String id;
bool isAdmin;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? memoriesEnabled;
String name;
String oauthId;
String profileImagePath;
int? quotaSizeInBytes;
int? quotaUsageInBytes;
bool shouldChangePassword;
UserStatus status;
String? storageLabel;
DateTime updatedAt;
@override
bool operator ==(Object other) => identical(this, other) || other is UserResponseDto &&
other.avatarColor == avatarColor &&
other.createdAt == createdAt &&
other.deletedAt == deletedAt &&
other.email == email &&
other.id == id &&
other.isAdmin == isAdmin &&
other.memoriesEnabled == memoriesEnabled &&
other.name == name &&
other.profileImagePath == profileImagePath;
other.oauthId == oauthId &&
other.profileImagePath == profileImagePath &&
other.quotaSizeInBytes == quotaSizeInBytes &&
other.quotaUsageInBytes == quotaUsageInBytes &&
other.shouldChangePassword == shouldChangePassword &&
other.status == status &&
other.storageLabel == storageLabel &&
other.updatedAt == updatedAt;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(avatarColor.hashCode) +
(createdAt.hashCode) +
(deletedAt == null ? 0 : deletedAt!.hashCode) +
(email.hashCode) +
(id.hashCode) +
(isAdmin.hashCode) +
(memoriesEnabled == null ? 0 : memoriesEnabled!.hashCode) +
(name.hashCode) +
(profileImagePath.hashCode);
(oauthId.hashCode) +
(profileImagePath.hashCode) +
(quotaSizeInBytes == null ? 0 : quotaSizeInBytes!.hashCode) +
(quotaUsageInBytes == null ? 0 : quotaUsageInBytes!.hashCode) +
(shouldChangePassword.hashCode) +
(status.hashCode) +
(storageLabel == null ? 0 : storageLabel!.hashCode) +
(updatedAt.hashCode);
@override
String toString() => 'UserResponseDto[avatarColor=$avatarColor, email=$email, id=$id, name=$name, profileImagePath=$profileImagePath]';
String toString() => 'UserResponseDto[avatarColor=$avatarColor, createdAt=$createdAt, deletedAt=$deletedAt, email=$email, id=$id, isAdmin=$isAdmin, memoriesEnabled=$memoriesEnabled, name=$name, oauthId=$oauthId, profileImagePath=$profileImagePath, quotaSizeInBytes=$quotaSizeInBytes, quotaUsageInBytes=$quotaUsageInBytes, shouldChangePassword=$shouldChangePassword, status=$status, storageLabel=$storageLabel, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'avatarColor'] = this.avatarColor;
json[r'createdAt'] = this.createdAt.toUtc().toIso8601String();
if (this.deletedAt != null) {
json[r'deletedAt'] = this.deletedAt!.toUtc().toIso8601String();
} else {
// json[r'deletedAt'] = null;
}
json[r'email'] = this.email;
json[r'id'] = this.id;
json[r'isAdmin'] = this.isAdmin;
if (this.memoriesEnabled != null) {
json[r'memoriesEnabled'] = this.memoriesEnabled;
} else {
// json[r'memoriesEnabled'] = null;
}
json[r'name'] = this.name;
json[r'oauthId'] = this.oauthId;
json[r'profileImagePath'] = this.profileImagePath;
if (this.quotaSizeInBytes != null) {
json[r'quotaSizeInBytes'] = this.quotaSizeInBytes;
} else {
// json[r'quotaSizeInBytes'] = null;
}
if (this.quotaUsageInBytes != null) {
json[r'quotaUsageInBytes'] = this.quotaUsageInBytes;
} else {
// json[r'quotaUsageInBytes'] = null;
}
json[r'shouldChangePassword'] = this.shouldChangePassword;
json[r'status'] = this.status;
if (this.storageLabel != null) {
json[r'storageLabel'] = this.storageLabel;
} else {
// json[r'storageLabel'] = null;
}
json[r'updatedAt'] = this.updatedAt.toUtc().toIso8601String();
return json;
}
@@ -69,10 +161,21 @@ class UserResponseDto {
return UserResponseDto(
avatarColor: UserAvatarColor.fromJson(json[r'avatarColor'])!,
createdAt: mapDateTime(json, r'createdAt', r'')!,
deletedAt: mapDateTime(json, r'deletedAt', r''),
email: mapValueOfType<String>(json, r'email')!,
id: mapValueOfType<String>(json, r'id')!,
isAdmin: mapValueOfType<bool>(json, r'isAdmin')!,
memoriesEnabled: mapValueOfType<bool>(json, r'memoriesEnabled'),
name: mapValueOfType<String>(json, r'name')!,
oauthId: mapValueOfType<String>(json, r'oauthId')!,
profileImagePath: mapValueOfType<String>(json, r'profileImagePath')!,
quotaSizeInBytes: mapValueOfType<int>(json, r'quotaSizeInBytes'),
quotaUsageInBytes: mapValueOfType<int>(json, r'quotaUsageInBytes'),
shouldChangePassword: mapValueOfType<bool>(json, r'shouldChangePassword')!,
status: UserStatus.fromJson(json[r'status'])!,
storageLabel: mapValueOfType<String>(json, r'storageLabel'),
updatedAt: mapDateTime(json, r'updatedAt', r'')!,
);
}
return null;
@@ -121,10 +224,20 @@ class UserResponseDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'avatarColor',
'createdAt',
'deletedAt',
'email',
'id',
'isAdmin',
'name',
'oauthId',
'profileImagePath',
'quotaSizeInBytes',
'quotaUsageInBytes',
'shouldChangePassword',
'status',
'storageLabel',
'updatedAt',
};
}

Some files were not shown because too many files have changed in this diff Show More