diff --git a/.gitattributes b/.gitattributes index f89b54de52..d321e2a910 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,8 +2,6 @@ mobile/openapi/**/*.md -diff -merge mobile/openapi/**/*.md linguist-generated=true mobile/openapi/**/*.dart -diff -merge mobile/openapi/**/*.dart linguist-generated=true -mobile/openapi/.openapi-generator/FILES -diff -merge -mobile/openapi/.openapi-generator/FILES linguist-generated=true mobile/lib/**/*.g.dart -diff -merge mobile/lib/**/*.g.dart linguist-generated=true diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index e522854059..a362dc3438 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -45,7 +45,7 @@ jobs: uses: subosito/flutter-action@v2 with: channel: 'stable' - flutter-version: '3.19.3' + flutter-version: '3.22.0' cache: true - name: Create the Keystore diff --git a/.github/workflows/pr-require-conventional-commit.yml b/.github/workflows/pr-require-conventional-commit.yml new file mode 100644 index 0000000000..4899031249 --- /dev/null +++ b/.github/workflows/pr-require-conventional-commit.yml @@ -0,0 +1,15 @@ +name: PR Conventional Commit Validation + +on: + pull_request: + types: [opened, synchronize, reopened, edited] + +jobs: + validate-pr-title: + runs-on: ubuntu-latest + steps: + - name: PR Conventional Commit Validation + uses: ytanikin/PRConventionalCommits@1.2.0 + with: + task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]' + add_label: 'false' diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index 1fb9cb55f1..6ebbb46f5e 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -22,8 +22,8 @@ jobs: - name: Setup Flutter SDK uses: subosito/flutter-action@v2 with: - channel: "stable" - flutter-version: "3.19.3" + channel: 'stable' + flutter-version: '3.22.0' - name: Install dependencies run: dart pub get diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 184d5a5165..ab22f255ee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -208,7 +208,7 @@ jobs: uses: subosito/flutter-action@v2 with: channel: 'stable' - flutter-version: '3.19.3' + flutter-version: '3.22.0' - name: Run tests working-directory: ./mobile run: flutter test -j 1 @@ -260,9 +260,18 @@ jobs: name: OpenAPI Clients runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - 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 + - name: Run API generation run: make open-api + - name: Find file changes uses: tj-actions/verify-changed-files@v20 id: verify-changed-files @@ -270,6 +279,8 @@ 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: | @@ -332,7 +343,7 @@ jobs: exit 1 - name: Run SQL generation - run: npm run sql:generate + run: npm run sync:sql env: DB_URL: postgres://postgres:postgres@localhost:5432/immich diff --git a/.gitignore b/.gitignore index c066157695..537e048be2 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,10 @@ mobile/gradle.properties mobile/openapi/pubspec.lock mobile/*.jks mobile/libisar.dylib +mobile/openapi/test +mobile/openapi/doc +mobile/openapi/.openapi-generator/FILES open-api/typescript-sdk/build mobile/android/fastlane/report.xml -mobile/ios/fastlane/report.xml \ No newline at end of file +mobile/ios/fastlane/report.xml diff --git a/.vscode/settings.json b/.vscode/settings.json index 3267c67132..a8661326a0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,16 @@ { "editor.formatOnSave": true, - "[javascript][typescript][css]": { + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.tabSize": 2, + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.tabSize": 2, + "editor.formatOnSave": true + }, + "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.tabSize": 2, "editor.formatOnSave": true @@ -31,4 +41,4 @@ "explorer.fileNesting.patterns": { "*.ts": "${capture}.spec.ts,${capture}.mock.ts" } -} \ No newline at end of file +} diff --git a/Makefile b/Makefile index ede70237fe..b7fe03591c 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ open-api-typescript: cd ./open-api && bash ./bin/generate-open-api.sh typescript sql: - npm --prefix server run sql:generate + npm --prefix server run sync:sql attach-server: docker exec -it docker_immich-server_1 sh diff --git a/README.md b/README.md index 563e8dcef1..8cb07a96ba 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM ``` ## Activities + ![Activities](https://repobeats.axiom.co/api/embed/9e86d9dc3ddd137161f2f6d2e758d7863b1789cb.svg "Repobeats analytics image") ## Features diff --git a/cli/.nvmrc b/cli/.nvmrc index 95267e9aae..973f49d55c 100644 --- a/cli/.nvmrc +++ b/cli/.nvmrc @@ -1 +1 @@ -v20.12 +20.13 diff --git a/cli/Dockerfile b/cli/Dockerfile index 015e9aba79..1f76e43c30 100644 --- a/cli/Dockerfile +++ b/cli/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine3.19@sha256:fac6f741d51194c175c517f66bc3125588313327ad7e0ecd673e161e4fa807f3 as core +FROM node:20-alpine3.19@sha256:291e84d956f1aff38454bbd3da38941461ad569a185c20aa289f71f37ea08e23 as core WORKDIR /usr/src/open-api/typescript-sdk COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./ diff --git a/cli/package-lock.json b/cli/package-lock.json index ba4c08cbc6..3521724701 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -31,7 +31,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "mock-fs": "^5.2.0", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", @@ -47,14 +47,14 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.103.1", + "version": "1.105.1", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" }, "devDependencies": { - "@types/node": "^20.12.8", + "@types/node": "^20.12.12", "typescript": "^5.3.3" } }, @@ -174,9 +174,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1113,12 +1113,6 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, "node_modules/@types/lodash": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", @@ -1144,10 +1138,11 @@ } }, "node_modules/@types/node": { - "version": "20.12.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz", - "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -1158,28 +1153,21 @@ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", - "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz", + "integrity": "sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/type-utils": "7.9.0", + "@typescript-eslint/utils": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -1200,15 +1188,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", - "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.9.0.tgz", + "integrity": "sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4" }, "engines": { @@ -1228,13 +1217,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz", + "integrity": "sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0" + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1245,13 +1235,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", - "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz", + "integrity": "sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/utils": "7.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1272,10 +1263,11 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.9.0.tgz", + "integrity": "sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -1285,13 +1277,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz", + "integrity": "sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1313,18 +1306,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.9.0.tgz", + "integrity": "sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1338,12 +1329,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz", + "integrity": "sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/types": "7.9.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1361,9 +1353,9 @@ "dev": true }, "node_modules/@vitest/coverage-v8": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.3.tgz", - "integrity": "sha512-DPyGSu/fPHOJuPxzFSQoT4N/Fu/2aJfZRtEpEp8GI7NHsXBGE94CQ+pbEGBUMFjatsHPDJw/+TAF9r4ens2CNw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", + "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -1384,17 +1376,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.5.3" + "vitest": "1.6.0" } }, "node_modules/@vitest/expect": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.3.tgz", - "integrity": "sha512-y+waPz31pOFr3rD7vWTbwiLe5+MgsMm40jTZbQE8p8/qXyBX3CQsIXRx9XK12IbY7q/t5a5aM/ckt33b4PxK2g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -1402,12 +1394,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz", - "integrity": "sha512-7PlfuReN8692IKQIdCxwir1AOaP5THfNkp0Uc4BKr2na+9lALNit7ub9l3/R7MP8aV61+mHKRGiqEKRIwu6iiQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.3", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -1443,9 +1435,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.3.tgz", - "integrity": "sha512-K3mvIsjyKYBhNIDujMD2gfQEzddLe51nNOAf45yKRt/QFJcUIeTQd2trRvv6M6oCBHNVnZwFWbQ4yj96ibiDsA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -1457,9 +1449,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.3.tgz", - "integrity": "sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -1469,9 +1461,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.3.tgz", - "integrity": "sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -1564,6 +1556,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1588,6 +1581,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -1822,12 +1816,12 @@ "dev": true }, "node_modules/core-js-compat": { - "version": "3.36.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", - "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", "dev": true, "dependencies": { - "browserslist": "^4.22.3" + "browserslist": "^4.23.0" }, "funding": { "type": "opencollective", @@ -1897,6 +1891,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -2094,17 +2089,17 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "52.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz", - "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==", + "version": "53.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz", + "integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "@eslint-community/eslint-utils": "^4.4.0", - "@eslint/eslintrc": "^2.1.4", + "@eslint/eslintrc": "^3.0.2", "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.34.0", + "core-js-compat": "^3.37.0", "esquery": "^1.5.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.1", @@ -2113,11 +2108,11 @@ "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.27", "regjsparser": "^0.10.0", - "semver": "^7.5.4", + "semver": "^7.6.1", "strip-indent": "^3.0.0" }, "engines": { - "node": ">=16" + "node": ">=18.18" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" @@ -2126,6 +2121,92 @@ "eslint": ">=8.56.0" } }, + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -2466,6 +2547,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -2969,6 +3051,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -3232,6 +3315,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3711,13 +3795,10 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -3725,18 +3806,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3781,6 +3850,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4265,9 +4335,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.3.tgz", - "integrity": "sha512-axFo00qiCpU/JLd8N1gu9iEYL3xTbMbMrbe5nDp9GL0nb6gurIdZLkkFogZXWnE8Oyy5kfSLwNVIcVsnhE7lgQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -4306,16 +4376,16 @@ } }, "node_modules/vitest": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.3.tgz", - "integrity": "sha512-2oM7nLXylw3mQlW6GXnRriw+7YvZFk/YNV8AxIC3Z3MfFbuziLGWP9GPxxu/7nRlXhqyxBikpamr+lEEj1sUEw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.3", - "@vitest/runner": "1.5.3", - "@vitest/snapshot": "1.5.3", - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -4329,7 +4399,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.3", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -4344,8 +4414,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.3", - "@vitest/ui": "1.5.3", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, @@ -4407,12 +4477,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yaml": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", diff --git a/cli/package.json b/cli/package.json index 3356f30503..1f6214ab5c 100644 --- a/cli/package.json +++ b/cli/package.json @@ -28,7 +28,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "mock-fs": "^5.2.0", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", @@ -62,6 +62,6 @@ "lodash-es": "^4.17.21" }, "volta": { - "node": "20.12.2" + "node": "20.13.1" } } diff --git a/cli/src/utils.ts b/cli/src/utils.ts index e63dc5ea4a..3b239bacc4 100644 --- a/cli/src/utils.ts +++ b/cli/src/utils.ts @@ -1,4 +1,4 @@ -import { defaults, getMyUserInfo, 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'; @@ -46,8 +46,7 @@ export const connect = async (url: string, key: string) => { // noop } - defaults.baseUrl = url; - defaults.headers = { 'x-api-key': key }; + init({ baseUrl: url, apiKey: key }); const [error] = await withError(getMyUserInfo()); if (isHttpError(error)) { diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 1b56637baf..29cea1a873 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -4,32 +4,29 @@ name: immich-dev -x-server-build: &server-common - image: immich-server-dev:latest - build: - context: ../ - dockerfile: server/Dockerfile - target: dev - restart: always - volumes: - - ../server:/usr/src/app - - ../open-api:/usr/src/open-api - - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload - - ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload - - /usr/src/app/node_modules - - /etc/localtime:/etc/localtime:ro - env_file: - - .env - ulimits: - nofile: - soft: 1048576 - hard: 1048576 - services: immich-server: container_name: immich_server - command: ['/usr/src/app/bin/immich-dev', 'immich'] - <<: *server-common + command: ['/usr/src/app/bin/immich-dev'] + image: immich-server-dev:latest + build: + context: ../ + dockerfile: server/Dockerfile + target: dev + restart: always + volumes: + - ../server:/usr/src/app + - ../open-api:/usr/src/open-api + - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload + - ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload + - /usr/src/app/node_modules + - /etc/localtime:/etc/localtime:ro + env_file: + - .env + ulimits: + nofile: + soft: 1048576 + hard: 1048576 ports: - 3001:3001 - 9230:9230 @@ -37,19 +34,6 @@ services: - redis - database - immich-microservices: - container_name: immich_microservices - command: ['/usr/src/app/bin/immich-dev', 'microservices'] - <<: *server-common - # extends: - # file: hwaccel.transcoding.yml - # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding - ports: - - 9231:9230 - depends_on: - - database - - immich-server - immich-web: container_name: immich_web image: immich-web-dev:latest @@ -97,7 +81,9 @@ services: redis: container_name: immich_redis - image: redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672 + image: redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93 + healthcheck: + test: redis-cli ping || exit 1 database: container_name: immich_postgres @@ -108,11 +94,18 @@ services: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} POSTGRES_DB: ${DB_DATABASE_NAME} + POSTGRES_INITDB_ARGS: '--data-checksums' volumes: - ${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 # immich-prometheus: # container_name: immich_prometheus diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index 56540bce36..6168ea66dd 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -1,39 +1,23 @@ name: immich-prod -x-server-build: &server-common - image: immich-server:latest - build: - context: ../ - dockerfile: server/Dockerfile - volumes: - - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload - - /etc/localtime:/etc/localtime:ro - env_file: - - .env - restart: always - services: immich-server: container_name: immich_server - command: ['start.sh', 'immich'] - <<: *server-common + image: immich-server:latest + build: + context: ../ + dockerfile: server/Dockerfile + volumes: + - ${UPLOAD_LOCATION}/photos:/usr/src/app/upload + - /etc/localtime:/etc/localtime:ro + env_file: + - .env ports: - 2283:3001 depends_on: - redis - database - - immich-microservices: - container_name: immich_microservices - command: ['start.sh', 'microservices'] - <<: *server-common - # extends: - # file: hwaccel.transcoding.yml - # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding - depends_on: - - redis - - database - - immich-server + restart: always immich-machine-learning: container_name: immich_machine_learning @@ -54,7 +38,9 @@ services: redis: container_name: immich_redis - image: redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672 + image: redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93 + healthcheck: + test: redis-cli ping || exit 1 restart: always database: @@ -66,10 +52,18 @@ services: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} POSTGRES_DB: ${DB_DATABASE_NAME} + POSTGRES_INITDB_ARGS: '--data-checksums' volumes: - ${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: @@ -88,7 +82,7 @@ services: command: ['./run.sh', '-disable-reporting'] ports: - 3000:3000 - image: grafana/grafana:10.4.2-ubuntu@sha256:4f55071b556fb03f12b41423c98a185ed6695ed9ff2558e35805f0dd765fd958 + image: grafana/grafana:11.0.0-ubuntu@sha256:02e99d1ee0b52dc9d3000c7b5314e7a07e0dfd69cc49bb3f8ce323491ed3406b volumes: - grafana-data:/var/lib/grafana diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 731bd4c90a..2669db5080 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -12,7 +12,6 @@ services: immich-server: container_name: immich_server image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} - command: ['start.sh', 'immich'] volumes: - ${UPLOAD_LOCATION}:/usr/src/app/upload - /etc/localtime:/etc/localtime:ro @@ -25,23 +24,6 @@ services: - database restart: always - immich-microservices: - container_name: immich_microservices - image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release} - # extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/hardware-transcoding - # file: hwaccel.transcoding.yml - # service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding - command: ['start.sh', 'microservices'] - volumes: - - ${UPLOAD_LOCATION}:/usr/src/app/upload - - /etc/localtime:/etc/localtime:ro - env_file: - - .env - depends_on: - - redis - - database - restart: always - immich-machine-learning: container_name: immich_machine_learning # For hardware acceleration, add one of -[armnn, cuda, openvino] to the image tag. @@ -58,18 +40,27 @@ services: redis: container_name: immich_redis - image: registry.hub.docker.com/library/redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672 + image: docker.io/redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93 + healthcheck: + test: redis-cli ping || exit 1 restart: always database: container_name: immich_postgres - image: registry.hub.docker.com/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 + image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_USER: ${DB_USERNAME} POSTGRES_DB: ${DB_DATABASE_NAME} + 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 volumes: diff --git a/docker/hwaccel.ml.yml b/docker/hwaccel.ml.yml index 3afc5ceafd..d9455d2bb7 100644 --- a/docker/hwaccel.ml.yml +++ b/docker/hwaccel.ml.yml @@ -1,9 +1,7 @@ -version: "3.8" - # Configurations for hardware-accelerated machine learning # If using Unraid or another platform that doesn't allow multiple Compose files, -# you can inline the config for a backend by copying its contents +# you can inline the config for a backend by copying its contents # into the immich-machine-learning service in the docker-compose.yml file. # See https://immich.app/docs/features/ml-hardware-acceleration for info on usage. @@ -30,7 +28,7 @@ services: openvino: device_cgroup_rules: - - "c 189:* rmw" + - 'c 189:* rmw' devices: - /dev/dri:/dev/dri volumes: diff --git a/docker/hwaccel.transcoding.yml b/docker/hwaccel.transcoding.yml index ef9c0a5bb1..bd4e2a46b8 100644 --- a/docker/hwaccel.transcoding.yml +++ b/docker/hwaccel.transcoding.yml @@ -1,5 +1,3 @@ -version: "3.8" - # Configurations for hardware-accelerated transcoding # If using Unraid or another platform that doesn't allow multiple Compose files, diff --git a/docs/.nvmrc b/docs/.nvmrc index 95267e9aae..973f49d55c 100644 --- a/docs/.nvmrc +++ b/docs/.nvmrc @@ -1 +1 @@ -v20.12 +20.13 diff --git a/docs/README.md b/docs/README.md index 0c6c2c27be..cdf0733949 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,13 +5,13 @@ This website is built using [Docusaurus](https://docusaurus.io/), a modern stati ### Installation ``` -$ yarn +$ npm install ``` ### Local Development ``` -$ yarn start +$ npm run start ``` This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. @@ -19,7 +19,7 @@ This command starts a local development server and opens up a browser window. Mo ### Build ``` -$ yarn build +$ npm run build ``` This command generates static content into the `build` directory and can be served using any static contents hosting service. @@ -29,13 +29,13 @@ This command generates static content into the `build` directory and can be serv Using SSH: ``` -$ USE_SSH=true yarn deploy +$ USE_SSH=true npm run deploy ``` Not using SSH: ``` -$ GIT_USER= yarn deploy +$ GIT_USER= npm run deploy ``` If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. diff --git a/docs/docs/FAQ.mdx b/docs/docs/FAQ.mdx index 6739670f46..5458a22620 100644 --- a/docs/docs/FAQ.mdx +++ b/docs/docs/FAQ.mdx @@ -399,8 +399,47 @@ If it mentions SIGILL (note the lack of a K) or error code 132, it most likely m If your version of Immich is below 1.92.0 and the crash occurs after logs about tracing or exporting a model, consider either upgrading or disabling the Tag Objects job. -### Why does Immich log migration errors on startup? +## Database -Sometimes Immich logs errors such as "duplicate key value violates unique constraint" or "column (...) of relation (...) already exists". Because of Immich's container structure, this error can be seen when both immich and immich-microservices start at the same time and attempt to migrate or create the database structure. Since the database migration is run sequentially and inside of transactions, this error message does not cause harm to your installation of Immich and can safely be ignored. If needed, you can manually restart Immich by running `docker restart immich immich-microservices`. +### Why am I getting database ownership errors? + +If you get database errors such as `FATAL: data directory "/var/lib/postgresql/data" has wrong ownership` upon database startup, this is likely due to an issue with your filesystem. +NTFS and ex/FAT/32 filesystems are not supported. See [here](/docs/install/environment-variables#supported-filesystems) for more details. + +### How can I verify the integrity of my database? + +If you installed Immich using v1.104.0 or later, you likely have database checksums enabled by default. You can check this by running the following command. +A result of `on` means that checksums are enabled. + +
+Check if checksums are enabled + +```bash +docker exec -it immich_postgres psql --dbname=immich --username= --command="show data_checksums" + data_checksums +---------------- + on +(1 row) +``` + +
+ +If checksums are enabled, you can check the status of the database with the following command. A normal result is all zeroes. + +
+Check for database corruption + +```bash +docker exec -it immich_postgres psql --dbname=immich --username= --command="SELECT datname, checksum_failures, checksum_last_failure FROM pg_stat_database WHERE datname IS NOT NULL" + datname | checksum_failures | checksum_last_failure +-----------+-------------------+----------------------- + postgres | 0 | + immich | 0 | + template1 | 0 | + template0 | 0 | +(4 rows) +``` + +
[huggingface]: https://huggingface.co/immich-app diff --git a/docs/docs/administration/backup-and-restore.md b/docs/docs/administration/backup-and-restore.md index ed62bdf201..7e10aada0a 100644 --- a/docs/docs/administration/backup-and-restore.md +++ b/docs/docs/administration/backup-and-restore.md @@ -55,7 +55,7 @@ docker compose pull # Update to latest version of Immich (if desired) docker compose create # Create Docker containers for Immich apps without running them. docker start immich_postgres # Start Postgres server sleep 10 # Wait for Postgres server to start up -gc "C:\path\to\backup\dump.sql" | docker exec -i immich_postgres psql --username=postgres # Restore Backup +gc "C:\path\to\backup\dump.sql" | docker exec -i immich_postgres psql --username=postgres # Restore Backup docker compose up -d # Start remainder of Immich apps ``` diff --git a/docs/docs/administration/postgres-standalone.md b/docs/docs/administration/postgres-standalone.md index e0a0cb875e..b5028c788e 100644 --- a/docs/docs/administration/postgres-standalone.md +++ b/docs/docs/administration/postgres-standalone.md @@ -5,7 +5,7 @@ While not officially recommended, it is possible to run Immich using a pre-exist By default, Immich expects superuser permission on the Postgres database and requires certain extensions to be installed. This guide outlines the steps required to prepare a pre-existing Postgres server to be used by Immich. :::tip -Running with a pre-existing Postgres server can unlock powerful administrative features, including logical replication, data page checksums, and streaming write-ahead log backups using programs like pgBackRest or Barman. +Running with a pre-existing Postgres server can unlock powerful administrative features, including logical replication and streaming write-ahead log backups using programs like pgBackRest or Barman. ::: ## Prerequisites diff --git a/docs/docs/administration/repair-page.md b/docs/docs/administration/repair-page.md index e5022970a2..f230c6d582 100644 --- a/docs/docs/administration/repair-page.md +++ b/docs/docs/administration/repair-page.md @@ -18,7 +18,7 @@ In any other situation, there are 3 different options that can appear: - MATCHES - These files are matched by their checksums. -- OFFLINE PATHS - These files are the result of manually deleting files in the upload library or a failed file move in the past (losing track of a file). +- OFFLINE PATHS - These files are the result of manually deleting files from immich or a failed file move in the past (losing track of a file). - UNTRACKED FILES - These files are not tracked by the application. They can be the result of failed moves, interrupted uploads, or left behind due to a bug. diff --git a/docs/docs/developer/pr-checklist.md b/docs/docs/developer/pr-checklist.md index 372dd2b1eb..d2e7fbee40 100644 --- a/docs/docs/developer/pr-checklist.md +++ b/docs/docs/developer/pr-checklist.md @@ -9,6 +9,11 @@ When contributing code through a pull request, please check the following: - [ ] `npm run check:svelte` (Type checking via SvelteKit) - [ ] `npm test` (unit tests) +## Documentation + +- [ ] `npm run format` (formatting via Prettier) +- [ ] Update the `_redirects` file if you have renamed a page or removed it from the documentation. + :::tip AIO Run all web checks with `npm run check:all` ::: diff --git a/docs/docs/features/hardware-transcoding.md b/docs/docs/features/hardware-transcoding.md index 835c92bc24..6067e7babb 100644 --- a/docs/docs/features/hardware-transcoding.md +++ b/docs/docs/features/hardware-transcoding.md @@ -22,7 +22,8 @@ You do not need to redo any transcoding jobs after enabling hardware acceleratio - WSL2 does not support Quick Sync. - Raspberry Pi is currently not supported. - Two-pass mode is only supported for NVENC. Other APIs will ignore this setting. -- Only encoding is currently hardware accelerated, so the CPU is still used for software decoding and tone-mapping. +- By default, only encoding is currently hardware accelerated. This means the CPU is still used for software decoding and tone-mapping. + - NVENC and RKMPP can be fully accelerated by enabling hardware decoding in the video transcoding settings. - Hardware dependent - Codec support varies, but H.264 and HEVC are usually supported. - Notably, NVIDIA and AMD GPUs do not support VP9 encoding. @@ -33,7 +34,7 @@ You do not need to redo any transcoding jobs after enabling hardware acceleratio #### NVENC - You must have the official NVIDIA driver installed on the server. -- On Linux (except for WSL2), you also need to have [NVIDIA Container Runtime][nvcr] installed. +- On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed. #### QSV @@ -65,6 +66,7 @@ For RKMPP to work: 3. Redeploy the `immich-microservices` container with these updated settings. 4. In the Admin page under `Video transcoding settings`, change the hardware acceleration setting to the appropriate option and save. +5. (Optional) If using a compatible backend, you may enable hardware decoding for optimal performance. #### Single Compose File @@ -122,7 +124,7 @@ Once this is done, you can continue to step 3 of "Basic Setup". - While you can use VAAPI with NVIDIA and Intel devices, prefer the more specific APIs since they're more optimized for their respective devices [hw-file]: https://github.com/immich-app/immich/releases/latest/download/hwaccel.transcoding.yml -[nvcr]: https://github.com/NVIDIA/nvidia-container-runtime/ +[nvct]: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html [jellyfin-lp]: https://jellyfin.org/docs/general/administration/hardware-acceleration/intel/#configure-and-verify-lp-mode-on-linux [jellyfin-kernel-bug]: https://jellyfin.org/docs/general/administration/hardware-acceleration/intel/#known-issues-and-limitations [libmali-rockchip]: https://github.com/tsukumijima/libmali-rockchip/releases diff --git a/docs/docs/features/libraries.md b/docs/docs/features/libraries.md index 628bb880c1..782dfdac14 100644 --- a/docs/docs/features/libraries.md +++ b/docs/docs/features/libraries.md @@ -4,13 +4,9 @@ Immich supports the creation of libraries which is a top-level asset container. Currently, there are two types of libraries: traditional upload libraries that can sync with a mobile device, and external libraries, that keeps up to date with files on disk. Libraries are different from albums in that an asset can belong to multiple albums but only one library, and deleting a library deletes all assets contained within. As of August 2023, this is a new feature and libraries have a lot of potential for future development beyond what is documented here. This document attempts to describe the current state of libraries. -## The Upload Library - -Immich comes preconfigured with an upload library for each user. All assets uploaded to Immich are added to this library. This library can be renamed, but not deleted. The upload library is the only library that can be synced with a mobile device. No items in an upload library is allowed to have the same sha1 hash as another item in the same library in order to prevent duplicates. - ## External Libraries -External libraries tracks assets stored outside of immich, i.e. in the file system. Immich will only read data from the files, and will not modify them in any way. Therefore, the delete button is disabled for external assets. When the external library is scanned, immich will read the metadata from the file and create an asset in the library for each image or video file. These items will then be shown in the main timeline, and they will look and behave like any other asset, including viewing on the map, adding to albums, etc. +External libraries tracks assets stored outside of Immich, i.e. in the file system. When the external library is scanned, Immich will read the metadata from the file and create an asset in the library for each image or video file. These items will then be shown in the main timeline, and they will look and behave like any other asset, including viewing on the map, adding to albums, etc. If a file is modified outside of Immich, the changes will not be reflected in immich until the library is scanned again. There are different ways to scan a library depending on the use case: diff --git a/docs/docs/features/ml-hardware-acceleration.md b/docs/docs/features/ml-hardware-acceleration.md index de4c2fa138..2bcb5ee8e8 100644 --- a/docs/docs/features/ml-hardware-acceleration.md +++ b/docs/docs/features/ml-hardware-acceleration.md @@ -38,7 +38,7 @@ You do not need to redo any machine learning jobs after enabling hardware accele - The GPU must have compute capability 5.2 or greater. - The server must have the official NVIDIA driver installed. - The installed driver must be >= 535 (it must support CUDA 12.2). -- On Linux (except for WSL2), you also need to have [NVIDIA Container Runtime][nvcr] installed. +- On Linux (except for WSL2), you also need to have [NVIDIA Container Toolkit][nvct] installed. #### OpenVINO @@ -95,11 +95,11 @@ immich-machine-learning: Once this is done, you can redeploy the `immich-machine-learning` container. :::info -You can confirm the device is being recognized and used by checking its utilization (via `nvtop` for CUDA, `intel_gpu_top` for OpenVINO, etc.). You can also enable debug logging by setting `LOG_LEVEL=debug` in the `.env` file and restarting the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, you should see a log for `Available ORT providers` containing the relevant provider. In the case of ARM NN, the absence of a `Could not load ANN shared libraries` log entry means it loaded successfully. +You can confirm the device is being recognized and used by checking its utilization (via `nvtop` for CUDA, `intel_gpu_top` for OpenVINO, etc.). You can also enable debug logging by setting `IMMICH_LOG_LEVEL=debug` in the `.env` file and restarting the `immich-machine-learning` container. When a Smart Search or Face Detection job begins, you should see a log for `Available ORT providers` containing the relevant provider. In the case of ARM NN, the absence of a `Could not load ANN shared libraries` log entry means it loaded successfully. ::: [hw-file]: https://github.com/immich-app/immich/releases/latest/download/hwaccel.ml.yml -[nvcr]: https://github.com/NVIDIA/nvidia-container-runtime/ +[nvct]: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html ## Tips diff --git a/docs/docs/guides/database-gui.md b/docs/docs/guides/database-gui.md index 1b0bd7931c..e0d6da1cbf 100644 --- a/docs/docs/guides/database-gui.md +++ b/docs/docs/guides/database-gui.md @@ -2,48 +2,52 @@ A short guide on connecting [pgAdmin](https://www.pgadmin.org/) to Immich. -:::note - -In order to connect to the database the immich_postgres container **must be running**. - -The passwords and usernames used below match the ones specified in the example `.env` file. If changed, please use actual values instead. - -**Optional:** To connect to the database **outside** of your Docker's network: - -- Expose port 5432 in your `docker-compose.yml` file. -- Edit the PostgreSQL [`pg_hba.conf`](https://www.postgresql.org/docs/current/auth-pg-hba-conf.html) file. -- Make sure your firewall does not block access to port 5432. - Note that exposing the database port increases the risk of getting attacked by hackers. - Make sure to remove the binding port after finishing the database's tasks. - -::: - ## 1. Install pgAdmin -Download and install [pgAdmin](https://www.pgadmin.org/download/) following the official documentation. +Add a file `docker-compose-pgadmin.yml` next to your `docker-compose.yml` with the following content: + +``` +name: immich + +services: + pgadmin: + image: dpage/pgadmin4 + container_name: pgadmin4_container + restart: always + ports: + - "8888:80" + environment: + PGADMIN_DEFAULT_EMAIL: user-name@domain-name.com + PGADMIN_DEFAULT_PASSWORD: strong-password + volumes: + - pgadmin-data:/var/lib/pgadmin + +volumes: + pgadmin-data: +``` + +Change the values of `PGADMIN_DEFAULT_EMAIL` and `PGADMIN_DEFAULT_PASSWORD` in this file. + +Run `docker compose -f docker-compose.yml -f docker-compose-pgadmin.yml up` to start immich along with `pgAdmin`. ## 2. Add a Server -Open pgAdmin and click "Add New Server". +Open [localhost:8888](http://localhost:8888) and login with the default credentials from above. - +Right click on `Servers` and click on `Register >> Server..` then enter the values below in the `Connection` tab. -## 3. Enter Connection Details + -| Name | Value | -| -------------------- | ----------- | -| Host name/address | `localhost` | -| Port | `5432` | -| Maintenance database | `immich` | -| Username | `postgres` | -| Password | `postgres` | +:::note +The parameters used here match those specified in the example `.env` file. If you have changed your `.env` file, you'll need to adjust accordingly. +::: - - -## 4. Save Connection +| Name | Value | +| -------------------- | ----------------- | +| Host name/address | `immich_postgres` | +| Port | `5432` | +| Maintenance database | `immich` | +| Username | `postgres` | +| Password | `postgres` | Click on "Save" to connect to the Immich database. - -:::tip -View [Database Queries](/docs/guides/database-queries/) for common database queries. -::: diff --git a/docs/docs/guides/database-queries.md b/docs/docs/guides/database-queries.md index e20321e052..8baf9cf825 100644 --- a/docs/docs/guides/database-queries.md +++ b/docs/docs/guides/database-queries.md @@ -96,7 +96,7 @@ SELECT * FROM "users"; ## System Config ```sql title="Custom settings" -SELECT "key", "value" FROM "system_config"; +SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config'; ``` (Only used when not using the [config file](/docs/install/config-file)) diff --git a/docs/docs/guides/external-library.md b/docs/docs/guides/external-library.md index b1d4b67b2e..042f3900cc 100644 --- a/docs/docs/guides/external-library.md +++ b/docs/docs/guides/external-library.md @@ -6,15 +6,19 @@ in a directory on the same machine. # Mount the directory into the containers. -Edit `docker-compose.yml` to add two new mount points under `volumes:` +Edit `docker-compose.yml` to add two new mount points in the sections `immich-server:` and `immich-microservices:` under `volumes:` -``` - immich-server: +```diff +immich-server: volumes: - - ${EXTERNAL_PATH}:/usr/src/app/external ++ - ${EXTERNAL_PATH}:/usr/src/app/external + +immich-microservices: + volumes: ++ - ${EXTERNAL_PATH}:/usr/src/app/external ``` -Be sure to add exactly the same line to both `immich-server:` and `immich-microservices:`. +Be sure to add exactly the same path to both services. Edit `.env` to define `EXTERNAL_PATH`, substituting in the correct path for your computer: diff --git a/docs/docs/guides/img/Connection-Pgadmin.png b/docs/docs/guides/img/Connection-Pgadmin.png deleted file mode 100644 index a5bcb2f91d..0000000000 Binary files a/docs/docs/guides/img/Connection-Pgadmin.png and /dev/null differ diff --git a/docs/docs/guides/img/add-new-server-option.png b/docs/docs/guides/img/add-new-server-option.png deleted file mode 100644 index 934c8c792f..0000000000 Binary files a/docs/docs/guides/img/add-new-server-option.png and /dev/null differ diff --git a/docs/docs/guides/img/pgadmin-add-new-server.png b/docs/docs/guides/img/pgadmin-add-new-server.png new file mode 100644 index 0000000000..978602e04d Binary files /dev/null and b/docs/docs/guides/img/pgadmin-add-new-server.png differ diff --git a/docs/docs/guides/remote-machine-learning.md b/docs/docs/guides/remote-machine-learning.md index e79f6b33e9..6caef05b3a 100644 --- a/docs/docs/guides/remote-machine-learning.md +++ b/docs/docs/guides/remote-machine-learning.md @@ -15,7 +15,7 @@ The [hwaccel.ml.yml](https://github.com/immich-app/immich/releases/latest/downlo ::: ```yaml -version: '3.8' +name: immich_remote_ml services: immich-machine-learning: diff --git a/docs/docs/install/config-file.md b/docs/docs/install/config-file.md index ad354e2c93..abbba8c6b3 100644 --- a/docs/docs/install/config-file.md +++ b/docs/docs/install/config-file.md @@ -77,6 +77,10 @@ The default configuration looks like this: "enabled": true, "modelName": "ViT-B-32__openai" }, + "duplicateDetection": { + "enabled": false, + "maxDistance": 0.03 + }, "facialRecognition": { "enabled": true, "modelName": "buffalo_l", @@ -153,9 +157,6 @@ The default configuration looks like this: "server": { "externalDomain": "", "loginPageMessage": "" - }, - "user": { - "deleteDelay": 7 } } ``` diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md index 6826107893..a3c08f2c70 100644 --- a/docs/docs/install/environment-variables.md +++ b/docs/docs/install/environment-variables.md @@ -24,18 +24,25 @@ If this should not work, try running `docker compose up -d --force-recreate`. | `DB_DATA_LOCATION` | Host Path for Postgres database | | database | :::tip - These environment variables are used by the `docker-compose.yml` file and do **NOT** affect the containers directly. - ::: +### Supported filesystems + +The Immich Postgres database (`DB_DATA_LOCATION`) must be located on a filesystem that supports user/group +ownership and permissions (EXT2/3/4, ZFS, APFS, BTRFS, XFS, etc.). It will not work on any filesystem formatted in NTFS or ex/FAT/32. +It will not work in WSL (Windows Subsystem for Linux) when using a mounted host directory (commonly under `/mnt`). +If this is an issue, you can change the bind mount to a Docker volume instead. + +Regardless of filesystem, it is not recommended to use a network share for your database location due to performance and possible data loss issues. + ## General | Variable | Description | Default | Services | | :------------------------------ | :------------------------------------------- | :----------------------: | :-------------------------------------- | | `TZ` | Timezone | | microservices | -| `NODE_ENV` | Environment (production, development) | `production` | server, microservices, machine learning | -| `LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices, machine learning | +| `IMMICH_ENV` | Environment (production, development) | `production` | server, microservices, machine learning | +| `IMMICH_LOG_LEVEL` | Log Level (verbose, debug, log, warn, error) | `log` | server, microservices, machine learning | | `IMMICH_MEDIA_LOCATION` | Media Location | `./upload`\*1 | server, microservices | | `IMMICH_CONFIG_FILE` | Path to config file | | server, microservices | | `IMMICH_WEB_ROOT` | Path of root index.html | `/usr/src/app/www` | server | @@ -52,13 +59,10 @@ It only need to be set if the Immich deployment method is changing. ## Ports -| Variable | Description | Default | Services | -| :---------------------- | :-------------------- | :-------: | :-------------------- | -| `HOST` | Host | `0.0.0.0` | server, microservices | -| `SERVER_PORT` | Server Port | `3001` | server | -| `MICROSERVICES_PORT` | Microservices Port | `3002` | microservices | -| `MACHINE_LEARNING_HOST` | Machine Learning Host | `0.0.0.0` | machine learning | -| `MACHINE_LEARNING_PORT` | Machine Learning Port | `3003` | machine learning | +| Variable | Description | Default | +| :------------ | :------------- | :------------------------------------: | +| `IMMICH_HOST` | Listening host | `0.0.0.0` | +| `IMMICH_PORT` | Listening port | 3001 (server), 3003 (machine learning) | ## Database diff --git a/docs/docs/install/portainer.md b/docs/docs/install/portainer.md index 2277ef9b9b..35fa7d67e4 100644 --- a/docs/docs/install/portainer.md +++ b/docs/docs/install/portainer.md @@ -38,8 +38,9 @@ style={{border: '1px solid #ddd'}} alt="Dot Env Example" /> -- Populate custom database information if necessary. -- Populate `UPLOAD_LOCATION` with your preferred location for storing backup assets. +- Change the default `DB_PASSWORD`, and add custom database connection information if necessary. +- Change `DB_DATA_LOCATION` to a folder where the database will be saved to disk. +- Change `UPLOAD_LOCATION` to a folder where media (uploaded and generated) will be stored. 11. Click on "**Deploy the stack**". diff --git a/docs/docs/install/requirements.md b/docs/docs/install/requirements.md index b611d04f2c..8944336ec7 100644 --- a/docs/docs/install/requirements.md +++ b/docs/docs/install/requirements.md @@ -15,12 +15,15 @@ Hardware and software requirements for Immich Immich requires the command `docker compose` - the similarly named `docker-compose` is [deprecated](https://docs.docker.com/compose/migrate/) and is no longer compatible with Immich. ::: -:::info Podman -You can also use Podman to run the application. However, additional configuration might be required. -::: - ## Hardware -- **OS**: Preferred unix-based operating system (Ubuntu, Debian, MacOS, etc). Windows works too, with [Docker Desktop on Windows](https://docs.docker.com/desktop/install/windows-install/) -- **RAM**: At least 4GB, preferred 6GB. -- **CPU**: At least 2 cores, preferred 4 cores. +- **OS**: Recommended Linux operating system (Ubuntu, Debian, etc). + - Windows is supported with [Docker Desktop on Windows](https://docs.docker.com/desktop/install/windows-install/) or [WSL 2](https://docs.docker.com/desktop/wsl/). + - macOS is supported with [Docker Desktop on Mac](https://docs.docker.com/desktop/install/mac-install/). +- **RAM**: Minimum 4GB, recommended 6GB. +- **CPU**: Minimum 2 cores, recommended 4 cores. +- **Storage**: Recommended Unix-compatible filesystem (EXT4, ZFS, APFS, etc.) with support for user/group ownership and permissions. + - This can present an issue for Windows users. See [here](/docs/install/environment-variables#supported-filesystems) + for more details and alternatives. + - The generation of thumbnails and transcoded video can increase the size of the photo library by 10-20% on average. + - Network shares are supported for the storage of image and video assets only. diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 75513e3d3b..a9680fb9a1 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -119,6 +119,11 @@ const config = { label: 'GitHub', position: 'right', }, + { + href: 'https://discord.gg/D8JsnBEuKb', + label: 'Discord', + position: 'right', + }, ], }, footer: { diff --git a/docs/package-lock.json b/docs/package-lock.json index f2ffc6dd2b..4b4ace630f 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -33,7 +33,7 @@ "typescript": "^5.1.6" }, "engines": { - "node": ">=16.14" + "node": ">=20" } }, "node_modules/@algolia/autocomplete-core": { @@ -2155,9 +2155,9 @@ } }, "node_modules/@docusaurus/core": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.2.1.tgz", - "integrity": "sha512-ZeMAqNvy0eBv2dThEeMuNzzuu+4thqMQakhxsgT5s02A8LqRcdkg+rbcnuNqUIpekQ4GRx3+M5nj0ODJhBXo9w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.3.2.tgz", + "integrity": "sha512-PzKMydKI3IU1LmeZQDi+ut5RSuilbXnA8QdowGeJEgU8EJjmx3rBHNT1LxQxOVqNEwpWi/csLwd9bn7rUjggPA==", "dependencies": { "@babel/core": "^7.23.3", "@babel/generator": "^7.23.3", @@ -2169,14 +2169,12 @@ "@babel/runtime": "^7.22.6", "@babel/runtime-corejs3": "^7.22.6", "@babel/traverse": "^7.22.8", - "@docusaurus/cssnano-preset": "3.2.1", - "@docusaurus/logger": "3.2.1", - "@docusaurus/mdx-loader": "3.2.1", - "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-common": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", - "@svgr/webpack": "^6.5.1", + "@docusaurus/cssnano-preset": "3.3.2", + "@docusaurus/logger": "3.3.2", + "@docusaurus/mdx-loader": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-common": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "autoprefixer": "^10.4.14", "babel-loader": "^9.1.3", "babel-plugin-dynamic-import-node": "^2.3.3", @@ -2190,8 +2188,8 @@ "copy-webpack-plugin": "^11.0.0", "core-js": "^3.31.1", "css-loader": "^6.8.1", - "css-minimizer-webpack-plugin": "^4.2.2", - "cssnano": "^5.1.15", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", "del": "^6.1.1", "detect-port": "^1.5.1", "escape-html": "^1.0.3", @@ -2211,7 +2209,7 @@ "prompts": "^2.4.2", "react-dev-utils": "^12.0.1", "react-helmet-async": "^1.3.0", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", "react-loadable-ssr-addon-v5-slorber": "^1.0.1", "react-router": "^5.3.4", "react-router-config": "^5.1.1", @@ -2242,13 +2240,13 @@ } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.2.1.tgz", - "integrity": "sha512-wTL9KuSSbMJjKrfu385HZEzAoamUsbKqwscAQByZw4k6Ja/RWpqgVvt/CbAC+aYEH6inLzOt+MjuRwMOrD3VBA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.3.2.tgz", + "integrity": "sha512-+5+epLk/Rp4vFML4zmyTATNc3Is+buMAL6dNjrMWahdJCJlMWMPd/8YfU+2PA57t8mlSbhLJ7vAZVy54cd1vRQ==", "dependencies": { - "cssnano-preset-advanced": "^5.3.10", - "postcss": "^8.4.26", - "postcss-sort-media-queries": "^4.4.1", + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.4.38", + "postcss-sort-media-queries": "^5.2.0", "tslib": "^2.6.0" }, "engines": { @@ -2256,9 +2254,9 @@ } }, "node_modules/@docusaurus/logger": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.2.1.tgz", - "integrity": "sha512-0voOKJCn9RaM3np6soqEfo7SsVvf2C+CDTWhW+H/1AyBhybASpExtDEz+7ECck9TwPzFQ5tt+I3zVugUJbJWDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.3.2.tgz", + "integrity": "sha512-Ldu38GJ4P8g4guN7d7pyCOJ7qQugG7RVyaxrK8OnxuTlaImvQw33aDRwaX2eNmX8YK6v+//Z502F4sOZbHHCHQ==", "dependencies": { "chalk": "^4.1.2", "tslib": "^2.6.0" @@ -2268,13 +2266,13 @@ } }, "node_modules/@docusaurus/mdx-loader": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.2.1.tgz", - "integrity": "sha512-Fs8tXhXKZjNkdGaOy1xSLXSwfjCMT73J3Zfrju2U16uGedRFRjgK0ojpK5tiC7TnunsL3tOFgp1BSMBRflX9gw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.3.2.tgz", + "integrity": "sha512-AFRxj/aOk3/mfYDPxE3wTbrjeayVRvNSZP7mgMuUlrb2UlPRbSVAFX1k2RbgAJrnTSwMgb92m2BhJgYRfptN3g==", "dependencies": { - "@docusaurus/logger": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/logger": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "@mdx-js/mdx": "^3.0.0", "@slorber/remark-comment": "^1.0.0", "escape-html": "^1.0.3", @@ -2306,18 +2304,17 @@ } }, "node_modules/@docusaurus/module-type-aliases": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.2.1.tgz", - "integrity": "sha512-FyViV5TqhL1vsM7eh29nJ5NtbRE6Ra6LP1PDcPvhwPSlA7eiWGRKAn3jWwMUcmjkos5SYY+sr0/feCdbM3eQHQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.3.2.tgz", + "integrity": "sha512-b/XB0TBJah5yKb4LYuJT4buFvL0MGAb0+vJDrJtlYMguRtsEBkf2nWl5xP7h4Dlw6ol0hsHrCYzJ50kNIOEclw==", "dependencies": { - "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "3.2.1", + "@docusaurus/types": "3.3.2", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", "@types/react-router-dom": "*", "react-helmet-async": "*", - "react-loadable": "npm:@docusaurus/react-loadable@5.5.2" + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" }, "peerDependencies": { "react": "*", @@ -2325,17 +2322,17 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.2.1.tgz", - "integrity": "sha512-lOx0JfhlGZoZu6pEJfeEpSISZR5dQbJGGvb42IP13G5YThNHhG9R9uoWuo4IOimPqBC7sHThdLA3VLevk61Fsw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.3.2.tgz", + "integrity": "sha512-fJU+dmqp231LnwDJv+BHVWft8pcUS2xVPZdeYH6/ibH1s2wQ/sLcmUrGWyIv/Gq9Ptj8XWjRPMghlxghuPPoxg==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/logger": "3.2.1", - "@docusaurus/mdx-loader": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-common": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/logger": "3.3.2", + "@docusaurus/mdx-loader": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-common": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^11.1.1", @@ -2356,18 +2353,18 @@ } }, "node_modules/@docusaurus/plugin-content-docs": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.2.1.tgz", - "integrity": "sha512-GHe5b/lCskAR8QVbfWAfPAApvRZgqk7FN3sOHgjCtjzQACZxkHmq6QqyqZ8Jp45V7lVck4wt2Xw2IzBJ7Cz3bA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.3.2.tgz", + "integrity": "sha512-Dm1ri2VlGATTN3VGk1ZRqdRXWa1UlFubjaEL6JaxaK7IIFqN/Esjpl+Xw10R33loHcRww/H76VdEeYayaL76eg==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/logger": "3.2.1", - "@docusaurus/mdx-loader": "3.2.1", - "@docusaurus/module-type-aliases": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-common": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/logger": "3.3.2", + "@docusaurus/mdx-loader": "3.3.2", + "@docusaurus/module-type-aliases": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-common": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "@types/react-router-config": "^5.0.7", "combine-promises": "^1.1.0", "fs-extra": "^11.1.1", @@ -2386,15 +2383,15 @@ } }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.2.1.tgz", - "integrity": "sha512-TOqVfMVTAHqWNEGM94Drz+PUpHDbwFy6ucHFgyTx9zJY7wPNSG5EN+rd/mU7OvAi26qpOn2o9xTdUmb28QLjEQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.3.2.tgz", + "integrity": "sha512-EKc9fQn5H2+OcGER8x1aR+7URtAGWySUgULfqE/M14+rIisdrBstuEZ4lUPDRrSIexOVClML82h2fDS+GSb8Ew==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/mdx-loader": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/mdx-loader": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "fs-extra": "^11.1.1", "tslib": "^2.6.0", "webpack": "^5.88.1" @@ -2408,13 +2405,13 @@ } }, "node_modules/@docusaurus/plugin-debug": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.2.1.tgz", - "integrity": "sha512-AMKq8NuUKf2sRpN1m/sIbqbRbnmk+rSA+8mNU1LNxEl9BW9F/Gng8m9HKlzeyMPrf5XidzS1jqkuTLDJ6KIrFw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.3.2.tgz", + "integrity": "sha512-oBIBmwtaB+YS0XlmZ3gCO+cMbsGvIYuAKkAopoCh0arVjtlyPbejzPrHuCoRHB9G7abjNZw7zoONOR8+8LM5+Q==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils": "3.3.2", "fs-extra": "^11.1.1", "react-json-view-lite": "^1.2.0", "tslib": "^2.6.0" @@ -2428,13 +2425,13 @@ } }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.2.1.tgz", - "integrity": "sha512-/rJ+9u+Px0eTCiF4TNcNtj3kHf8cp6K1HCwOTdbsSlz6Xn21syZYcy+f1VM9wF6HrvUkXUcbM5TDCvg2IRL6bQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.3.2.tgz", + "integrity": "sha512-jXhrEIhYPSClMBK6/IA8qf1/FBoxqGXZvg7EuBax9HaK9+kL3L0TJIlatd8jQJOMtds8mKw806TOCc3rtEad1A==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "tslib": "^2.6.0" }, "engines": { @@ -2446,13 +2443,13 @@ } }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.2.1.tgz", - "integrity": "sha512-XtuJnlMvYfppeVdUyKiDIJAa/gTJKCQU92z8CLZZ9ibJdgVjFOLS10s0hIC0eL5z0U2u2loJz2rZ63HOkNHbBA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.3.2.tgz", + "integrity": "sha512-vcrKOHGbIDjVnNMrfbNpRQR1x6Jvcrb48kVzpBAOsKbj9rXZm/idjVAXRaewwobHdOrJkfWS/UJoxzK8wyLRBQ==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "@types/gtag.js": "^0.0.12", "tslib": "^2.6.0" }, @@ -2465,13 +2462,13 @@ } }, "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.2.1.tgz", - "integrity": "sha512-wiS/kE0Ny5pnjTxVCs8ljRnkL1RVMj59t6jmSsgEX7piDOoaXSMIUaoIt9ogS/v132uO0xEsxHstkRUZHQyPcQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.3.2.tgz", + "integrity": "sha512-ldkR58Fdeks0vC+HQ+L+bGFSJsotQsipXD+iKXQFvkOfmPIV6QbHRd7IIcm5b6UtwOiK33PylNS++gjyLUmaGw==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "tslib": "^2.6.0" }, "engines": { @@ -2483,16 +2480,16 @@ } }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.2.1.tgz", - "integrity": "sha512-uWZ7AxzdeaQSTCwD2yZtOiEm9zyKU+wqCmi/Sf25kQQqqFSBZUStXfaQ8OHP9cecnw893ZpZ811rPhB/wfujJw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.3.2.tgz", + "integrity": "sha512-/ZI1+bwZBhAgC30inBsHe3qY9LOZS+79fRGkNdTcGHRMcdAp6Vw2pCd1gzlxd/xU+HXsNP6cLmTOrggmRp3Ujg==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/logger": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-common": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/logger": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-common": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "fs-extra": "^11.1.1", "sitemap": "^7.1.1", "tslib": "^2.6.0" @@ -2506,23 +2503,23 @@ } }, "node_modules/@docusaurus/preset-classic": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.2.1.tgz", - "integrity": "sha512-E3OHSmttpEBcSMhfPBq3EJMBxZBM01W1rnaCUTXy9EHvkmB5AwgTfW1PwGAybPAX579ntE03R+2zmXdizWfKnQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.3.2.tgz", + "integrity": "sha512-1SDS7YIUN1Pg3BmD6TOTjhB7RSBHJRpgIRKx9TpxqyDrJ92sqtZhomDc6UYoMMLQNF2wHFZZVGFjxJhw2VpL+Q==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/plugin-content-blog": "3.2.1", - "@docusaurus/plugin-content-docs": "3.2.1", - "@docusaurus/plugin-content-pages": "3.2.1", - "@docusaurus/plugin-debug": "3.2.1", - "@docusaurus/plugin-google-analytics": "3.2.1", - "@docusaurus/plugin-google-gtag": "3.2.1", - "@docusaurus/plugin-google-tag-manager": "3.2.1", - "@docusaurus/plugin-sitemap": "3.2.1", - "@docusaurus/theme-classic": "3.2.1", - "@docusaurus/theme-common": "3.2.1", - "@docusaurus/theme-search-algolia": "3.2.1", - "@docusaurus/types": "3.2.1" + "@docusaurus/core": "3.3.2", + "@docusaurus/plugin-content-blog": "3.3.2", + "@docusaurus/plugin-content-docs": "3.3.2", + "@docusaurus/plugin-content-pages": "3.3.2", + "@docusaurus/plugin-debug": "3.3.2", + "@docusaurus/plugin-google-analytics": "3.3.2", + "@docusaurus/plugin-google-gtag": "3.3.2", + "@docusaurus/plugin-google-tag-manager": "3.3.2", + "@docusaurus/plugin-sitemap": "3.3.2", + "@docusaurus/theme-classic": "3.3.2", + "@docusaurus/theme-common": "3.3.2", + "@docusaurus/theme-search-algolia": "3.3.2", + "@docusaurus/types": "3.3.2" }, "engines": { "node": ">=18.0" @@ -2532,35 +2529,23 @@ "react-dom": "^18.0.0" } }, - "node_modules/@docusaurus/react-loadable": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", - "dependencies": { - "@types/react": "*", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": "*" - } - }, "node_modules/@docusaurus/theme-classic": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.2.1.tgz", - "integrity": "sha512-+vSbnQyoWjc6vRZi4vJO2dBU02wqzynsai15KK+FANZudrYaBHtkbLZAQhgmxzBGVpxzi87gRohlMm+5D8f4tA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.3.2.tgz", + "integrity": "sha512-gepHFcsluIkPb4Im9ukkiO4lXrai671wzS3cKQkY9BXQgdVwsdPf/KS0Vs4Xlb0F10fTz+T3gNjkxNEgSN9M0A==", "dependencies": { - "@docusaurus/core": "3.2.1", - "@docusaurus/mdx-loader": "3.2.1", - "@docusaurus/module-type-aliases": "3.2.1", - "@docusaurus/plugin-content-blog": "3.2.1", - "@docusaurus/plugin-content-docs": "3.2.1", - "@docusaurus/plugin-content-pages": "3.2.1", - "@docusaurus/theme-common": "3.2.1", - "@docusaurus/theme-translations": "3.2.1", - "@docusaurus/types": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-common": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/mdx-loader": "3.3.2", + "@docusaurus/module-type-aliases": "3.3.2", + "@docusaurus/plugin-content-blog": "3.3.2", + "@docusaurus/plugin-content-docs": "3.3.2", + "@docusaurus/plugin-content-pages": "3.3.2", + "@docusaurus/theme-common": "3.3.2", + "@docusaurus/theme-translations": "3.3.2", + "@docusaurus/types": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-common": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "@mdx-js/react": "^3.0.0", "clsx": "^2.0.0", "copy-text-to-clipboard": "^3.2.0", @@ -2584,17 +2569,17 @@ } }, "node_modules/@docusaurus/theme-common": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.2.1.tgz", - "integrity": "sha512-d+adiD7L9xv6EvfaAwUqdKf4orsM3jqgeqAM+HAjgL/Ux0GkVVnfKr+tsoe+4ow4rHe6NUt+nkkW8/K8dKdilA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.3.2.tgz", + "integrity": "sha512-kXqSaL/sQqo4uAMQ4fHnvRZrH45Xz2OdJ3ABXDS7YVGPSDTBC8cLebFrRR4YF9EowUHto1UC/EIklJZQMG/usA==", "dependencies": { - "@docusaurus/mdx-loader": "3.2.1", - "@docusaurus/module-type-aliases": "3.2.1", - "@docusaurus/plugin-content-blog": "3.2.1", - "@docusaurus/plugin-content-docs": "3.2.1", - "@docusaurus/plugin-content-pages": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-common": "3.2.1", + "@docusaurus/mdx-loader": "3.3.2", + "@docusaurus/module-type-aliases": "3.3.2", + "@docusaurus/plugin-content-blog": "3.3.2", + "@docusaurus/plugin-content-docs": "3.3.2", + "@docusaurus/plugin-content-pages": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-common": "3.3.2", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2613,18 +2598,18 @@ } }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.2.1.tgz", - "integrity": "sha512-bzhCrpyXBXzeydNUH83II2akvFEGfhsNTPPWsk5N7e+odgQCQwoHhcF+2qILbQXjaoZ6B3c48hrvkyCpeyqGHw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.3.2.tgz", + "integrity": "sha512-qLkfCl29VNBnF1MWiL9IyOQaHxUvicZp69hISyq/xMsNvFKHFOaOfk9xezYod2Q9xx3xxUh9t/QPigIei2tX4w==", "dependencies": { "@docsearch/react": "^3.5.2", - "@docusaurus/core": "3.2.1", - "@docusaurus/logger": "3.2.1", - "@docusaurus/plugin-content-docs": "3.2.1", - "@docusaurus/theme-common": "3.2.1", - "@docusaurus/theme-translations": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-validation": "3.2.1", + "@docusaurus/core": "3.3.2", + "@docusaurus/logger": "3.3.2", + "@docusaurus/plugin-content-docs": "3.3.2", + "@docusaurus/theme-common": "3.3.2", + "@docusaurus/theme-translations": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-validation": "3.3.2", "algoliasearch": "^4.18.0", "algoliasearch-helper": "^3.13.3", "clsx": "^2.0.0", @@ -2643,9 +2628,9 @@ } }, "node_modules/@docusaurus/theme-translations": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.2.1.tgz", - "integrity": "sha512-jAUMkIkFfY+OAhJhv6mV8zlwY6J4AQxJPTgLdR2l+Otof9+QdJjHNh/ifVEu9q0lp3oSPlJj9l05AaP7Ref+cg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.3.2.tgz", + "integrity": "sha512-bPuiUG7Z8sNpGuTdGnmKl/oIPeTwKr0AXLGu9KaP6+UFfRZiyWbWE87ti97RrevB2ffojEdvchNujparR3jEZQ==", "dependencies": { "fs-extra": "^11.1.1", "tslib": "^2.6.0" @@ -2655,9 +2640,9 @@ } }, "node_modules/@docusaurus/types": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.2.1.tgz", - "integrity": "sha512-n/toxBzL2oxTtRTOFiGKsHypzn/Pm+sXyw+VSk1UbqbXQiHOwHwts55bpKwbcUgA530Is6kix3ELiFOv9GAMfw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.3.2.tgz", + "integrity": "sha512-5p201S7AZhliRxTU7uMKtSsoC8mgPA9bs9b5NQg1IRdRxJfflursXNVsgc3PcMqiUTul/v1s3k3rXXFlRE890w==", "dependencies": { "@mdx-js/mdx": "^3.0.0", "@types/history": "^4.7.11", @@ -2675,13 +2660,13 @@ } }, "node_modules/@docusaurus/utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.2.1.tgz", - "integrity": "sha512-DPkIS/EPc+pGAV798PUXgNzJFM3HJouoQXgr0KDZuJVz1EkWbDLOcQwLIz8Qx7liI9ddfkN/TXTRQdsTPZNakw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.3.2.tgz", + "integrity": "sha512-f4YMnBVymtkSxONv4Y8js3Gez9IgHX+Lcg6YRMOjVbq8sgCcdYK1lf6SObAuz5qB/mxiSK7tW0M9aaiIaUSUJg==", "dependencies": { - "@docusaurus/logger": "3.2.1", - "@docusaurus/utils-common": "3.2.1", - "@svgr/webpack": "^6.5.1", + "@docusaurus/logger": "3.3.2", + "@docusaurus/utils-common": "3.3.2", + "@svgr/webpack": "^8.1.0", "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", "fs-extra": "^11.1.1", @@ -2712,9 +2697,9 @@ } }, "node_modules/@docusaurus/utils-common": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.2.1.tgz", - "integrity": "sha512-N5vadULnRLiqX2QfTjVEU3u5vo6RG2EZTdyXvJdzDOdrLCGIZAfnf/VkssinFZ922sVfaFfQ4FnStdhn5TWdVg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.3.2.tgz", + "integrity": "sha512-QWFTLEkPYsejJsLStgtmetMFIA3pM8EPexcZ4WZ7b++gO5jGVH7zsipREnCHzk6+eDgeaXfkR6UPaTt86bp8Og==", "dependencies": { "tslib": "^2.6.0" }, @@ -2731,13 +2716,13 @@ } }, "node_modules/@docusaurus/utils-validation": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.2.1.tgz", - "integrity": "sha512-+x7IR9hNMXi62L1YAglwd0s95fR7+EtirjTxSN4kahYRWGqOi3jlQl1EV0az/yTEvKbxVvOPcdYicGu9dk4LJw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.3.2.tgz", + "integrity": "sha512-itDgFs5+cbW9REuC7NdXals4V6++KifgVMzoGOOOSIifBQw+8ULhy86u5e1lnptVL0sv8oAjq2alO7I40GR7pA==", "dependencies": { - "@docusaurus/logger": "3.2.1", - "@docusaurus/utils": "3.2.1", - "@docusaurus/utils-common": "3.2.1", + "@docusaurus/logger": "3.3.2", + "@docusaurus/utils": "3.3.2", + "@docusaurus/utils-common": "3.3.2", "joi": "^17.9.2", "js-yaml": "^4.1.0", "tslib": "^2.6.0" @@ -3127,11 +3112,11 @@ } }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", - "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3172,11 +3157,11 @@ } }, "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", - "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3187,11 +3172,11 @@ } }, "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", - "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3202,11 +3187,11 @@ } }, "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", - "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3217,11 +3202,11 @@ } }, "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", - "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3232,9 +3217,9 @@ } }, "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", - "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", "engines": { "node": ">=12" }, @@ -3247,21 +3232,21 @@ } }, "node_modules/@svgr/babel-preset": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", - "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", - "@svgr/babel-plugin-remove-jsx-attribute": "*", - "@svgr/babel-plugin-remove-jsx-empty-expression": "*", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", - "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", - "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", - "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", - "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3272,18 +3257,18 @@ } }, "node_modules/@svgr/core": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", - "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dependencies": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.1" + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3291,15 +3276,15 @@ } }, "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", - "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", "dependencies": { - "@babel/types": "^7.20.0", + "@babel/types": "^7.21.3", "entities": "^4.4.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3307,37 +3292,37 @@ } }, "node_modules/@svgr/plugin-jsx": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", - "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", "dependencies": { - "@babel/core": "^7.19.6", - "@svgr/babel-preset": "^6.5.1", - "@svgr/hast-util-to-babel-ast": "^6.5.1", + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", "svg-parser": "^2.0.4" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "@svgr/core": "^6.0.0" + "@svgr/core": "*" } }, "node_modules/@svgr/plugin-svgo": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", - "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", "dependencies": { - "cosmiconfig": "^7.0.1", - "deepmerge": "^4.2.2", - "svgo": "^2.8.0" + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -3348,21 +3333,21 @@ } }, "node_modules/@svgr/webpack": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-6.5.1.tgz", - "integrity": "sha512-cQ/AsnBkXPkEK8cLbv4Dm7JGXq2XrumKnL1dRpJD9rIO2fTIlJI9a1uCciYG1F2aUsox/hJQyNGbt3soDxSRkA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", "dependencies": { - "@babel/core": "^7.19.6", - "@babel/plugin-transform-react-constant-elements": "^7.18.12", - "@babel/preset-env": "^7.19.4", + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.18.6", - "@babel/preset-typescript": "^7.18.6", - "@svgr/core": "^6.5.1", - "@svgr/plugin-jsx": "^6.5.1", - "@svgr/plugin-svgo": "^6.5.1" + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { "type": "github", @@ -5340,18 +5325,28 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/cross-spawn": { @@ -5398,11 +5393,11 @@ } }, "node_modules/css-declaration-sorter": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz", - "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", + "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", "engines": { - "node": "^10 || ^12 || >=14" + "node": "^14 || ^16 || >=18" }, "peerDependencies": { "postcss": "^8.0.9" @@ -5443,16 +5438,16 @@ } }, "node_modules/css-minimizer-webpack-plugin": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-4.2.2.tgz", - "integrity": "sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", "dependencies": { - "cssnano": "^5.1.8", - "jest-worker": "^29.1.2", - "postcss": "^8.4.17", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" }, "engines": { "node": ">= 14.15.0" @@ -5485,14 +5480,6 @@ } } }, - "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/css-select": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -5514,23 +5501,15 @@ "integrity": "sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==" }, "node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-tree/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, "node_modules/css-what": { @@ -5556,108 +5535,139 @@ } }, "node_modules/cssnano": { - "version": "5.1.15", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", - "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", "dependencies": { - "cssnano-preset-default": "^5.2.14", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/cssnano-preset-advanced": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.3.10.tgz", - "integrity": "sha512-fnYJyCS9jgMU+cmHO1rPSPf9axbQyD7iUhLO5Df6O4G+fKIOMps+ZbU0PdGFejFBBZ3Pftf18fn1eG7MAPUSWQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", + "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", "dependencies": { - "autoprefixer": "^10.4.12", - "cssnano-preset-default": "^5.2.14", - "postcss-discard-unused": "^5.1.0", - "postcss-merge-idents": "^5.1.1", - "postcss-reduce-idents": "^5.2.0", - "postcss-zindex": "^5.1.0" + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.0", + "cssnano-preset-default": "^6.1.2", + "postcss-discard-unused": "^6.0.5", + "postcss-merge-idents": "^6.0.3", + "postcss-reduce-idents": "^6.0.3", + "postcss-zindex": "^6.0.2" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/cssnano-preset-default": { - "version": "5.2.14", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", - "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^3.1.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^5.3.1", - "postcss-convert-values": "^5.1.3", - "postcss-discard-comments": "^5.1.2", - "postcss-discard-duplicates": "^5.1.0", - "postcss-discard-empty": "^5.1.1", - "postcss-discard-overridden": "^5.1.0", - "postcss-merge-longhand": "^5.1.7", - "postcss-merge-rules": "^5.1.4", - "postcss-minify-font-values": "^5.1.0", - "postcss-minify-gradients": "^5.1.1", - "postcss-minify-params": "^5.1.4", - "postcss-minify-selectors": "^5.2.1", - "postcss-normalize-charset": "^5.1.0", - "postcss-normalize-display-values": "^5.1.0", - "postcss-normalize-positions": "^5.1.1", - "postcss-normalize-repeat-style": "^5.1.1", - "postcss-normalize-string": "^5.1.0", - "postcss-normalize-timing-functions": "^5.1.0", - "postcss-normalize-unicode": "^5.1.1", - "postcss-normalize-url": "^5.1.0", - "postcss-normalize-whitespace": "^5.1.1", - "postcss-ordered-values": "^5.1.3", - "postcss-reduce-initial": "^5.1.2", - "postcss-reduce-transforms": "^5.1.0", - "postcss-svgo": "^5.1.0", - "postcss-unique-selectors": "^5.1.1" + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/cssnano-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", - "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dependencies": { - "css-tree": "^1.1.2" + "css-tree": "~2.2.0" }, "engines": { - "node": ">=8.0.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" } }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -5971,9 +5981,9 @@ } }, "node_modules/docusaurus-lunr-search": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-3.3.2.tgz", - "integrity": "sha512-+TXfiRAwIAaNwME8bBZvC+osfoXjJSNs5BcZu92lIHoWc3Myct4Nw3jU0FMXQCQGQcQ0FgFqMDoh56LPCLVaxQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/docusaurus-lunr-search/-/docusaurus-lunr-search-3.4.0.tgz", + "integrity": "sha512-GfllnNXCLgTSPH9TAKWmbn8VMfwpdOAZ1xl3T2GgX8Pm26qSDLfrrdVwjguaLfMJfzciFL97RKrAJlgrFM48yw==", "dependencies": { "autocomplete.js": "^0.37.0", "clsx": "^1.2.1", @@ -9956,9 +9966,9 @@ } }, "node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" }, "node_modules/media-typer": { "version": "0.3.0", @@ -11957,17 +11967,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/not": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/not/-/not-0.1.0.tgz", @@ -12756,105 +12755,108 @@ } }, "node_modules/postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", "dependencies": { - "postcss-selector-parser": "^6.0.9", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, "peerDependencies": { "postcss": "^8.2.2" } }, "node_modules/postcss-colormin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", - "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "caniuse-api": "^3.0.0", - "colord": "^2.9.1", + "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-convert-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", - "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-comments": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", - "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-duplicates": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", - "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-empty": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", - "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-overridden": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", - "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-discard-unused": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.1.0.tgz", - "integrity": "sha512-KwLWymI9hbwXmJa0dkrzpRbSJEh0vVUd7r8t0yOGPcfKzyJJxFM8kLyC5Ev9avji6nY95pOp1W6HqIrfT+0VGw==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", "dependencies": { - "postcss-selector-parser": "^6.0.5" + "postcss-selector-parser": "^6.0.16" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-import": { @@ -12968,136 +12970,111 @@ "webpack": "^5.0.0" } }, - "node_modules/postcss-loader/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/postcss-merge-idents": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.1.1.tgz", - "integrity": "sha512-pCijL1TREiCoog5nQp7wUe+TUonA2tC2sQ54UGeMmryK3UFGIYKqDyjnqd6RcuI4znFn9hWSLNN8xKE/vWcUQw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", + "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", "dependencies": { - "cssnano-utils": "^3.1.0", + "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-merge-longhand": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", - "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.1.1" + "stylehacks": "^6.1.1" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-merge-rules": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", - "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.1.0", - "postcss-selector-parser": "^6.0.5" + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-minify-font-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", - "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-minify-gradients": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", - "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^3.1.0", + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-minify-params": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", - "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", "dependencies": { - "browserslist": "^4.21.4", - "cssnano-utils": "^3.1.0", + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-minify-selectors": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", - "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", "dependencies": { - "postcss-selector-parser": "^6.0.5" + "postcss-selector-parser": "^6.0.16" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-modules-extract-imports": { @@ -13174,186 +13151,185 @@ } }, "node_modules/postcss-normalize-charset": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", - "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-display-values": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", - "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-positions": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", - "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-repeat-style": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", - "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-string": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", - "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-timing-functions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", - "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-unicode": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", - "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", - "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", "dependencies": { - "normalize-url": "^6.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-normalize-whitespace": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", - "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-ordered-values": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", - "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", "dependencies": { - "cssnano-utils": "^3.1.0", + "cssnano-utils": "^4.0.2", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-reduce-idents": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.2.0.tgz", - "integrity": "sha512-BTrLjICoSB6gxbc58D5mdBK8OhXRDqud/zodYfdSi52qvDHdMwk+9kB9xsM8yJThH/sZU5A6QVSmMmaN001gIg==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", + "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-reduce-initial": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", - "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", "dependencies": { - "browserslist": "^4.21.4", + "browserslist": "^4.23.0", "caniuse-api": "^3.0.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-reduce-transforms": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", - "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-selector-parser": { @@ -13369,46 +13345,46 @@ } }, "node_modules/postcss-sort-media-queries": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", - "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", + "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", "dependencies": { - "sort-css-media-queries": "2.1.0" + "sort-css-media-queries": "2.2.0" }, "engines": { - "node": ">=10.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "postcss": "^8.4.16" + "postcss": "^8.4.23" } }, "node_modules/postcss-svgo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", - "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", "dependencies": { "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" + "svgo": "^3.2.0" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >= 18" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-unique-selectors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", - "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", "dependencies": { - "postcss-selector-parser": "^6.0.5" + "postcss-selector-parser": "^6.0.16" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postcss-value-parser": { @@ -13417,14 +13393,14 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/postcss-zindex": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.1.0.tgz", - "integrity": "sha512-fgFMf0OtVSBR1va1JNHYgMxYk73yhn/qb4uQDq1DLGYolz8gHCyr/sesEuGUaYs58E3ZJRcpoGuPVoB7Meiq9A==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", + "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/postman-code-generators": { @@ -14101,12 +14077,11 @@ }, "node_modules/react-loadable": { "name": "@docusaurus/react-loadable", - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz", - "integrity": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", + "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", "dependencies": { - "@types/react": "*", - "prop-types": "^15.6.2" + "@types/react": "*" }, "peerDependencies": { "react": "*" @@ -15554,6 +15529,15 @@ "node": ">=8" } }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -15565,9 +15549,9 @@ } }, "node_modules/sort-css-media-queries": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.1.0.tgz", - "integrity": "sha512-IeWvo8NkNiY2vVYdPa27MCQiR0MN0M80johAYFVxWWXQ44KU84WNxjslwBHmc/7ZL2ccwkM7/e6S5aiKZXm7jA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", + "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", "engines": { "node": ">= 6.3.0" } @@ -15658,12 +15642,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" - }, "node_modules/state-local": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", @@ -15840,18 +15818,18 @@ } }, "node_modules/stylehacks": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", - "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" }, "engines": { - "node": "^10 || ^12 || >=14.0" + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "postcss": "^8.2.15" + "postcss": "^8.4.31" } }, "node_modules/sucrase": { @@ -15976,23 +15954,27 @@ "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" }, "node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" }, "bin": { "svgo": "bin/svgo" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, "node_modules/svgo/node_modules/commander": { @@ -16003,69 +15985,6 @@ "node": ">= 10" } }, - "node_modules/svgo/node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/svgo/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/tailwindcss": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", diff --git a/docs/package.json b/docs/package.json index ce9efbe6b4..fabfbae4c8 100644 --- a/docs/package.json +++ b/docs/package.json @@ -56,6 +56,6 @@ "node": ">=20" }, "volta": { - "node": "20.12.2" + "node": "20.13.1" } } diff --git a/docs/src/components/community-guides.tsx b/docs/src/components/community-guides.tsx index 5a17e3b295..d69d7ef92c 100644 --- a/docs/src/components/community-guides.tsx +++ b/docs/src/components/community-guides.tsx @@ -10,17 +10,17 @@ interface CommunityGuidesProps { const guides: CommunityGuidesProps[] = [ { title: 'Cloudflare Tunnels with SSO/OAuth', - description: `Setting up Cloudflare Tunnels and a SaaS App for immich.`, + description: `Setting up Cloudflare Tunnels and a SaaS App for Immich.`, url: 'https://github.com/immich-app/immich/discussions/8299', }, { - title: 'Database backup in Truenas', - description: `Create a database backup with pgAdmin in Truenas.`, + title: 'Database backup in TrueNAS', + description: `Create a database backup with pgAdmin in TrueNAS.`, url: 'https://github.com/immich-app/immich/discussions/8809', }, { title: 'Unraid backup scripts', - description: `Back up your assets in Unarid with a pre-prepared script.`, + description: `Back up your assets in Unraid with a pre-prepared script.`, url: 'https://github.com/immich-app/immich/discussions/8416', }, { @@ -33,6 +33,11 @@ const guides: CommunityGuidesProps[] = [ description: 'Documentation for simple podman setup using quadlets.', url: 'https://github.com/tbelway/immich-podman-quadlets/blob/main/docs/install/podman-quadlet.md', }, + { + title: 'Google Photos import + albums', + description: 'Import your Google Photos files into Immich and add your albums', + url: 'https://github.com/immich-app/immich/discussions/1340', + }, ]; function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element { diff --git a/docs/src/components/community-projects.tsx b/docs/src/components/community-projects.tsx index b452e9fd44..9b602f4e08 100644 --- a/docs/src/components/community-projects.tsx +++ b/docs/src/components/community-projects.tsx @@ -10,7 +10,7 @@ interface CommunityProjectProps { const projects: CommunityProjectProps[] = [ { title: 'immich-go', - description: `An alternative to the immich-CLI command that doesn't depend on nodejs installation. It tries its best for importing google photos takeout archives.`, + description: `An alternative to the immich-CLI that doesn't depend on nodejs. It specializes in importing Google Photos Takeout archives.`, url: 'https://github.com/simulot/immich-go', }, { @@ -33,6 +33,11 @@ const projects: CommunityProjectProps[] = [ description: 'A Python script to create albums based on the folder structure of an external library.', url: 'https://github.com/Salvoxia/immich-folder-album-creator', }, + { + title: 'Immich-Tools', + description: 'Provides scripts for handling problems on the repair page.', + url: 'https://github.com/clumsyCoder00/Immich-Tools', + }, { title: 'Lightroom Publisher: mi.Immich.Publisher', description: 'Lightroom plugin to publish photos from Lightroom collections to Immich albums.', diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index f864c07633..de634da70a 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -33,6 +33,13 @@ function HomepageHeader() { > Demo portal + + + Discord + screenshots
diff --git a/docs/static/img/ios-app-store-badge.png b/docs/static/img/ios-app-store-badge.png new file mode 100644 index 0000000000..fd3d3a3358 Binary files /dev/null and b/docs/static/img/ios-app-store-badge.png differ diff --git a/e2e/.nvmrc b/e2e/.nvmrc index 95267e9aae..973f49d55c 100644 --- a/e2e/.nvmrc +++ b/e2e/.nvmrc @@ -1 +1 @@ -v20.12 +20.13 diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 703a07254e..dca9ca0b2d 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -2,40 +2,32 @@ version: '3.8' name: immich-e2e -x-server-build: &server-common - image: immich-server:latest - build: - context: ../ - dockerfile: server/Dockerfile - environment: - - DB_HOSTNAME=database - - DB_USERNAME=postgres - - DB_PASSWORD=postgres - - DB_DATABASE_NAME=immich - - IMMICH_MACHINE_LEARNING_ENABLED=false - - IMMICH_METRICS=true - volumes: - - upload:/usr/src/app/upload - - ./test-assets:/test-assets - depends_on: - - redis - - database - services: immich-server: container_name: immich-e2e-server - command: ['./start.sh', 'immich'] - <<: *server-common + command: ['./start.sh'] + image: immich-server:latest + build: + context: ../ + dockerfile: server/Dockerfile + environment: + - DB_HOSTNAME=database + - DB_USERNAME=postgres + - DB_PASSWORD=postgres + - DB_DATABASE_NAME=immich + - IMMICH_MACHINE_LEARNING_ENABLED=false + - IMMICH_METRICS=true + volumes: + - upload:/usr/src/app/upload + - ./test-assets:/test-assets + depends_on: + - redis + - database ports: - 2283:3001 - immich-microservices: - container_name: immich-e2e-microservices - command: ['./start.sh', 'microservices'] - <<: *server-common - redis: - image: redis:6.2-alpine@sha256:84882e87b54734154586e5f8abd4dce69fe7311315e2fc6d67c29614c8de2672 + image: redis:6.2-alpine@sha256:e31ca60b18f7e9b78b573d156702471d4eda038803c0b8e6f01559f350031e93 database: image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0 diff --git a/e2e/package-lock.json b/e2e/package-lock.json index e01a570197..20edb870aa 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -1,17 +1,17 @@ { "name": "immich-e2e", - "version": "1.103.1", + "version": "1.105.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-e2e", - "version": "1.103.1", + "version": "1.105.1", "license": "GNU Affero General Public License version 3", "devDependencies": { "@immich/cli": "file:../cli", "@immich/sdk": "file:../open-api/typescript-sdk", - "@playwright/test": "^1.41.2", + "@playwright/test": "^1.44.1", "@types/luxon": "^3.4.2", "@types/node": "^20.11.17", "@types/pg": "^8.11.0", @@ -23,7 +23,7 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "exiftool-vendored": "^26.0.0", "luxon": "^3.4.4", "pg": "^8.11.3", @@ -65,7 +65,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "mock-fs": "^5.2.0", "prettier": "^3.2.5", "prettier-plugin-organize-imports": "^3.2.4", @@ -81,7 +81,7 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.103.1", + "version": "1.105.1", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { @@ -208,9 +208,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -971,12 +971,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.43.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz", - "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==", + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", + "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", "dev": true, "dependencies": { - "playwright": "1.43.1" + "playwright": "1.44.1" }, "bin": { "playwright": "cli.js" @@ -1217,12 +1217,6 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, "node_modules/@types/luxon": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", @@ -1236,10 +1230,11 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz", - "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -1251,9 +1246,9 @@ "dev": true }, "node_modules/@types/pg": { - "version": "8.11.5", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.5.tgz", - "integrity": "sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==", + "version": "8.11.6", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.6.tgz", + "integrity": "sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -1327,12 +1322,6 @@ "@types/node": "*" } }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/superagent": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.3.tgz", @@ -1355,21 +1344,20 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", - "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz", + "integrity": "sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/type-utils": "7.9.0", + "@typescript-eslint/utils": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -1390,15 +1378,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", - "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.9.0.tgz", + "integrity": "sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4" }, "engines": { @@ -1418,13 +1407,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz", + "integrity": "sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0" + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1435,13 +1425,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", - "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz", + "integrity": "sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/utils": "7.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1462,10 +1453,11 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.9.0.tgz", + "integrity": "sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -1475,13 +1467,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz", + "integrity": "sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1507,6 +1500,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -1516,6 +1510,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1527,18 +1522,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.9.0.tgz", + "integrity": "sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1552,12 +1545,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz", + "integrity": "sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/types": "7.9.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -1575,9 +1569,9 @@ "dev": true }, "node_modules/@vitest/coverage-v8": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.3.tgz", - "integrity": "sha512-DPyGSu/fPHOJuPxzFSQoT4N/Fu/2aJfZRtEpEp8GI7NHsXBGE94CQ+pbEGBUMFjatsHPDJw/+TAF9r4ens2CNw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", + "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -1598,17 +1592,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.5.3" + "vitest": "1.6.0" } }, "node_modules/@vitest/expect": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.3.tgz", - "integrity": "sha512-y+waPz31pOFr3rD7vWTbwiLe5+MgsMm40jTZbQE8p8/qXyBX3CQsIXRx9XK12IbY7q/t5a5aM/ckt33b4PxK2g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -1616,12 +1610,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz", - "integrity": "sha512-7PlfuReN8692IKQIdCxwir1AOaP5THfNkp0Uc4BKr2na+9lALNit7ub9l3/R7MP8aV61+mHKRGiqEKRIwu6iiQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.3", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -1630,9 +1624,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.3.tgz", - "integrity": "sha512-K3mvIsjyKYBhNIDujMD2gfQEzddLe51nNOAf45yKRt/QFJcUIeTQd2trRvv6M6oCBHNVnZwFWbQ4yj96ibiDsA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -1644,9 +1638,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.3.tgz", - "integrity": "sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -1656,9 +1650,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.3.tgz", - "integrity": "sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -1785,6 +1779,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1840,6 +1835,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -2121,12 +2117,12 @@ "dev": true }, "node_modules/core-js-compat": { - "version": "3.36.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", - "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", "dev": true, "dependencies": { - "browserslist": "^4.22.3" + "browserslist": "^4.23.0" }, "funding": { "type": "opencollective", @@ -2247,6 +2243,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -2487,17 +2484,17 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "52.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz", - "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==", + "version": "53.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz", + "integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "@eslint-community/eslint-utils": "^4.4.0", - "@eslint/eslintrc": "^2.1.4", + "@eslint/eslintrc": "^3.0.2", "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.34.0", + "core-js-compat": "^3.37.0", "esquery": "^1.5.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.1", @@ -2506,11 +2503,11 @@ "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.27", "regjsparser": "^0.10.0", - "semver": "^7.5.4", + "semver": "^7.6.1", "strip-indent": "^3.0.0" }, "engines": { - "node": ">=16" + "node": ">=18.18" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" @@ -2519,6 +2516,70 @@ "eslint": ">=8.56.0" } }, + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -2692,6 +2753,7 @@ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -2708,6 +2770,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -2759,6 +2822,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3001,6 +3065,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -3276,6 +3341,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3491,18 +3557,6 @@ "get-func-name": "^2.0.1" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/luxon": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", @@ -3561,6 +3615,7 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -3579,6 +3634,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -4047,6 +4103,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4175,6 +4232,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -4194,12 +4252,12 @@ } }, "node_modules/playwright": { - "version": "1.43.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", - "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==", + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", + "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", "dev": true, "dependencies": { - "playwright-core": "1.43.1" + "playwright-core": "1.44.1" }, "bin": { "playwright": "cli.js" @@ -4212,9 +4270,9 @@ } }, "node_modules/playwright-core": { - "version": "1.43.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz", - "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==", + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", + "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -4710,13 +4768,10 @@ ] }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4809,6 +4864,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5135,6 +5191,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -5349,9 +5406,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.3.tgz", - "integrity": "sha512-axFo00qiCpU/JLd8N1gu9iEYL3xTbMbMrbe5nDp9GL0nb6gurIdZLkkFogZXWnE8Oyy5kfSLwNVIcVsnhE7lgQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -5385,16 +5442,16 @@ } }, "node_modules/vitest": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.3.tgz", - "integrity": "sha512-2oM7nLXylw3mQlW6GXnRriw+7YvZFk/YNV8AxIC3Z3MfFbuziLGWP9GPxxu/7nRlXhqyxBikpamr+lEEj1sUEw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.3", - "@vitest/runner": "1.5.3", - "@vitest/snapshot": "1.5.3", - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -5408,7 +5465,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.3", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -5423,8 +5480,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.3", - "@vitest/ui": "1.5.3", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, diff --git a/e2e/package.json b/e2e/package.json index 9ae68f7dbb..e8747194d4 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -1,6 +1,6 @@ { "name": "immich-e2e", - "version": "1.103.1", + "version": "1.105.1", "description": "", "main": "index.js", "type": "module", @@ -21,7 +21,7 @@ "devDependencies": { "@immich/cli": "file:../cli", "@immich/sdk": "file:../open-api/typescript-sdk", - "@playwright/test": "^1.41.2", + "@playwright/test": "^1.44.1", "@types/luxon": "^3.4.2", "@types/node": "^20.11.17", "@types/pg": "^8.11.0", @@ -33,7 +33,7 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "exiftool-vendored": "^26.0.0", "luxon": "^3.4.4", "pg": "^8.11.3", @@ -47,6 +47,6 @@ "vitest": "^1.3.0" }, "volta": { - "node": "20.12.2" + "node": "20.13.1" } } diff --git a/e2e/src/api/specs/activity.e2e-spec.ts b/e2e/src/api/specs/activity.e2e-spec.ts index a1b717883d..3258f74d6e 100644 --- a/e2e/src/api/specs/activity.e2e-spec.ts +++ b/e2e/src/api/specs/activity.e2e-spec.ts @@ -14,7 +14,7 @@ import { app, asBearerAuth, utils } from 'src/utils'; import request from 'supertest'; import { beforeAll, beforeEach, describe, expect, it } from 'vitest'; -describe('/activity', () => { +describe('/activities', () => { let admin: LoginResponseDto; let nonOwner: LoginResponseDto; let asset: AssetFileUploadResponseDto; @@ -45,22 +45,24 @@ describe('/activity', () => { await utils.resetDatabase(['activity']); }); - describe('GET /activity', () => { + describe('GET /activities', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/activity'); + const { status, body } = await request(app).get('/activities'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); it('should require an albumId', async () => { - const { status, body } = await request(app).get('/activity').set('Authorization', `Bearer ${admin.accessToken}`); + const { status, body } = await request(app) + .get('/activities') + .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('/activity') + .get('/activities') .query({ albumId: uuidDto.invalid }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(400); @@ -69,7 +71,7 @@ describe('/activity', () => { it('should reject an invalid assetId', async () => { const { status, body } = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: uuidDto.notFound, assetId: uuidDto.invalid }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(400); @@ -78,7 +80,7 @@ describe('/activity', () => { it('should start off empty', async () => { const { status, body } = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: album.id }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(body).toEqual([]); @@ -102,7 +104,7 @@ describe('/activity', () => { ]); const { status, body } = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: album.id }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(200); @@ -121,7 +123,7 @@ describe('/activity', () => { ]); const { status, body } = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: album.id, type: 'comment' }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(200); @@ -140,7 +142,7 @@ describe('/activity', () => { ]); const { status, body } = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: album.id, type: 'like' }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(200); @@ -152,7 +154,7 @@ describe('/activity', () => { const reaction = await createActivity({ albumId: album.id, type: ReactionType.Like }); const response1 = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: album.id, userId: uuidDto.notFound }) .set('Authorization', `Bearer ${admin.accessToken}`); @@ -160,7 +162,7 @@ describe('/activity', () => { expect(response1.body.length).toBe(0); const response2 = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: album.id, userId: admin.userId }) .set('Authorization', `Bearer ${admin.accessToken}`); @@ -180,7 +182,7 @@ describe('/activity', () => { ]); const { status, body } = await request(app) - .get('/activity') + .get('/activities') .query({ albumId: album.id, assetId: asset.id }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(200); @@ -189,16 +191,16 @@ describe('/activity', () => { }); }); - describe('POST /activity', () => { + describe('POST /activities', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post('/activity'); + const { status, body } = await request(app).post('/activities'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); it('should require an albumId', async () => { const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: uuidDto.invalid }); expect(status).toEqual(400); @@ -207,7 +209,7 @@ describe('/activity', () => { it('should require a comment when type is comment', async () => { const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: uuidDto.notFound, type: 'comment', comment: null }); expect(status).toEqual(400); @@ -216,7 +218,7 @@ describe('/activity', () => { it('should add a comment to an album', async () => { const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: album.id, @@ -236,7 +238,7 @@ describe('/activity', () => { it('should add a like to an album', async () => { const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: album.id, type: 'like' }); expect(status).toEqual(201); @@ -253,7 +255,7 @@ describe('/activity', () => { 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('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: album.id, type: 'like' }); expect(status).toEqual(200); @@ -267,7 +269,7 @@ describe('/activity', () => { type: ReactionType.Like, }); const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: album.id, type: 'like' }); expect(status).toEqual(201); @@ -276,7 +278,7 @@ describe('/activity', () => { it('should add a comment to an asset', async () => { const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: album.id, @@ -297,7 +299,7 @@ describe('/activity', () => { it('should add a like to an asset', async () => { const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: album.id, assetId: asset.id, type: 'like' }); expect(status).toEqual(201); @@ -319,7 +321,7 @@ describe('/activity', () => { }); const { status, body } = await request(app) - .post('/activity') + .post('/activities') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ albumId: album.id, assetId: asset.id, type: 'like' }); expect(status).toEqual(200); @@ -327,16 +329,16 @@ describe('/activity', () => { }); }); - describe('DELETE /activity/:id', () => { + describe('DELETE /activities/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).delete(`/activity/${uuidDto.notFound}`); + const { status, body } = await request(app).delete(`/activities/${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(`/activity/${uuidDto.invalid}`) + .delete(`/activities/${uuidDto.invalid}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(400); expect(body).toEqual(errorDto.badRequest(['id must be a UUID'])); @@ -349,7 +351,7 @@ describe('/activity', () => { comment: 'This is a test comment', }); const { status } = await request(app) - .delete(`/activity/${reaction.id}`) + .delete(`/activities/${reaction.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(204); }); @@ -360,7 +362,7 @@ describe('/activity', () => { type: ReactionType.Like, }); const { status } = await request(app) - .delete(`/activity/${reaction.id}`) + .delete(`/activities/${reaction.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(204); }); @@ -373,7 +375,7 @@ describe('/activity', () => { }); const { status } = await request(app) - .delete(`/activity/${reaction.id}`) + .delete(`/activities/${reaction.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(204); @@ -387,7 +389,7 @@ describe('/activity', () => { }); const { status, body } = await request(app) - .delete(`/activity/${reaction.id}`) + .delete(`/activities/${reaction.id}`) .set('Authorization', `Bearer ${nonOwner.accessToken}`); expect(status).toBe(400); @@ -405,7 +407,7 @@ describe('/activity', () => { ); const { status } = await request(app) - .delete(`/activity/${reaction.id}`) + .delete(`/activities/${reaction.id}`) .set('Authorization', `Bearer ${nonOwner.accessToken}`); expect(status).toBe(204); diff --git a/e2e/src/api/specs/album.e2e-spec.ts b/e2e/src/api/specs/album.e2e-spec.ts index f7d05aac50..4a231dbf9b 100644 --- a/e2e/src/api/specs/album.e2e-spec.ts +++ b/e2e/src/api/specs/album.e2e-spec.ts @@ -23,7 +23,7 @@ const user2SharedUser = 'user2SharedUser'; const user2SharedLink = 'user2SharedLink'; const user2NotShared = 'user2NotShared'; -describe('/album', () => { +describe('/albums', () => { let admin: LoginResponseDto; let user1: LoginResponseDto; let user1Asset1: AssetFileUploadResponseDto; @@ -110,16 +110,16 @@ describe('/album', () => { await deleteUser({ id: user3.userId, deleteUserDto: {} }, { headers: asBearerAuth(admin.accessToken) }); }); - describe('GET /album', () => { + describe('GET /albums', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/album'); + const { status, body } = await request(app).get('/albums'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); it('should reject an invalid shared param', async () => { const { status, body } = await request(app) - .get('/album?shared=invalid') + .get('/albums?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('/album', () => { it('should reject an invalid assetId param', async () => { const { status, body } = await request(app) - .get('/album?assetId=invalid') + .get('/albums?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('/album', () => { it("should not show other users' favorites", async () => { const { status, body } = await request(app) - .get(`/album/${user1Albums[0].id}?withoutAssets=false`) + .get(`/albums/${user1Albums[0].id}?withoutAssets=false`) .set('Authorization', `Bearer ${user2.accessToken}`); expect(status).toEqual(200); expect(body).toEqual({ @@ -146,7 +146,7 @@ describe('/album', () => { it('should not return shared albums with a deleted owner', async () => { const { status, body } = await request(app) - .get('/album?shared=true') + .get('/albums?shared=true') .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -178,7 +178,7 @@ describe('/album', () => { }); it('should return the album collection including owned and shared', async () => { - const { status, body } = await request(app).get('/album').set('Authorization', `Bearer ${user1.accessToken}`); + const { status, body } = await request(app).get('/albums').set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); expect(body).toHaveLength(4); expect(body).toEqual( @@ -209,7 +209,7 @@ describe('/album', () => { it('should return the album collection filtered by shared', async () => { const { status, body } = await request(app) - .get('/album?shared=true') + .get('/albums?shared=true') .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); expect(body).toHaveLength(4); @@ -241,7 +241,7 @@ describe('/album', () => { it('should return the album collection filtered by NOT shared', async () => { const { status, body } = await request(app) - .get('/album?shared=false') + .get('/albums?shared=false') .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); expect(body).toHaveLength(1); @@ -258,7 +258,7 @@ describe('/album', () => { it('should return the album collection filtered by assetId', async () => { const { status, body } = await request(app) - .get(`/album?assetId=${user1Asset2.id}`) + .get(`/albums?assetId=${user1Asset2.id}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); expect(body).toHaveLength(1); @@ -266,7 +266,7 @@ describe('/album', () => { it('should return the album collection filtered by assetId and ignores shared=true', async () => { const { status, body } = await request(app) - .get(`/album?shared=true&assetId=${user1Asset1.id}`) + .get(`/albums?shared=true&assetId=${user1Asset1.id}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); expect(body).toHaveLength(5); @@ -274,23 +274,23 @@ describe('/album', () => { it('should return the album collection filtered by assetId and ignores shared=false', async () => { const { status, body } = await request(app) - .get(`/album?shared=false&assetId=${user1Asset1.id}`) + .get(`/albums?shared=false&assetId=${user1Asset1.id}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); expect(body).toHaveLength(5); }); }); - describe('GET /album/:id', () => { + describe('GET /albums/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get(`/album/${user1Albums[0].id}`); + const { status, body } = await request(app).get(`/albums/${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(`/album/${user1Albums[0].id}?withoutAssets=false`) + .get(`/albums/${user1Albums[0].id}?withoutAssets=false`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -302,7 +302,7 @@ describe('/album', () => { it('should return album info for shared album (editor)', async () => { const { status, body } = await request(app) - .get(`/album/${user2Albums[0].id}?withoutAssets=false`) + .get(`/albums/${user2Albums[0].id}?withoutAssets=false`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -311,7 +311,7 @@ describe('/album', () => { it('should return album info for shared album (viewer)', async () => { const { status, body } = await request(app) - .get(`/album/${user1Albums[3].id}?withoutAssets=false`) + .get(`/albums/${user1Albums[3].id}?withoutAssets=false`) .set('Authorization', `Bearer ${user2.accessToken}`); expect(status).toBe(200); @@ -320,7 +320,7 @@ describe('/album', () => { it('should return album info with assets when withoutAssets is undefined', async () => { const { status, body } = await request(app) - .get(`/album/${user1Albums[0].id}`) + .get(`/albums/${user1Albums[0].id}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -332,7 +332,7 @@ describe('/album', () => { it('should return album info without assets when withoutAssets is true', async () => { const { status, body } = await request(app) - .get(`/album/${user1Albums[0].id}?withoutAssets=true`) + .get(`/albums/${user1Albums[0].id}?withoutAssets=true`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -344,16 +344,16 @@ describe('/album', () => { }); }); - describe('GET /album/count', () => { + describe('GET /albums/count', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/album/count'); + const { status, body } = await request(app).get('/albums/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('/album/count') + .get('/albums/count') .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -361,16 +361,16 @@ describe('/album', () => { }); }); - describe('POST /album', () => { + describe('POST /albums', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post('/album').send({ albumName: 'New album' }); + const { status, body } = await request(app).post('/albums').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('/album') + .post('/albums') .send({ albumName: 'New album' }) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(201); @@ -383,7 +383,6 @@ describe('/album', () => { description: '', albumThumbnailAssetId: null, shared: false, - sharedUsers: [], albumUsers: [], hasSharedLink: false, assets: [], @@ -395,9 +394,9 @@ describe('/album', () => { }); }); - describe('PUT /album/:id/assets', () => { + describe('PUT /albums/:id/assets', () => { it('should require authentication', async () => { - const { status, body } = await request(app).put(`/album/${user1Albums[0].id}/assets`); + const { status, body } = await request(app).put(`/albums/${user1Albums[0].id}/assets`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); @@ -405,7 +404,7 @@ describe('/album', () => { 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(`/album/${user1Albums[0].id}/assets`) + .put(`/albums/${user1Albums[0].id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ ids: [asset.id] }); @@ -416,7 +415,7 @@ describe('/album', () => { 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(`/album/${user2Albums[0].id}/assets`) + .put(`/albums/${user2Albums[0].id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ ids: [asset.id] }); @@ -427,19 +426,33 @@ describe('/album', () => { 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(`/album/${user1Albums[3].id}/assets`) + .put(`/albums/${user1Albums[3].id}/assets`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ ids: [asset.id] }); expect(status).toBe(400); expect(body).toEqual(errorDto.badRequest('Not found or no album.addAsset access')); }); + + 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`) + .set('Authorization', `Bearer ${user1.accessToken}`) + .send({ ids: [asset.id, asset.id] }); + + expect(status).toBe(200); + expect(body).toEqual([ + expect.objectContaining({ id: asset.id, success: true }), + expect.objectContaining({ id: asset.id, success: false, error: 'duplicate' }), + ]); + }); }); - describe('PATCH /album/:id', () => { + describe('PATCH /albums/:id', () => { it('should require authentication', async () => { const { status, body } = await request(app) - .patch(`/album/${uuidDto.notFound}`) + .patch(`/albums/${uuidDto.notFound}`) .send({ albumName: 'New album name' }); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -450,7 +463,7 @@ describe('/album', () => { albumName: 'New album', }); const { status, body } = await request(app) - .patch(`/album/${album.id}`) + .patch(`/albums/${album.id}`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ albumName: 'New album name', @@ -467,7 +480,7 @@ describe('/album', () => { it('should not be able to update as a viewer', async () => { const { status, body } = await request(app) - .patch(`/album/${user1Albums[3].id}`) + .patch(`/albums/${user1Albums[3].id}`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ albumName: 'New album name' }); @@ -477,7 +490,7 @@ describe('/album', () => { it('should not be able to update as an editor', async () => { const { status, body } = await request(app) - .patch(`/album/${user1Albums[0].id}`) + .patch(`/albums/${user1Albums[0].id}`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ albumName: 'New album name' }); @@ -486,10 +499,10 @@ describe('/album', () => { }); }); - describe('DELETE /album/:id/assets', () => { + describe('DELETE /albums/:id/assets', () => { it('should require authentication', async () => { const { status, body } = await request(app) - .delete(`/album/${user1Albums[0].id}/assets`) + .delete(`/albums/${user1Albums[0].id}/assets`) .send({ ids: [user1Asset1.id] }); expect(status).toBe(401); @@ -498,7 +511,7 @@ describe('/album', () => { it('should not be able to remove foreign asset from own album', async () => { const { status, body } = await request(app) - .delete(`/album/${user2Albums[0].id}/assets`) + .delete(`/albums/${user2Albums[0].id}/assets`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ ids: [user1Asset1.id] }); @@ -514,7 +527,7 @@ describe('/album', () => { it('should not be able to remove foreign asset from foreign album', async () => { const { status, body } = await request(app) - .delete(`/album/${user1Albums[0].id}/assets`) + .delete(`/albums/${user1Albums[0].id}/assets`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ ids: [user1Asset1.id] }); @@ -530,7 +543,7 @@ describe('/album', () => { it('should be able to remove own asset from own album', async () => { const { status, body } = await request(app) - .delete(`/album/${user1Albums[0].id}/assets`) + .delete(`/albums/${user1Albums[0].id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ ids: [user1Asset1.id] }); @@ -540,7 +553,7 @@ describe('/album', () => { it('should be able to remove own asset from shared album', async () => { const { status, body } = await request(app) - .delete(`/album/${user2Albums[0].id}/assets`) + .delete(`/albums/${user2Albums[0].id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ ids: [user1Asset1.id] }); @@ -550,13 +563,26 @@ describe('/album', () => { it('should not be able to remove assets from album as a viewer', async () => { const { status, body } = await request(app) - .delete(`/album/${user1Albums[3].id}/assets`) + .delete(`/albums/${user1Albums[3].id}/assets`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ ids: [user1Asset1.id] }); expect(status).toBe(400); expect(body).toEqual(errorDto.badRequest('Not found or no album.removeAsset access')); }); + + it('should remove duplicate assets only once', async () => { + const { status, body } = await request(app) + .delete(`/albums/${user1Albums[1].id}/assets`) + .set('Authorization', `Bearer ${user1.accessToken}`) + .send({ ids: [user1Asset1.id, user1Asset1.id] }); + + expect(status).toBe(200); + expect(body).toEqual([ + expect.objectContaining({ id: user1Asset1.id, success: true }), + expect.objectContaining({ id: user1Asset1.id, success: false, error: 'not_found' }), + ]); + }); }); describe('PUT :id/users', () => { @@ -569,7 +595,7 @@ describe('/album', () => { }); it('should require authentication', async () => { - const { status, body } = await request(app).put(`/album/${user1Albums[0].id}/users`).send({ sharedUserIds: [] }); + const { status, body } = await request(app).put(`/albums/${user1Albums[0].id}/users`).send({ sharedUserIds: [] }); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -577,21 +603,25 @@ describe('/album', () => { it('should be able to add user to own album', async () => { const { status, body } = await request(app) - .put(`/album/${album.id}/users`) + .put(`/albums/${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({ - sharedUsers: [expect.objectContaining({ id: user2.userId })], + albumUsers: [ + expect.objectContaining({ + user: expect.objectContaining({ id: user2.userId }), + }), + ], }), ); }); it('should not be able to share album with owner', async () => { const { status, body } = await request(app) - .put(`/album/${album.id}/users`) + .put(`/albums/${album.id}/users`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ albumUsers: [{ userId: user1.userId, role: AlbumUserRole.Editor }] }); @@ -601,12 +631,12 @@ describe('/album', () => { it('should not be able to add existing user to shared album', async () => { await request(app) - .put(`/album/${album.id}/users`) + .put(`/albums/${album.id}/users`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Editor }] }); const { status, body } = await request(app) - .put(`/album/${album.id}/users`) + .put(`/albums/${album.id}/users`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Editor }] }); @@ -625,14 +655,16 @@ describe('/album', () => { expect(album.albumUsers[0].role).toEqual(AlbumUserRole.Viewer); const { status } = await request(app) - .put(`/album/${album.id}/user/${user2.userId}`) + .put(`/albums/${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(`/album/${album.id}`).set('Authorization', `Bearer ${user1.accessToken}`); + const { body } = await request(app) + .get(`/albums/${album.id}`) + .set('Authorization', `Bearer ${user1.accessToken}`); expect(body).toEqual( expect.objectContaining({ albumUsers: [expect.objectContaining({ role: AlbumUserRole.Editor })], @@ -649,7 +681,7 @@ describe('/album', () => { expect(album.albumUsers[0].role).toEqual(AlbumUserRole.Viewer); const { status, body } = await request(app) - .put(`/album/${album.id}/user/${user2.userId}`) + .put(`/albums/${album.id}/user/${user2.userId}`) .set('Authorization', `Bearer ${user2.accessToken}`) .send({ role: AlbumUserRole.Editor }); diff --git a/e2e/src/api/specs/asset.e2e-spec.ts b/e2e/src/api/specs/asset.e2e-spec.ts index 864fe47196..e3dedf84e0 100644 --- a/e2e/src/api/specs/asset.e2e-spec.ts +++ b/e2e/src/api/specs/asset.e2e-spec.ts @@ -2,11 +2,10 @@ import { AssetFileUploadResponseDto, AssetResponseDto, AssetTypeEnum, - LibraryResponseDto, LoginResponseDto, SharedLinkType, - getAllLibraries, getAssetInfo, + getMyUserInfo, updateAssets, } from '@immich/sdk'; import { exiftool } from 'exiftool-vendored'; @@ -73,7 +72,7 @@ describe('/asset', () => { let stackAssets: AssetFileUploadResponseDto[]; let locationAsset: AssetFileUploadResponseDto; - beforeAll(async () => { + const setupTests = async () => { await utils.resetDatabase(); admin = await utils.adminSetup({ onboarding: false }); @@ -87,6 +86,8 @@ 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: { @@ -156,7 +157,8 @@ describe('/asset', () => { assetId: user1Assets[0].id, personId: person1.id, }); - }, 30_000); + }; + beforeAll(setupTests, 30_000); afterAll(() => { utils.disconnectWebsocket(websocket); @@ -236,6 +238,35 @@ describe('/asset', () => { expect(data.status).toBe(200); expect(data.body).not.toHaveProperty('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', () => { @@ -546,14 +577,321 @@ 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); }); - const invalid = [ + it.each([ { should: 'require `deviceAssetId`', dto: { ...makeUploadDto({ omit: 'deviceAssetId' }) } }, { should: 'require `deviceId`', dto: { ...makeUploadDto({ omit: 'deviceId' }) } }, { should: 'require `fileCreatedAt`', dto: { ...makeUploadDto({ omit: 'fileCreatedAt' }) } }, @@ -562,21 +900,17 @@ 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()); + }); - 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 = [ + it.each([ { input: 'formats/avif/8bit-sRGB.avif', expected: { @@ -792,26 +1126,22 @@ describe('/asset', () => { }, }, }, - ]; - - 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); + ])(`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) }, }); - } + + 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'; @@ -825,25 +1155,6 @@ describe('/asset', () => { expect(duplicate).toBe(true); }); - it("should not upload to another user's library", async () => { - const libraries = await getAllLibraries({}, { headers: asBearerAuth(admin.accessToken) }); - const library = libraries.find((library) => library.ownerId === user1.userId) as LibraryResponseDto; - - const { body, status } = await request(app) - .post('/asset/upload') - .set('Authorization', `Bearer ${admin.accessToken}`) - .field('libraryId', library.id) - .field('deviceAssetId', 'example-image') - .field('deviceId', 'e2e') - .field('fileCreatedAt', new Date().toISOString()) - .field('fileModifiedAt', new Date().toISOString()) - .field('duration', '0:00:00.000000') - .attach('assetData', makeRandomImage(), 'example.png'); - - expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Not found or no asset.upload access')); - }); - it('should update the used quota', async () => { const { body, status } = await request(app) .post('/asset/upload') @@ -857,7 +1168,7 @@ describe('/asset', () => { expect(body).toEqual({ id: expect.any(String), duplicate: false }); expect(status).toBe(201); - const { body: user } = await request(app).get('/user/me').set('Authorization', `Bearer ${quotaUser.accessToken}`); + const user = await getMyUserInfo({ headers: asBearerAuth(quotaUser.accessToken) }); expect(user).toEqual(expect.objectContaining({ quotaUsageInBytes: 70 })); }); @@ -881,7 +1192,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. - const motionTests = [ + it.each([ { filepath: 'formats/motionphoto/Samsung One UI 5.jpg', checksum: 'fr14niqCq6N20HB8rJYEvpsUVtI=', @@ -894,329 +1205,23 @@ describe('/asset', () => { filepath: 'formats/motionphoto/Samsung One UI 6.heic', checksum: '/ejgzywvgvzvVhUYVfvkLzFBAF0=', }, - ]; - - 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, + ])(`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), + }, }); - const { status, body, type } = await request(app) - .get(`/asset/thumbnail/${locationAsset.id}?format=WEBP`) - .set('Authorization', `Bearer ${admin.accessToken}`); + await utils.waitForWebsocketEvent({ event: 'assetUpload', id: response.id }); - expect(status).toBe(200); - expect(body).toBeDefined(); - expect(type).toBe('image/webp'); + expect(response.duplicate).toBe(false); - const exifData = await readTags(body, 'thumbnail.webp'); - expect(exifData).not.toHaveProperty('GPSLongitude'); - expect(exifData).not.toHaveProperty('GPSLatitude'); - }); + const asset = await utils.getAssetInfo(admin.accessToken, response.id); + expect(asset.livePhotoVideoId).toBeDefined(); - 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 }), - ]), - ); + const video = await utils.getAssetInfo(admin.accessToken, asset.livePhotoVideoId as string); + expect(video.checksum).toStrictEqual(checksum); }); }); }); diff --git a/e2e/src/api/specs/audit.e2e-spec.ts b/e2e/src/api/specs/audit.e2e-spec.ts index ec8c3799c8..c6a2adbb0a 100644 --- a/e2e/src/api/specs/audit.e2e-spec.ts +++ b/e2e/src/api/specs/audit.e2e-spec.ts @@ -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('/audit', () => { +describe('/audits', () => { let admin: LoginResponseDto; beforeAll(async () => { diff --git a/e2e/src/api/specs/library.e2e-spec.ts b/e2e/src/api/specs/library.e2e-spec.ts index 18becec770..762606de5e 100644 --- a/e2e/src/api/specs/library.e2e-spec.ts +++ b/e2e/src/api/specs/library.e2e-spec.ts @@ -1,11 +1,4 @@ -import { - LibraryResponseDto, - LibraryType, - LoginResponseDto, - ScanLibraryDto, - getAllLibraries, - scanLibrary, -} from '@immich/sdk'; +import { LibraryResponseDto, LoginResponseDto, ScanLibraryDto, getAllLibraries, scanLibrary } from '@immich/sdk'; import { cpSync, existsSync } from 'node:fs'; import { Socket } from 'socket.io-client'; import { userDto, uuidDto } from 'src/fixtures'; @@ -18,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('/library', () => { +describe('/libraries', () => { let admin: LoginResponseDto; let user: LoginResponseDto; let library: LibraryResponseDto; @@ -29,7 +22,7 @@ describe('/library', () => { admin = await utils.adminSetup(); await utils.resetAdminConfig(admin.accessToken); user = await utils.userSetup(admin.accessToken, userDto.user1); - library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, type: LibraryType.External }); + library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId }); websocket = await utils.connectWebsocket(admin.accessToken); utils.createImageFile(`${testAssetDir}/temp/directoryA/assetA.png`); utils.createImageFile(`${testAssetDir}/temp/directoryB/assetB.png`); @@ -44,44 +37,26 @@ describe('/library', () => { utils.resetEvents(); }); - describe('GET /library', () => { + describe('GET /libraries', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/library'); + const { status, body } = await request(app).get('/libraries'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); - - it('should start with a default upload library', async () => { - const { status, body } = await request(app).get('/library').set('Authorization', `Bearer ${admin.accessToken}`); - expect(status).toBe(200); - expect(body).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - ownerId: admin.userId, - type: LibraryType.Upload, - name: 'Default Library', - refreshedAt: null, - assetCount: 0, - importPaths: [], - exclusionPatterns: [], - }), - ]), - ); - }); }); - describe('POST /library', () => { + describe('POST /libraries', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post('/library').send({}); + const { status, body } = await request(app).post('/libraries').send({}); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); it('should require admin authentication', async () => { const { status, body } = await request(app) - .post('/library') + .post('/libraries') .set('Authorization', `Bearer ${user.accessToken}`) - .send({ ownerId: admin.userId, type: LibraryType.External }); + .send({ ownerId: admin.userId }); expect(status).toBe(403); expect(body).toEqual(errorDto.forbidden); @@ -89,15 +64,14 @@ describe('/library', () => { it('should create an external library with defaults', async () => { const { status, body } = await request(app) - .post('/library') + .post('/libraries') .set('Authorization', `Bearer ${admin.accessToken}`) - .send({ ownerId: admin.userId, type: LibraryType.External }); + .send({ ownerId: admin.userId }); expect(status).toBe(201); expect(body).toEqual( expect.objectContaining({ ownerId: admin.userId, - type: LibraryType.External, name: 'New External Library', refreshedAt: null, assetCount: 0, @@ -109,11 +83,10 @@ describe('/library', () => { it('should create an external library with options', async () => { const { status, body } = await request(app) - .post('/library') + .post('/libraries') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ ownerId: admin.userId, - type: LibraryType.External, name: 'My Awesome Library', importPaths: ['/path/to/import'], exclusionPatterns: ['**/Raw/**'], @@ -130,11 +103,10 @@ describe('/library', () => { it('should not create an external library with duplicate import paths', async () => { const { status, body } = await request(app) - .post('/library') + .post('/libraries') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ ownerId: admin.userId, - type: LibraryType.External, name: 'My Awesome Library', importPaths: ['/path', '/path'], exclusionPatterns: ['**/Raw/**'], @@ -146,11 +118,10 @@ describe('/library', () => { it('should not create an external library with duplicate exclusion patterns', async () => { const { status, body } = await request(app) - .post('/library') + .post('/libraries') .set('Authorization', `Bearer ${admin.accessToken}`) .send({ ownerId: admin.userId, - type: LibraryType.External, name: 'My Awesome Library', importPaths: ['/path/to/import'], exclusionPatterns: ['**/Raw/**', '**/Raw/**'], @@ -159,72 +130,18 @@ describe('/library', () => { expect(status).toBe(400); expect(body).toEqual(errorDto.badRequest(["All exclusionPatterns's elements must be unique"])); }); - - it('should create an upload library with defaults', async () => { - const { status, body } = await request(app) - .post('/library') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send({ ownerId: admin.userId, type: LibraryType.Upload }); - - expect(status).toBe(201); - expect(body).toEqual( - expect.objectContaining({ - ownerId: admin.userId, - type: LibraryType.Upload, - name: 'New Upload Library', - refreshedAt: null, - assetCount: 0, - importPaths: [], - exclusionPatterns: [], - }), - ); - }); - - it('should create an upload library with options', async () => { - const { status, body } = await request(app) - .post('/library') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send({ ownerId: admin.userId, type: LibraryType.Upload, name: 'My Awesome Library' }); - - expect(status).toBe(201); - expect(body).toEqual( - expect.objectContaining({ - name: 'My Awesome Library', - }), - ); - }); - - it('should not allow upload libraries to have import paths', async () => { - const { status, body } = await request(app) - .post('/library') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send({ ownerId: admin.userId, type: LibraryType.Upload, importPaths: ['/path/to/import'] }); - - expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Upload libraries cannot have import paths')); - }); - - it('should not allow upload libraries to have exclusion patterns', async () => { - const { status, body } = await request(app) - .post('/library') - .set('Authorization', `Bearer ${admin.accessToken}`) - .send({ ownerId: admin.userId, type: LibraryType.Upload, exclusionPatterns: ['**/Raw/**'] }); - - expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Upload libraries cannot have exclusion patterns')); - }); }); - describe('PUT /library/:id', () => { + describe('PUT /libraries/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).put(`/library/${uuidDto.notFound}`).send({}); + const { status, body } = await request(app).put(`/libraries/${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(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ name: 'New Library Name' }); @@ -238,7 +155,7 @@ describe('/library', () => { it('should not set an empty name', async () => { const { status, body } = await request(app) - .put(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ name: '' }); @@ -248,7 +165,7 @@ describe('/library', () => { it('should change the import paths', async () => { const { status, body } = await request(app) - .put(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ importPaths: [testAssetDirInternal] }); @@ -262,7 +179,7 @@ describe('/library', () => { it('should reject an empty import path', async () => { const { status, body } = await request(app) - .put(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ importPaths: [''] }); @@ -272,7 +189,7 @@ describe('/library', () => { it('should reject duplicate import paths', async () => { const { status, body } = await request(app) - .put(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ importPaths: ['/path', '/path'] }); @@ -282,7 +199,7 @@ describe('/library', () => { it('should change the exclusion pattern', async () => { const { status, body } = await request(app) - .put(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ exclusionPatterns: ['**/Raw/**'] }); @@ -296,7 +213,7 @@ describe('/library', () => { it('should reject duplicate exclusion patterns', async () => { const { status, body } = await request(app) - .put(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ exclusionPatterns: ['**/*.jpg', '**/*.jpg'] }); @@ -306,7 +223,7 @@ describe('/library', () => { it('should reject an empty exclusion pattern', async () => { const { status, body } = await request(app) - .put(`/library/${library.id}`) + .put(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ exclusionPatterns: [''] }); @@ -315,9 +232,9 @@ describe('/library', () => { }); }); - describe('GET /library/:id', () => { + describe('GET /libraries/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get(`/library/${uuidDto.notFound}`); + const { status, body } = await request(app).get(`/libraries/${uuidDto.notFound}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -325,27 +242,23 @@ describe('/library', () => { it('should require admin access', async () => { const { status, body } = await request(app) - .get(`/library/${uuidDto.notFound}`) + .get(`/libraries/${uuidDto.notFound}`) .set('Authorization', `Bearer ${user.accessToken}`); expect(status).toBe(403); expect(body).toEqual(errorDto.forbidden); }); it('should get library by id', async () => { - const library = await utils.createLibrary(admin.accessToken, { - ownerId: admin.userId, - type: LibraryType.External, - }); + const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId }); const { status, body } = await request(app) - .get(`/library/${library.id}`) + .get(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); expect(body).toEqual( expect.objectContaining({ ownerId: admin.userId, - type: LibraryType.External, name: 'New External Library', refreshedAt: null, assetCount: 0, @@ -356,41 +269,26 @@ describe('/library', () => { }); }); - describe('GET /library/:id/statistics', () => { + describe('GET /libraries/:id/statistics', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get(`/library/${uuidDto.notFound}/statistics`); + const { status, body } = await request(app).get(`/libraries/${uuidDto.notFound}/statistics`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); }); - describe('POST /library/:id/scan', () => { + describe('POST /libraries/:id/scan', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post(`/library/${uuidDto.notFound}/scan`).send({}); + const { status, body } = await request(app).post(`/libraries/${uuidDto.notFound}/scan`).send({}); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); - it('should not scan an upload library', async () => { - const library = await utils.createLibrary(admin.accessToken, { - ownerId: admin.userId, - type: LibraryType.Upload, - }); - - const { status, body } = await request(app) - .post(`/library/${library.id}/scan`) - .set('Authorization', `Bearer ${admin.accessToken}`); - - expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Can only refresh external libraries')); - }); - it('should scan external library', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp/directoryA`], }); @@ -406,7 +304,6 @@ describe('/library', () => { it('should scan external library with exclusion pattern', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], exclusionPatterns: ['**/directoryA'], }); @@ -423,7 +320,6 @@ describe('/library', () => { it('should scan multiple import paths', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp/directoryA`, `${testAssetDirInternal}/temp/directoryB`], }); @@ -440,7 +336,6 @@ describe('/library', () => { it('should pick up new files', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -466,7 +361,6 @@ describe('/library', () => { utils.createImageFile(`${testAssetDir}/temp/directoryA/assetB.png`); const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -493,7 +387,6 @@ describe('/library', () => { it('should scan new files', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -521,7 +414,6 @@ describe('/library', () => { it('should reimport modified files', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -549,7 +441,6 @@ describe('/library', () => { it('should not reimport unmodified files', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -579,7 +470,6 @@ describe('/library', () => { it('should reimport all files', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -606,9 +496,9 @@ describe('/library', () => { }); }); - describe('POST /library/:id/removeOffline', () => { + describe('POST /libraries/:id/removeOffline', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post(`/library/${uuidDto.notFound}/removeOffline`).send({}); + const { status, body } = await request(app).post(`/libraries/${uuidDto.notFound}/removeOffline`).send({}); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -617,7 +507,6 @@ describe('/library', () => { it('should remove offline files', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -643,7 +532,7 @@ describe('/library', () => { expect(offlineAssets.count).toBe(1); const { status } = await request(app) - .post(`/library/${library.id}/removeOffline`) + .post(`/libraries/${library.id}/removeOffline`) .set('Authorization', `Bearer ${admin.accessToken}`) .send(); expect(status).toBe(204); @@ -658,7 +547,6 @@ describe('/library', () => { it('should not remove online files', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -669,7 +557,7 @@ describe('/library', () => { expect(assetsBefore.count).toBeGreaterThan(1); const { status } = await request(app) - .post(`/library/${library.id}/removeOffline`) + .post(`/libraries/${library.id}/removeOffline`) .set('Authorization', `Bearer ${admin.accessToken}`) .send(); expect(status).toBe(204); @@ -681,9 +569,9 @@ describe('/library', () => { }); }); - describe('POST /library/:id/validate', () => { + describe('POST /libraries/:id/validate', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post(`/library/${uuidDto.notFound}/validate`).send({}); + const { status, body } = await request(app).post(`/libraries/${uuidDto.notFound}/validate`).send({}); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -729,54 +617,25 @@ describe('/library', () => { }); }); - describe('DELETE /library/:id', () => { + describe('DELETE /libraries/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).delete(`/library/${uuidDto.notFound}`); + const { status, body } = await request(app).delete(`/libraries/${uuidDto.notFound}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); - it('should not delete the last upload library', async () => { - const libraries = await getAllLibraries( - { $type: LibraryType.Upload }, - { headers: asBearerAuth(admin.accessToken) }, - ); - - const adminLibraries = libraries.filter((library) => library.ownerId === admin.userId); - expect(adminLibraries.length).toBeGreaterThanOrEqual(1); - const lastLibrary = adminLibraries.pop() as LibraryResponseDto; - - // delete all but the last upload library - for (const library of adminLibraries) { - const { status } = await request(app) - .delete(`/library/${library.id}`) - .set('Authorization', `Bearer ${admin.accessToken}`); - expect(status).toBe(204); - } - - const { status, body } = await request(app) - .delete(`/library/${lastLibrary.id}`) - .set('Authorization', `Bearer ${admin.accessToken}`); - - expect(body).toEqual(errorDto.noDeleteUploadLibrary); - expect(status).toBe(400); - }); - it('should delete an external library', async () => { - const library = await utils.createLibrary(admin.accessToken, { - ownerId: admin.userId, - type: LibraryType.External, - }); + const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId }); const { status, body } = await request(app) - .delete(`/library/${library.id}`) + .delete(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(204); expect(body).toEqual({}); - const libraries = await getAllLibraries({}, { headers: asBearerAuth(admin.accessToken) }); + const libraries = await getAllLibraries({ headers: asBearerAuth(admin.accessToken) }); expect(libraries).not.toEqual( expect.arrayContaining([ expect.objectContaining({ @@ -789,7 +648,6 @@ describe('/library', () => { it('should delete an external library with assets', async () => { const library = await utils.createLibrary(admin.accessToken, { ownerId: admin.userId, - type: LibraryType.External, importPaths: [`${testAssetDirInternal}/temp`], }); @@ -797,13 +655,13 @@ describe('/library', () => { await utils.waitForWebsocketEvent({ event: 'assetUpload', total: 2 }); const { status, body } = await request(app) - .delete(`/library/${library.id}`) + .delete(`/libraries/${library.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(204); expect(body).toEqual({}); - const libraries = await getAllLibraries({}, { headers: asBearerAuth(admin.accessToken) }); + const libraries = await getAllLibraries({ headers: asBearerAuth(admin.accessToken) }); expect(libraries).not.toEqual( expect.arrayContaining([ expect.objectContaining({ diff --git a/e2e/src/api/specs/partner.e2e-spec.ts b/e2e/src/api/specs/partner.e2e-spec.ts index b2fb7f4101..1654f04e18 100644 --- a/e2e/src/api/specs/partner.e2e-spec.ts +++ b/e2e/src/api/specs/partner.e2e-spec.ts @@ -5,7 +5,7 @@ import { app, asBearerAuth, utils } from 'src/utils'; import request from 'supertest'; import { beforeAll, describe, expect, it } from 'vitest'; -describe('/partner', () => { +describe('/partners', () => { let admin: LoginResponseDto; let user1: LoginResponseDto; let user2: LoginResponseDto; @@ -28,9 +28,9 @@ describe('/partner', () => { ]); }); - describe('GET /partner', () => { + describe('GET /partners', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/partner'); + const { status, body } = await request(app).get('/partners'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -38,7 +38,7 @@ describe('/partner', () => { it('should get all partners shared by user', async () => { const { status, body } = await request(app) - .get('/partner') + .get('/partners') .set('Authorization', `Bearer ${user1.accessToken}`) .query({ direction: 'shared-by' }); @@ -48,7 +48,7 @@ describe('/partner', () => { it('should get all partners that share with user', async () => { const { status, body } = await request(app) - .get('/partner') + .get('/partners') .set('Authorization', `Bearer ${user1.accessToken}`) .query({ direction: 'shared-with' }); @@ -57,9 +57,9 @@ describe('/partner', () => { }); }); - describe('POST /partner/:id', () => { + describe('POST /partners/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post(`/partner/${user3.userId}`); + const { status, body } = await request(app).post(`/partners/${user3.userId}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -67,7 +67,7 @@ describe('/partner', () => { it('should share with new partner', async () => { const { status, body } = await request(app) - .post(`/partner/${user3.userId}`) + .post(`/partners/${user3.userId}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(201); @@ -76,7 +76,7 @@ describe('/partner', () => { it('should not share with new partner if already sharing with this partner', async () => { const { status, body } = await request(app) - .post(`/partner/${user2.userId}`) + .post(`/partners/${user2.userId}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(400); @@ -84,9 +84,9 @@ describe('/partner', () => { }); }); - describe('PUT /partner/:id', () => { + describe('PUT /partners/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).put(`/partner/${user2.userId}`); + const { status, body } = await request(app).put(`/partners/${user2.userId}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -94,7 +94,7 @@ describe('/partner', () => { it('should update partner', async () => { const { status, body } = await request(app) - .put(`/partner/${user2.userId}`) + .put(`/partners/${user2.userId}`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ inTimeline: false }); @@ -103,9 +103,9 @@ describe('/partner', () => { }); }); - describe('DELETE /partner/:id', () => { + describe('DELETE /partners/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).delete(`/partner/${user3.userId}`); + const { status, body } = await request(app).delete(`/partners/${user3.userId}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -113,7 +113,7 @@ describe('/partner', () => { it('should delete partner', async () => { const { status } = await request(app) - .delete(`/partner/${user3.userId}`) + .delete(`/partners/${user3.userId}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -121,7 +121,7 @@ describe('/partner', () => { it('should throw a bad request if partner not found', async () => { const { status, body } = await request(app) - .delete(`/partner/${user3.userId}`) + .delete(`/partners/${user3.userId}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(400); diff --git a/e2e/src/api/specs/person.e2e-spec.ts b/e2e/src/api/specs/person.e2e-spec.ts index 54fbfa9be5..963b4cf7bc 100644 --- a/e2e/src/api/specs/person.e2e-spec.ts +++ b/e2e/src/api/specs/person.e2e-spec.ts @@ -12,7 +12,7 @@ const invalidBirthday = [ { birthDate: new Date(9999, 0, 0).toISOString(), response: ['Birth date cannot be in the future'] }, ]; -describe('/person', () => { +describe('/people', () => { let admin: LoginResponseDto; let visiblePerson: PersonResponseDto; let hiddenPerson: PersonResponseDto; @@ -47,11 +47,11 @@ describe('/person', () => { ]); }); - describe('GET /person', () => { + describe('GET /people', () => { beforeEach(async () => {}); it('should require authentication', async () => { - const { status, body } = await request(app).get('/person'); + const { status, body } = await request(app).get('/people'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -59,7 +59,7 @@ describe('/person', () => { it('should return all people (including hidden)', async () => { const { status, body } = await request(app) - .get('/person') + .get('/people') .set('Authorization', `Bearer ${admin.accessToken}`) .query({ withHidden: true }); @@ -76,7 +76,7 @@ describe('/person', () => { }); it('should return only visible people', async () => { - const { status, body } = await request(app).get('/person').set('Authorization', `Bearer ${admin.accessToken}`); + const { status, body } = await request(app).get('/people').set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); expect(body).toEqual({ @@ -90,9 +90,9 @@ describe('/person', () => { }); }); - describe('GET /person/:id', () => { + describe('GET /people/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get(`/person/${uuidDto.notFound}`); + const { status, body } = await request(app).get(`/people/${uuidDto.notFound}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -100,7 +100,7 @@ describe('/person', () => { it('should throw error if person with id does not exist', async () => { const { status, body } = await request(app) - .get(`/person/${uuidDto.notFound}`) + .get(`/people/${uuidDto.notFound}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(400); @@ -109,7 +109,7 @@ describe('/person', () => { it('should return person information', async () => { const { status, body } = await request(app) - .get(`/person/${visiblePerson.id}`) + .get(`/people/${visiblePerson.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); @@ -117,9 +117,9 @@ describe('/person', () => { }); }); - describe('GET /person/:id/statistics', () => { + describe('GET /people/:id/statistics', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get(`/person/${multipleAssetsPerson.id}/statistics`); + const { status, body } = await request(app).get(`/people/${multipleAssetsPerson.id}/statistics`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -127,7 +127,7 @@ describe('/person', () => { it('should throw error if person with id does not exist', async () => { const { status, body } = await request(app) - .get(`/person/${uuidDto.notFound}/statistics`) + .get(`/people/${uuidDto.notFound}/statistics`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(400); @@ -136,7 +136,7 @@ describe('/person', () => { it('should return the correct number of assets', async () => { const { status, body } = await request(app) - .get(`/person/${multipleAssetsPerson.id}/statistics`) + .get(`/people/${multipleAssetsPerson.id}/statistics`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); @@ -144,9 +144,9 @@ describe('/person', () => { }); }); - describe('POST /person', () => { + describe('POST /people', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post(`/person`); + const { status, body } = await request(app).post(`/people`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); @@ -154,7 +154,7 @@ describe('/person', () => { for (const { birthDate, response } of invalidBirthday) { it(`should not accept an invalid birth date [${birthDate}]`, async () => { const { status, body } = await request(app) - .post(`/person`) + .post(`/people`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ birthDate }); expect(status).toBe(400); @@ -164,7 +164,7 @@ describe('/person', () => { it('should create a person', async () => { const { status, body } = await request(app) - .post(`/person`) + .post(`/people`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ name: 'New Person', @@ -179,9 +179,9 @@ describe('/person', () => { }); }); - describe('PUT /person/:id', () => { + describe('PUT /people/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).put(`/person/${uuidDto.notFound}`); + const { status, body } = await request(app).put(`/people/${uuidDto.notFound}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); @@ -193,7 +193,7 @@ describe('/person', () => { ]) { it(`should not allow null ${key}`, async () => { const { status, body } = await request(app) - .put(`/person/${visiblePerson.id}`) + .put(`/people/${visiblePerson.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ [key]: null }); expect(status).toBe(400); @@ -204,7 +204,7 @@ describe('/person', () => { for (const { birthDate, response } of invalidBirthday) { it(`should not accept an invalid birth date [${birthDate}]`, async () => { const { status, body } = await request(app) - .put(`/person/${visiblePerson.id}`) + .put(`/people/${visiblePerson.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ birthDate }); expect(status).toBe(400); @@ -214,7 +214,7 @@ describe('/person', () => { it('should update a date of birth', async () => { const { status, body } = await request(app) - .put(`/person/${visiblePerson.id}`) + .put(`/people/${visiblePerson.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ birthDate: '1990-01-01T05:00:00.000Z' }); expect(status).toBe(200); @@ -223,7 +223,7 @@ describe('/person', () => { it('should clear a date of birth', async () => { const { status, body } = await request(app) - .put(`/person/${visiblePerson.id}`) + .put(`/people/${visiblePerson.id}`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ birthDate: null }); expect(status).toBe(200); diff --git a/e2e/src/api/specs/server-info.e2e-spec.ts b/e2e/src/api/specs/server-info.e2e-spec.ts index b900a59235..431971ac85 100644 --- a/e2e/src/api/specs/server-info.e2e-spec.ts +++ b/e2e/src/api/specs/server-info.e2e-spec.ts @@ -15,16 +15,16 @@ describe('/server-info', () => { nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user1); }); - describe('GET /server-info', () => { + describe('GET /server-info/storage', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/server-info'); + const { status, body } = await request(app).get('/server-info/storage'); 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') + .get('/server-info/storage') .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); expect(body).toEqual({ @@ -66,6 +66,7 @@ describe('/server-info', () => { expect(body).toEqual({ smartSearch: false, configFile: false, + duplicateDetection: false, facialRecognition: false, map: true, reverseGeocoding: true, diff --git a/e2e/src/api/specs/shared-link.e2e-spec.ts b/e2e/src/api/specs/shared-link.e2e-spec.ts index c446fe9cdb..aa4ec7e349 100644 --- a/e2e/src/api/specs/shared-link.e2e-spec.ts +++ b/e2e/src/api/specs/shared-link.e2e-spec.ts @@ -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-link', () => { +describe('/shared-links', () => { let admin: LoginResponseDto; let asset1: AssetFileUploadResponseDto; let asset2: AssetFileUploadResponseDto; @@ -114,9 +114,9 @@ describe('/shared-link', () => { }); }); - describe('GET /shared-link', () => { + describe('GET /shared-links', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/shared-link'); + const { status, body } = await request(app).get('/shared-links'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -124,7 +124,7 @@ describe('/shared-link', () => { it('should get all shared links created by user', async () => { const { status, body } = await request(app) - .get('/shared-link') + .get('/shared-links') .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -142,7 +142,7 @@ describe('/shared-link', () => { it('should not get shared links created by other users', async () => { const { status, body } = await request(app) - .get('/shared-link') + .get('/shared-links') .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); @@ -150,15 +150,15 @@ describe('/shared-link', () => { }); }); - describe('GET /shared-link/me', () => { + describe('GET /shared-links/me', () => { it('should not require admin authentication', async () => { - const { status } = await request(app).get('/shared-link/me').set('Authorization', `Bearer ${admin.accessToken}`); + const { status } = await request(app).get('/shared-links/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-link/me').query({ key: linkWithAlbum.key }); + const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithAlbum.key }); expect(status).toBe(200); expect(body).toEqual( @@ -172,7 +172,7 @@ describe('/shared-link', () => { it('should return unauthorized for incorrect shared link', async () => { const { status, body } = await request(app) - .get('/shared-link/me') + .get('/shared-links/me') .query({ key: linkWithAlbum.key + 'foo' }); expect(status).toBe(401); @@ -180,14 +180,14 @@ describe('/shared-link', () => { }); it('should return unauthorized if target has been soft deleted', async () => { - const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithDeletedAlbum.key }); + const { status, body } = await request(app).get('/shared-links/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-link/me').query({ key: linkWithPassword.key }); + const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithPassword.key }); expect(status).toBe(401); expect(body).toEqual(errorDto.invalidSharePassword); @@ -195,7 +195,7 @@ describe('/shared-link', () => { it('should get data for correct password protected link', async () => { const { status, body } = await request(app) - .get('/shared-link/me') + .get('/shared-links/me') .query({ key: linkWithPassword.key, password: 'foo' }); expect(status).toBe(200); @@ -209,7 +209,7 @@ describe('/shared-link', () => { }); it('should return metadata for album shared link', async () => { - const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithMetadata.key }); + const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithMetadata.key }); expect(status).toBe(200); expect(body.assets).toHaveLength(1); @@ -225,7 +225,7 @@ describe('/shared-link', () => { }); it('should not return metadata for album shared link without metadata', async () => { - const { status, body } = await request(app).get('/shared-link/me').query({ key: linkWithoutMetadata.key }); + const { status, body } = await request(app).get('/shared-links/me').query({ key: linkWithoutMetadata.key }); expect(status).toBe(200); expect(body.assets).toHaveLength(1); @@ -239,9 +239,9 @@ describe('/shared-link', () => { }); }); - describe('GET /shared-link/:id', () => { + describe('GET /shared-links/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get(`/shared-link/${linkWithAlbum.id}`); + const { status, body } = await request(app).get(`/shared-links/${linkWithAlbum.id}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -249,7 +249,7 @@ describe('/shared-link', () => { it('should get shared link by id', async () => { const { status, body } = await request(app) - .get(`/shared-link/${linkWithAlbum.id}`) + .get(`/shared-links/${linkWithAlbum.id}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); @@ -264,7 +264,7 @@ describe('/shared-link', () => { 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-link/${linkWithAlbum.id}`) + .get(`/shared-links/${linkWithAlbum.id}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(400); @@ -272,10 +272,10 @@ describe('/shared-link', () => { }); }); - describe('POST /shared-link', () => { + describe('POST /shared-links', () => { it('should require authentication', async () => { const { status, body } = await request(app) - .post('/shared-link') + .post('/shared-links') .send({ type: SharedLinkType.Album, albumId: uuidDto.notFound }); expect(status).toBe(401); @@ -284,7 +284,7 @@ describe('/shared-link', () => { it('should require a type and the correspondent asset/album id', async () => { const { status, body } = await request(app) - .post('/shared-link') + .post('/shared-links') .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(400); @@ -293,7 +293,7 @@ describe('/shared-link', () => { it('should require an asset/album id', async () => { const { status, body } = await request(app) - .post('/shared-link') + .post('/shared-links') .set('Authorization', `Bearer ${user1.accessToken}`) .send({ type: SharedLinkType.Album }); @@ -303,7 +303,7 @@ describe('/shared-link', () => { it('should require a valid asset id', async () => { const { status, body } = await request(app) - .post('/shared-link') + .post('/shared-links') .set('Authorization', `Bearer ${user1.accessToken}`) .send({ type: SharedLinkType.Individual, assetId: uuidDto.notFound }); @@ -313,7 +313,7 @@ describe('/shared-link', () => { it('should create a shared link', async () => { const { status, body } = await request(app) - .post('/shared-link') + .post('/shared-links') .set('Authorization', `Bearer ${user1.accessToken}`) .send({ type: SharedLinkType.Album, albumId: album.id }); @@ -327,10 +327,10 @@ describe('/shared-link', () => { }); }); - describe('PATCH /shared-link/:id', () => { + describe('PATCH /shared-links/:id', () => { it('should require authentication', async () => { const { status, body } = await request(app) - .patch(`/shared-link/${linkWithAlbum.id}`) + .patch(`/shared-links/${linkWithAlbum.id}`) .send({ description: 'foo' }); expect(status).toBe(401); @@ -339,7 +339,7 @@ describe('/shared-link', () => { it('should fail if invalid link', async () => { const { status, body } = await request(app) - .patch(`/shared-link/${uuidDto.notFound}`) + .patch(`/shared-links/${uuidDto.notFound}`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ description: 'foo' }); @@ -349,7 +349,7 @@ describe('/shared-link', () => { it('should update shared link', async () => { const { status, body } = await request(app) - .patch(`/shared-link/${linkWithAlbum.id}`) + .patch(`/shared-links/${linkWithAlbum.id}`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ description: 'foo' }); @@ -364,10 +364,10 @@ describe('/shared-link', () => { }); }); - describe('PUT /shared-link/:id/assets', () => { + describe('PUT /shared-links/:id/assets', () => { it('should not add assets to shared link (album)', async () => { const { status, body } = await request(app) - .put(`/shared-link/${linkWithAlbum.id}/assets`) + .put(`/shared-links/${linkWithAlbum.id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ assetIds: [asset2.id] }); @@ -377,7 +377,7 @@ describe('/shared-link', () => { it('should add an assets to a shared link (individual)', async () => { const { status, body } = await request(app) - .put(`/shared-link/${linkWithAssets.id}/assets`) + .put(`/shared-links/${linkWithAssets.id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ assetIds: [asset2.id] }); @@ -386,10 +386,10 @@ describe('/shared-link', () => { }); }); - describe('DELETE /shared-link/:id/assets', () => { + describe('DELETE /shared-links/:id/assets', () => { it('should not remove assets from a shared link (album)', async () => { const { status, body } = await request(app) - .delete(`/shared-link/${linkWithAlbum.id}/assets`) + .delete(`/shared-links/${linkWithAlbum.id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ assetIds: [asset2.id] }); @@ -399,7 +399,7 @@ describe('/shared-link', () => { it('should remove assets from a shared link (individual)', async () => { const { status, body } = await request(app) - .delete(`/shared-link/${linkWithAssets.id}/assets`) + .delete(`/shared-links/${linkWithAssets.id}/assets`) .set('Authorization', `Bearer ${user1.accessToken}`) .send({ assetIds: [asset2.id] }); @@ -408,9 +408,9 @@ describe('/shared-link', () => { }); }); - describe('DELETE /shared-link/:id', () => { + describe('DELETE /shared-links/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).delete(`/shared-link/${linkWithAlbum.id}`); + const { status, body } = await request(app).delete(`/shared-links/${linkWithAlbum.id}`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); @@ -418,7 +418,7 @@ describe('/shared-link', () => { it('should fail if invalid link', async () => { const { status, body } = await request(app) - .delete(`/shared-link/${uuidDto.notFound}`) + .delete(`/shared-links/${uuidDto.notFound}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(400); @@ -427,7 +427,7 @@ describe('/shared-link', () => { it('should delete a shared link', async () => { const { status } = await request(app) - .delete(`/shared-link/${linkWithAlbum.id}`) + .delete(`/shared-links/${linkWithAlbum.id}`) .set('Authorization', `Bearer ${user1.accessToken}`); expect(status).toBe(200); diff --git a/e2e/src/api/specs/system-config.e2e-spec.ts b/e2e/src/api/specs/system-config.e2e-spec.ts index 04cfec91e0..6be2683898 100644 --- a/e2e/src/api/specs/system-config.e2e-spec.ts +++ b/e2e/src/api/specs/system-config.e2e-spec.ts @@ -86,6 +86,26 @@ describe('/system-config', () => { expect(body).toEqual(errorDto.unauthorized); }); + it('should always return the new config', async () => { + const config = await getSystemConfig(admin.accessToken); + + const response1 = await request(app) + .put('/system-config') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ ...config, newVersionCheck: { enabled: false } }); + + expect(response1.status).toBe(200); + expect(response1.body).toEqual({ ...config, newVersionCheck: { enabled: false } }); + + const response2 = await request(app) + .put('/system-config') + .set('Authorization', `Bearer ${admin.accessToken}`) + .send({ ...config, newVersionCheck: { enabled: true } }); + + expect(response2.status).toBe(200); + expect(response2.body).toEqual({ ...config, newVersionCheck: { enabled: true } }); + }); + it('should reject an invalid config entry', async () => { const { status, body } = await request(app) .put('/system-config') diff --git a/e2e/src/api/specs/trash.e2e-spec.ts b/e2e/src/api/specs/trash.e2e-spec.ts index dc2cadc498..3049ff1511 100644 --- a/e2e/src/api/specs/trash.e2e-spec.ts +++ b/e2e/src/api/specs/trash.e2e-spec.ts @@ -1,4 +1,4 @@ -import { LoginResponseDto, getAllAssets } from '@immich/sdk'; +import { LoginResponseDto, getAssetInfo, getAssetStatistics } from '@immich/sdk'; import { Socket } from 'socket.io-client'; import { errorDto } from 'src/responses'; import { app, asBearerAuth, utils } from 'src/utils'; @@ -31,17 +31,16 @@ describe('/trash', () => { const { id: assetId } = await utils.createAsset(admin.accessToken); await utils.deleteAssets(admin.accessToken, [assetId]); - const before = await getAllAssets({}, { headers: asBearerAuth(admin.accessToken) }); - - expect(before.length).toBeGreaterThanOrEqual(1); + const before = await getAssetInfo({ id: assetId }, { 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 getAllAssets({}, { headers: asBearerAuth(admin.accessToken) }); - expect(after.length).toBe(0); + const after = await getAssetStatistics({ isTrashed: true }, { headers: asBearerAuth(admin.accessToken) }); + expect(after.total).toBe(0); }); }); @@ -57,14 +56,14 @@ describe('/trash', () => { const { id: assetId } = await utils.createAsset(admin.accessToken); await utils.deleteAssets(admin.accessToken, [assetId]); - const before = await utils.getAssetInfo(admin.accessToken, assetId); - expect(before.isTrashed).toBe(true); + const before = await getAssetInfo({ id: assetId }, { 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 utils.getAssetInfo(admin.accessToken, assetId); - expect(after.isTrashed).toBe(false); + const after = await getAssetInfo({ id: assetId }, { headers: asBearerAuth(admin.accessToken) }); + expect(after).toStrictEqual(expect.objectContaining({ id: assetId, isTrashed: false })); }); }); diff --git a/e2e/src/api/specs/user.e2e-spec.ts b/e2e/src/api/specs/user.e2e-spec.ts index 911f25381a..08b2d34ef6 100644 --- a/e2e/src/api/specs/user.e2e-spec.ts +++ b/e2e/src/api/specs/user.e2e-spec.ts @@ -6,7 +6,7 @@ import { app, asBearerAuth, utils } from 'src/utils'; import request from 'supertest'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -describe('/user', () => { +describe('/users', () => { let websocket: Socket; let admin: LoginResponseDto; @@ -34,15 +34,15 @@ describe('/user', () => { utils.disconnectWebsocket(websocket); }); - describe('GET /user', () => { + describe('GET /users', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get('/user'); + const { status, body } = await request(app).get('/users'); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); it('should get users', async () => { - const { status, body } = await request(app).get('/user').set('Authorization', `Bearer ${admin.accessToken}`); + const { status, body } = await request(app).get('/users').set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toEqual(200); expect(body).toHaveLength(5); expect(body).toEqual( @@ -58,7 +58,7 @@ describe('/user', () => { it('should hide deleted users', async () => { const { status, body } = await request(app) - .get(`/user`) + .get(`/users`) .query({ isAll: true }) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); @@ -75,7 +75,7 @@ describe('/user', () => { it('should include deleted users', async () => { const { status, body } = await request(app) - .get(`/user`) + .get(`/users`) .query({ isAll: false }) .set('Authorization', `Bearer ${admin.accessToken}`); @@ -93,15 +93,15 @@ describe('/user', () => { }); }); - describe('GET /user/info/:id', () => { + describe('GET /users/:id', () => { it('should require authentication', async () => { - const { status } = await request(app).get(`/user/info/${admin.userId}`); + const { status } = await request(app).get(`/users/${admin.userId}`); expect(status).toEqual(401); }); it('should get the user info', async () => { const { status, body } = await request(app) - .get(`/user/info/${admin.userId}`) + .get(`/users/${admin.userId}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); expect(body).toMatchObject({ @@ -111,15 +111,15 @@ describe('/user', () => { }); }); - describe('GET /user/me', () => { + describe('GET /users/me', () => { it('should require authentication', async () => { - const { status, body } = await request(app).get(`/user/me`); + const { status, body } = await request(app).get(`/users/me`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); it('should get my info', async () => { - const { status, body } = await request(app).get(`/user/me`).set('Authorization', `Bearer ${admin.accessToken}`); + const { status, body } = await request(app).get(`/users/me`).set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); expect(body).toMatchObject({ id: admin.userId, @@ -128,9 +128,9 @@ describe('/user', () => { }); }); - describe('POST /user', () => { + describe('POST /users', () => { it('should require authentication', async () => { - const { status, body } = await request(app).post(`/user`).send(createUserDto.user1); + const { status, body } = await request(app).post(`/users`).send(createUserDto.user1); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); @@ -138,7 +138,7 @@ describe('/user', () => { for (const key of Object.keys(createUserDto.user1)) { it(`should not allow null ${key}`, async () => { const { status, body } = await request(app) - .post(`/user`) + .post(`/users`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ ...createUserDto.user1, [key]: null }); expect(status).toBe(400); @@ -148,7 +148,7 @@ describe('/user', () => { it('should ignore `isAdmin`', async () => { const { status, body } = await request(app) - .post(`/user`) + .post(`/users`) .send({ isAdmin: true, email: 'user5@immich.cloud', @@ -166,7 +166,7 @@ describe('/user', () => { it('should create a user without memories enabled', async () => { const { status, body } = await request(app) - .post(`/user`) + .post(`/users`) .send({ email: 'no-memories@immich.cloud', password: 'Password123', @@ -182,16 +182,16 @@ describe('/user', () => { }); }); - describe('DELETE /user/:id', () => { + describe('DELETE /users/:id', () => { it('should require authentication', async () => { - const { status, body } = await request(app).delete(`/user/${userToDelete.userId}`); + const { status, body } = await request(app).delete(`/users/${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}`) + .delete(`/users/${userToDelete.userId}`) .set('Authorization', `Bearer ${admin.accessToken}`); expect(status).toBe(200); @@ -204,7 +204,7 @@ describe('/user', () => { it('should hard delete user', async () => { const { status, body } = await request(app) - .delete(`/user/${userToHardDelete.userId}`) + .delete(`/users/${userToHardDelete.userId}`) .send({ force: true }) .set('Authorization', `Bearer ${admin.accessToken}`); @@ -219,9 +219,9 @@ describe('/user', () => { }); }); - describe('PUT /user', () => { + describe('PUT /users', () => { it('should require authentication', async () => { - const { status, body } = await request(app).put(`/user`); + const { status, body } = await request(app).put(`/users`); expect(status).toBe(401); expect(body).toEqual(errorDto.unauthorized); }); @@ -229,7 +229,7 @@ describe('/user', () => { for (const key of Object.keys(userDto.admin)) { it(`should not allow null ${key}`, async () => { const { status, body } = await request(app) - .put(`/user`) + .put(`/users`) .set('Authorization', `Bearer ${admin.accessToken}`) .send({ ...userDto.admin, [key]: null }); expect(status).toBe(400); @@ -239,7 +239,7 @@ describe('/user', () => { it('should not allow a non-admin to become an admin', async () => { const { status, body } = await request(app) - .put(`/user`) + .put(`/users`) .send({ isAdmin: true, id: nonAdmin.userId }) .set('Authorization', `Bearer ${admin.accessToken}`); @@ -249,7 +249,7 @@ describe('/user', () => { it('ignores updates to profileImagePath', async () => { const { status, body } = await request(app) - .put(`/user`) + .put(`/users`) .send({ id: admin.userId, profileImagePath: 'invalid.jpg' }) .set('Authorization', `Bearer ${admin.accessToken}`); @@ -257,28 +257,11 @@ describe('/user', () => { 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(`/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`) + .put(`/users`) .send({ id: admin.userId, name: 'Name', @@ -297,7 +280,7 @@ describe('/user', () => { it('should update memories enabled', async () => { const before = await getUserById({ id: admin.userId }, { headers: asBearerAuth(admin.accessToken) }); const { status, body } = await request(app) - .put(`/user`) + .put(`/users`) .send({ id: admin.userId, memoriesEnabled: false, diff --git a/e2e/src/cli/specs/upload.e2e-spec.ts b/e2e/src/cli/specs/upload.e2e-spec.ts index 89f38feadc..db2b6c5341 100644 --- a/e2e/src/cli/specs/upload.e2e-spec.ts +++ b/e2e/src/cli/specs/upload.e2e-spec.ts @@ -1,4 +1,4 @@ -import { LoginResponseDto, getAllAlbums, getAllAssets } from '@immich/sdk'; +import { LoginResponseDto, getAllAlbums, getAssetStatistics } 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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(1); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(1); }); it('should skip a duplicate file', async () => { @@ -40,8 +40,8 @@ describe(`immich upload`, () => { ); expect(first.exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(1); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(0); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(0); }); it('should have accurate dry run', async () => { @@ -76,8 +76,8 @@ describe(`immich upload`, () => { ); expect(exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(0); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(0); }); it('dry run should handle duplicates', async () => { @@ -88,8 +88,8 @@ describe(`immich upload`, () => { ); expect(first.exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(1); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(9); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(9); }); }); @@ -135,8 +135,8 @@ describe(`immich upload`, () => { expect(stderr).toBe(''); expect(exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(9); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets1.length).toBe(9); + const assets1 = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets1.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets2.length).toBe(9); + const assets2 = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets2.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(0); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(9); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(0); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(9); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(0); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(0); }); }); @@ -328,8 +328,8 @@ describe(`immich upload`, () => { ); expect(exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(1); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).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 getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(0); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(0); }); }); @@ -367,8 +367,8 @@ describe(`immich upload`, () => { ); expect(exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(9); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(9); }); it('should reject string argument', async () => { @@ -408,8 +408,8 @@ describe(`immich upload`, () => { ); expect(exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(8); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(8); }); it('should ignore assets matching glob pattern', async () => { @@ -429,8 +429,8 @@ describe(`immich upload`, () => { ); expect(exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(1); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(1); }); it('should have accurate dry run', async () => { @@ -451,8 +451,8 @@ describe(`immich upload`, () => { ); expect(exitCode).toBe(0); - const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); - expect(assets.length).toBe(0); + const assets = await getAssetStatistics({}, { headers: asKeyAuth(key) }); + expect(assets.total).toBe(0); }); }); }); diff --git a/e2e/src/responses.ts b/e2e/src/responses.ts index 37892be0c8..afe3334a7f 100644 --- a/e2e/src/responses.ts +++ b/e2e/src/responses.ts @@ -51,11 +51,6 @@ export const errorDto = { statusCode: 400, message: 'The server already has an admin', }, - noDeleteUploadLibrary: { - error: 'Bad Request', - statusCode: 400, - message: 'Cannot delete the last upload library', - }, }; export const signupResponseDto = { diff --git a/e2e/src/setup.ts b/e2e/src/setup.ts index e9395ddd35..3ae87417a2 100644 --- a/e2e/src/setup.ts +++ b/e2e/src/setup.ts @@ -17,7 +17,7 @@ const setup = async () => { child.stdout.on('data', (data) => { const input = data.toString(); console.log(input); - if (input.includes('Immich Microservices is listening')) { + if (input.includes('Immich Microservices is running')) { _resolve(); } }); diff --git a/e2e/src/utils.ts b/e2e/src/utils.ts index 908c87faed..1454135c12 100644 --- a/e2e/src/utils.ts +++ b/e2e/src/utils.ts @@ -13,17 +13,17 @@ import { createAlbum, createApiKey, createLibrary, + createPartner, createPerson, createSharedLink, createUser, - defaults, deleteAssets, - getAllAssets, getAllJobsStatus, getAssetInfo, getConfigDefaults, login, searchMetadata, + setBaseUrl, signUpAdmin, updateAdminOnboarding, updateAlbumUser, @@ -145,7 +145,6 @@ export const utils = { 'sessions', 'users', 'system_metadata', - 'system_config', ]; const sql: string[] = []; @@ -256,8 +255,8 @@ export const utils = { }); }, - setApiEndpoint: () => { - defaults.baseUrl = app; + initSdk: () => { + setBaseUrl(app); }, adminSetup: async (options?: AdminSetupOptions) => { @@ -341,8 +340,6 @@ 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) }); }, @@ -389,6 +386,8 @@ 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([ { @@ -463,7 +462,7 @@ export const utils = { }, }; -utils.setApiEndpoint(); +utils.initSdk(); if (!existsSync(`${testAssetDir}/albums`)) { throw new Error( diff --git a/e2e/src/web/specs/asset-viewer/detail-panel.e2e-spec.ts b/e2e/src/web/specs/asset-viewer/detail-panel.e2e-spec.ts new file mode 100644 index 0000000000..9cfcc4f37b --- /dev/null +++ b/e2e/src/web/specs/asset-viewer/detail-panel.e2e-spec.ts @@ -0,0 +1,60 @@ +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(); + }); +}); diff --git a/e2e/src/web/specs/asset-viewer/navbar.e2e-spec.ts b/e2e/src/web/specs/asset-viewer/navbar.e2e-spec.ts new file mode 100644 index 0000000000..642d63d5d3 --- /dev/null +++ b/e2e/src/web/specs/asset-viewer/navbar.e2e-spec.ts @@ -0,0 +1,52 @@ +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]); + } + }); + }); +}); diff --git a/e2e/src/web/specs/auth.e2e-spec.ts b/e2e/src/web/specs/auth.e2e-spec.ts index 73d62f1b10..ebafbf1f67 100644 --- a/e2e/src/web/specs/auth.e2e-spec.ts +++ b/e2e/src/web/specs/auth.e2e-spec.ts @@ -3,7 +3,7 @@ import { utils } from 'src/utils'; test.describe('Registration', () => { test.beforeAll(() => { - utils.setApiEndpoint(); + utils.initSdk(); }); test.beforeEach(async () => { diff --git a/e2e/src/web/specs/shared-link.e2e-spec.ts b/e2e/src/web/specs/shared-link.e2e-spec.ts index 3540ed72e2..8687306615 100644 --- a/e2e/src/web/specs/shared-link.e2e-spec.ts +++ b/e2e/src/web/specs/shared-link.e2e-spec.ts @@ -17,7 +17,7 @@ test.describe('Shared Links', () => { let sharedLinkPassword: SharedLinkResponseDto; test.beforeAll(async () => { - utils.setApiEndpoint(); + utils.initSdk(); await utils.resetDatabase(); admin = await utils.adminSetup(); asset = await utils.createAsset(admin.accessToken); diff --git a/install.sh b/install.sh index 92d9c1b8be..e9c65b3283 100755 --- a/install.sh +++ b/install.sh @@ -2,14 +2,15 @@ set -o nounset set -o pipefail -create_immich_directory() { local -r Tgt='./immich-app' +create_immich_directory() { + local -r Tgt='./immich-app' echo "Creating Immich directory..." if [[ -e $Tgt ]]; then echo "Found existing directory $Tgt, will overwrite YAML files" else mkdir "$Tgt" || return - fi - cd "$Tgt" || return + fi + cd "$Tgt" || return 1 } download_docker_compose_file() { @@ -22,6 +23,16 @@ download_dot_env_file() { "${Curl[@]}" "$RepoUrl"/example.env -o ./.env } +generate_random_password() { + echo "Generate random password for .env file..." + rand_pass=$(echo "$RANDOM$(date)$RANDOM" | sha256sum | base64 | head -c10) + if [ -z "$rand_pass" ]; then + sed -i -e "s/DB_PASSWORD=postgres/DB_PASSWORD=postgres${RANDOM}${RANDOM}/" ./.env + else + sed -i -e "s/DB_PASSWORD=postgres/DB_PASSWORD=${rand_pass}/" ./.env + fi +} + start_docker_compose() { echo "Starting Immich's docker containers" @@ -40,16 +51,16 @@ start_docker_compose() { show_friendly_message() { local ip_address ip_address=$(hostname -I | awk '{print $1}') - cat << EOF + cat <=6)"] [[package]] -name = "fastapi" -version = "0.110.3" +name = "fastapi-slim" +version = "0.111.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.110.3-py3-none-any.whl", hash = "sha256:fd7600612f755e4050beb74001310b5a7e1796d149c2ee363124abdfa0289d32"}, - {file = "fastapi-0.110.3.tar.gz", hash = "sha256:555700b0159379e94fdbfc6bb66a0f1c43f4cf7060f25239af3d84b63a656626"}, + {file = "fastapi_slim-0.111.0-py3-none-any.whl", hash = "sha256:6e4b04a555496e5a2590031fcae3ef8e364ad4901b340033e2e1d8136471aca2"}, + {file = "fastapi_slim-0.111.0.tar.gz", hash = "sha256:100720e4362ec4de97dee83a579b970e79fb5bf48073b37c9ce9b0e63dda4bec"}, ] [package.dependencies] @@ -695,7 +695,8 @@ starlette = ">=0.37.2,<0.38.0" typing-extensions = ">=4.8.0" [package.extras] -all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +all = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email_validator (>=2.0.0)", "fastapi-cli (>=0.0.2)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.7)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" @@ -737,13 +738,13 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-cors" -version = "4.0.0" +version = "4.0.1" description = "A Flask extension adding a decorator for CORS support" optional = false python-versions = "*" files = [ - {file = "Flask-Cors-4.0.0.tar.gz", hash = "sha256:f268522fcb2f73e2ecdde1ef45e2fd5c71cc48fe03cffb4b441c6d1b40684eb0"}, - {file = "Flask_Cors-4.0.0-py2.py3-none-any.whl", hash = "sha256:bc3492bfd6368d27cfe79c7821df5a8a319e1a6d5eab277a3794be19bdc51783"}, + {file = "Flask_Cors-4.0.1-py2.py3-none-any.whl", hash = "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677"}, + {file = "flask_cors-4.0.1.tar.gz", hash = "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4"}, ] [package.dependencies] @@ -1235,13 +1236,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" -version = "0.22.2" +version = "0.23.0" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.22.2-py3-none-any.whl", hash = "sha256:3429e25f38ccb834d310804a3b711e7e4953db5a9e420cc147a5e194ca90fd17"}, - {file = "huggingface_hub-0.22.2.tar.gz", hash = "sha256:32e9a9a6843c92f253ff9ca16b9985def4d80a93fb357af5353f770ef74a81be"}, + {file = "huggingface_hub-0.23.0-py3-none-any.whl", hash = "sha256:075c30d48ee7db2bba779190dc526d2c11d422aed6f9044c5e2fdc2c432fdb91"}, + {file = "huggingface_hub-0.23.0.tar.gz", hash = "sha256:7126dedd10a4c6fac796ced4d87a8cf004efc722a5125c2c09299017fa366fa9"}, ] [package.dependencies] @@ -1254,16 +1255,16 @@ tqdm = ">=4.42.1" typing-extensions = ">=3.7.4.3" [package.extras] -all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] cli = ["InquirerPy (==0.3.4)"] -dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] hf-transfer = ["hf-transfer (>=0.1.4)"] inference = ["aiohttp", "minijinja (>=1.0)"] quality = ["mypy (==1.5.1)", "ruff (>=0.3.0)"] tensorflow = ["graphviz", "pydot", "tensorflow"] tensorflow-testing = ["keras (<3.0)", "tensorflow"] -testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] torch = ["safetensors", "torch"] typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] @@ -1373,13 +1374,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.3" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, - {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -1529,13 +1530,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"] [[package]] name = "locust" -version = "2.26.0" +version = "2.27.0" description = "Developer friendly load testing framework" optional = false python-versions = ">=3.9" files = [ - {file = "locust-2.26.0-py3-none-any.whl", hash = "sha256:7957d8346e5830ba35e3a7a9c1eebe0fb73b0be117e54213c61ef3bc658a1ae6"}, - {file = "locust-2.26.0.tar.gz", hash = "sha256:a5cb4c96b8fa1ae5c20876ab8ca9d1e980d56148ed3c187df610cc2546705bff"}, + {file = "locust-2.27.0-py3-none-any.whl", hash = "sha256:c4db5747eb9a3851216deae8147143d335db41978a9291ac32e113fa9ec8ad39"}, + {file = "locust-2.27.0.tar.gz", hash = "sha256:0c6d3d2523976dafe734012c41b2f7d9ad7120cbcea76d47d80cec5d6d139905"}, ] [package.dependencies] @@ -1550,7 +1551,6 @@ psutil = ">=5.9.1" pywin32 = {version = "*", markers = "platform_system == \"Windows\""} pyzmq = ">=25.0.0" requests = ">=2.26.0" -roundrobin = ">=0.0.2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} Werkzeug = ">=2.0.0" @@ -2797,40 +2797,30 @@ pygments = ">=2.13.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] -[[package]] -name = "roundrobin" -version = "0.0.4" -description = "Collection of roundrobin utilities" -optional = false -python-versions = "*" -files = [ - {file = "roundrobin-0.0.4.tar.gz", hash = "sha256:7e9d19a5bd6123d99993fb935fa86d25c88bb2096e493885f61737ed0f5e9abd"}, -] - [[package]] name = "ruff" -version = "0.4.2" +version = "0.4.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.4.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d14dc8953f8af7e003a485ef560bbefa5f8cc1ad994eebb5b12136049bbccc5"}, - {file = "ruff-0.4.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:24016ed18db3dc9786af103ff49c03bdf408ea253f3cb9e3638f39ac9cf2d483"}, - {file = "ruff-0.4.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2e06459042ac841ed510196c350ba35a9b24a643e23db60d79b2db92af0c2b"}, - {file = "ruff-0.4.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3afabaf7ba8e9c485a14ad8f4122feff6b2b93cc53cd4dad2fd24ae35112d5c5"}, - {file = "ruff-0.4.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:799eb468ea6bc54b95527143a4ceaf970d5aa3613050c6cff54c85fda3fde480"}, - {file = "ruff-0.4.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ec4ba9436a51527fb6931a8839af4c36a5481f8c19e8f5e42c2f7ad3a49f5069"}, - {file = "ruff-0.4.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a2243f8f434e487c2a010c7252150b1fdf019035130f41b77626f5655c9ca22"}, - {file = "ruff-0.4.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8772130a063f3eebdf7095da00c0b9898bd1774c43b336272c3e98667d4fb8fa"}, - {file = "ruff-0.4.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ab165ef5d72392b4ebb85a8b0fbd321f69832a632e07a74794c0e598e7a8376"}, - {file = "ruff-0.4.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1f32cadf44c2020e75e0c56c3408ed1d32c024766bd41aedef92aa3ca28eef68"}, - {file = "ruff-0.4.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:22e306bf15e09af45ca812bc42fa59b628646fa7c26072555f278994890bc7ac"}, - {file = "ruff-0.4.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:82986bb77ad83a1719c90b9528a9dd663c9206f7c0ab69282af8223566a0c34e"}, - {file = "ruff-0.4.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:652e4ba553e421a6dc2a6d4868bc3b3881311702633eb3672f9f244ded8908cd"}, - {file = "ruff-0.4.2-py3-none-win32.whl", hash = "sha256:7891ee376770ac094da3ad40c116258a381b86c7352552788377c6eb16d784fe"}, - {file = "ruff-0.4.2-py3-none-win_amd64.whl", hash = "sha256:5ec481661fb2fd88a5d6cf1f83403d388ec90f9daaa36e40e2c003de66751798"}, - {file = "ruff-0.4.2-py3-none-win_arm64.whl", hash = "sha256:cbd1e87c71bca14792948c4ccb51ee61c3296e164019d2d484f3eaa2d360dfaf"}, - {file = "ruff-0.4.2.tar.gz", hash = "sha256:33bcc160aee2520664bc0859cfeaebc84bb7323becff3f303b8f1f2d81cb4edc"}, + {file = "ruff-0.4.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:29d44ef5bb6a08e235c8249294fa8d431adc1426bfda99ed493119e6f9ea1bf6"}, + {file = "ruff-0.4.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c4efe62b5bbb24178c950732ddd40712b878a9b96b1d02b0ff0b08a090cbd891"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8e2f1e8fc12d07ab521a9005d68a969e167b589cbcaee354cb61e9d9de9c15"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60ed88b636a463214905c002fa3eaab19795679ed55529f91e488db3fe8976ab"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b90fc5e170fc71c712cc4d9ab0e24ea505c6a9e4ebf346787a67e691dfb72e85"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8e7e6ebc10ef16dcdc77fd5557ee60647512b400e4a60bdc4849468f076f6eef"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9ddb2c494fb79fc208cd15ffe08f32b7682519e067413dbaf5f4b01a6087bcd"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c51c928a14f9f0a871082603e25a1588059b7e08a920f2f9fa7157b5bf08cfe9"}, + {file = "ruff-0.4.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5eb0a4bfd6400b7d07c09a7725e1a98c3b838be557fee229ac0f84d9aa49c36"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b1867ee9bf3acc21778dcb293db504692eda5f7a11a6e6cc40890182a9f9e595"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1aecced1269481ef2894cc495647392a34b0bf3e28ff53ed95a385b13aa45768"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9da73eb616b3241a307b837f32756dc20a0b07e2bcb694fec73699c93d04a69e"}, + {file = "ruff-0.4.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:958b4ea5589706a81065e2a776237de2ecc3e763342e5cc8e02a4a4d8a5e6f95"}, + {file = "ruff-0.4.4-py3-none-win32.whl", hash = "sha256:cb53473849f011bca6e754f2cdf47cafc9c4f4ff4570003a0dad0b9b6890e876"}, + {file = "ruff-0.4.4-py3-none-win_amd64.whl", hash = "sha256:424e5b72597482543b684c11def82669cc6b395aa8cc69acc1858b5ef3e5daae"}, + {file = "ruff-0.4.4-py3-none-win_arm64.whl", hash = "sha256:39df0537b47d3b597293edbb95baf54ff5b49589eb7ff41926d8243caa995ea6"}, + {file = "ruff-0.4.4.tar.gz", hash = "sha256:f87ea42d5cdebdc6a69761a9d0bc83ae9b3b30d0ad78952005ba6568d6c022af"}, ] [[package]] @@ -3197,13 +3187,13 @@ files = [ [[package]] name = "tqdm" -version = "4.66.1" +version = "4.66.3" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, - {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, + {file = "tqdm-4.66.3-py3-none-any.whl", hash = "sha256:4f41d54107ff9a223dca80b53efe4fb654c67efaba7f47bada3ee9d50e05bd53"}, + {file = "tqdm-4.66.3.tar.gz", hash = "sha256:23097a41eba115ba99ecae40d06444c15d1c0c698d527a01c6c8bd1c5d0647e5"}, ] [package.dependencies] @@ -3493,13 +3483,13 @@ files = [ [[package]] name = "werkzeug" -version = "3.0.1" +version = "3.0.3" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" files = [ - {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"}, - {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"}, + {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, + {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, ] [package.dependencies] @@ -3582,4 +3572,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "1b014276ec94f9389459a70d31f0d96d1dd5a138bcc988900865e5f07a72bc62" +content-hash = "db51ad1e631b569e106927683a13124252bd80974def1f2edbe23ac87d89c461" diff --git a/machine-learning/pyproject.toml b/machine-learning/pyproject.toml index 645d9b07c4..2c8eb39b59 100644 --- a/machine-learning/pyproject.toml +++ b/machine-learning/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "machine-learning" -version = "1.103.1" +version = "1.105.1" description = "" authors = ["Hau Tran "] readme = "README.md" @@ -11,7 +11,7 @@ python = ">=3.10,<3.12" insightface = ">=0.7.3,<1.0" opencv-python-headless = ">=4.7.0.72,<5.0" pillow = ">=9.5.0,<11.0" -fastapi = ">=0.95.2,<1.0" +fastapi-slim = ">=0.95.2,<1.0" uvicorn = {extras = ["standard"], version = ">=0.22.0,<1.0"} pydantic = "^1.10.8" aiocache = ">=0.12.1,<1.0" diff --git a/machine-learning/start.sh b/machine-learning/start.sh index 7a5cb919a6..9d0a505c0c 100755 --- a/machine-learning/start.sh +++ b/machine-learning/start.sh @@ -2,20 +2,20 @@ lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.2" # mimalloc seems to increase memory usage dramatically with openvino, need to investigate -if ! [ "$DEVICE" = "openvino" ]; then +if ! [ "$DEVICE" = "openvino" ]; then export LD_PRELOAD="$lib_path" export LD_BIND_NOW=1 fi -: "${MACHINE_LEARNING_HOST:=[::]}" -: "${MACHINE_LEARNING_PORT:=3003}" +: "${IMMICH_HOST:=[::]}" +: "${IMMICH_PORT:=3003}" : "${MACHINE_LEARNING_WORKERS:=1}" : "${MACHINE_LEARNING_WORKER_TIMEOUT:=120}" gunicorn app.main:app \ -k app.config.CustomUvicornWorker \ + -b "$IMMICH_HOST":"$IMMICH_PORT" \ -w "$MACHINE_LEARNING_WORKERS" \ - -b "$MACHINE_LEARNING_HOST":"$MACHINE_LEARNING_PORT" \ -t "$MACHINE_LEARNING_WORKER_TIMEOUT" \ --log-config-json log_conf.json \ --graceful-timeout 0 diff --git a/misc/release/pump-version.sh b/misc/release/pump-version.sh index 14f0b3a817..0d0ae4b9e2 100755 --- a/misc/release/pump-version.sh +++ b/misc/release/pump-version.sh @@ -62,6 +62,8 @@ 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" diff --git a/mobile/.fvmrc b/mobile/.fvmrc index 03c3fb3b9a..7c3d0b51c1 100644 --- a/mobile/.fvmrc +++ b/mobile/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.19.6" + "flutter": "3.22.0" } \ No newline at end of file diff --git a/mobile/.vscode/settings.json b/mobile/.vscode/settings.json index 2959ff4e5e..c487d1fe87 100644 --- a/mobile/.vscode/settings.json +++ b/mobile/.vscode/settings.json @@ -1,5 +1,5 @@ { - "dart.flutterSdkPath": ".fvm/versions/3.19.3", + "dart.flutterSdkPath": ".fvm/versions/3.22.0", "search.exclude": { "**/.fvm": true }, diff --git a/mobile/android/Gemfile.lock b/mobile/android/Gemfile.lock index bafb6314c3..b41cba39e6 100644 --- a/mobile/android/Gemfile.lock +++ b/mobile/android/Gemfile.lock @@ -10,16 +10,16 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.925.0) - aws-sdk-core (3.194.1) + aws-partitions (1.932.0) + aws-sdk-core (3.196.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.80.0) + aws-sdk-kms (1.81.0) aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.149.1) + aws-sdk-s3 (1.151.0) aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) @@ -155,7 +155,7 @@ GEM mini_magick (4.12.0) mini_mime (1.1.5) multi_json (1.15.0) - multipart-post (2.4.0) + multipart-post (2.4.1) nanaimo (0.3.0) naturally (2.2.1) nkf (0.2.0) @@ -169,7 +169,8 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.6) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (2.0.7) ruby2_keywords (0.0.5) rubyzip (2.3.2) @@ -182,6 +183,7 @@ GEM simctl (1.6.10) CFPropertyList naturally + strscan (3.1.0) terminal-notifier (2.0.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 64ac762f7a..a26d055cba 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -81,8 +81,8 @@ flutter { } dependencies { - def kotlin_version = '1.9.23' - def kotlin_coroutines_version = '1.8.0' + def kotlin_version = '1.9.24' + def kotlin_coroutines_version = '1.8.1' def work_version = '2.9.0' def concurrent_version = '1.1.0' def guava_version = '33.2.0-android' diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle index 5e374c9f64..9b757fbc36 100644 --- a/mobile/android/build.gradle +++ b/mobile/android/build.gradle @@ -1,4 +1,6 @@ allprojects { + ext.kotlin_version = '1.9.24' + repositories { google() mavenCentral() diff --git a/mobile/android/fastlane/Fastfile b/mobile/android/fastlane/Fastfile index 6b50ca60ca..7a75bd1137 100644 --- a/mobile/android/fastlane/Fastfile +++ b/mobile/android/fastlane/Fastfile @@ -35,8 +35,8 @@ platform :android do task: 'bundle', build_type: 'Release', properties: { - "android.injected.version.code" => 137, - "android.injected.version.name" => "1.103.1", + "android.injected.version.code" => 140, + "android.injected.version.name" => "1.105.1", } ) upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') diff --git a/mobile/android/fastlane/report.xml b/mobile/android/fastlane/report.xml index 358fb9618c..756794b7ac 100644 --- a/mobile/android/fastlane/report.xml +++ b/mobile/android/fastlane/report.xml @@ -5,17 +5,17 @@ - + - + - + diff --git a/mobile/android/settings.gradle b/mobile/android/settings.gradle index 7ea6533b65..e832517e64 100644 --- a/mobile/android/settings.gradle +++ b/mobile/android/settings.gradle @@ -19,8 +19,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "7.4.2" apply false - id "org.jetbrains.kotlin.android" version "1.9.23" apply false - id "org.jetbrains.kotlin.kapt" version "1.9.23" apply false + id "org.jetbrains.kotlin.android" version "1.9.24" apply false + id "org.jetbrains.kotlin.kapt" version "1.9.24" apply false } include ":app" diff --git a/mobile/assets/i18n/ar-JO.json b/mobile/assets/i18n/ar-JO.json index 03d95e3231..fe19784f58 100644 --- a/mobile/assets/i18n/ar-JO.json +++ b/mobile/assets/i18n/ar-JO.json @@ -410,6 +410,7 @@ "share_add": "يضيف", "share_add_photos": "إضافة الصور", "share_add_title": "إضافة عنوان", + "share_assets_selected": "{} selected", "share_create_album": "إنشاء ألبوم", "shared_album_activities_input_disable": "التعليق معطل", "shared_album_activities_input_hint": "قل شيئا", diff --git a/mobile/assets/i18n/cs-CZ.json b/mobile/assets/i18n/cs-CZ.json index 52abe306d5..dea62eae6e 100644 --- a/mobile/assets/i18n/cs-CZ.json +++ b/mobile/assets/i18n/cs-CZ.json @@ -410,6 +410,7 @@ "share_add": "Přidat", "share_add_photos": "Přidat fotografie", "share_add_title": "Přidat název", + "share_assets_selected": "{} vybráno", "share_create_album": "Vytvořit album", "shared_album_activities_input_disable": "Komentář je vypnutý", "shared_album_activities_input_hint": "Řekněte něco", diff --git a/mobile/assets/i18n/da-DK.json b/mobile/assets/i18n/da-DK.json index b6a19cf4f5..20ad69f3e0 100644 --- a/mobile/assets/i18n/da-DK.json +++ b/mobile/assets/i18n/da-DK.json @@ -410,6 +410,7 @@ "share_add": "Tilføj", "share_add_photos": "Tilføj billeder", "share_add_title": "Tilføj en titel", + "share_assets_selected": "{} valgt", "share_create_album": "Opret album", "shared_album_activities_input_disable": "Kommentarer er deaktiveret", "shared_album_activities_input_hint": "Skriv noget", diff --git a/mobile/assets/i18n/de-DE.json b/mobile/assets/i18n/de-DE.json index af17d3c59a..b8cb59c00d 100644 --- a/mobile/assets/i18n/de-DE.json +++ b/mobile/assets/i18n/de-DE.json @@ -391,6 +391,7 @@ "setting_image_viewer_original_title": "Original laden", "setting_image_viewer_preview_subtitle": "Aktivieren, um ein Bild mit mittlerer Auflösung zu laden. Deaktivieren, um entweder das Original direkt zu laden oder nur die Miniaturansicht zu verwenden.", "setting_image_viewer_preview_title": "Vorschaubild laden", + "setting_image_viewer_title": "Bilder", "setting_languages_apply": "Anwenden", "setting_languages_title": "Sprachen", "setting_notifications_notify_failures_grace_period": "Benachrichtigung über Fehler bei der Hintergrundsicherung: {}", @@ -406,10 +407,14 @@ "setting_notifications_total_progress_subtitle": "Gesamter Upload-Fortschritt (abgeschlossen/Anzahl Elemente)", "setting_notifications_total_progress_title": "Zeige Gesamtfortschritt bei der Hintergrundsicherung", "setting_pages_app_bar_settings": "Einstellungen", + "setting_video_viewer_looping_subtitle": "Aktivieren, damit sich ein Video in der Detailansicht automatisch wiederholt.", + "setting_video_viewer_looping_title": "Wiederholen", + "setting_video_viewer_title": "Videos", "settings_require_restart": "Bitte starte Immich neu, um diese Einstellung anzuwenden.", "share_add": "Hinzufügen", "share_add_photos": "Fotos hinzufügen", "share_add_title": "Titel hinzufügen", + "share_assets_selected": "{} ausgewählt", "share_create_album": "Album erstellen", "shared_album_activities_input_disable": "Kommentare sind deaktiviert.", "shared_album_activities_input_hint": "Sag etwas", diff --git a/mobile/assets/i18n/el-GR.json b/mobile/assets/i18n/el-GR.json index 53ea170140..6623a6dae3 100644 --- a/mobile/assets/i18n/el-GR.json +++ b/mobile/assets/i18n/el-GR.json @@ -410,6 +410,7 @@ "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", + "share_assets_selected": "{} selected", "share_create_album": "Create album", "shared_album_activities_input_disable": "Το σχόλιο είναι απενεργοποιημένο", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/en-US.json b/mobile/assets/i18n/en-US.json index 84a8d94ee0..8a986c6f99 100644 --- a/mobile/assets/i18n/en-US.json +++ b/mobile/assets/i18n/en-US.json @@ -391,6 +391,7 @@ "setting_image_viewer_original_title": "Load original image", "setting_image_viewer_preview_subtitle": "Enable to load a medium-resolution image. Disable to either directly load the original or only use the thumbnail.", "setting_image_viewer_preview_title": "Load preview image", + "setting_image_viewer_title": "Images", "setting_languages_apply": "Apply", "setting_languages_title": "Languages", "setting_notifications_notify_failures_grace_period": "Notify background backup failures: {}", @@ -406,12 +407,15 @@ "setting_notifications_total_progress_subtitle": "Overall upload progress (done/total assets)", "setting_notifications_total_progress_title": "Show background backup total progress", "setting_pages_app_bar_settings": "Settings", + "setting_video_viewer_looping_subtitle": "Enable to automatically loop a video in the detail viewer.", + "setting_video_viewer_looping_title": "Looping", + "setting_video_viewer_title": "Videos", "settings_require_restart": "Please restart Immich to apply this setting", "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", - "share_create_album": "Create album", "share_assets_selected": "{} selected", + "share_create_album": "Create album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", "shared_album_activity_remove_content": "Do you want to delete this activity?", diff --git a/mobile/assets/i18n/es-ES.json b/mobile/assets/i18n/es-ES.json index 005ebaa72d..5f64bbb4e8 100644 --- a/mobile/assets/i18n/es-ES.json +++ b/mobile/assets/i18n/es-ES.json @@ -7,7 +7,7 @@ "add_to_album_bottom_sheet_added": "Agregado a {album}", "add_to_album_bottom_sheet_already_exists": "Ya se encuentra en {album}", "advanced_settings_log_level_title": "Nivel de registro: {}", - "advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de recursos encontrados el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.", + "advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de los elementos encontrados en el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.", "advanced_settings_prefer_remote_title": "Preferir imágenes remotas", "advanced_settings_self_signed_ssl_subtitle": "Omitir verificación del certificado SSL del servidor. Requerido para certificados autofirmados", "advanced_settings_self_signed_ssl_title": "Permitir certificados autofirmados", @@ -26,7 +26,7 @@ "album_viewer_appbar_share_delete": "Eliminar álbum ", "album_viewer_appbar_share_err_delete": "No ha podido eliminar el álbum", "album_viewer_appbar_share_err_leave": "No se ha podido abandonar el álbum", - "album_viewer_appbar_share_err_remove": "Hay problemas para eliminar los archivos del álbum", + "album_viewer_appbar_share_err_remove": "Hay problemas para eliminar los elementos del álbum", "album_viewer_appbar_share_err_title": "Error al cambiar el título del álbum ", "album_viewer_appbar_share_leave": "Abandonar álbum ", "album_viewer_appbar_share_remove": "Eliminar del álbum ", @@ -37,14 +37,14 @@ "app_bar_signout_dialog_content": "¿Estás seguro que quieres cerrar sesión?", "app_bar_signout_dialog_ok": "Sí", "app_bar_signout_dialog_title": "Cerrar sesión", - "archive_page_no_archived_assets": "No se encontraron recursos archivados", + "archive_page_no_archived_assets": "No se encontraron elementos archivados", "archive_page_title": "Archivo ({})", "asset_action_delete_err_read_only": "No se pueden borrar el archivo(s) de solo lectura, omitiendo", "asset_action_share_err_offline": "No se pudo obtener el archivo(s) sin conexión, omitiendo", "asset_list_group_by_sub_title": "Agrupar por", "asset_list_layout_settings_dynamic_layout_title": "Diseño dinámico", "asset_list_layout_settings_group_automatically": "Automatico", - "asset_list_layout_settings_group_by": "Agrupar recursos por", + "asset_list_layout_settings_group_by": "Agrupar elementos por", "asset_list_layout_settings_group_by_month": "Mes", "asset_list_layout_settings_group_by_month_day": "Mes + día", "asset_list_layout_sub_title": "Disposición", @@ -53,17 +53,17 @@ "asset_viewer_settings_title": "Visor de Archivos", "backup_album_selection_page_albums_device": "Álbumes en el dispositivo ({})", "backup_album_selection_page_albums_tap": "Toque para incluir, doble toque para excluir", - "backup_album_selection_page_assets_scatter": "Los archivos pueden dispersarse en varios álbumes. De este modo, los álbumes pueden ser incluidos o excluidos durante el proceso de copia de seguridad.", + "backup_album_selection_page_assets_scatter": "Los elementos pueden dispersarse en varios álbumes. De este modo, los álbumes pueden ser incluidos o excluidos durante el proceso de copia de seguridad.", "backup_album_selection_page_select_albums": "Seleccionar Álbumes", "backup_album_selection_page_selection_info": "Información sobre la Selección", - "backup_album_selection_page_total_assets": "Total de archivos únicos", + "backup_album_selection_page_total_assets": "Total de elementos únicos", "backup_all": "Todos", - "backup_background_service_backup_failed_message": "Error al copiar archivos. Reintentando...", + "backup_background_service_backup_failed_message": "Error al copiar elementos. Reintentando...", "backup_background_service_connection_failed_message": "Error al conectar con el servidor. Reintentando...", "backup_background_service_current_upload_notification": "Cargando {}", - "backup_background_service_default_notification": "Verificando si hay nuevos archivos", + "backup_background_service_default_notification": "Verificando si hay nuevos elementos", "backup_background_service_error_title": "Error de copia de seguridad", - "backup_background_service_in_progress_notification": "Creando copia de seguridad de tus archivos...", + "backup_background_service_in_progress_notification": "Creando copia de seguridad de tus elementos...", "backup_background_service_upload_failure_notification": "Error al cargar {}", "backup_controller_page_albums": "Álbumes de copia de seguridad", "backup_controller_page_background_app_refresh_disabled_content": "Activa la actualización en segundo plano de la aplicación en Configuración > General > Actualización en segundo plano para usar la copia de seguridad en segundo plano.", @@ -76,7 +76,7 @@ "backup_controller_page_background_charging": "Solo mientras se carga", "backup_controller_page_background_configure_error": "Error al configurar el servicio en segundo plano", "backup_controller_page_background_delay": "Retraso en la copia de seguridad de nuevos elementos: {}", - "backup_controller_page_background_description": "Activa el servicio en segundo plano para copiar automáticamente cualquier nuevos archivos sin necesidad de abrir la aplicación.", + "backup_controller_page_background_description": "Activa el servicio en segundo plano para copiar automáticamente cualquier nuevos elementos sin necesidad de abrir la aplicación.", "backup_controller_page_background_is_off": "La copia de seguridad en segundo plano automática está desactivada", "backup_controller_page_background_is_on": "La copia de seguridad en segundo plano automática está activada", "backup_controller_page_background_turn_off": "Desactivar el servicio en segundo plano", @@ -109,28 +109,28 @@ "backup_controller_page_turn_on": "Activar la copia de seguridad", "backup_controller_page_uploading_file_info": "Cargando información del archivo", "backup_err_only_album": "No se puede eliminar el único álbum", - "backup_info_card_assets": "archivos", + "backup_info_card_assets": "elementos", "backup_manual_cancelled": "Cancelado", "backup_manual_failed": "Fallido", "backup_manual_in_progress": "Subida en progreso. Espere", "backup_manual_success": "Éxito", "backup_manual_title": "Estado de la subida", "backup_options_page_title": "Opciones de Copia de Seguridad", - "cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} archivos)", + "cache_settings_album_thumbnails": "Miniaturas de la página de la biblioteca ({} elementos)", "cache_settings_clear_cache_button": "Borrar caché", "cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.", "cache_settings_duplicated_assets_clear_button": "LIMPIAR", "cache_settings_duplicated_assets_subtitle": "Fotos y vídeos en la lista negra de la app", - "cache_settings_duplicated_assets_title": "Archivos duplicados ({})", - "cache_settings_image_cache_size": "Tamaño de la caché de imágenes ({} archivos)", + "cache_settings_duplicated_assets_title": "Elementos duplicados ({})", + "cache_settings_image_cache_size": "Tamaño de la caché de imágenes ({} elementos)", "cache_settings_statistics_album": "Miniaturas de la biblioteca", - "cache_settings_statistics_assets": "{} archivos ({})", + "cache_settings_statistics_assets": "{} elementos ({})", "cache_settings_statistics_full": "Imágenes completas", "cache_settings_statistics_shared": "Miniaturas de álbumes compartidos", "cache_settings_statistics_thumbnail": "Miniaturas", "cache_settings_statistics_title": "Uso de caché", "cache_settings_subtitle": "Controla el comportamiento del almacenamiento en caché de la aplicación móvil Immich", - "cache_settings_thumbnail_size": "Tamaño de la caché de miniaturas ({} archivos)", + "cache_settings_thumbnail_size": "Tamaño de la caché de miniaturas ({} elementos)", "cache_settings_tile_subtitle": "Controla el comportamiento del almacenamiento local", "cache_settings_tile_title": "Almacenamiento local", "cache_settings_title": "Configuración de la caché", @@ -165,7 +165,7 @@ "create_album_page_untitled": "Sin título", "create_shared_album_page_create": "Crear", "create_shared_album_page_share": "Compartir", - "create_shared_album_page_share_add_assets": "AGREGAR ARCHIVOS", + "create_shared_album_page_share_add_assets": "AGREGAR ELEMENTOS", "create_shared_album_page_share_select_photos": "Seleccionar Fotos", "curated_location_page_title": "Lugares", "curated_object_page_title": "Objetos", @@ -199,26 +199,26 @@ "experimental_settings_new_asset_list_title": "Habilitar cuadrícula fotográfica experimental", "experimental_settings_subtitle": "Úsalo bajo tu responsabilidad", "experimental_settings_title": "Experimental", - "favorites_page_no_favorites": "No se encontraron recursos marcados como favoritos", + "favorites_page_no_favorites": "No se encontraron elementos marcados como favoritos", "favorites_page_title": "Favoritos", "haptic_feedback_switch": "Activar respuesta háptica", "haptic_feedback_title": "Respuesta Háptica", "home_page_add_to_album_conflicts": "{added} elementos agregados al álbum {album}.{failed} elementos ya existen en el álbum.", - "home_page_add_to_album_err_local": "Aún no se pueden agregar recursos locales a álbumes, omitiendo", + "home_page_add_to_album_err_local": "Aún no se pueden agregar elementos locales a álbumes, omitiendo", "home_page_add_to_album_success": "{added} elementos agregados al álbum {album}. ", - "home_page_album_err_partner": "Aún no se pueden agregar activos a un album de un compañero, omitiendo", - "home_page_archive_err_local": "Los recursos locales no pueden ser archivados, omitiendo", - "home_page_archive_err_partner": "No se pueden archivar activos de un compañero, omitiendo", + "home_page_album_err_partner": "Aún no se pueden agregar elementos a un álbum de un compañero, omitiendo", + "home_page_archive_err_local": "Los elementos locales no pueden ser archivados, omitiendo", + "home_page_archive_err_partner": "No se pueden archivar elementos de un compañero, omitiendo", "home_page_building_timeline": "Construyendo la línea de tiempo", - "home_page_delete_err_partner": "No se pueden eliminar activos de un compañero, omitiendo", - "home_page_delete_remote_err_local": "Archivos locales en eliminación de selección remota, omitiendo", - "home_page_favorite_err_local": "Aún no se pueden archivar recursos locales, omitiendo", - "home_page_favorite_err_partner": "Aún no se pueden marcar recursos de compañeros como favoritos, omitiendo", + "home_page_delete_err_partner": "No se pueden eliminar elementos de un compañero, omitiendo", + "home_page_delete_remote_err_local": "Elementos locales en la selección de eliminación remota, omitiendo", + "home_page_favorite_err_local": "Aún no se pueden archivar elementos locales, omitiendo", + "home_page_favorite_err_partner": "Aún no se pueden marcar elementos de compañeros como favoritos, omitiendo", "home_page_first_time_notice": "Si esta es la primera vez que usas la app, por favor, asegúrate de elegir un álbum de respaldo para que la línea de tiempo pueda cargar fotos y videos en los álbumes.", - "home_page_share_err_local": "No se pueden compartir activos locales a través de un enlace, omitiendo", + "home_page_share_err_local": "No se pueden compartir elementos locales a través de un enlace, omitiendo", "home_page_upload_err_limit": "Solo se pueden subir 30 elementos simultáneamente, omitiendo", "image_viewer_page_state_provider_download_error": "Error de descarga", - "image_viewer_page_state_provider_download_started": "Download Started", + "image_viewer_page_state_provider_download_started": "Descarga Iniciada", "image_viewer_page_state_provider_download_success": "Descarga exitosa", "image_viewer_page_state_provider_share_error": "Error al compartir", "library_page_albums": "Álbumes", @@ -227,7 +227,7 @@ "library_page_favorites": "Favoritos", "library_page_new_album": "Nuevo álbum", "library_page_sharing": "Compartiendo", - "library_page_sort_asset_count": "Número de archivos", + "library_page_sort_asset_count": "Número de elementos", "library_page_sort_created": "Creado más recientemente", "library_page_sort_last_modified": "Última modificación", "library_page_sort_most_oldest_photo": "Foto más antigua", @@ -299,7 +299,7 @@ "motion_photos_page_title": "Foto en Movimiento", "multiselect_grid_edit_date_time_err_read_only": "No se puede cambiar la fecha del archivo(s) de solo lectura, omitiendo", "multiselect_grid_edit_gps_err_read_only": "No se puede cambiar la localización de archivos de solo lectura. Saltando.", - "no_assets_to_show": "No assets to show", + "no_assets_to_show": "No hay elementos a mostrar", "notification_permission_dialog_cancel": "Cancelar", "notification_permission_dialog_content": "Para activar las notificaciones, ve a Configuración y selecciona permitir.", "notification_permission_dialog_settings": "Ajustes", @@ -403,13 +403,14 @@ "setting_notifications_single_progress_title": "Mostrar progreso detallado de copia de seguridad en segundo plano", "setting_notifications_subtitle": "Ajusta tus preferencias de notificación", "setting_notifications_title": "Notificaciones", - "setting_notifications_total_progress_subtitle": "Progreso general de subida (archivos completados/total)", + "setting_notifications_total_progress_subtitle": "Progreso general de subida (elementos completados/total)", "setting_notifications_total_progress_title": "Mostrar progreso total de copia de seguridad en segundo plano", "setting_pages_app_bar_settings": "Ajustes", "settings_require_restart": "Por favor, reinicia Immich para aplicar este ajuste", "share_add": "Agregar", "share_add_photos": "Agregar fotos", "share_add_title": "Agregar un título", + "share_assets_selected": "{} selected", "share_create_album": "Crear álbum", "shared_album_activities_input_disable": "Los comentarios están deshabilitados", "shared_album_activities_input_hint": "Comenta algo", @@ -462,7 +463,7 @@ "shared_link_expires_never": "Caduca ∞", "shared_link_expires_second": "Caduca en {} segundo", "shared_link_expires_seconds": "Caduca en {} segundos", - "shared_link_individual_shared": "Individual shared", + "shared_link_individual_shared": "Compartido individualmente", "shared_link_info_chip_download": "Descargar", "shared_link_info_chip_metadata": "EXIF", "shared_link_info_chip_upload": "Subir", diff --git a/mobile/assets/i18n/es-MX.json b/mobile/assets/i18n/es-MX.json index 13255a6f4c..2f8b14fcfe 100644 --- a/mobile/assets/i18n/es-MX.json +++ b/mobile/assets/i18n/es-MX.json @@ -410,6 +410,7 @@ "share_add": "Agregar", "share_add_photos": "Agregar fotos", "share_add_title": "Agregar un título", + "share_assets_selected": "{} selected", "share_create_album": "Crear álbum", "shared_album_activities_input_disable": "Los comentarios están deshabilitados", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/es-PE.json b/mobile/assets/i18n/es-PE.json index 2904a3b412..cc0439af98 100644 --- a/mobile/assets/i18n/es-PE.json +++ b/mobile/assets/i18n/es-PE.json @@ -410,6 +410,7 @@ "share_add": "Agregar", "share_add_photos": "Agregar fotos", "share_add_title": "Agregar un título", + "share_assets_selected": "{} selected", "share_create_album": "Crear álbum", "shared_album_activities_input_disable": "Los comentarios están deshabilitados", "shared_album_activities_input_hint": "Comenta algo", diff --git a/mobile/assets/i18n/es-US.json b/mobile/assets/i18n/es-US.json index c6235208a8..6a3270c5ef 100644 --- a/mobile/assets/i18n/es-US.json +++ b/mobile/assets/i18n/es-US.json @@ -410,6 +410,7 @@ "share_add": "Agregar", "share_add_photos": "Agregar fotos", "share_add_title": "Agregar un título", + "share_assets_selected": "{} selected", "share_create_album": "Crear álbum", "shared_album_activities_input_disable": "Los comentarios están deshabilitados", "shared_album_activities_input_hint": "Di algo", diff --git a/mobile/assets/i18n/fi-FI.json b/mobile/assets/i18n/fi-FI.json index 00e7963fe5..49807fcd1d 100644 --- a/mobile/assets/i18n/fi-FI.json +++ b/mobile/assets/i18n/fi-FI.json @@ -410,6 +410,7 @@ "share_add": "Lisää", "share_add_photos": "Lisää kuvia", "share_add_title": "Lisää nimi", + "share_assets_selected": "{} selected", "share_create_album": "Luo albumi", "shared_album_activities_input_disable": "Kommentointi on kytketty pois päältä", "shared_album_activities_input_hint": "Sano jotain", diff --git a/mobile/assets/i18n/fr-CA.json b/mobile/assets/i18n/fr-CA.json index 5e5a15c984..b2b51bdb55 100644 --- a/mobile/assets/i18n/fr-CA.json +++ b/mobile/assets/i18n/fr-CA.json @@ -410,6 +410,7 @@ "share_add": "Ajouter", "share_add_photos": "Ajouter des photos", "share_add_title": "Ajouter un titre", + "share_assets_selected": "{} selected", "share_create_album": "Créer un album", "shared_album_activities_input_disable": "Les commentaires sont désactivés", "shared_album_activities_input_hint": "Dire quelque chose", diff --git a/mobile/assets/i18n/fr-FR.json b/mobile/assets/i18n/fr-FR.json index f4c00c9662..061a0df3c2 100644 --- a/mobile/assets/i18n/fr-FR.json +++ b/mobile/assets/i18n/fr-FR.json @@ -410,6 +410,7 @@ "share_add": "Ajouter", "share_add_photos": "Ajouter des photos", "share_add_title": "Ajouter un titre", + "share_assets_selected": "{} selected", "share_create_album": "Créer un album", "shared_album_activities_input_disable": "Les commentaires sont désactivés", "shared_album_activities_input_hint": "Dire quelque chose", diff --git a/mobile/assets/i18n/he-IL.json b/mobile/assets/i18n/he-IL.json index ce48e1ff74..9c914d5d39 100644 --- a/mobile/assets/i18n/he-IL.json +++ b/mobile/assets/i18n/he-IL.json @@ -410,6 +410,7 @@ "share_add": "הוסף", "share_add_photos": "הוסף תמונות", "share_add_title": "הוסף כותרת", + "share_assets_selected": "{} selected", "share_create_album": "צור אלבום", "shared_album_activities_input_disable": "התגובה מושבתת", "shared_album_activities_input_hint": "הגב/י משהו", diff --git a/mobile/assets/i18n/hi-IN.json b/mobile/assets/i18n/hi-IN.json index a1e01d2f74..3efddab4c2 100644 --- a/mobile/assets/i18n/hi-IN.json +++ b/mobile/assets/i18n/hi-IN.json @@ -410,6 +410,7 @@ "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", + "share_assets_selected": "{} selected", "share_create_album": "Create album", "shared_album_activities_input_disable": "कॉमेंट डिजेबल्ड है", "shared_album_activities_input_hint": "कुछ कहें", diff --git a/mobile/assets/i18n/hu-HU.json b/mobile/assets/i18n/hu-HU.json index bf7c5cbff7..034a2ece15 100644 --- a/mobile/assets/i18n/hu-HU.json +++ b/mobile/assets/i18n/hu-HU.json @@ -1,28 +1,28 @@ { - "action_common_back": "Back", + "action_common_back": "Vissza", "action_common_cancel": "Mégsem", - "action_common_clear": "Clear", - "action_common_confirm": "Confirm", + "action_common_clear": "Kitöröl", + "action_common_confirm": "Jóváhagy", "action_common_update": "Frissít", - "add_to_album_bottom_sheet_added": "Hozzáadva a(z) {album} nevű albumhoz", - "add_to_album_bottom_sheet_already_exists": "Már eleme a(z) {album} nevű albumnak", + "add_to_album_bottom_sheet_added": "Hozzáadva a(z) \"{album}\" albumhoz", + "add_to_album_bottom_sheet_already_exists": "Már benne van a(z) \"{album}\" albumban", "advanced_settings_log_level_title": "Naplózás szintje: {}", - "advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő elemeket. Ezzel a beállítással inkább a távoli képeket töltjük be helyette.", - "advanced_settings_prefer_remote_title": "Távoli képek preferálása", - "advanced_settings_self_signed_ssl_subtitle": "SSL tanúsítvány ellenőrzésének kihagyása a szerver végponthoz. Ehhez saját aláírt tanúsítványok szükségesek.", - "advanced_settings_self_signed_ssl_title": "Saját aláírt SSL tanúsítványok engedélyezése", + "advanced_settings_prefer_remote_subtitle": "Néhány eszköz fájdalmasan lassan tölti be az eszközön lévő bélyegképeket. Ezzel a beállítással inkább a távoli képeket töltjük be helyette.", + "advanced_settings_prefer_remote_title": "Távoli képek előnyben részesítése", + "advanced_settings_self_signed_ssl_subtitle": "Nem ellenőrzi a szerver SSL tanúsítványát. Önaláírt tanúsítvány esetén szükséges beállítás.", + "advanced_settings_self_signed_ssl_title": "Önaláírt SSL tanúsítványok engedélyezése", "advanced_settings_tile_subtitle": "Haladó felhasználói beállítások", "advanced_settings_tile_title": "Haladó", "advanced_settings_troubleshooting_subtitle": "További funkciók engedélyezése hibaelhárítás céljából", "advanced_settings_troubleshooting_title": "Hibaelhárítás", - "album_info_card_backup_album_excluded": "KIZÁRVA", + "album_info_card_backup_album_excluded": "KIHAGYVA", "album_info_card_backup_album_included": "BELEÉRTVE", "album_thumbnail_card_item": "1 elem", "album_thumbnail_card_items": "{} elem", "album_thumbnail_card_shared": "· Megosztott", "album_thumbnail_owned": "Tulajdonos", "album_thumbnail_shared_by": "Megosztotta: {}", - "album_viewer_appbar_delete_confirm": "Are you sure you want to delete this album from your account?", + "album_viewer_appbar_delete_confirm": "Biztos, hogy törölni szeretnéd ezt az albumot?", "album_viewer_appbar_share_delete": "Album törlése", "album_viewer_appbar_share_err_delete": "Nem sikerült törölni az albumot", "album_viewer_appbar_share_err_leave": "Nem sikerült kilépni az albumból", @@ -39,18 +39,18 @@ "app_bar_signout_dialog_title": "Kijelentkezés", "archive_page_no_archived_assets": "Nem található archivált elem", "archive_page_title": "Archívum ({})", - "asset_action_delete_err_read_only": "Nem sikerült törölni a csak-olvasható elem(ek)et, így ezeket átugorjuk", - "asset_action_share_err_offline": "Nem sikerült betölteni az offline elem(ek)et, így ezeket kihagyjuk", - "asset_list_group_by_sub_title": "Group by", + "asset_action_delete_err_read_only": "Csak-olvasható elem(ek)et nem lehet törölni, így ezeket átugorjuk", + "asset_action_share_err_offline": "Nem sikerült betölteni a kapcsolat nélküli elem(ek)et, így ezeket kihagyjuk", + "asset_list_group_by_sub_title": "Csoportosítás", "asset_list_layout_settings_dynamic_layout_title": "Dinamikus elrendezés", "asset_list_layout_settings_group_automatically": "Automatikus", "asset_list_layout_settings_group_by": "Elemek csoportosítása", "asset_list_layout_settings_group_by_month": "hónapok szerint", "asset_list_layout_settings_group_by_month_day": "hónap és nap szerint", - "asset_list_layout_sub_title": "Layout", + "asset_list_layout_sub_title": "Elrendezés", "asset_list_settings_subtitle": "Fotórács elrendezése", "asset_list_settings_title": "Fotórács", - "asset_viewer_settings_title": "Asset Viewer", + "asset_viewer_settings_title": "Elem Megjelenítő", "backup_album_selection_page_albums_device": "Ezen az eszközön lévő albumok ({})", "backup_album_selection_page_albums_tap": "Koppincs a hozzáadáshoz, duplán koppincs az eltávolításhoz", "backup_album_selection_page_assets_scatter": "Egy elem több albumban is lehet. Ezért a mentéshez albumokat lehet hozzáadni vagy azokat a mentésből kihagyni.", @@ -58,13 +58,13 @@ "backup_album_selection_page_selection_info": "Összegzés", "backup_album_selection_page_total_assets": "Összes egyedi elem", "backup_all": "Összes", - "backup_background_service_backup_failed_message": "HIba a mentés közben. Újrapróbálkozás...", - "backup_background_service_connection_failed_message": "HIba a szerverhez való csatlakozás közben. Újrapróbálkozás...", + "backup_background_service_backup_failed_message": "Hiba a mentés közben. Újrapróbálkozás...", + "backup_background_service_connection_failed_message": "Hiba a szerverhez való csatlakozás közben. Újrapróbálkozás...", "backup_background_service_current_upload_notification": "Feltöltés {}", "backup_background_service_default_notification": "Új elemek keresése...", "backup_background_service_error_title": "Hiba mentés közben", - "backup_background_service_in_progress_notification": "Elemek mentés alatt..", - "backup_background_service_upload_failure_notification": "Hiba feltöltés közben {}", + "backup_background_service_in_progress_notification": "Elemek mentése folyamatban…", + "backup_background_service_upload_failure_notification": "Hiba a feltöltés közben {}", "backup_controller_page_albums": "Albumok Mentése", "backup_controller_page_background_app_refresh_disabled_content": "Engedélyezd a háttérben történő frissítést a Beállítások > Általános > Háttérben Frissítés menüpontban.", "backup_controller_page_background_app_refresh_disabled_title": "Háttérben frissítés kikapcsolva", @@ -78,9 +78,9 @@ "backup_controller_page_background_delay": "Új elemek mentésének késleltetése: {}", "backup_controller_page_background_description": "Kapcsold be a háttérfolyamatot, hogy automatikusan mentsen elemeket az applikáció megnyitása nélkül", "backup_controller_page_background_is_off": "Automatikus mentés a háttérben ki van kapcsolva", - "backup_controller_page_background_is_on": "Automatikus mentés a háttérben bekapcsolva", - "backup_controller_page_background_turn_off": "Háttérfolyamat kikapcsolása", - "backup_controller_page_background_turn_on": "Háttérfolyamat bekapcsolása", + "backup_controller_page_background_is_on": "Automatikus mentés a háttérben be van kapcsolva", + "backup_controller_page_background_turn_off": "Háttérszolgáltatás kikapcsolása", + "backup_controller_page_background_turn_on": "Háttérszolgáltatás bekapcsolása", "backup_controller_page_background_wifi": "Csak WiFi-n", "backup_controller_page_backup": "Mentés", "backup_controller_page_backup_selected": "Kiválasztva:", @@ -92,15 +92,15 @@ "backup_controller_page_failed": "Sikertelen ({})", "backup_controller_page_filename": "Fájlnév: {}[{}]", "backup_controller_page_id": "Azonosító: {}", - "backup_controller_page_info": "Mentésinformációk", + "backup_controller_page_info": "Mentési Információk", "backup_controller_page_none_selected": "Egy sincs kiválasztva", "backup_controller_page_remainder": "Hátralévő", "backup_controller_page_remainder_sub": "Hátralévő fotók és videók a kijelöltek közül", "backup_controller_page_select": "Kiválaszt", "backup_controller_page_server_storage": "Szerver Tárhely", - "backup_controller_page_start_backup": "Mentés Elindítása", - "backup_controller_page_status_off": "Automatikus mentés az előtérben kikapcsolva", - "backup_controller_page_status_on": "Automatikus mentés az előtérben bekapcsolva", + "backup_controller_page_start_backup": "Mentés Indítása", + "backup_controller_page_status_off": "Automatikus mentés az előtérben ki van kapcsolva", + "backup_controller_page_status_on": "Automatikus mentés az előtérben be van kapcsolva", "backup_controller_page_storage_format": "{} / {} felhasználva", "backup_controller_page_to_backup": "Mentésre kijelölt albumok", "backup_controller_page_total": "Összesen", @@ -115,15 +115,15 @@ "backup_manual_in_progress": "Feltöltés már folyamatban. Próbáld meg később", "backup_manual_success": "Sikeres", "backup_manual_title": "Feltöltés állapota", - "backup_options_page_title": "Backup options", - "cache_settings_album_thumbnails": "Library page thumbnails ({} assets)", + "backup_options_page_title": "Biztonági mentés beállításai", + "cache_settings_album_thumbnails": "Képtár oldalankénti bélyegképei ({} elem)", "cache_settings_clear_cache_button": "Gyorsítótár kiürítése", - "cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.", + "cache_settings_clear_cache_button_title": "Kiüríti az alkalmazás gyorsítótárát. Ez jelentősen kihat az alkalmazás teljesítményére, amíg a gyorsítótár újra nem épül.", "cache_settings_duplicated_assets_clear_button": "KIÜRÍT", "cache_settings_duplicated_assets_subtitle": "Fotók és videók, amiket az alkalmazás fekete listára tett", "cache_settings_duplicated_assets_title": "Duplikált Elemek ({})", "cache_settings_image_cache_size": "Kép gyorsítótár mérete ({} elem)", - "cache_settings_statistics_album": "Mappa bélyegképei", + "cache_settings_statistics_album": "Képtár bélyegképei", "cache_settings_statistics_assets": "{} elem ({})", "cache_settings_statistics_full": "Teljes méretű képek", "cache_settings_statistics_shared": "Megosztott album bélyegképei", @@ -135,20 +135,20 @@ "cache_settings_tile_title": "Helyi Tárhely", "cache_settings_title": "Gyorsítótár Beállítások", "change_password_form_confirm_password": "Jelszó Megerősítése", - "change_password_form_description": "Kedves {name}!\n\nMost jelentkezel be először a rendszerbe vagy más okból szükséges a jelszavad meváltoztatása. Kérjük, add meg új jelszavad.", + "change_password_form_description": "Szia {name}!\n\nMost jelentkezel be először a rendszerbe vagy más okból szükséges a jelszavad meváltoztatása. Kérjük, add meg új jelszavad.", "change_password_form_new_password": "Új Jelszó", - "change_password_form_password_mismatch": "A két beírt jelszó nem egyezik", + "change_password_form_password_mismatch": "A beírt jelszavak nem egyeznek", "change_password_form_reenter_new_password": "Jelszó (még egyszer)", "common_add_to_album": "Albumhoz ad", "common_change_password": "Jelszócsere", "common_create_new_album": "Új album létrehozása", "common_server_error": "Kérjük, ellenőrizd a hálózati kapcsolatot, gondoskodj róla, hogy a szerver elérhető legyen, valamint az alkalmazás és a szerver kompatibilis verziójú legyen.", "common_shared": "Megosztva", - "control_bottom_app_bar_add_to_album": "Hozzáadás az albumhoz", + "control_bottom_app_bar_add_to_album": "Albumhoz ad", "control_bottom_app_bar_album_info": "{} elem", - "control_bottom_app_bar_album_info_shared": "{} elemek· Megosztva", + "control_bottom_app_bar_album_info_shared": "{} elemek · Megosztva", "control_bottom_app_bar_archive": "Archivál", - "control_bottom_app_bar_create_new_album": "Album létrehozása", + "control_bottom_app_bar_create_new_album": "Új album létrehozása", "control_bottom_app_bar_delete": "Törlés", "control_bottom_app_bar_delete_from_immich": "Törlés az Immich-ből", "control_bottom_app_bar_delete_from_local": "Törlés az eszközről", @@ -157,7 +157,7 @@ "control_bottom_app_bar_favorite": "Kedvenc", "control_bottom_app_bar_share": "Megosztás", "control_bottom_app_bar_share_to": "Megosztás Ide", - "control_bottom_app_bar_stack": "Stack", + "control_bottom_app_bar_stack": "Fotók csoportosítása", "control_bottom_app_bar_trash_from_immich": "Lomtárba Helyez", "control_bottom_app_bar_unarchive": "Nem Archivált", "control_bottom_app_bar_unfavorite": "Nem Kedvenc", @@ -169,93 +169,93 @@ "create_shared_album_page_share_select_photos": "Fotók választása", "curated_location_page_title": "Helyek", "curated_object_page_title": "Dolgok", - "daily_title_text_date": "E, MMM dd", - "daily_title_text_date_year": "E, MMM dd, yyyy", - "date_format": "E, LLL d, y • h:mm a", + "daily_title_text_date": "MMM dd (E)", + "daily_title_text_date_year": "yyyy MMM dd (E)", + "date_format": "y LLL d (E) • HH:mm", "delete_dialog_alert": "Ezek az elemek véglegesen törölve lesznek Immich-ről és az eszközödről is", - "delete_dialog_alert_local": "These items will be permanently removed from your device but still be available on the Immich server", - "delete_dialog_alert_local_non_backed_up": "Some of the items aren't backed up to Immich and will be permanently removed from your device", - "delete_dialog_alert_remote": "These items will be permanently deleted from the Immich server", - "delete_dialog_cancel": "Mégse", + "delete_dialog_alert_local": "Ezek az elemek véglegesen törölve lesznek az eszközödről, de továbbra is elérhetőek maradnak az Immich szerveren", + "delete_dialog_alert_local_non_backed_up": "Néhány elem nem lett elmentve az Immich szerverre és most véglegesen törölve lesznek az eszközödről is", + "delete_dialog_alert_remote": "Ezek az elemek véglegesen törlésre kerülnek az Immich szerverről", + "delete_dialog_cancel": "Mégsem", "delete_dialog_ok": "Törlés", - "delete_dialog_ok_force": "Delete Anyway", - "delete_dialog_title": "Törlés véglegesen", - "delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only", - "delete_local_dialog_ok_force": "Delete Anyway", - "delete_shared_link_dialog_content": "Are you sure you want to delete this shared link?", - "delete_shared_link_dialog_title": "Delete Shared Link", + "delete_dialog_ok_force": "Törlés Mindenképp", + "delete_dialog_title": "Végleges Törlés", + "delete_local_dialog_ok_backed_up_only": "Csak a Biztonsági Mentés Törlése", + "delete_local_dialog_ok_force": "Törlés Mindenképp", + "delete_shared_link_dialog_content": "Biztos, hogy törlöd ezt a megosztott linket?", + "delete_shared_link_dialog_title": "Megosztott Link Törlése", "description_input_hint_text": "Leírás hozzáadása...", "description_input_submit_error": "Nem sikerült frissíteni a leírást. További információért kérjük, nézd meg az eseménynaplót", - "edit_date_time_dialog_date_time": "Date and Time", - "edit_date_time_dialog_timezone": "Timezone", - "edit_location_dialog_title": "Location", - "exif_bottom_sheet_description": "Leírás hozzáadása...", + "edit_date_time_dialog_date_time": "Dátum és Idő", + "edit_date_time_dialog_timezone": "Időzóna", + "edit_location_dialog_title": "Hely", + "exif_bottom_sheet_description": "Leírás Hozzáadása...", "exif_bottom_sheet_details": "RÉSZLETEK", - "exif_bottom_sheet_location": "HELYSZÍN", - "exif_bottom_sheet_location_add": "Add a location", - "exif_bottom_sheet_people": "PEOPLE", - "exif_bottom_sheet_person_add_person": "Add name", + "exif_bottom_sheet_location": "HELY", + "exif_bottom_sheet_location_add": "Hely hozzáadása", + "exif_bottom_sheet_people": "EMBEREK", + "exif_bottom_sheet_person_add_person": "Név hozzáadása", "experimental_settings_new_asset_list_subtitle": "Fejlesztés alatt", - "experimental_settings_new_asset_list_title": "Enable experimental photo grid", - "experimental_settings_subtitle": "Csak saját felelősségre használd", + "experimental_settings_new_asset_list_title": "Kisérleti képrács engedélyezése", + "experimental_settings_subtitle": "Csak saját felelősségre használd!", "experimental_settings_title": "Kísérleti", - "favorites_page_no_favorites": "Nem található kedvencnek jelölt média", + "favorites_page_no_favorites": "Nem található kedvencnek jelölt elem", "favorites_page_title": "Kedvencek", - "haptic_feedback_switch": "Enable haptic feedback", - "haptic_feedback_title": "Haptic Feedback", - "home_page_add_to_album_conflicts": "Added {added} assets to album {album}. {failed} assets are already in the album.", - "home_page_add_to_album_err_local": "Helyi médiát még nem lehet albumba tenni. Kihagyjuk.", - "home_page_add_to_album_success": "Added {added} assets to album {album}.", - "home_page_album_err_partner": "Can not add partner assets to an album yet, skipping", - "home_page_archive_err_local": "Helyi média archiválása még nem támogatott, úgyhogy kihagyjuk", - "home_page_archive_err_partner": "Can not archive partner assets, skipping", - "home_page_building_timeline": "Building the timeline", - "home_page_delete_err_partner": "Can not delete partner assets, skipping", - "home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping", - "home_page_favorite_err_local": "Helyi médiát még nem lehet a kedvencek közé tenni. Kihagyjuk.", - "home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping", - "home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).", - "home_page_share_err_local": "Can not share local assets via link, skipping", - "home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, átugrás", + "haptic_feedback_switch": "Rezgéses visszajelzés engedélyezése", + "haptic_feedback_title": "Rezgéses Visszajelzés", + "home_page_add_to_album_conflicts": "{added} elem hozzáadva a(z) \"{album}\" albumhoz. {failed} elem már eleve az albumban volt.", + "home_page_add_to_album_err_local": "Helyi elemeket még nem lehet albumba tenni. Kihagyjuk.", + "home_page_add_to_album_success": "{added} elem hozzáadva a(z) \"{album}\" albumhoz.", + "home_page_album_err_partner": "Még nem lehet a partner elemeit albumokhoz adni, úghogy kihagyjuk.", + "home_page_archive_err_local": "Helyi elemek archiválása még nem támogatott, úgyhogy kihagyjuk", + "home_page_archive_err_partner": "Partner elemeit nem lehet archiválni, úgyhogy kihagyjuk", + "home_page_building_timeline": "Idővonal összeállítása", + "home_page_delete_err_partner": "Partner elemeit nem lehet törölni, úgyhogy kihagyjuk", + "home_page_delete_remote_err_local": "Helyi elemek vannak távoli törlésre kiválasztva, úgyhogy ezeket kihagyjuk", + "home_page_favorite_err_local": "Helyi elemeket még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", + "home_page_favorite_err_partner": "Partner elemeit még nem lehet a kedvencek közé tenni, úgyhogy ezeket kihagyjuk", + "home_page_first_time_notice": "Ha most használod először az alkalmazást, akkor ahhoz, hogy megjelenjenek a fotók és a videók az idővonaladon, állítsd be, hogy melyik albumaidról készüljön biztonsági mentés.", + "home_page_share_err_local": "Helyi elemekről nem lehet megosztási linket készíteni, úgyhogy kihagyjuk", + "home_page_upload_err_limit": "Csak 30 elemet tudsz egyszerre feltölteni, úgyhogy kihagyjuk", "image_viewer_page_state_provider_download_error": "Letöltési Hiba", - "image_viewer_page_state_provider_download_started": "Download Started", + "image_viewer_page_state_provider_download_started": "Letöltés Megkezdődött", "image_viewer_page_state_provider_download_success": "Letöltés Sikeres", - "image_viewer_page_state_provider_share_error": "Share Error", + "image_viewer_page_state_provider_share_error": "Megosztási Hiba", "library_page_albums": "Albumok", "library_page_archive": "Archívum", "library_page_device_albums": "Albumok az Eszközön", "library_page_favorites": "Kedvencek", "library_page_new_album": "Új album", - "library_page_sharing": "Megosztás\n", - "library_page_sort_asset_count": "Number of assets", - "library_page_sort_created": "Legutoljára létrehozott", - "library_page_sort_last_modified": "Last modified", - "library_page_sort_most_oldest_photo": "Oldest photo", - "library_page_sort_most_recent_photo": "Most recent photo", + "library_page_sharing": "Megosztás", + "library_page_sort_asset_count": "Eszközök száma", + "library_page_sort_created": "Létrehozás ideje", + "library_page_sort_last_modified": "Utolsó módosítás ideje", + "library_page_sort_most_oldest_photo": "Legrégebbi fotó", + "library_page_sort_most_recent_photo": "Legújabb fotó", "library_page_sort_title": "Album címe", - "location_picker_choose_on_map": "Choose on map", - "location_picker_latitude": "Latitude", - "location_picker_latitude_error": "Enter a valid latitude", - "location_picker_latitude_hint": "Enter your latitude here", - "location_picker_longitude": "Longitude", - "location_picker_longitude_error": "Enter a valid longitude", - "location_picker_longitude_hint": "Enter your longitude here", + "location_picker_choose_on_map": "Válassz a térképen", + "location_picker_latitude": "Szélességi kör", + "location_picker_latitude_error": "Érvényes szélességi kört írj be", + "location_picker_latitude_hint": "Ide írd a szélességi kört", + "location_picker_longitude": "Hosszúsági kör", + "location_picker_longitude_error": "Érvényes hosszúsági kört írj be", + "location_picker_longitude_hint": "Ide írd a hosszúsági kört", "login_disabled": "A bejelentkezés letiltva", "login_form_api_exception": "API hiba. Kérljük, ellenőrid a szerver címét, majd próbáld újra.", - "login_form_back_button_text": "Back", + "login_form_back_button_text": "Vissza", "login_form_button_text": "Bejelentkezés", "login_form_email_hint": "email@cimed.hu", - "login_form_endpoint_hint": "http://szerver-címe:port/api", + "login_form_endpoint_hint": "http(s)://szerver-címe:port/api", "login_form_endpoint_url": "Szerver címe", - "login_form_err_http": "Kérem, adjon meg egy http:// vagy https:// címet", + "login_form_err_http": "Kérjük, adj meg egy http:// vagy https:// címet", "login_form_err_invalid_email": "Érvénytelen email cím", "login_form_err_invalid_url": "Érvénytelen cím", "login_form_err_leading_whitespace": "Az első karakter szóköz", "login_form_err_trailing_whitespace": "Az utolsó karakter szóköz", - "login_form_failed_get_oauth_server_config": "Error logging using OAuth, check server URL", - "login_form_failed_get_oauth_server_disable": "OAuth feature is not available on this server", + "login_form_failed_get_oauth_server_config": "Nem sikerült az OAuth bejelentkezés. Ellenőrizd a szerver címét.", + "login_form_failed_get_oauth_server_disable": "OAuth bejelentkezés nem elérhető ezen a szerveren", "login_form_failed_login": "Hiba bejelentkezés közben, ellenőrizd a címet, email-t és a jelszót", - "login_form_handshake_exception": "There was an Handshake Exception with the server. Enable self-signed certificate support in the settings if you are using a self-signed certificate.", + "login_form_handshake_exception": "SSL Kézfogási Hiba törént. Engedélyezd az önaláírt tanúsítvényokat a beállításokban, hogy ha önaláírt tanúsítványt használsz.", "login_form_label_email": "Email", "login_form_label_password": "Jelszó", "login_form_next_button": "Következő", @@ -263,61 +263,61 @@ "login_form_save_login": "Maradjon bejelentkezve", "login_form_server_empty": "Add meg a szerver címét.", "login_form_server_error": "Nem sikerült kapcsolódni a szerverhez.", - "login_password_changed_error": "There was an error updating your password", - "login_password_changed_success": "Password updated successfully", - "map_assets_in_bound": "{} photo", - "map_assets_in_bounds": "{} photos", - "map_cannot_get_user_location": "Cannot get user's location", - "map_location_dialog_cancel": "Cancel", - "map_location_dialog_yes": "Yes", - "map_location_picker_page_use_location": "Use this location", - "map_location_service_disabled_content": "Location service needs to be enabled to display assets from your current location. Do you want to enable it now?", - "map_location_service_disabled_title": "Location Service disabled", - "map_no_assets_in_bounds": "No photos in this area", - "map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?", - "map_no_location_permission_title": "Location Permission denied", - "map_settings_dark_mode": "Dark mode", - "map_settings_date_range_option_all": "All", - "map_settings_date_range_option_day": "Past 24 hours", - "map_settings_date_range_option_days": "Past {} days", - "map_settings_date_range_option_year": "Past year", - "map_settings_date_range_option_years": "Past {} years", - "map_settings_dialog_cancel": "Cancel", - "map_settings_dialog_save": "Save", - "map_settings_dialog_title": "Map Settings", - "map_settings_include_show_archived": "Include Archived", - "map_settings_include_show_partners": "Include Partners", - "map_settings_only_relative_range": "Date range", - "map_settings_only_show_favorites": "Show Favorite Only", - "map_settings_theme_settings": "Map Theme", - "map_zoom_to_see_photos": "Zoom out to see photos", - "memories_all_caught_up": "All caught up", - "memories_check_back_tomorrow": "Check back tomorrow for more memories", - "memories_start_over": "Start Over", - "memories_swipe_to_close": "Swipe up to close", - "monthly_title_text_date_format": "MMMM y", + "login_password_changed_error": "Nem sikerült módosítani a jelszót", + "login_password_changed_success": "Jelszó sikeresen módosítva", + "map_assets_in_bound": "{} fotó", + "map_assets_in_bounds": "{} fotó", + "map_cannot_get_user_location": "A helymeghatározás nem sikerült", + "map_location_dialog_cancel": "Mégsem", + "map_location_dialog_yes": "Igen", + "map_location_picker_page_use_location": "Kiválasztott hely használata", + "map_location_service_disabled_content": "A helymeghatározás szolgáltatást engedélyezni kell a jelenlegi helyednél lévő elemek megjelenítéséhez. Szeretnéd most engedélyezni?", + "map_location_service_disabled_title": "Helymeghatározás Szolgáltatás letiltva", + "map_no_assets_in_bounds": "Nincsenek fotók a környéken", + "map_no_location_permission_content": "A helymeghatározást engedélyezni kell a jelenlegi helyednél lévő elemek megjelenítéséhez. Szeretnéd most engedélyezni?", + "map_no_location_permission_title": "Helymeghatározás letiltva", + "map_settings_dark_mode": "Sötét mód", + "map_settings_date_range_option_all": "Összes", + "map_settings_date_range_option_day": "Elmúlt 24 óra", + "map_settings_date_range_option_days": "Elmúlt {} nap", + "map_settings_date_range_option_year": "Elmúlt év", + "map_settings_date_range_option_years": "Elmúlt {} év", + "map_settings_dialog_cancel": "Mégsem", + "map_settings_dialog_save": "Mentés", + "map_settings_dialog_title": "Térkép Beállítások", + "map_settings_include_show_archived": "Archívokkal Együtt", + "map_settings_include_show_partners": "Partnerével Együtt", + "map_settings_only_relative_range": "Dátum intervallum", + "map_settings_only_show_favorites": "Csak Kedvencek Mutatása", + "map_settings_theme_settings": "Térkép Témája", + "map_zoom_to_see_photos": "Kicsinyíts, hogy láss fényképeket", + "memories_all_caught_up": "Naprakész vagy", + "memories_check_back_tomorrow": "Nézz vissza holnap újabb emlékekért", + "memories_start_over": "Újrakezdés", + "memories_swipe_to_close": "Bezáráshoz söpörd ki felfelé", + "monthly_title_text_date_format": "y MMMM", "motion_photos_page_title": "Mozgó Fotók", - "multiselect_grid_edit_date_time_err_read_only": "Cannot edit date of read only asset(s), skipping", - "multiselect_grid_edit_gps_err_read_only": "Cannot edit location of read only asset(s), skipping", - "no_assets_to_show": "No assets to show", + "multiselect_grid_edit_date_time_err_read_only": "Csak-olvasható elem(ek) dátuma nem módosítható, ezért kihagyjuk", + "multiselect_grid_edit_gps_err_read_only": "Csak-olvasható elem(ek) helyszíne nem módosítható, ezért kihagyjuk", + "no_assets_to_show": "Nincs megjeleníthető elem", "notification_permission_dialog_cancel": "Mégsem", "notification_permission_dialog_content": "Az értesítések bekapcsolásához a Beállítások menüben válaszd ki az Engedélyezés-t.", "notification_permission_dialog_settings": "Beállítások", "notification_permission_list_tile_content": "Értesítések engedélyezése", "notification_permission_list_tile_enable_button": "Értesítések Bekapcsolása", "notification_permission_list_tile_title": "Engedély az Értesítésekhez", - "partner_list_user_photos": "{user}'s photos", - "partner_list_view_all": "View all", - "partner_page_add_partner": "Add partner", - "partner_page_empty_message": "Your photos are not yet shared with any partner.", - "partner_page_no_more_users": "No more users to add", - "partner_page_partner_add_failed": "Failed to add partner", - "partner_page_select_partner": "Select partner", - "partner_page_shared_to_title": "Shared to", - "partner_page_stop_sharing_content": "{} will no longer be able to access your photos.", - "partner_page_stop_sharing_title": "Stop sharing your photos?", + "partner_list_user_photos": "{user} fényképei", + "partner_list_view_all": "Összes mutatása", + "partner_page_add_partner": "Partner hozzáadása", + "partner_page_empty_message": "Még senkivel nem osztottad meg a fényképeidet.", + "partner_page_no_more_users": "Nincs hozzáadható felhasználó", + "partner_page_partner_add_failed": "Nem sikerült hozzáadni a felhasználót", + "partner_page_select_partner": "Partner kiválasztása", + "partner_page_shared_to_title": "Megosztva: ", + "partner_page_stop_sharing_content": "{} nem fog többé hozzáférni a fotóidhoz.", + "partner_page_stop_sharing_title": "Fotók megosztásának megszűntetése?", "partner_page_title": "Partner", - "permission_onboarding_back": "Back", + "permission_onboarding_back": "Vissza", "permission_onboarding_continue_anyway": "Folytatás mindenképp", "permission_onboarding_get_started": "Kezdjük el", "permission_onboarding_go_to_settings": "Beállítások megnyitása", @@ -327,47 +327,47 @@ "permission_onboarding_permission_granted": "Hozzáférés engedélyezve! Minden készen áll.", "permission_onboarding_permission_limited": "Korlátozott hozzáférés. Ha szeretnéd, hogy az Immich a teljes galéria gyűjteményedet mentse és kezelje, akkor a Beállításokban engedélyezd a fotó és videó jogosultságokat.", "permission_onboarding_request": "Engedélyezni kell, hogy az Immich hozzáférjen a képekhez és videókhoz", - "preferences_settings_title": "Preferences", + "preferences_settings_title": "Beállítások", "profile_drawer_app_logs": "Naplók", - "profile_drawer_client_out_of_date_major": "Mobile App is out of date. Please update to the latest major version.", - "profile_drawer_client_out_of_date_minor": "Mobile App is out of date. Please update to the latest minor version.", + "profile_drawer_client_out_of_date_major": "A mobilalkalmazás elavult. Kérjük, frissítsd a legfrisebb főverzióra.", + "profile_drawer_client_out_of_date_minor": "A mobilalkalmazás elavult. Kérjük, frissítsd a legfrisebb alverzióra.", "profile_drawer_client_server_up_to_date": "Kliens és a szerver is naprakész", - "profile_drawer_documentation": "Documentation", + "profile_drawer_documentation": "Dokumentáció", "profile_drawer_github": "GitHub", - "profile_drawer_server_out_of_date_major": "Server is out of date. Please update to the latest major version.", - "profile_drawer_server_out_of_date_minor": "Server is out of date. Please update to the latest minor version.", + "profile_drawer_server_out_of_date_major": "A szerver elavult. Kérjük, frissítsd a legfrisebb főverzióra.", + "profile_drawer_server_out_of_date_minor": "A szerver elavult. Kérjük, frissítsd a legfrisebb alverzióra.", "profile_drawer_settings": "Beállítások", "profile_drawer_sign_out": "Kijelentkezés", - "profile_drawer_trash": "Trash", + "profile_drawer_trash": "Lomtár", "recently_added_page_title": "Nemrég Hozzáadott", - "scaffold_body_error_occurred": "Error occurred", - "search_bar_hint": "Keress a fotóid között", - "search_filter_apply": "Apply filter", - "search_filter_camera_make": "Make", - "search_filter_camera_model": "Model", - "search_filter_display_option_archive": "Archive", - "search_filter_display_option_favorite": "Favorite", - "search_filter_display_option_not_in_album": "Not in album", - "search_filter_location_city": "City", - "search_filter_location_country": "Country", - "search_filter_location_state": "State", - "search_filter_media_type_all": "All", - "search_filter_media_type_image": "Image", - "search_filter_media_type_video": "Video", + "scaffold_body_error_occurred": "Hiba történt", + "search_bar_hint": "Fotók keresése", + "search_filter_apply": "Szűrő alkalmazása", + "search_filter_camera_make": "Gyártó", + "search_filter_camera_model": "Modell", + "search_filter_display_option_archive": "Archivált", + "search_filter_display_option_favorite": "Kedvenc", + "search_filter_display_option_not_in_album": "Nincs albumban", + "search_filter_location_city": "Város", + "search_filter_location_country": "Ország", + "search_filter_location_state": "Állam", + "search_filter_media_type_all": "Összes", + "search_filter_media_type_image": "Kép", + "search_filter_media_type_video": "Videó", "search_page_categories": "Kategóriák", "search_page_favorites": "Kedvencek", "search_page_motion_photos": "Mozgó Fotók", - "search_page_no_objects": "No Objects Info Available", - "search_page_no_places": "Helyinformáció nem érhető el", + "search_page_no_objects": "Nincs Információ a Tárgyakról", + "search_page_no_places": "Nincs Információ a Helyszínekről", "search_page_people": "Emberek", - "search_page_person_add_name_dialog_cancel": "Cancel", - "search_page_person_add_name_dialog_hint": "Name", - "search_page_person_add_name_dialog_save": "Save", - "search_page_person_add_name_dialog_title": "Add a name", - "search_page_person_add_name_subtitle": "Find them fast by name with search", - "search_page_person_add_name_title": "Add a name", - "search_page_person_edit_name": "Edit name", - "search_page_places": "Helyszínek", + "search_page_person_add_name_dialog_cancel": "Mégsem", + "search_page_person_add_name_dialog_hint": "Név", + "search_page_person_add_name_dialog_save": "Mentés", + "search_page_person_add_name_dialog_title": "Név hozzáadása", + "search_page_person_add_name_subtitle": "Név szerint gyorsan megtalálhatod a keresőben", + "search_page_person_add_name_title": "Név hozzáadása", + "search_page_person_edit_name": "Név módosítása", + "search_page_places": "Helyek", "search_page_recently_added": "Nemrég hozzáadott", "search_page_screenshots": "Képernyőképek", "search_page_selfies": "Szelfik", @@ -375,7 +375,7 @@ "search_page_videos": "Videók", "search_page_view_all_button": "Összes mutatása", "search_page_your_activity": "Tevékenységeid", - "search_page_your_map": "Your Map", + "search_page_your_map": "Térképed", "search_result_page_new_search_hint": "Új keresés", "search_suggestion_list_smart_search_hint_1": "Az intelligens keresés alapértelmezetten be van kapcsolva, metaadatokat így kereshetsz", "search_suggestion_list_smart_search_hint_2": "m:keresési-kifejezés", @@ -383,137 +383,138 @@ "select_user_for_sharing_page_err_album": "Nem sikerült létrehozni az albumot", "select_user_for_sharing_page_share_suggestions": "Javaslatok", "server_info_box_app_version": "Alkalmazás Verzió", - "server_info_box_latest_release": "Latest Version", - "server_info_box_server_url": "Server URL", + "server_info_box_latest_release": "Legfrissebb Verzió", + "server_info_box_server_url": "Szerver Címe", "server_info_box_server_version": "Szerver Verzió", - "setting_image_viewer_help": "The detail viewer loads the small thumbnail first, then loads the medium-size preview (if enabled), finally loads the original (if enabled).", - "setting_image_viewer_original_subtitle": "Enable to load the original full-resolution image (large!). Disable to reduce data usage (both network and on device cache).", - "setting_image_viewer_original_title": "Load original image", - "setting_image_viewer_preview_subtitle": "Enable to load a medium-resolution image. Disable to either directly load the original or only use the thumbnail.", - "setting_image_viewer_preview_title": "Load preview image", - "setting_languages_apply": "Apply", - "setting_languages_title": "Languages", - "setting_notifications_notify_failures_grace_period": "Notify background backup failures: {}", + "setting_image_viewer_help": "A képnézegető először a kis bélyegképet tölti be, aztán a közepes méretű előnézetet (ha elérhető), végül az eredetit (ha elérhető).", + "setting_image_viewer_original_subtitle": "Engedélyezi az eredeti teljes felbontású kép betöltését (nagy!). Kikapcsolva csökkenti az adathasználatot (a neten és az eszköz gyorsítótárán is).", + "setting_image_viewer_original_title": "Eredeti kép betöltése", + "setting_image_viewer_preview_subtitle": "Engedélyezi a közepes felbontású kép betöltését. Kikapcsolva vagy az eredeti kép töltődik be, vagy csak a bélyegkép.", + "setting_image_viewer_preview_title": "Előnézet betöltése", + "setting_languages_apply": "Alkalmaz", + "setting_languages_title": "Nyelvek", + "setting_notifications_notify_failures_grace_period": "Értesítés a háttérben történő mentés hibáiról: {}", "setting_notifications_notify_hours": "{} óra", "setting_notifications_notify_immediately": "azonnal", "setting_notifications_notify_minutes": "{} perc", "setting_notifications_notify_never": "soha", "setting_notifications_notify_seconds": "{} másodperc", - "setting_notifications_single_progress_subtitle": "Detailed upload progress information per asset", - "setting_notifications_single_progress_title": "Show background backup detail progress", - "setting_notifications_subtitle": "Adjust your notification preferences", + "setting_notifications_single_progress_subtitle": "Részletes feltöltési folyamat információ minden elemről", + "setting_notifications_single_progress_title": "Mutassa a háttérben történő mentés részletes folyamatát", + "setting_notifications_subtitle": "Értesítési beállítások módosítása", "setting_notifications_title": "Értesítések", - "setting_notifications_total_progress_subtitle": "Overall upload progress (done/total assets)", - "setting_notifications_total_progress_title": "Show background backup total progress", + "setting_notifications_total_progress_subtitle": "Átfogó feltöltési folyamat (kész/összes elem)", + "setting_notifications_total_progress_title": "Mutassa a háttérben történő mentés teljes folyamatát", "setting_pages_app_bar_settings": "Beállítások", - "settings_require_restart": "Kérlek indítsd újra az Immich-et hogy alkalmazd ezt a beállítást", + "settings_require_restart": "Ennek a beállításnak az érvénybe lépéséhez indítsd újra az Immich-et", "share_add": "Hozzáadás", "share_add_photos": "Fotók hozzáadása", "share_add_title": "Album neve", + "share_assets_selected": "{} kiválasztva", "share_create_album": "Album létrehozása", - "shared_album_activities_input_disable": "Comment is disabled", - "shared_album_activities_input_hint": "Say something", - "shared_album_activity_remove_content": "Do you want to delete this activity?", - "shared_album_activity_remove_title": "Delete Activity", - "shared_album_activity_setting_subtitle": "Let others respond", - "shared_album_activity_setting_title": "Comments & likes", - "shared_album_section_people_action_error": "Error leaving/removing from album", - "shared_album_section_people_action_leave": "Remove user from album", - "shared_album_section_people_action_remove_user": "Remove user from album", - "shared_album_section_people_owner_label": "Owner", - "shared_album_section_people_title": "PEOPLE", + "shared_album_activities_input_disable": "Hozzászólások kikapcsolva", + "shared_album_activities_input_hint": "Szólj hozzá", + "shared_album_activity_remove_content": "Törölni szeretnéd ezt a tevékenységet?", + "shared_album_activity_remove_title": "Tevékenység Törlése", + "shared_album_activity_setting_subtitle": "Engedd, hogy mások reagáljanak", + "shared_album_activity_setting_title": "Hozzászólások és lájkok", + "shared_album_section_people_action_error": "Hiba az albummal kapcsolatos kilépés/eltávolítás közben", + "shared_album_section_people_action_leave": "Felhasználó eltávolítása az albumból", + "shared_album_section_people_action_remove_user": "Felhasználó eltávolítása az albumból", + "shared_album_section_people_owner_label": "Tulajdonos", + "shared_album_section_people_title": "EMBEREK", "share_dialog_preparing": "Előkészítés...", - "shared_link_app_bar_title": "Shared Links", - "shared_link_clipboard_copied_massage": "Copied to clipboard", - "shared_link_clipboard_text": "Link: {}\nPassword: {}", - "shared_link_create_app_bar_title": "Create link to share", - "shared_link_create_error": "Error while creating shared link", - "shared_link_create_info": "Let anyone with the link see the selected photo(s)", - "shared_link_create_submit_button": "Create link", - "shared_link_edit_allow_download": "Allow public user to download", - "shared_link_edit_allow_upload": "Allow public user to upload", - "shared_link_edit_app_bar_title": "Edit link", - "shared_link_edit_change_expiry": "Change expiration time", - "shared_link_edit_description": "Description", - "shared_link_edit_description_hint": "Enter the share description", - "shared_link_edit_expire_after": "Expire after", - "shared_link_edit_expire_after_option_day": "1 day", - "shared_link_edit_expire_after_option_days": "{} days", - "shared_link_edit_expire_after_option_hour": "1 hour", - "shared_link_edit_expire_after_option_hours": "{} hours", - "shared_link_edit_expire_after_option_minute": "1 minute", - "shared_link_edit_expire_after_option_minutes": "{} minutes", - "shared_link_edit_expire_after_option_months": "{} months", - "shared_link_edit_expire_after_option_never": "Never", - "shared_link_edit_expire_after_option_year": "{} year", - "shared_link_edit_password": "Password", - "shared_link_edit_password_hint": "Enter the share password", - "shared_link_edit_show_meta": "Show metadata", - "shared_link_edit_submit_button": "Update link", - "shared_link_empty": "You don't have any shared links", - "shared_link_error_server_url_fetch": "Cannot fetch the server url", - "shared_link_expired": "Expired", - "shared_link_expires_day": "Expires in {} day", - "shared_link_expires_days": "Expires in {} days", - "shared_link_expires_hour": "Expires in {} hour", - "shared_link_expires_hours": "Expires in {} hours", - "shared_link_expires_minute": "Expires in {} minute", - "shared_link_expires_minutes": "Expires in {} minutes", - "shared_link_expires_never": "Expires ∞", - "shared_link_expires_second": "Expires in {} second", - "shared_link_expires_seconds": "Expires in {} seconds", - "shared_link_individual_shared": "Individual shared", - "shared_link_info_chip_download": "Download", + "shared_link_app_bar_title": "Megosztott Linkek", + "shared_link_clipboard_copied_massage": "Vágólapra másolva", + "shared_link_clipboard_text": "Link: {}\nJelszó: {}", + "shared_link_create_app_bar_title": "Megosztási link létrehozása", + "shared_link_create_error": "Hiba a megosztási link létrehozásakor", + "shared_link_create_info": "A linket használva bárki megnézheti a kiválasztott kép(ek)et", + "shared_link_create_submit_button": "Link létrehozása", + "shared_link_edit_allow_download": "Letöltés engedélyezése", + "shared_link_edit_allow_upload": "Feltöltés engedélyezése", + "shared_link_edit_app_bar_title": "Link módosítása", + "shared_link_edit_change_expiry": "Lejárati idő megváltoztatása", + "shared_link_edit_description": "Leírás", + "shared_link_edit_description_hint": "Add meg a megosztás leírását", + "shared_link_edit_expire_after": "Lejárati idő", + "shared_link_edit_expire_after_option_day": "1 nap", + "shared_link_edit_expire_after_option_days": "{} nap", + "shared_link_edit_expire_after_option_hour": "1 óra", + "shared_link_edit_expire_after_option_hours": "{} óra", + "shared_link_edit_expire_after_option_minute": "1 perc", + "shared_link_edit_expire_after_option_minutes": "{} perc", + "shared_link_edit_expire_after_option_months": "{} hónap", + "shared_link_edit_expire_after_option_never": "Soha", + "shared_link_edit_expire_after_option_year": "{} év", + "shared_link_edit_password": "Jelszó", + "shared_link_edit_password_hint": "Add meg a megosztási jelszót", + "shared_link_edit_show_meta": "Metaadatok mutatása", + "shared_link_edit_submit_button": "Link frissítése", + "shared_link_empty": "Nincsenek megosztási linkek", + "shared_link_error_server_url_fetch": "A szerver címét nem sikerült betölteni", + "shared_link_expired": "Lejárt", + "shared_link_expires_day": "{} nap múlva lejár", + "shared_link_expires_days": "{} nap múlva lejár", + "shared_link_expires_hour": "{} óra múlva lejár", + "shared_link_expires_hours": "{} óra múlva lejár", + "shared_link_expires_minute": "{} perc múlva lejár", + "shared_link_expires_minutes": "{} perc múlva lejár", + "shared_link_expires_never": "Nem jár le", + "shared_link_expires_second": "{} másodperc múlva lejár", + "shared_link_expires_seconds": "{} másodperc múlva lejár", + "shared_link_individual_shared": "Egyénileg megosztva", + "shared_link_info_chip_download": "Letöltés", "shared_link_info_chip_metadata": "EXIF", - "shared_link_info_chip_upload": "Upload", - "shared_link_manage_links": "Manage Shared links", - "shared_link_public_album": "Public album", - "share_done": "Done", + "shared_link_info_chip_upload": "Feltöltés", + "shared_link_manage_links": "Megosztási linkek kezelése", + "shared_link_public_album": "Nyilvános album", + "share_done": "Kész", "share_invite": "Meghívás az albumba", "sharing_page_album": "Megosztott albumok", - "sharing_page_description": "Megosztott albumok létrehozásával fényképeket és videókatoszthatsz meg a hálózatodban lévő emberekkel.", + "sharing_page_description": "Megosztott albumok létrehozásával fényképeket és videókat oszthatsz meg a hálózatodban lévő emberekkel.", "sharing_page_empty_list": "ÜRES LISTA", - "sharing_silver_appbar_create_shared_album": "Megosztott album létrehozása", - "sharing_silver_appbar_shared_links": "Shared links", + "sharing_silver_appbar_create_shared_album": "Új megosztott album", + "sharing_silver_appbar_shared_links": "Megosztási linkek", "sharing_silver_appbar_share_partner": "Megosztás partnerrel", - "tab_controller_nav_library": "Könyvtár", + "tab_controller_nav_library": "Képtár", "tab_controller_nav_photos": "Képek", "tab_controller_nav_search": "Keresés", "tab_controller_nav_sharing": "Megosztás", - "theme_setting_asset_list_storage_indicator_title": "Show storage indicator on asset tiles", - "theme_setting_asset_list_tiles_per_row_title": "Number of assets per row ({})", + "theme_setting_asset_list_storage_indicator_title": "Tárhely ikon mutatása az elemeken", + "theme_setting_asset_list_tiles_per_row_title": "Elemek száma soronként ({})", "theme_setting_dark_mode_switch": "Sötét mód", - "theme_setting_image_viewer_quality_subtitle": "Adjust the quality of the detail image viewer", - "theme_setting_image_viewer_quality_title": "Image viewer quality", + "theme_setting_image_viewer_quality_subtitle": "Részletes képmegjelenítő minőségének beállítása", + "theme_setting_image_viewer_quality_title": "Képmegjelenítő minősége", "theme_setting_system_theme_switch": "Automatikus (követi a rendszer témáját)", - "theme_setting_theme_subtitle": "Choose the app's theme setting", + "theme_setting_theme_subtitle": "Alkalmazás témájának választása", "theme_setting_theme_title": "Téma", - "theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load", - "theme_setting_three_stage_loading_title": "Enable three-stage loading", - "translated_text_options": "Options", - "trash_page_delete": "Delete", - "trash_page_delete_all": "Delete All", - "trash_page_empty_trash_btn": "Empty trash", - "trash_page_empty_trash_dialog_content": "Do you want to empty your trashed assets? These items will be permanently removed from Immich", + "theme_setting_three_stage_loading_subtitle": "A háromlépcsős betöltés javíthatja a betöltési teljesítményt, de jelentősen növeli a hálózati forgalmat", + "theme_setting_three_stage_loading_title": "Háromlépcsős betöltés engedélyezése", + "translated_text_options": "Beállítások", + "trash_page_delete": "Töröl", + "trash_page_delete_all": "Mindet Töröl", + "trash_page_empty_trash_btn": "Lomtár Ürítése", + "trash_page_empty_trash_dialog_content": "Ki szeretnéd üríteni a lomtárban lévő elemeket? Ezeket véglegesen eltávolítjuk az Immich-ből", "trash_page_empty_trash_dialog_ok": "Ok", - "trash_page_info": "Trashed items will be permanently deleted after {} days", - "trash_page_no_assets": "No trashed assets", - "trash_page_restore": "Restore", - "trash_page_restore_all": "Restore All", - "trash_page_select_assets_btn": "Select assets", - "trash_page_select_btn": "Select", - "trash_page_title": "Trash ({})", - "upload_dialog_cancel": "Mégse", - "upload_dialog_info": "Akarod menteni a kiválasztott eleme(ke)t a szerverre?", + "trash_page_info": "A Lomátrba helyezett elemek {} nap után véglegesen törlődnek", + "trash_page_no_assets": "Nincsen semmi a Lomtárban", + "trash_page_restore": "Visszaállít", + "trash_page_restore_all": "Mindet Visszaállítja", + "trash_page_select_assets_btn": "Elemek kiválasztása", + "trash_page_select_btn": "Kiválaszt", + "trash_page_title": "Lomtár ({})", + "upload_dialog_cancel": "Mégsem", + "upload_dialog_info": "Szeretnél mentést készíteni a kiválasztott elem(ek)ről a szerverre?", "upload_dialog_ok": "Feltöltés", - "upload_dialog_title": "Elem feltöltése", + "upload_dialog_title": "Elem Feltöltése", "version_announcement_overlay_ack": "Megértettem", "version_announcement_overlay_release_notes": "a változtatások listáját elolvasd", "version_announcement_overlay_text_1": "Szia, egy új verzió érhető el", "version_announcement_overlay_text_2": "kérlek szánj időt arra, hogy ", - "version_announcement_overlay_text_3": "és gyöződj meg róla, hogy a docker-compose és .env beállításai naprakészek és pontosak, különösen akkor, ha használsz watchtower-t vagy bármi olyan megoldást ami automatikusan frissíti a szervert.", - "version_announcement_overlay_title": "Új szerververzió érhető el \uD83C\uDF89", - "viewer_remove_from_stack": "Remove from Stack", - "viewer_stack_use_as_main_asset": "Use as Main Asset", - "viewer_unstack": "Un-Stack" + "version_announcement_overlay_text_3": "és gyöződj meg róla, hogy a docker-compose és .env beállításai naprakészek és pontosak, különösen akkor, ha watchtower-t vagy bármi olyan megoldást használsz, ami automatikusan frissíti a szervert.", + "version_announcement_overlay_title": "Új Szerververzió Érhető El \uD83C\uDF89", + "viewer_remove_from_stack": "Eltávolít a Csoportból", + "viewer_stack_use_as_main_asset": "Fő Elemnek Beállít", + "viewer_unstack": "Csoport Megszűntetése" } \ No newline at end of file diff --git a/mobile/assets/i18n/it-IT.json b/mobile/assets/i18n/it-IT.json index b30ce5dc95..dbd93587fb 100644 --- a/mobile/assets/i18n/it-IT.json +++ b/mobile/assets/i18n/it-IT.json @@ -410,6 +410,7 @@ "share_add": "Aggiungi", "share_add_photos": "Aggiungi foto", "share_add_title": "Aggiungi un titolo ", + "share_assets_selected": "{} selected", "share_create_album": "Crea album", "shared_album_activities_input_disable": "I commenti sono disabilitati", "shared_album_activities_input_hint": "Dici qualcosa", diff --git a/mobile/assets/i18n/ja-JP.json b/mobile/assets/i18n/ja-JP.json index 2cad0ff929..da482d75cb 100644 --- a/mobile/assets/i18n/ja-JP.json +++ b/mobile/assets/i18n/ja-JP.json @@ -218,7 +218,7 @@ "home_page_share_err_local": "ローカルのみの項目をリンクで共有はできません。スキップします", "home_page_upload_err_limit": "1回でアップロードできる写真の数は30枚です。スキップします", "image_viewer_page_state_provider_download_error": "ダウンロード失敗", - "image_viewer_page_state_provider_download_started": "Download Started", + "image_viewer_page_state_provider_download_started": "ダウンロードが始まります", "image_viewer_page_state_provider_download_success": "ダウンロード成功", "image_viewer_page_state_provider_share_error": "共有エラー", "library_page_albums": "アルバム", @@ -410,6 +410,7 @@ "share_add": "追加", "share_add_photos": "写真を追加", "share_add_title": "タイトルを追加", + "share_assets_selected": "{}選択されました", "share_create_album": "アルバムを作成", "shared_album_activities_input_disable": "コメントはオフになってます", "shared_album_activities_input_hint": "何か書き込みましょう", diff --git a/mobile/assets/i18n/ko-KR.json b/mobile/assets/i18n/ko-KR.json index d505533ee7..bea52a3476 100644 --- a/mobile/assets/i18n/ko-KR.json +++ b/mobile/assets/i18n/ko-KR.json @@ -218,7 +218,7 @@ "home_page_share_err_local": "링크를 통해 로컬 미디어를 공유할 수 없으므로 건너뜁니다", "home_page_upload_err_limit": "한번에 최대 30개의 미디어만 업로드할 수 있습니다", "image_viewer_page_state_provider_download_error": "다운로드 에러", - "image_viewer_page_state_provider_download_started": "Download Started", + "image_viewer_page_state_provider_download_started": "다운로드 시작", "image_viewer_page_state_provider_download_success": "다운로드 완료", "image_viewer_page_state_provider_share_error": "공유 오류", "library_page_albums": "앨범", @@ -410,6 +410,7 @@ "share_add": "추가", "share_add_photos": "사진 추가", "share_add_title": "새 앨범제목", + "share_assets_selected": "{} 선택됨", "share_create_album": "앨범 만들기", "shared_album_activities_input_disable": "댓글이 비활성화되었습니다.", "shared_album_activities_input_hint": "말하기", diff --git a/mobile/assets/i18n/lt-LT.json b/mobile/assets/i18n/lt-LT.json index 379deed82d..c968c603f7 100644 --- a/mobile/assets/i18n/lt-LT.json +++ b/mobile/assets/i18n/lt-LT.json @@ -410,6 +410,7 @@ "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", + "share_assets_selected": "{} selected", "share_create_album": "Create album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/lv-LV.json b/mobile/assets/i18n/lv-LV.json index 61f5631478..2379306d9d 100644 --- a/mobile/assets/i18n/lv-LV.json +++ b/mobile/assets/i18n/lv-LV.json @@ -410,6 +410,7 @@ "share_add": "Pievienot", "share_add_photos": "Pievienot fotoattēlus", "share_add_title": "Pievienot virsrakstu", + "share_assets_selected": "{} selected", "share_create_album": "Izveidot albumu", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/mn.json b/mobile/assets/i18n/mn.json index 37603e8d1b..66e6e0f723 100644 --- a/mobile/assets/i18n/mn.json +++ b/mobile/assets/i18n/mn.json @@ -410,6 +410,7 @@ "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", + "share_assets_selected": "{} selected", "share_create_album": "Create album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/nb-NO.json b/mobile/assets/i18n/nb-NO.json index 994220a72f..32862e2ecf 100644 --- a/mobile/assets/i18n/nb-NO.json +++ b/mobile/assets/i18n/nb-NO.json @@ -410,6 +410,7 @@ "share_add": "Legg til", "share_add_photos": "Legg til bilder", "share_add_title": "Legg til tittel", + "share_assets_selected": "{} valgt", "share_create_album": "Opprett album", "shared_album_activities_input_disable": "Kommenterer er deaktivert", "shared_album_activities_input_hint": "Si noe", diff --git a/mobile/assets/i18n/nl-NL.json b/mobile/assets/i18n/nl-NL.json index 2b1dc7847e..283a060a70 100644 --- a/mobile/assets/i18n/nl-NL.json +++ b/mobile/assets/i18n/nl-NL.json @@ -410,6 +410,7 @@ "share_add": "Toevoegen", "share_add_photos": "Foto's toevoegen", "share_add_title": "Titel toevoegen", + "share_assets_selected": "{} geselecteerd", "share_create_album": "Album aanmaken", "shared_album_activities_input_disable": "Reactie is uitgeschakeld", "shared_album_activities_input_hint": "Zeg iets", diff --git a/mobile/assets/i18n/pl-PL.json b/mobile/assets/i18n/pl-PL.json index f4d17a4601..a517467400 100644 --- a/mobile/assets/i18n/pl-PL.json +++ b/mobile/assets/i18n/pl-PL.json @@ -410,6 +410,7 @@ "share_add": "Dodaj", "share_add_photos": "Dodaj zdjęcia", "share_add_title": "Dodaj tytuł", + "share_assets_selected": "{} selected", "share_create_album": "Utwórz album", "shared_album_activities_input_disable": "Komentarz jest wyłączony", "shared_album_activities_input_hint": "Powiedz coś", diff --git a/mobile/assets/i18n/pt-PT.json b/mobile/assets/i18n/pt-PT.json index 99942749af..646758c39c 100644 --- a/mobile/assets/i18n/pt-PT.json +++ b/mobile/assets/i18n/pt-PT.json @@ -410,6 +410,7 @@ "share_add": "Adicionar", "share_add_photos": "Adicionar fotos", "share_add_title": "Adicione um título", + "share_assets_selected": "{} selected", "share_create_album": "Criar álbum", "shared_album_activities_input_disable": "Comentários desativados", "shared_album_activities_input_hint": "Dizer alguma coisa", diff --git a/mobile/assets/i18n/ro-RO.json b/mobile/assets/i18n/ro-RO.json index 838f42c425..032e46fcaf 100644 --- a/mobile/assets/i18n/ro-RO.json +++ b/mobile/assets/i18n/ro-RO.json @@ -410,6 +410,7 @@ "share_add": "Adaugă", "share_add_photos": "Adaugă fotografii", "share_add_title": "Adaugă un titlu", + "share_assets_selected": "{} selected", "share_create_album": "Creează album", "shared_album_activities_input_disable": "Cometariile sunt dezactivate", "shared_album_activities_input_hint": "Spune ceva", diff --git a/mobile/assets/i18n/ru-RU.json b/mobile/assets/i18n/ru-RU.json index 80ceee10f1..2ccada2c76 100644 --- a/mobile/assets/i18n/ru-RU.json +++ b/mobile/assets/i18n/ru-RU.json @@ -410,6 +410,7 @@ "share_add": "Добавить", "share_add_photos": "Добавить фото", "share_add_title": "Добавить название", + "share_assets_selected": "{} выбрано", "share_create_album": "Создать альбом", "shared_album_activities_input_disable": "Комментирование отключено", "shared_album_activities_input_hint": "Скажите что-нибудь", diff --git a/mobile/assets/i18n/sk-SK.json b/mobile/assets/i18n/sk-SK.json index d3cdd32e83..ffdcc2dffe 100644 --- a/mobile/assets/i18n/sk-SK.json +++ b/mobile/assets/i18n/sk-SK.json @@ -410,6 +410,7 @@ "share_add": "Pridať", "share_add_photos": "Pridať fotografie", "share_add_title": "Pridať názov", + "share_assets_selected": "{} selected", "share_create_album": "Vytvoriť album", "shared_album_activities_input_disable": "Komentár je zakázaný", "shared_album_activities_input_hint": "Napíšte niečo", diff --git a/mobile/assets/i18n/sl-SI.json b/mobile/assets/i18n/sl-SI.json index 439a5da16f..254e385bf3 100644 --- a/mobile/assets/i18n/sl-SI.json +++ b/mobile/assets/i18n/sl-SI.json @@ -410,6 +410,7 @@ "share_add": "Dodaj", "share_add_photos": "Dodaj fotografije", "share_add_title": "Dodaj naslov", + "share_assets_selected": "{} selected", "share_create_album": "Ustvari album", "shared_album_activities_input_disable": "Komentiranje je onemogočeno", "shared_album_activities_input_hint": "Reci kaj", diff --git a/mobile/assets/i18n/sr-Cyrl.json b/mobile/assets/i18n/sr-Cyrl.json index 379deed82d..c968c603f7 100644 --- a/mobile/assets/i18n/sr-Cyrl.json +++ b/mobile/assets/i18n/sr-Cyrl.json @@ -410,6 +410,7 @@ "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", + "share_assets_selected": "{} selected", "share_create_album": "Create album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/sr-Latn.json b/mobile/assets/i18n/sr-Latn.json index 0f7615550e..3ae3f63498 100644 --- a/mobile/assets/i18n/sr-Latn.json +++ b/mobile/assets/i18n/sr-Latn.json @@ -410,6 +410,7 @@ "share_add": "Dodaj", "share_add_photos": "Dodaj fotografije", "share_add_title": "Dodaj naslov", + "share_assets_selected": "{} selected", "share_create_album": "Napravi album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/sv-FI.json b/mobile/assets/i18n/sv-FI.json index 379deed82d..c968c603f7 100644 --- a/mobile/assets/i18n/sv-FI.json +++ b/mobile/assets/i18n/sv-FI.json @@ -410,6 +410,7 @@ "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", + "share_assets_selected": "{} selected", "share_create_album": "Create album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/sv-SE.json b/mobile/assets/i18n/sv-SE.json index 5cd119f7e3..710045f5da 100644 --- a/mobile/assets/i18n/sv-SE.json +++ b/mobile/assets/i18n/sv-SE.json @@ -410,6 +410,7 @@ "share_add": "Lägg till", "share_add_photos": "Lägg till foton", "share_add_title": "Lägg till en titel", + "share_assets_selected": "{} selected", "share_create_album": "Skapa album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/assets/i18n/th-TH.json b/mobile/assets/i18n/th-TH.json index 5166d90561..815182942f 100644 --- a/mobile/assets/i18n/th-TH.json +++ b/mobile/assets/i18n/th-TH.json @@ -410,6 +410,7 @@ "share_add": "เพิ่ม", "share_add_photos": "เพิ่มรูปภาพ", "share_add_title": "เพิ่มชื่อ", + "share_assets_selected": "{} selected", "share_create_album": "สร้างอัลบั้ม", "shared_album_activities_input_disable": "คอมเมนต์ถูกปิด", "shared_album_activities_input_hint": "พูดอะไรสักอย่าง", diff --git a/mobile/assets/i18n/uk-UA.json b/mobile/assets/i18n/uk-UA.json index 851092f7ec..11dafc0ce8 100644 --- a/mobile/assets/i18n/uk-UA.json +++ b/mobile/assets/i18n/uk-UA.json @@ -410,6 +410,7 @@ "share_add": "Додати", "share_add_photos": "Додати знімки", "share_add_title": "Додати назву", + "share_assets_selected": "{} обрано", "share_create_album": "Створити альбом", "shared_album_activities_input_disable": "Коментування вимкнено", "shared_album_activities_input_hint": "Скажіть що-небудь", diff --git a/mobile/assets/i18n/vi-VN.json b/mobile/assets/i18n/vi-VN.json index 975da42be0..fc569d2795 100644 --- a/mobile/assets/i18n/vi-VN.json +++ b/mobile/assets/i18n/vi-VN.json @@ -410,6 +410,7 @@ "share_add": "Thêm", "share_add_photos": "Thêm ảnh", "share_add_title": "Thêm tiêu đề", + "share_assets_selected": "{} selected", "share_create_album": "Tạo album", "shared_album_activities_input_disable": "Nhận xét hiện đã tắt", "shared_album_activities_input_hint": "Nói điều gì đó", diff --git a/mobile/assets/i18n/zh-CN.json b/mobile/assets/i18n/zh-CN.json index 157e7f500b..6d57bb26b1 100644 --- a/mobile/assets/i18n/zh-CN.json +++ b/mobile/assets/i18n/zh-CN.json @@ -410,6 +410,7 @@ "share_add": "添加", "share_add_photos": "添加项目", "share_add_title": "添加标题", + "share_assets_selected": "{}已选择", "share_create_album": "创建相册", "shared_album_activities_input_disable": "评论已禁用", "shared_album_activities_input_hint": "说些什么", diff --git a/mobile/assets/i18n/zh-Hans.json b/mobile/assets/i18n/zh-Hans.json index 671c953dd1..4e459141dc 100644 --- a/mobile/assets/i18n/zh-Hans.json +++ b/mobile/assets/i18n/zh-Hans.json @@ -410,6 +410,7 @@ "share_add": "添加", "share_add_photos": "添加项目", "share_add_title": "添加标题", + "share_assets_selected": "{}已选择", "share_create_album": "创建相册", "shared_album_activities_input_disable": "评论已禁用", "shared_album_activities_input_hint": "说些什么", diff --git a/mobile/assets/i18n/zh-TW.json b/mobile/assets/i18n/zh-TW.json index 379deed82d..c968c603f7 100644 --- a/mobile/assets/i18n/zh-TW.json +++ b/mobile/assets/i18n/zh-TW.json @@ -410,6 +410,7 @@ "share_add": "Add", "share_add_photos": "Add photos", "share_add_title": "Add a title", + "share_assets_selected": "{} selected", "share_create_album": "Create album", "shared_album_activities_input_disable": "Comment is disabled", "shared_album_activities_input_hint": "Say something", diff --git a/mobile/ios/Gemfile.lock b/mobile/ios/Gemfile.lock index bafb6314c3..b41cba39e6 100644 --- a/mobile/ios/Gemfile.lock +++ b/mobile/ios/Gemfile.lock @@ -10,16 +10,16 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.925.0) - aws-sdk-core (3.194.1) + aws-partitions (1.932.0) + aws-sdk-core (3.196.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.80.0) + aws-sdk-kms (1.81.0) aws-sdk-core (~> 3, >= 3.193.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.149.1) + aws-sdk-s3 (1.151.0) aws-sdk-core (~> 3, >= 3.194.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) @@ -155,7 +155,7 @@ GEM mini_magick (4.12.0) mini_mime (1.1.5) multi_json (1.15.0) - multipart-post (2.4.0) + multipart-post (2.4.1) nanaimo (0.3.0) naturally (2.2.1) nkf (0.2.0) @@ -169,7 +169,8 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.6) + rexml (3.2.8) + strscan (>= 3.0.9) rouge (2.0.7) ruby2_keywords (0.0.5) rubyzip (2.3.2) @@ -182,6 +183,7 @@ GEM simctl (1.6.10) CFPropertyList naturally + strscan (3.1.0) terminal-notifier (2.0.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock index 5493fc2840..bc79594ee9 100644 --- a/mobile/ios/Podfile.lock +++ b/mobile/ios/Podfile.lock @@ -159,7 +159,7 @@ SPEC CHECKSUMS: FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a geolocator_apple: 9157311f654584b9bb72686c55fc02a97b73f461 image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 - integration_test: 13825b8a9334a850581300559b8839134b124670 + integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4 isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 MapLibre: 620fc933c1d6029b33738c905c1490d024e5d4ef maplibre_gl: a2efec727dd340e4c65e26d2b03b584f14881fd9 diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index f473cd0250..fee475376b 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -383,7 +383,7 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 157; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -525,7 +525,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 157; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -553,7 +553,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 155; + CURRENT_PROJECT_VERSION = 157; DEVELOPMENT_TEAM = 2F67MQ8R79; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index a30399428a..507418cf96 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -58,11 +58,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.103.0 + 1.105.0 CFBundleSignature ???? CFBundleVersion - 155 + 157 FLTEnableImpeller ITSAppUsesNonExemptEncryption diff --git a/mobile/ios/fastlane/Fastfile b/mobile/ios/fastlane/Fastfile index 9e5c3018bd..603283547a 100644 --- a/mobile/ios/fastlane/Fastfile +++ b/mobile/ios/fastlane/Fastfile @@ -19,7 +19,7 @@ platform :ios do desc "iOS Beta" lane :beta do increment_version_number( - version_number: "1.103.1" + version_number: "1.105.1" ) increment_build_number( build_number: latest_testflight_build_number + 1, diff --git a/mobile/ios/fastlane/report.xml b/mobile/ios/fastlane/report.xml index f23fb703e5..d672cb7859 100644 --- a/mobile/ios/fastlane/report.xml +++ b/mobile/ios/fastlane/report.xml @@ -5,32 +5,32 @@ - + - + - + - + - + - + diff --git a/mobile/lib/entities/album.entity.dart b/mobile/lib/entities/album.entity.dart index 49a38322ee..c05b849dcd 100644 --- a/mobile/lib/entities/album.entity.dart +++ b/mobile/lib/entities/album.entity.dart @@ -145,9 +145,10 @@ class Album { .remoteIdEqualTo(dto.albumThumbnailAssetId) .findFirst(); } - if (dto.sharedUsers.isNotEmpty) { - final users = await db.users - .getAllById(dto.sharedUsers.map((e) => e.id).toList(growable: false)); + if (dto.albumUsers.isNotEmpty) { + final users = await db.users.getAllById( + dto.albumUsers.map((e) => e.user.id).toList(growable: false), + ); a.sharedUsers.addAll(users.cast()); } if (dto.assets.isNotEmpty) { diff --git a/mobile/lib/entities/store.entity.dart b/mobile/lib/entities/store.entity.dart index 053fdc4e3c..e7f1a6bce0 100644 --- a/mobile/lib/entities/store.entity.dart +++ b/mobile/lib/entities/store.entity.dart @@ -182,6 +182,7 @@ enum StoreKey { advancedTroubleshooting(114, type: bool), logLevel(115, type: int), preferRemoteImage(116, type: bool), + loopVideo(117, type: bool), // map related settings mapShowFavoriteOnly(118, type: bool), mapRelativeDate(119, type: int), diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index b2c10fdace..2a320fbddb 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -16,7 +16,7 @@ import 'package:immich_mobile/entities/backup_album.entity.dart'; import 'package:immich_mobile/entities/duplicated_asset.entity.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/tab_navigation_observer.dart'; -import 'package:immich_mobile/shared/cache/widgets_binding.dart'; +import 'package:immich_mobile/utils/cache/widgets_binding.dart'; import 'package:immich_mobile/entities/album.entity.dart'; import 'package:immich_mobile/entities/android_device_asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; diff --git a/mobile/lib/models/server_info/server_disk_info.model.dart b/mobile/lib/models/server_info/server_disk_info.model.dart index 95e94e369c..01ce49beec 100644 --- a/mobile/lib/models/server_info/server_disk_info.model.dart +++ b/mobile/lib/models/server_info/server_disk_info.model.dart @@ -32,7 +32,7 @@ class ServerDiskInfo { return 'ServerDiskInfo(diskAvailable: $diskAvailable, diskSize: $diskSize, diskUse: $diskUse, diskUsagePercentage: $diskUsagePercentage)'; } - ServerDiskInfo.fromDto(ServerInfoResponseDto dto) + ServerDiskInfo.fromDto(ServerStorageResponseDto dto) : diskAvailable = dto.diskAvailable, diskSize = dto.diskSize, diskUse = dto.diskUse, diff --git a/mobile/lib/pages/backup/album_preview.page.dart b/mobile/lib/pages/backup/album_preview.page.dart index 7e1486208e..218127ff43 100644 --- a/mobile/lib/pages/backup/album_preview.page.dart +++ b/mobile/lib/pages/backup/album_preview.page.dart @@ -54,7 +54,7 @@ class AlbumPreviewPage extends HookConsumerWidget { ], ), leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_new_rounded), ), ), diff --git a/mobile/lib/pages/backup/backup_album_selection.page.dart b/mobile/lib/pages/backup/backup_album_selection.page.dart index 3890726fc1..ecfebd3cb7 100644 --- a/mobile/lib/pages/backup/backup_album_selection.page.dart +++ b/mobile/lib/pages/backup/backup_album_selection.page.dart @@ -191,7 +191,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), title: const Text( diff --git a/mobile/lib/pages/backup/backup_controller.page.dart b/mobile/lib/pages/backup/backup_controller.page.dart index 4efa59f959..89384cf97a 100644 --- a/mobile/lib/pages/backup/backup_controller.page.dart +++ b/mobile/lib/pages/backup/backup_controller.page.dart @@ -7,16 +7,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/models/backup/backup_state.model.dart'; import 'package:immich_mobile/providers/album/album.provider.dart'; +import 'package:immich_mobile/providers/backup/backup.provider.dart'; import 'package:immich_mobile/providers/backup/error_backup_list.provider.dart'; import 'package:immich_mobile/providers/backup/ios_background_settings.provider.dart'; import 'package:immich_mobile/providers/backup/manual_upload.provider.dart'; -import 'package:immich_mobile/widgets/backup/current_backup_asset_info_box.dart'; -import 'package:immich_mobile/models/backup/backup_state.model.dart'; -import 'package:immich_mobile/providers/backup/backup.provider.dart'; -import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/providers/websocket.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/backup/backup_info_card.dart'; +import 'package:immich_mobile/widgets/backup/current_backup_asset_info_box.dart'; @RoutePage() class BackupControllerPage extends HookConsumerWidget { @@ -260,7 +260,7 @@ class BackupControllerPage extends HookConsumerWidget { leading: IconButton( onPressed: () { ref.watch(websocketProvider.notifier).listenUploadEvent(); - context.popRoute(true); + context.maybePop(true); }, splashRadius: 24, icon: const Icon( diff --git a/mobile/lib/pages/backup/backup_options.page.dart b/mobile/lib/pages/backup/backup_options.page.dart index 9a639c844e..29822cab15 100644 --- a/mobile/lib/pages/backup/backup_options.page.dart +++ b/mobile/lib/pages/backup/backup_options.page.dart @@ -13,7 +13,7 @@ class BackupOptionsPage extends StatelessWidget { elevation: 0, title: const Text("backup_options_page_title").tr(), leading: IconButton( - onPressed: () => context.popRoute(true), + onPressed: () => context.maybePop(true), splashRadius: 24, icon: const Icon( Icons.arrow_back_ios_rounded, diff --git a/mobile/lib/pages/backup/failed_backup_status.page.dart b/mobile/lib/pages/backup/failed_backup_status.page.dart index b4e75e7ae0..1c6d3a7aad 100644 --- a/mobile/lib/pages/backup/failed_backup_status.page.dart +++ b/mobile/lib/pages/backup/failed_backup_status.page.dart @@ -23,7 +23,7 @@ class FailedBackupStatusPage extends HookConsumerWidget { ), leading: IconButton( onPressed: () { - context.popRoute(true); + context.maybePop(true); }, splashRadius: 24, icon: const Icon( diff --git a/mobile/lib/pages/common/album_additional_shared_user_selection.page.dart b/mobile/lib/pages/common/album_additional_shared_user_selection.page.dart index 33c4708dd2..5e253a7b58 100644 --- a/mobile/lib/pages/common/album_additional_shared_user_selection.page.dart +++ b/mobile/lib/pages/common/album_additional_shared_user_selection.page.dart @@ -26,7 +26,7 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { final sharedUsersList = useState>({}); addNewUsersHandler() { - context.popRoute(sharedUsersList.value.map((e) => e.id).toList()); + context.maybePop(sharedUsersList.value.map((e) => e.id).toList()); } buildTileIcon(User user) { @@ -55,10 +55,9 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { child: Chip( backgroundColor: context.primaryColor.withOpacity(0.15), label: Text( - user.email, + user.name, style: const TextStyle( fontSize: 12, - color: Colors.black87, fontWeight: FontWeight.bold, ), ), @@ -88,13 +87,20 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { itemBuilder: ((context, index) { return ListTile( leading: buildTileIcon(users[index]), + dense: true, title: Text( - users[index].email, + users[index].name, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, ), ), + subtitle: Text( + users[index].email, + style: const TextStyle( + fontSize: 12, + ), + ), onTap: () { if (sharedUsersList.value.contains(users[index])) { sharedUsersList.value = sharedUsersList.value @@ -127,7 +133,7 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget { leading: IconButton( icon: const Icon(Icons.close_rounded), onPressed: () { - context.popRoute(null); + context.maybePop(null); }, ), actions: [ diff --git a/mobile/lib/pages/common/album_options.page.dart b/mobile/lib/pages/common/album_options.page.dart index fe1cd2f777..1cc24af09c 100644 --- a/mobile/lib/pages/common/album_options.page.dart +++ b/mobile/lib/pages/common/album_options.page.dart @@ -184,7 +184,7 @@ class AlbumOptionsPage extends HookConsumerWidget { appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new_rounded), - onPressed: () => context.popRoute(null), + onPressed: () => context.maybePop(null), ), centerTitle: true, title: Text("translated_text_options".tr()), diff --git a/mobile/lib/pages/common/album_shared_user_selection.page.dart b/mobile/lib/pages/common/album_shared_user_selection.page.dart index 387894c063..d8cf4ecd27 100644 --- a/mobile/lib/pages/common/album_shared_user_selection.page.dart +++ b/mobile/lib/pages/common/album_shared_user_selection.page.dart @@ -36,7 +36,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums(); // ref.watch(assetSelectionProvider.notifier).removeAll(); ref.watch(albumTitleProvider.notifier).clearAlbumTitle(); - context.popRoute(true); + context.maybePop(true); context .navigateTo(const TabControllerRoute(children: [SharingRoute()])); } @@ -152,7 +152,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget { leading: IconButton( icon: const Icon(Icons.close_rounded), onPressed: () async { - context.popRoute(); + context.maybePop(); }, ), actions: [ diff --git a/mobile/lib/pages/common/app_log.page.dart b/mobile/lib/pages/common/app_log.page.dart index 808933918c..58086cd8b9 100644 --- a/mobile/lib/pages/common/app_log.page.dart +++ b/mobile/lib/pages/common/app_log.page.dart @@ -105,7 +105,7 @@ class AppLogPage extends HookConsumerWidget { ], leading: IconButton( onPressed: () { - context.popRoute(); + context.maybePop(); }, icon: const Icon( Icons.arrow_back_ios_new_rounded, diff --git a/mobile/lib/pages/common/create_album.page.dart b/mobile/lib/pages/common/create_album.page.dart index 885d65b9f0..053057425e 100644 --- a/mobile/lib/pages/common/create_album.page.dart +++ b/mobile/lib/pages/common/create_album.page.dart @@ -3,16 +3,16 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/models/albums/asset_selection_page_result.model.dart'; import 'package:immich_mobile/providers/album/album.provider.dart'; import 'package:immich_mobile/providers/album/album_title.provider.dart'; +import 'package:immich_mobile/providers/asset.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/album/album_action_outlined_button.dart'; import 'package:immich_mobile/widgets/album/album_title_text_field.dart'; import 'package:immich_mobile/widgets/album/shared_album_thumbnail_image.dart'; -import 'package:immich_mobile/routing/router.dart'; -import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:immich_mobile/providers/asset.provider.dart'; @RoutePage() // ignore: must_be_immutable @@ -216,7 +216,7 @@ class CreateAlbumPage extends HookConsumerWidget { leading: IconButton( onPressed: () { selectedAssets.value = {}; - context.popRoute(); + context.maybePop(); }, icon: const Icon(Icons.close_rounded), ), diff --git a/mobile/lib/pages/common/gallery_viewer.page.dart b/mobile/lib/pages/common/gallery_viewer.page.dart index 52ae695997..505d339aba 100644 --- a/mobile/lib/pages/common/gallery_viewer.page.dart +++ b/mobile/lib/pages/common/gallery_viewer.page.dart @@ -2,32 +2,33 @@ import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'dart:ui' as ui; + import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart' hide Store; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/providers/image/immich_remote_image_provider.dart'; +import 'package:immich_mobile/pages/common/video_viewer.page.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/asset_stack.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; +import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; +import 'package:immich_mobile/providers/image/immich_remote_image_provider.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/widgets/asset_viewer/advanced_bottom_sheet.dart'; import 'package:immich_mobile/widgets/asset_viewer/bottom_gallery_bar.dart'; import 'package:immich_mobile/widgets/asset_viewer/exif_sheet/exif_bottom_sheet.dart'; import 'package:immich_mobile/widgets/asset_viewer/gallery_app_bar.dart'; -import 'package:immich_mobile/providers/app_settings.provider.dart'; -import 'package:immich_mobile/pages/common/video_viewer.page.dart'; -import 'package:immich_mobile/services/app_settings.service.dart'; -import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; import 'package:immich_mobile/widgets/common/immich_image.dart'; import 'package:immich_mobile/widgets/common/immich_thumbnail.dart'; import 'package:immich_mobile/widgets/photo_view/photo_view_gallery.dart'; import 'package:immich_mobile/widgets/photo_view/src/photo_view_computed_scale.dart'; import 'package:immich_mobile/widgets/photo_view/src/photo_view_scale_state.dart'; import 'package:immich_mobile/widgets/photo_view/src/utils/photo_view_hero_attributes.dart'; -import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:isar/isar.dart'; import 'package:openapi/api.dart' show ThumbnailFormat; @@ -59,6 +60,7 @@ class GalleryViewerPage extends HookConsumerWidget { final settings = ref.watch(appSettingsServiceProvider); final isLoadPreview = useState(AppSettingsEnum.loadPreview.defaultValue); final isLoadOriginal = useState(AppSettingsEnum.loadOriginal.defaultValue); + final shouldLoopVideo = useState(AppSettingsEnum.loopVideo.defaultValue); final isZoomed = useState(false); final isPlayingVideo = useState(false); final localPosition = useState(null); @@ -101,6 +103,8 @@ class GalleryViewerPage extends HookConsumerWidget { settings.getSetting(AppSettingsEnum.loadPreview); isLoadOriginal.value = settings.getSetting(AppSettingsEnum.loadOriginal); + shouldLoopVideo.value = + settings.getSetting(AppSettingsEnum.loopVideo); return null; }, [], @@ -174,7 +178,7 @@ class GalleryViewerPage extends HookConsumerWidget { final ratio = d.dy / max(d.dx.abs(), 1); if (d.dy > sensitivity && ratio > ratioThreshold) { - context.popRoute(); + context.maybePop(); } else if (d.dy < -sensitivity && ratio < -ratioThreshold) { showInfo(); } @@ -261,12 +265,9 @@ class GalleryViewerPage extends HookConsumerWidget { } return PopScope( - canPop: false, - onPopInvoked: (_) { - // Change immersive mode back to normal "edgeToEdge" mode - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - context.pop(); - }, + // Change immersive mode back to normal "edgeToEdge" mode + onPopInvoked: (_) => + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge), child: Scaffold( backgroundColor: Colors.black, body: Stack( @@ -370,6 +371,7 @@ class GalleryViewerPage extends HookConsumerWidget { key: ValueKey(a), asset: a, isMotionVideo: a.livePhotoVideoId != null, + loopVideo: shouldLoopVideo.value, placeholder: Image( image: provider, fit: BoxFit.contain, diff --git a/mobile/lib/pages/common/settings.page.dart b/mobile/lib/pages/common/settings.page.dart index e20b06c24a..486eeba4cd 100644 --- a/mobile/lib/pages/common/settings.page.dart +++ b/mobile/lib/pages/common/settings.page.dart @@ -5,8 +5,8 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/widgets/settings/advanced_settings.dart'; import 'package:immich_mobile/widgets/settings/asset_list_settings/asset_list_settings.dart'; +import 'package:immich_mobile/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart'; import 'package:immich_mobile/widgets/settings/backup_settings/backup_settings.dart'; -import 'package:immich_mobile/widgets/settings/image_viewer_quality_setting.dart'; import 'package:immich_mobile/widgets/settings/language_settings.dart'; import 'package:immich_mobile/widgets/settings/notification_setting.dart'; import 'package:immich_mobile/widgets/settings/preference_settings/preference_setting.dart'; @@ -33,7 +33,7 @@ enum SettingSection { SettingSection.preferences => const PreferenceSetting(), SettingSection.backup => const BackupSettings(), SettingSection.timeline => const AssetListSettings(), - SettingSection.viewer => const ImageViewerQualitySetting(), + SettingSection.viewer => const AssetViewerSettings(), SettingSection.advanced => const AdvancedSettings(), }; diff --git a/mobile/lib/pages/common/video_viewer.page.dart b/mobile/lib/pages/common/video_viewer.page.dart index d52836de41..4c6f7344f7 100644 --- a/mobile/lib/pages/common/video_viewer.page.dart +++ b/mobile/lib/pages/common/video_viewer.page.dart @@ -1,18 +1,15 @@ -import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_controller_provider.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provider.dart'; import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; import 'package:immich_mobile/widgets/asset_viewer/video_player.dart'; -import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; -@RoutePage() -// ignore: must_be_immutable class VideoViewerPage extends HookConsumerWidget { final Asset asset; final bool isMotionVideo; @@ -20,6 +17,7 @@ class VideoViewerPage extends HookConsumerWidget { final Duration hideControlsTimer; final bool showControls; final bool showDownloadingIndicator; + final bool loopVideo; const VideoViewerPage({ super.key, @@ -29,6 +27,7 @@ class VideoViewerPage extends HookConsumerWidget { this.showControls = true, this.hideControlsTimer = const Duration(seconds: 5), this.showDownloadingIndicator = true, + this.loopVideo = false, }); @override @@ -76,7 +75,9 @@ class VideoViewerPage extends HookConsumerWidget { // Also sets the error if there is an error in the playback void updateVideoPlayback() { final videoPlayback = VideoPlaybackValue.fromController(controller); - ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback; + if (!loopVideo) { + ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback; + } final state = videoPlayback.state; // Enable the WakeLock while the video is playing @@ -156,6 +157,7 @@ class VideoViewerPage extends HookConsumerWidget { hideControlsTimer: hideControlsTimer, showControls: showControls, showDownloadingIndicator: showDownloadingIndicator, + loopVideo: loopVideo, ), ), ], diff --git a/mobile/lib/pages/library/archive.page.dart b/mobile/lib/pages/library/archive.page.dart index 9051a99d48..0082142113 100644 --- a/mobile/lib/pages/library/archive.page.dart +++ b/mobile/lib/pages/library/archive.page.dart @@ -17,7 +17,7 @@ class ArchivePage extends HookConsumerWidget { final count = archivedAssets.value?.totalAssets.toString() ?? "?"; return AppBar( leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), centerTitle: true, diff --git a/mobile/lib/pages/library/favorite.page.dart b/mobile/lib/pages/library/favorite.page.dart index cc867525ac..7462dc8f21 100644 --- a/mobile/lib/pages/library/favorite.page.dart +++ b/mobile/lib/pages/library/favorite.page.dart @@ -15,7 +15,7 @@ class FavoritesPage extends HookConsumerWidget { AppBar buildAppBar() { return AppBar( leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), centerTitle: true, diff --git a/mobile/lib/pages/library/trash.page.dart b/mobile/lib/pages/library/trash.page.dart index 931c1eef6b..3bba2f2dfe 100644 --- a/mobile/lib/pages/library/trash.page.dart +++ b/mobile/lib/pages/library/trash.page.dart @@ -143,7 +143,7 @@ class TrashPage extends HookConsumerWidget { return AppBar( leading: IconButton( onPressed: !selectionEnabledHook.value - ? () => context.popRoute() + ? () => context.maybePop() : () { selectionEnabledHook.value = false; selection.value = {}; diff --git a/mobile/lib/pages/onboarding/permission_onboarding.page.dart b/mobile/lib/pages/onboarding/permission_onboarding.page.dart index 8d2c049c50..e5408f2297 100644 --- a/mobile/lib/pages/onboarding/permission_onboarding.page.dart +++ b/mobile/lib/pages/onboarding/permission_onboarding.page.dart @@ -176,7 +176,7 @@ class PermissionOnboardingPage extends HookConsumerWidget { ), TextButton( child: const Text('permission_onboarding_back').tr(), - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), ), ], ), diff --git a/mobile/lib/pages/photos/memory.page.dart b/mobile/lib/pages/photos/memory.page.dart index daa291503c..3f86f5be08 100644 --- a/mobile/lib/pages/photos/memory.page.dart +++ b/mobile/lib/pages/photos/memory.page.dart @@ -3,14 +3,14 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/models/memories/memory.model.dart'; +import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; +import 'package:immich_mobile/widgets/common/immich_image.dart'; import 'package:immich_mobile/widgets/memories/memory_bottom_info.dart'; import 'package:immich_mobile/widgets/memories/memory_card.dart'; import 'package:immich_mobile/widgets/memories/memory_epilogue.dart'; import 'package:immich_mobile/widgets/memories/memory_progress_indicator.dart'; -import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; -import 'package:immich_mobile/widgets/common/immich_image.dart'; @RoutePage() class MemoryPage extends HookConsumerWidget { @@ -153,7 +153,7 @@ class MemoryPage extends HookConsumerWidget { final offset = notification.metrics.pixels; if (isEpiloguePage && (offset > notification.metrics.maxScrollExtent + 150)) { - context.popRoute(); + context.maybePop(); return true; } } @@ -256,7 +256,7 @@ class MemoryPage extends HookConsumerWidget { // auto_route doesn't invoke pop scope, so // turn off full screen mode here // https://github.com/Milad-Akarie/auto_route_library/issues/1799 - context.popRoute(); + context.maybePop(); SystemChrome.setEnabledSystemUIMode( SystemUiMode.edgeToEdge, ); diff --git a/mobile/lib/pages/photos/photos.page.dart b/mobile/lib/pages/photos/photos.page.dart index 2ef738aaf1..aecac56065 100644 --- a/mobile/lib/pages/photos/photos.page.dart +++ b/mobile/lib/pages/photos/photos.page.dart @@ -33,7 +33,6 @@ class PhotosPage extends HookConsumerWidget { () { ref.read(websocketProvider.notifier).connect(); Future(() => ref.read(assetProvider.notifier).getAllAsset()); - ref.read(assetProvider.notifier).getPartnerAssets(); ref.read(albumProvider.notifier).getAllAlbums(); ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums(); ref.read(serverInfoProvider.notifier).getServerInfo(); @@ -85,9 +84,6 @@ class PhotosPage extends HookConsumerWidget { Future refreshAssets() async { final fullRefresh = refreshCount.value > 0; await ref.read(assetProvider.notifier).getAllAsset(clear: fullRefresh); - if (timelineUsers.length > 1) { - await ref.read(assetProvider.notifier).getPartnerAssets(); - } if (fullRefresh) { // refresh was forced: user requested another refresh within 2 seconds refreshCount.value = 0; diff --git a/mobile/lib/pages/search/all_motion_videos.page.dart b/mobile/lib/pages/search/all_motion_videos.page.dart index adccdc4e01..1c070a51c8 100644 --- a/mobile/lib/pages/search/all_motion_videos.page.dart +++ b/mobile/lib/pages/search/all_motion_videos.page.dart @@ -18,7 +18,7 @@ class AllMotionPhotosPage extends HookConsumerWidget { appBar: AppBar( title: const Text('motion_photos_page_title').tr(), leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), ), diff --git a/mobile/lib/pages/search/all_people.page.dart b/mobile/lib/pages/search/all_people.page.dart index 8699eff1c1..e9e491ae1b 100644 --- a/mobile/lib/pages/search/all_people.page.dart +++ b/mobile/lib/pages/search/all_people.page.dart @@ -21,7 +21,7 @@ class AllPeoplePage extends HookConsumerWidget { 'all_people_page_title', ).tr(), leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), ), diff --git a/mobile/lib/pages/search/all_places.page.dart b/mobile/lib/pages/search/all_places.page.dart index 4f848f3fa8..9d9f5e9e90 100644 --- a/mobile/lib/pages/search/all_places.page.dart +++ b/mobile/lib/pages/search/all_places.page.dart @@ -22,7 +22,7 @@ class AllPlacesPage extends HookConsumerWidget { 'curated_location_page_title', ).tr(), leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), ), diff --git a/mobile/lib/pages/search/all_videos.page.dart b/mobile/lib/pages/search/all_videos.page.dart index add70261a2..e96e060255 100644 --- a/mobile/lib/pages/search/all_videos.page.dart +++ b/mobile/lib/pages/search/all_videos.page.dart @@ -15,7 +15,7 @@ class AllVideosPage extends HookConsumerWidget { appBar: AppBar( title: const Text('all_videos_page_title').tr(), leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), ), diff --git a/mobile/lib/pages/search/map/map_location_picker.page.dart b/mobile/lib/pages/search/map/map_location_picker.page.dart index 47f4d3d0eb..db0c980c89 100644 --- a/mobile/lib/pages/search/map/map_location_picker.page.dart +++ b/mobile/lib/pages/search/map/map_location_picker.page.dart @@ -41,7 +41,7 @@ class MapLocationPickerPage extends HookConsumerWidget { } void onClose([LatLng? selected]) { - context.popRoute(selected); + context.maybePop(selected); } Future getCurrentLocation() async { diff --git a/mobile/lib/pages/search/person_result.page.dart b/mobile/lib/pages/search/person_result.page.dart index ec3f0f31ef..1fec9a4a33 100644 --- a/mobile/lib/pages/search/person_result.page.dart +++ b/mobile/lib/pages/search/person_result.page.dart @@ -102,7 +102,7 @@ class PersonResultPage extends HookConsumerWidget { appBar: AppBar( title: Text(name.value), leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), actions: [ diff --git a/mobile/lib/pages/search/recently_added.page.dart b/mobile/lib/pages/search/recently_added.page.dart index d52841c4f4..b79527e222 100644 --- a/mobile/lib/pages/search/recently_added.page.dart +++ b/mobile/lib/pages/search/recently_added.page.dart @@ -18,7 +18,7 @@ class RecentlyAddedPage extends HookConsumerWidget { appBar: AppBar( title: const Text('recently_added_page_title').tr(), leading: IconButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), ), ), diff --git a/mobile/lib/pages/search/search_input.page.dart b/mobile/lib/pages/search/search_input.page.dart index 3bf6c39189..e166777439 100644 --- a/mobile/lib/pages/search/search_input.page.dart +++ b/mobile/lib/pages/search/search_input.page.dart @@ -4,9 +4,11 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; import 'package:immich_mobile/providers/search/paginated_search.provider.dart'; +import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart'; import 'package:immich_mobile/widgets/search/search_filter/camera_picker.dart'; import 'package:immich_mobile/widgets/search/search_filter/display_option_picker.dart'; import 'package:immich_mobile/widgets/search/search_filter/filter_bottom_sheet_scaffold.dart'; @@ -15,8 +17,6 @@ import 'package:immich_mobile/widgets/search/search_filter/media_type_picker.dar import 'package:immich_mobile/widgets/search/search_filter/people_picker.dart'; import 'package:immich_mobile/widgets/search/search_filter/search_filter_chip.dart'; import 'package:immich_mobile/widgets/search/search_filter/search_filter_utils.dart'; -import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:immich_mobile/widgets/asset_grid/multiselect_grid.dart'; import 'package:openapi/api.dart'; @RoutePage() @@ -480,9 +480,7 @@ class SearchInputPage extends HookConsumerWidget { ], leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new_rounded), - onPressed: () { - context.router.pop(); - }, + onPressed: () => context.router.maybePop(), ), title: TextField( controller: textSearchController, diff --git a/mobile/lib/pages/sharing/partner/partner_detail.page.dart b/mobile/lib/pages/sharing/partner/partner_detail.page.dart index a858320b12..8a2dd4b820 100644 --- a/mobile/lib/pages/sharing/partner/partner_detail.page.dart +++ b/mobile/lib/pages/sharing/partner/partner_detail.page.dart @@ -22,7 +22,7 @@ class PartnerDetailPage extends HookConsumerWidget { useEffect( () { - ref.read(assetProvider.notifier).getPartnerAssets(partner); + ref.read(assetProvider.notifier).getAllAsset(); return null; }, [], @@ -78,8 +78,7 @@ class PartnerDetailPage extends HookConsumerWidget { ), body: MultiselectGrid( renderListProvider: assetsProvider(partner.isarId), - onRefresh: () => - ref.read(assetProvider.notifier).getPartnerAssets(partner), + onRefresh: () => ref.read(assetProvider.notifier).getAllAsset(), deleteEnabled: false, favoriteEnabled: false, ), diff --git a/mobile/lib/pages/sharing/shared_link/shared_link_edit.page.dart b/mobile/lib/pages/sharing/shared_link/shared_link_edit.page.dart index 356bd5e945..6223e110e1 100644 --- a/mobile/lib/pages/sharing/shared_link/shared_link_edit.page.dart +++ b/mobile/lib/pages/sharing/shared_link/shared_link_edit.page.dart @@ -328,7 +328,7 @@ class SharedLinkEditPage extends HookConsumerWidget { alignment: Alignment.bottomRight, child: ElevatedButton( onPressed: () { - context.popRoute(); + context.maybePop(); }, child: const Text( "share_done", @@ -431,7 +431,7 @@ class SharedLinkEditPage extends HookConsumerWidget { changeExpiry: changeExpiry, ); ref.invalidate(sharedLinksStateProvider); - context.popRoute(); + context.maybePop(); } return Scaffold( diff --git a/mobile/lib/providers/app_life_cycle.provider.dart b/mobile/lib/providers/app_life_cycle.provider.dart index bb6c9722cc..938961efb6 100644 --- a/mobile/lib/providers/app_life_cycle.provider.dart +++ b/mobile/lib/providers/app_life_cycle.provider.dart @@ -56,11 +56,10 @@ class AppLifeCycleNotifier extends StateNotifier { switch (_ref.read(tabProvider)) { case TabEnum.home: _ref.read(assetProvider.notifier).getAllAsset(); - _ref.read(assetProvider.notifier).getPartnerAssets(); case TabEnum.search: // nothing to do case TabEnum.sharing: - _ref.read(assetProvider.notifier).getPartnerAssets(); + _ref.read(assetProvider.notifier).getAllAsset(); _ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums(); case TabEnum.library: _ref.read(albumProvider.notifier).getAllAlbums(); diff --git a/mobile/lib/providers/asset.provider.dart b/mobile/lib/providers/asset.provider.dart index 4c12ed2f10..a0a3879db5 100644 --- a/mobile/lib/providers/asset.provider.dart +++ b/mobile/lib/providers/asset.provider.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/providers/memory.provider.dart'; import 'package:immich_mobile/services/album.service.dart'; import 'package:immich_mobile/entities/exif_info.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; -import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/services/asset.service.dart'; @@ -23,10 +23,10 @@ class AssetNotifier extends StateNotifier { final UserService _userService; final SyncService _syncService; final Isar _db; + final StateNotifierProviderRef _ref; final log = Logger('AssetNotifier'); bool _getAllAssetInProgress = false; bool _deleteInProgress = false; - bool _getPartnerAssetsInProgress = false; AssetNotifier( this._assetService, @@ -34,6 +34,7 @@ class AssetNotifier extends StateNotifier { this._userService, this._syncService, this._db, + this._ref, ) : super(false); Future getAllAsset({bool clear = false}) async { @@ -49,9 +50,15 @@ class AssetNotifier extends StateNotifier { await clearAssetsAndAlbums(_db); log.info("Manual refresh requested, cleared assets and albums from db"); } + final bool changedUsers = await _userService.refreshUsers(); final bool newRemote = await _assetService.refreshRemoteAssets(); final bool newLocal = await _albumService.refreshDeviceAlbums(); - debugPrint("newRemote: $newRemote, newLocal: $newLocal"); + debugPrint( + "changedUsers: $changedUsers, newRemote: $newRemote, newLocal: $newLocal", + ); + if (newRemote) { + _ref.invalidate(memoryFutureProvider); + } log.info("Load assets: ${stopwatch.elapsedMilliseconds}ms"); } finally { @@ -60,27 +67,6 @@ class AssetNotifier extends StateNotifier { } } - Future getPartnerAssets([User? partner]) async { - if (_getPartnerAssetsInProgress) return; - try { - final stopwatch = Stopwatch()..start(); - _getPartnerAssetsInProgress = true; - if (partner == null) { - await _userService.refreshUsers(); - final List partners = - await _db.users.filter().isPartnerSharedWithEqualTo(true).findAll(); - for (User u in partners) { - await _assetService.refreshRemoteAssets(u); - } - } else { - await _assetService.refreshRemoteAssets(partner); - } - log.info("Load partner assets: ${stopwatch.elapsedMilliseconds}ms"); - } finally { - _getPartnerAssetsInProgress = false; - } - } - Future clearAllAsset() { return clearAssetsAndAlbums(_db); } @@ -321,6 +307,7 @@ final assetProvider = StateNotifierProvider((ref) { ref.watch(userServiceProvider), ref.watch(syncServiceProvider), ref.watch(dbProvider), + ref, ); }); diff --git a/mobile/lib/providers/backup/backup.provider.dart b/mobile/lib/providers/backup/backup.provider.dart index ab869c2328..58027e3b94 100644 --- a/mobile/lib/providers/backup/backup.provider.dart +++ b/mobile/lib/providers/backup/backup.provider.dart @@ -374,7 +374,7 @@ class BackupNotifier extends StateNotifier { if (state.backupProgress != BackUpProgressEnum.inBackground) { await _getBackupAlbumsInfo(); - await updateServerInfo(); + await updateDiskInfo(); await _updateBackupAssetCount(); } else { log.warning("cannot get backup info - background backup is in progress!"); @@ -542,7 +542,7 @@ class BackupNotifier extends StateNotifier { _updatePersistentAlbumsSelection(); } - updateServerInfo(); + updateDiskInfo(); } void _onUploadProgress(int sent, int total) { @@ -579,13 +579,13 @@ class BackupNotifier extends StateNotifier { ); } - Future updateServerInfo() async { - final serverInfo = await _serverInfoService.getServerInfo(); + Future updateDiskInfo() async { + final diskInfo = await _serverInfoService.getDiskInfo(); // Update server info - if (serverInfo != null) { + if (diskInfo != null) { state = state.copyWith( - serverInfo: serverInfo, + serverInfo: diskInfo, ); } } diff --git a/mobile/lib/providers/backup/manual_upload.provider.dart b/mobile/lib/providers/backup/manual_upload.provider.dart index 1de7f7a788..b446711226 100644 --- a/mobile/lib/providers/backup/manual_upload.provider.dart +++ b/mobile/lib/providers/backup/manual_upload.provider.dart @@ -121,7 +121,7 @@ class ManualUploadNotifier extends StateNotifier { bool isDuplicated, ) { state = state.copyWith(successfulUploads: state.successfulUploads + 1); - _backupProvider.updateServerInfo(); + _backupProvider.updateDiskInfo(); } void _onAssetUploadError(ErrorUploadAsset errorAssetInfo) { diff --git a/mobile/lib/routing/router.dart b/mobile/lib/routing/router.dart index 98c0142452..f51f11230b 100644 --- a/mobile/lib/routing/router.dart +++ b/mobile/lib/routing/router.dart @@ -1,35 +1,32 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/models/memories/memory.model.dart'; -import 'package:immich_mobile/models/search/search_filter.model.dart'; -import 'package:immich_mobile/pages/common/activities.page.dart'; -import 'package:immich_mobile/models/albums/asset_selection_page_result.model.dart'; -import 'package:immich_mobile/pages/common/album_options.page.dart'; -import 'package:immich_mobile/pages/common/album_viewer.page.dart'; -import 'package:immich_mobile/pages/common/album_asset_selection.page.dart'; -import 'package:immich_mobile/pages/common/create_album.page.dart'; -import 'package:immich_mobile/models/shared_link/shared_link.model.dart'; -import 'package:immich_mobile/pages/common/album_additional_shared_user_selection.page.dart'; -import 'package:immich_mobile/pages/common/album_shared_user_selection.page.dart'; -import 'package:immich_mobile/providers/gallery_permission.provider.dart'; -import 'package:immich_mobile/routing/auth_guard.dart'; -import 'package:immich_mobile/routing/custom_transition_builders.dart'; -import 'package:immich_mobile/routing/duplicate_guard.dart'; -import 'package:immich_mobile/routing/backup_permission_guard.dart'; -import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/album.entity.dart'; +import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/logger_message.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart'; -import 'package:immich_mobile/providers/api.provider.dart'; -import 'package:immich_mobile/pages/common/app_log_detail.page.dart'; -import 'package:immich_mobile/pages/common/app_log.page.dart'; +import 'package:immich_mobile/models/albums/asset_selection_page_result.model.dart'; +import 'package:immich_mobile/models/memories/memory.model.dart'; +import 'package:immich_mobile/models/search/search_filter.model.dart'; +import 'package:immich_mobile/models/shared_link/shared_link.model.dart'; import 'package:immich_mobile/pages/backup/album_preview.page.dart'; import 'package:immich_mobile/pages/backup/backup_album_selection.page.dart'; import 'package:immich_mobile/pages/backup/backup_controller.page.dart'; import 'package:immich_mobile/pages/backup/backup_options.page.dart'; import 'package:immich_mobile/pages/backup/failed_backup_status.page.dart'; +import 'package:immich_mobile/pages/common/activities.page.dart'; +import 'package:immich_mobile/pages/common/album_additional_shared_user_selection.page.dart'; +import 'package:immich_mobile/pages/common/album_asset_selection.page.dart'; +import 'package:immich_mobile/pages/common/album_options.page.dart'; +import 'package:immich_mobile/pages/common/album_shared_user_selection.page.dart'; +import 'package:immich_mobile/pages/common/album_viewer.page.dart'; +import 'package:immich_mobile/pages/common/app_log.page.dart'; +import 'package:immich_mobile/pages/common/app_log_detail.page.dart'; +import 'package:immich_mobile/pages/common/create_album.page.dart'; import 'package:immich_mobile/pages/common/gallery_viewer.page.dart'; +import 'package:immich_mobile/pages/common/settings.page.dart'; +import 'package:immich_mobile/pages/common/splash_screen.page.dart'; +import 'package:immich_mobile/pages/common/tab_controller.page.dart'; import 'package:immich_mobile/pages/library/archive.page.dart'; import 'package:immich_mobile/pages/library/favorite.page.dart'; import 'package:immich_mobile/pages/library/library.page.dart'; @@ -43,21 +40,23 @@ import 'package:immich_mobile/pages/search/all_motion_videos.page.dart'; import 'package:immich_mobile/pages/search/all_people.page.dart'; import 'package:immich_mobile/pages/search/all_places.page.dart'; import 'package:immich_mobile/pages/search/all_videos.page.dart'; -import 'package:immich_mobile/pages/search/map/map_location_picker.page.dart'; import 'package:immich_mobile/pages/search/map/map.page.dart'; +import 'package:immich_mobile/pages/search/map/map_location_picker.page.dart'; import 'package:immich_mobile/pages/search/person_result.page.dart'; import 'package:immich_mobile/pages/search/recently_added.page.dart'; -import 'package:immich_mobile/pages/search/search_input.page.dart'; import 'package:immich_mobile/pages/search/search.page.dart'; -import 'package:immich_mobile/pages/common/settings.page.dart'; -import 'package:immich_mobile/pages/sharing/partner/partner_detail.page.dart'; +import 'package:immich_mobile/pages/search/search_input.page.dart'; import 'package:immich_mobile/pages/sharing/partner/partner.page.dart'; -import 'package:immich_mobile/pages/sharing/shared_link/shared_link_edit.page.dart'; +import 'package:immich_mobile/pages/sharing/partner/partner_detail.page.dart'; import 'package:immich_mobile/pages/sharing/shared_link/shared_link.page.dart'; +import 'package:immich_mobile/pages/sharing/shared_link/shared_link_edit.page.dart'; import 'package:immich_mobile/pages/sharing/sharing.page.dart'; -import 'package:immich_mobile/pages/common/splash_screen.page.dart'; -import 'package:immich_mobile/pages/common/tab_controller.page.dart'; -import 'package:immich_mobile/pages/common/video_viewer.page.dart'; +import 'package:immich_mobile/providers/api.provider.dart'; +import 'package:immich_mobile/providers/gallery_permission.provider.dart'; +import 'package:immich_mobile/routing/auth_guard.dart'; +import 'package:immich_mobile/routing/backup_permission_guard.dart'; +import 'package:immich_mobile/routing/custom_transition_builders.dart'; +import 'package:immich_mobile/routing/duplicate_guard.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:isar/isar.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; @@ -120,10 +119,6 @@ class AppRouter extends _$AppRouter { guards: [_authGuard, _duplicateGuard], transitionsBuilder: CustomTransitionsBuilders.zoomedPage, ), - AutoRoute( - page: VideoViewerRoute.page, - guards: [_authGuard, _duplicateGuard], - ), AutoRoute( page: BackupControllerRoute.page, guards: [_authGuard, _duplicateGuard, _backupPermissionGuard], diff --git a/mobile/lib/routing/router.gr.dart b/mobile/lib/routing/router.gr.dart index 0c519eb2bc..806dd7f6ff 100644 --- a/mobile/lib/routing/router.gr.dart +++ b/mobile/lib/routing/router.gr.dart @@ -21,6 +21,29 @@ abstract class _$AppRouter extends RootStackRouter { child: const ActivitiesPage(), ); }, + AlbumAdditionalSharedUserSelectionRoute.name: (routeData) { + final args = + routeData.argsAs(); + return AutoRoutePage?>( + routeData: routeData, + child: AlbumAdditionalSharedUserSelectionPage( + key: args.key, + album: args.album, + ), + ); + }, + AlbumAssetSelectionRoute.name: (routeData) { + final args = routeData.argsAs(); + return AutoRoutePage( + routeData: routeData, + child: AlbumAssetSelectionPage( + key: args.key, + existingAssets: args.existingAssets, + canDeselect: args.canDeselect, + query: args.query, + ), + ); + }, AlbumOptionsRoute.name: (routeData) { final args = routeData.argsAs(); return AutoRoutePage( @@ -41,6 +64,16 @@ abstract class _$AppRouter extends RootStackRouter { ), ); }, + AlbumSharedUserSelectionRoute.name: (routeData) { + final args = routeData.argsAs(); + return AutoRoutePage>( + routeData: routeData, + child: AlbumSharedUserSelectionPage( + key: args.key, + assets: args.assets, + ), + ); + }, AlbumViewerRoute.name: (routeData) { final args = routeData.argsAs(); return AutoRoutePage( @@ -97,18 +130,6 @@ abstract class _$AppRouter extends RootStackRouter { child: const ArchivePage(), ); }, - AlbumAssetSelectionRoute.name: (routeData) { - final args = routeData.argsAs(); - return AutoRoutePage( - routeData: routeData, - child: AlbumAssetSelectionPage( - key: args.key, - existingAssets: args.existingAssets, - canDeselect: args.canDeselect, - query: args.query, - ), - ); - }, BackupAlbumSelectionRoute.name: (routeData) { return AutoRoutePage( routeData: routeData, @@ -170,12 +191,6 @@ abstract class _$AppRouter extends RootStackRouter { ), ); }, - PhotosRoute.name: (routeData) { - return AutoRoutePage( - routeData: routeData, - child: const PhotosPage(), - ); - }, LibraryRoute.name: (routeData) { return AutoRoutePage( routeData: routeData, @@ -249,6 +264,12 @@ abstract class _$AppRouter extends RootStackRouter { ), ); }, + PhotosRoute.name: (routeData) { + return AutoRoutePage( + routeData: routeData, + child: const PhotosPage(), + ); + }, RecentlyAddedRoute.name: (routeData) { return AutoRoutePage( routeData: routeData, @@ -272,26 +293,6 @@ abstract class _$AppRouter extends RootStackRouter { child: const SearchPage(), ); }, - AlbumAdditionalSharedUserSelectionRoute.name: (routeData) { - final args = routeData.argsAs(); - return AutoRoutePage?>( - routeData: routeData, - child: AlbumAdditionalSharedUserSelectionPage( - key: args.key, - album: args.album, - ), - ); - }, - AlbumSharedUserSelectionRoute.name: (routeData) { - final args = routeData.argsAs(); - return AutoRoutePage>( - routeData: routeData, - child: AlbumSharedUserSelectionPage( - key: args.key, - assets: args.assets, - ), - ); - }, SettingsRoute.name: (routeData) { return AutoRoutePage( routeData: routeData, @@ -351,21 +352,6 @@ abstract class _$AppRouter extends RootStackRouter { child: const TrashPage(), ); }, - VideoViewerRoute.name: (routeData) { - final args = routeData.argsAs(); - return AutoRoutePage( - routeData: routeData, - child: VideoViewerPage( - key: args.key, - asset: args.asset, - isMotionVideo: args.isMotionVideo, - placeholder: args.placeholder, - showControls: args.showControls, - hideControlsTimer: args.hideControlsTimer, - showDownloadingIndicator: args.showDownloadingIndicator, - ), - ); - }, }; } @@ -383,6 +369,94 @@ class ActivitiesRoute extends PageRouteInfo { static const PageInfo page = PageInfo(name); } +/// generated route for +/// [AlbumAdditionalSharedUserSelectionPage] +class AlbumAdditionalSharedUserSelectionRoute + extends PageRouteInfo { + AlbumAdditionalSharedUserSelectionRoute({ + Key? key, + required Album album, + List? children, + }) : super( + AlbumAdditionalSharedUserSelectionRoute.name, + args: AlbumAdditionalSharedUserSelectionRouteArgs( + key: key, + album: album, + ), + initialChildren: children, + ); + + static const String name = 'AlbumAdditionalSharedUserSelectionRoute'; + + static const PageInfo page = + PageInfo(name); +} + +class AlbumAdditionalSharedUserSelectionRouteArgs { + const AlbumAdditionalSharedUserSelectionRouteArgs({ + this.key, + required this.album, + }); + + final Key? key; + + final Album album; + + @override + String toString() { + return 'AlbumAdditionalSharedUserSelectionRouteArgs{key: $key, album: $album}'; + } +} + +/// generated route for +/// [AlbumAssetSelectionPage] +class AlbumAssetSelectionRoute + extends PageRouteInfo { + AlbumAssetSelectionRoute({ + Key? key, + required Set existingAssets, + bool canDeselect = false, + required QueryBuilder? query, + List? children, + }) : super( + AlbumAssetSelectionRoute.name, + args: AlbumAssetSelectionRouteArgs( + key: key, + existingAssets: existingAssets, + canDeselect: canDeselect, + query: query, + ), + initialChildren: children, + ); + + static const String name = 'AlbumAssetSelectionRoute'; + + static const PageInfo page = + PageInfo(name); +} + +class AlbumAssetSelectionRouteArgs { + const AlbumAssetSelectionRouteArgs({ + this.key, + required this.existingAssets, + this.canDeselect = false, + required this.query, + }); + + final Key? key; + + final Set existingAssets; + + final bool canDeselect; + + final QueryBuilder? query; + + @override + String toString() { + return 'AlbumAssetSelectionRouteArgs{key: $key, existingAssets: $existingAssets, canDeselect: $canDeselect, query: $query}'; + } +} + /// generated route for /// [AlbumOptionsPage] class AlbumOptionsRoute extends PageRouteInfo { @@ -459,6 +533,45 @@ class AlbumPreviewRouteArgs { } } +/// generated route for +/// [AlbumSharedUserSelectionPage] +class AlbumSharedUserSelectionRoute + extends PageRouteInfo { + AlbumSharedUserSelectionRoute({ + Key? key, + required Set assets, + List? children, + }) : super( + AlbumSharedUserSelectionRoute.name, + args: AlbumSharedUserSelectionRouteArgs( + key: key, + assets: assets, + ), + initialChildren: children, + ); + + static const String name = 'AlbumSharedUserSelectionRoute'; + + static const PageInfo page = + PageInfo(name); +} + +class AlbumSharedUserSelectionRouteArgs { + const AlbumSharedUserSelectionRouteArgs({ + this.key, + required this.assets, + }); + + final Key? key; + + final Set assets; + + @override + String toString() { + return 'AlbumSharedUserSelectionRouteArgs{key: $key, assets: $assets}'; + } +} + /// generated route for /// [AlbumViewerPage] class AlbumViewerRoute extends PageRouteInfo { @@ -619,54 +732,6 @@ class ArchiveRoute extends PageRouteInfo { static const PageInfo page = PageInfo(name); } -/// generated route for -/// [AlbumAssetSelectionPage] -class AlbumAssetSelectionRoute extends PageRouteInfo { - AlbumAssetSelectionRoute({ - Key? key, - required Set existingAssets, - bool canDeselect = false, - required QueryBuilder? query, - List? children, - }) : super( - AlbumAssetSelectionRoute.name, - args: AssetSelectionRouteArgs( - key: key, - existingAssets: existingAssets, - canDeselect: canDeselect, - query: query, - ), - initialChildren: children, - ); - - static const String name = 'AlbumAssetSelectionRoute'; - - static const PageInfo page = - PageInfo(name); -} - -class AssetSelectionRouteArgs { - const AssetSelectionRouteArgs({ - this.key, - required this.existingAssets, - this.canDeselect = false, - required this.query, - }); - - final Key? key; - - final Set existingAssets; - - final bool canDeselect; - - final QueryBuilder? query; - - @override - String toString() { - return 'AssetSelectionRouteArgs{key: $key, existingAssets: $existingAssets, canDeselect: $canDeselect, query: $query}'; - } -} - /// generated route for /// [BackupAlbumSelectionPage] class BackupAlbumSelectionRoute extends PageRouteInfo { @@ -852,20 +917,6 @@ class GalleryViewerRouteArgs { } } -/// generated route for -/// [PhotosPage] -class PhotosRoute extends PageRouteInfo { - const PhotosRoute({List? children}) - : super( - PhotosRoute.name, - initialChildren: children, - ); - - static const String name = 'PhotosRoute'; - - static const PageInfo page = PageInfo(name); -} - /// generated route for /// [LibraryPage] class LibraryRoute extends PageRouteInfo { @@ -1097,6 +1148,20 @@ class PersonResultRouteArgs { } } +/// generated route for +/// [PhotosPage] +class PhotosRoute extends PageRouteInfo { + const PhotosRoute({List? children}) + : super( + PhotosRoute.name, + initialChildren: children, + ); + + static const String name = 'PhotosRoute'; + + static const PageInfo page = PageInfo(name); +} + /// generated route for /// [RecentlyAddedPage] class RecentlyAddedRoute extends PageRouteInfo { @@ -1163,84 +1228,6 @@ class SearchRoute extends PageRouteInfo { static const PageInfo page = PageInfo(name); } -/// generated route for -/// [AlbumAdditionalSharedUserSelectionPage] -class AlbumAdditionalSharedUserSelectionRoute - extends PageRouteInfo { - AlbumAdditionalSharedUserSelectionRoute({ - Key? key, - required Album album, - List? children, - }) : super( - AlbumAdditionalSharedUserSelectionRoute.name, - args: SelectAdditionalUserForSharingRouteArgs( - key: key, - album: album, - ), - initialChildren: children, - ); - - static const String name = 'AlbumAdditionalSharedUserSelectionRoute'; - - static const PageInfo page = - PageInfo(name); -} - -class SelectAdditionalUserForSharingRouteArgs { - const SelectAdditionalUserForSharingRouteArgs({ - this.key, - required this.album, - }); - - final Key? key; - - final Album album; - - @override - String toString() { - return 'SelectAdditionalUserForSharingRouteArgs{key: $key, album: $album}'; - } -} - -/// generated route for -/// [AlbumSharedUserSelectionPage] -class AlbumSharedUserSelectionRoute - extends PageRouteInfo { - AlbumSharedUserSelectionRoute({ - Key? key, - required Set assets, - List? children, - }) : super( - AlbumSharedUserSelectionRoute.name, - args: SelectUserForSharingRouteArgs( - key: key, - assets: assets, - ), - initialChildren: children, - ); - - static const String name = 'AlbumSharedUserSelectionRoute'; - - static const PageInfo page = - PageInfo(name); -} - -class SelectUserForSharingRouteArgs { - const SelectUserForSharingRouteArgs({ - this.key, - required this.assets, - }); - - final Key? key; - - final Set assets; - - @override - String toString() { - return 'SelectUserForSharingRouteArgs{key: $key, assets: $assets}'; - } -} - /// generated route for /// [SettingsPage] class SettingsRoute extends PageRouteInfo { @@ -1410,66 +1397,3 @@ class TrashRoute extends PageRouteInfo { static const PageInfo page = PageInfo(name); } - -/// generated route for -/// [VideoViewerPage] -class VideoViewerRoute extends PageRouteInfo { - VideoViewerRoute({ - Key? key, - required Asset asset, - bool isMotionVideo = false, - Widget? placeholder, - bool showControls = true, - Duration hideControlsTimer = const Duration(seconds: 5), - bool showDownloadingIndicator = true, - List? children, - }) : super( - VideoViewerRoute.name, - args: VideoViewerRouteArgs( - key: key, - asset: asset, - isMotionVideo: isMotionVideo, - placeholder: placeholder, - showControls: showControls, - hideControlsTimer: hideControlsTimer, - showDownloadingIndicator: showDownloadingIndicator, - ), - initialChildren: children, - ); - - static const String name = 'VideoViewerRoute'; - - static const PageInfo page = - PageInfo(name); -} - -class VideoViewerRouteArgs { - const VideoViewerRouteArgs({ - this.key, - required this.asset, - this.isMotionVideo = false, - this.placeholder, - this.showControls = true, - this.hideControlsTimer = const Duration(seconds: 5), - this.showDownloadingIndicator = true, - }); - - final Key? key; - - final Asset asset; - - final bool isMotionVideo; - - final Widget? placeholder; - - final bool showControls; - - final Duration hideControlsTimer; - - final bool showDownloadingIndicator; - - @override - String toString() { - return 'VideoViewerRouteArgs{key: $key, asset: $asset, isMotionVideo: $isMotionVideo, placeholder: $placeholder, showControls: $showControls, hideControlsTimer: $hideControlsTimer, showDownloadingIndicator: $showDownloadingIndicator}'; - } -} diff --git a/mobile/lib/routing/tab_navigation_observer.dart b/mobile/lib/routing/tab_navigation_observer.dart index d60cdb683f..f88adbda91 100644 --- a/mobile/lib/routing/tab_navigation_observer.dart +++ b/mobile/lib/routing/tab_navigation_observer.dart @@ -43,7 +43,7 @@ class TabNavigationObserver extends AutoRouterObserver { if (route.name == 'SharingRoute') { ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums(); - ref.read(assetProvider.notifier).getPartnerAssets(); + Future(() => ref.read(assetProvider.notifier).getAllAsset()); } if (route.name == 'LibraryRoute') { diff --git a/mobile/lib/services/album.service.dart b/mobile/lib/services/album.service.dart index bdf38a42af..c6d70c269a 100644 --- a/mobile/lib/services/album.service.dart +++ b/mobile/lib/services/album.service.dart @@ -180,7 +180,14 @@ class AlbumService { CreateAlbumDto( albumName: albumName, assetIds: assets.map((asset) => asset.remoteId!).toList(), - sharedWithUserIds: sharedUsers.map((e) => e.id).toList(), + albumUsers: sharedUsers + .map( + (e) => AlbumUserCreateDto( + userId: e.id, + role: AlbumUserRole.editor, + ), + ) + .toList(), ), ); if (remote != null) { diff --git a/mobile/lib/services/api.service.dart b/mobile/lib/services/api.service.dart index cc57d6b26e..07b9a6e177 100644 --- a/mobile/lib/services/api.service.dart +++ b/mobile/lib/services/api.service.dart @@ -23,6 +23,7 @@ class ApiService { late PersonApi personApi; late AuditApi auditApi; late SharedLinkApi sharedLinkApi; + late SyncApi syncApi; late SystemConfigApi systemConfigApi; late ActivityApi activityApi; late DownloadApi downloadApi; @@ -53,6 +54,7 @@ class ApiService { personApi = PersonApi(_apiClient); auditApi = AuditApi(_apiClient); sharedLinkApi = SharedLinkApi(_apiClient); + syncApi = SyncApi(_apiClient); systemConfigApi = SystemConfigApi(_apiClient); activityApi = ActivityApi(_apiClient); downloadApi = DownloadApi(_apiClient); diff --git a/mobile/lib/services/app_settings.service.dart b/mobile/lib/services/app_settings.service.dart index a803a6807f..fd6c2d89a7 100644 --- a/mobile/lib/services/app_settings.service.dart +++ b/mobile/lib/services/app_settings.service.dart @@ -46,6 +46,7 @@ enum AppSettingsEnum { advancedTroubleshooting(StoreKey.advancedTroubleshooting, null, false), logLevel(StoreKey.logLevel, null, 5), // Level.INFO = 5 preferRemoteImage(StoreKey.preferRemoteImage, null, false), + loopVideo(StoreKey.loopVideo, "loopVideo", true), mapThemeMode(StoreKey.mapThemeMode, null, 0), mapShowFavoriteOnly(StoreKey.mapShowFavoriteOnly, null, false), mapIncludeArchived(StoreKey.mapIncludeArchived, null, false), diff --git a/mobile/lib/services/asset.service.dart b/mobile/lib/services/asset.service.dart index f85808dece..d8555c0129 100644 --- a/mobile/lib/services/asset.service.dart +++ b/mobile/lib/services/asset.service.dart @@ -5,13 +5,14 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; +import 'package:immich_mobile/entities/etag.entity.dart'; import 'package:immich_mobile/entities/exif_info.entity.dart'; -import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/user.entity.dart'; import 'package:immich_mobile/providers/api.provider.dart'; import 'package:immich_mobile/providers/db.provider.dart'; import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/sync.service.dart'; +import 'package:immich_mobile/services/user.service.dart'; import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; import 'package:maplibre_gl/maplibre_gl.dart'; @@ -21,6 +22,7 @@ final assetServiceProvider = Provider( (ref) => AssetService( ref.watch(apiServiceProvider), ref.watch(syncServiceProvider), + ref.watch(userServiceProvider), ref.watch(dbProvider), ), ); @@ -28,24 +30,33 @@ final assetServiceProvider = Provider( class AssetService { final ApiService _apiService; final SyncService _syncService; + final UserService _userService; final log = Logger('AssetService'); final Isar _db; AssetService( this._apiService, this._syncService, + this._userService, this._db, ); /// Checks the server for updated assets and updates the local database if /// required. Returns `true` if there were any changes. - Future refreshRemoteAssets([User? user]) async { - user ??= Store.get(StoreKey.currentUser); + Future refreshRemoteAssets() async { + final syncedUserIds = await _db.eTags.where().idProperty().findAll(); + final List syncedUsers = syncedUserIds.isEmpty + ? [] + : await _db.users + .where() + .anyOf(syncedUserIds, (q, id) => q.idEqualTo(id)) + .findAll(); final Stopwatch sw = Stopwatch()..start(); final bool changes = await _syncService.syncRemoteAssetsToDb( - user, - _getRemoteAssetChanges, - _getRemoteAssets, + users: syncedUsers, + getChangedAssets: _getRemoteAssetChanges, + loadAssets: _getRemoteAssets, + refreshUsers: _userService.getUsersFromServer, ); debugPrint("refreshRemoteAssets full took ${sw.elapsedMilliseconds}ms"); return changes; @@ -53,14 +64,15 @@ class AssetService { /// Returns `(null, null)` if changes are invalid -> requires full sync Future<(List? toUpsert, List? toDelete)> - _getRemoteAssetChanges(User user, DateTime since) async { - final deleted = await _apiService.auditApi - .getAuditDeletes(since, EntityType.ASSET, userId: user.id); - if (deleted == null || deleted.needsFullSync) return (null, null); - final assetDto = await _apiService.assetApi - .getAllAssets(userId: user.id, updatedAfter: since); - if (assetDto == null) return (null, null); - return (assetDto.map(Asset.remote).toList(), deleted.ids); + _getRemoteAssetChanges(List users, DateTime since) async { + final dto = AssetDeltaSyncDto( + updatedAfter: since, + userIds: users.map((e) => e.id).toList(), + ); + final changes = await _apiService.syncApi.getDeltaSync(dto); + return changes == null || changes.needsFullSync + ? (null, null) + : (changes.upserted.map(Asset.remote).toList(), changes.deleted); } /// Returns the list of people of the given asset id. @@ -85,38 +97,32 @@ class AssetService { } /// Returns `null` if the server state did not change, else list of assets - Future?> _getRemoteAssets(User user) async { + Future?> _getRemoteAssets(User user, DateTime until) async { const int chunkSize = 10000; try { - final DateTime now = DateTime.now().toUtc(); final List allAssets = []; - for (int i = 0;; i += chunkSize) { - final List? assets = - await _apiService.assetApi.getAllAssets( + DateTime? lastCreationDate; + String? lastId; + // will break on error or once all assets are loaded + while (true) { + final dto = AssetFullSyncDto( + limit: chunkSize, + updatedUntil: until, + lastId: lastId, + lastCreationDate: lastCreationDate, userId: user.id, - // updatedBefore is important! without it we could - // a) get the same Asset multiple times in different versions (when - // the asset is modified while the chunks are loaded from the server) - // b) miss assets when new assets are inserted in between the calls - updatedBefore: now, - skip: i, - take: chunkSize, ); - if (assets == null) { - return null; - } + final List? assets = + await _apiService.syncApi.getFullSyncForUser(dto); + if (assets == null) return null; allAssets.addAll(assets.map(Asset.remote)); - if (assets.length < chunkSize) { - break; - } + if (assets.isEmpty) break; + lastCreationDate = assets.last.fileCreatedAt; + lastId = assets.last.id; } return allAssets; } catch (error, stack) { - log.severe( - 'Error while getting remote assets', - error, - stack, - ); + log.severe('Error while getting remote assets', error, stack); return null; } } diff --git a/mobile/lib/services/background.service.dart b/mobile/lib/services/background.service.dart index 8e451cc271..ba8f5c01ed 100644 --- a/mobile/lib/services/background.service.dart +++ b/mobile/lib/services/background.service.dart @@ -20,6 +20,7 @@ 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'; @@ -590,6 +591,7 @@ 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(); diff --git a/mobile/lib/services/memory.service.dart b/mobile/lib/services/memory.service.dart index 0a1ceecf16..b426214c03 100644 --- a/mobile/lib/services/memory.service.dart +++ b/mobile/lib/services/memory.service.dart @@ -8,6 +8,8 @@ import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; import 'package:openapi/api.dart'; +import '../utils/string_helper.dart'; + final memoryServiceProvider = StateProvider((ref) { return MemoryService( ref.watch(apiServiceProvider), @@ -36,13 +38,17 @@ class MemoryService { } List memories = []; - for (final MemoryLaneResponseDto(:title, :assets) in data) { - memories.add( - Memory( - title: title, - assets: await _db.assets.getAllByRemoteId(assets.map((e) => e.id)), - ), - ); + for (final MemoryLaneResponseDto(:yearsAgo, :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', + assets: dbAssets, + ), + ); + } } return memories.isNotEmpty ? memories : null; diff --git a/mobile/lib/services/server_info.service.dart b/mobile/lib/services/server_info.service.dart index a2ce77c820..e2b7db2fce 100644 --- a/mobile/lib/services/server_info.service.dart +++ b/mobile/lib/services/server_info.service.dart @@ -18,14 +18,14 @@ class ServerInfoService { ServerInfoService(this._apiService); - Future getServerInfo() async { + Future getDiskInfo() async { try { - final dto = await _apiService.serverInfoApi.getServerInfo(); + final dto = await _apiService.serverInfoApi.getStorage(); if (dto != null) { return ServerDiskInfo.fromDto(dto); } } catch (e) { - debugPrint("Error [getServerInfo] ${e.toString()}"); + debugPrint("Error [getDiskInfo] ${e.toString()}"); } return null; } diff --git a/mobile/lib/services/sync.service.dart b/mobile/lib/services/sync.service.dart index ba4336c59d..8ec56e925f 100644 --- a/mobile/lib/services/sync.service.dart +++ b/mobile/lib/services/sync.service.dart @@ -40,18 +40,20 @@ class SyncService { /// Syncs remote assets owned by the logged-in user to the DB /// Returns `true` if there were any changes - Future syncRemoteAssetsToDb( - User user, - Future<(List? toUpsert, List? toDelete)> Function( - User user, + Future syncRemoteAssetsToDb({ + required List users, + required Future<(List? toUpsert, List? toDelete)> Function( + List users, DateTime since, ) getChangedAssets, - FutureOr?> Function(User user) loadAssets, - ) => + required FutureOr?> Function(User user, DateTime until) + loadAssets, + required FutureOr?> Function() refreshUsers, + }) => _lock.run( () async => - await _syncRemoteAssetChanges(user, getChangedAssets) ?? - await _syncRemoteAssetsFull(user, loadAssets), + await _syncRemoteAssetChanges(users, getChangedAssets) ?? + await _syncRemoteAssetsFull(refreshUsers, loadAssets), ); /// Syncs remote albums to the database @@ -111,7 +113,8 @@ class SyncService { both: (User a, User b) { if (!a.updatedAt.isAtSameMomentAs(b.updatedAt) || a.isPartnerSharedBy != b.isPartnerSharedBy || - a.isPartnerSharedWith != b.isPartnerSharedWith) { + a.isPartnerSharedWith != b.isPartnerSharedWith || + a.inTimeline != b.inTimeline) { toUpsert.add(a); return true; } @@ -149,17 +152,22 @@ class SyncService { /// Efficiently syncs assets via changes. Returns `null` when a full sync is required. Future _syncRemoteAssetChanges( - User user, + List users, Future<(List? toUpsert, List? toDelete)> Function( - User user, + List users, DateTime since, ) getChangedAssets, ) async { - final DateTime? since = _db.eTags.getByIdSync(user.id)?.time?.toUtc(); + final currentUser = Store.get(StoreKey.currentUser); + final DateTime? since = + _db.eTags.getSync(currentUser.isarId)?.time?.toUtc(); if (since == null) return null; final DateTime now = DateTime.now(); - final (toUpsert, toDelete) = await getChangedAssets(user, since); - if (toUpsert == null || toDelete == null) return null; + final (toUpsert, toDelete) = await getChangedAssets(users, since); + if (toUpsert == null || toDelete == null) { + await _clearUserAssetsETag(users); + return null; + } try { if (toDelete.isNotEmpty) { await handleRemoteAssetRemoval(toDelete); @@ -169,7 +177,7 @@ class SyncService { await upsertAssetsWithExif(updated); } if (toUpsert.isNotEmpty || toDelete.isNotEmpty) { - await _updateUserAssetsETag(user, now); + await _updateUserAssetsETag(users, now); return true; } return false; @@ -203,11 +211,34 @@ class SyncService { /// Syncs assets by loading and comparing all assets from the server. Future _syncRemoteAssetsFull( + FutureOr?> Function() refreshUsers, + FutureOr?> Function(User user, DateTime until) loadAssets, + ) async { + final serverUsers = await refreshUsers(); + if (serverUsers == null) { + _log.warning("_syncRemoteAssetsFull aborted because user refresh failed"); + return false; + } + await _syncUsersFromServer(serverUsers); + final List users = await _db.users + .filter() + .isPartnerSharedWithEqualTo(true) + .or() + .isarIdEqualTo(Store.get(StoreKey.currentUser).isarId) + .findAll(); + bool changes = false; + for (User u in users) { + changes |= await _syncRemoteAssetsForUser(u, loadAssets); + } + return changes; + } + + Future _syncRemoteAssetsForUser( User user, - FutureOr?> Function(User user) loadAssets, + FutureOr?> Function(User user, DateTime until) loadAssets, ) async { final DateTime now = DateTime.now().toUtc(); - final List? remote = await loadAssets(user); + final List? remote = await loadAssets(user, now); if (remote == null) { return false; } @@ -225,7 +256,7 @@ class SyncService { final (toAdd, toUpdate, toRemove) = _diffAssets(remote, inDb, remote: true); if (toAdd.isEmpty && toUpdate.isEmpty && toRemove.isEmpty) { - await _updateUserAssetsETag(user, now); + await _updateUserAssetsETag([user], now); return false; } final idsToDelete = toRemove.map((e) => e.id).toList(); @@ -235,12 +266,19 @@ class SyncService { } on IsarError catch (e) { _log.severe("Failed to sync remote assets to db", e); } - await _updateUserAssetsETag(user, now); + await _updateUserAssetsETag([user], now); return true; } - Future _updateUserAssetsETag(User user, DateTime time) => - _db.writeTxn(() => _db.eTags.put(ETag(id: user.id, time: time))); + Future _updateUserAssetsETag(List users, DateTime time) { + final etags = users.map((u) => ETag(id: u.id, time: time)).toList(); + return _db.writeTxn(() => _db.eTags.putAll(etags)); + } + + Future _clearUserAssetsETag(List users) { + final ids = users.map((u) => u.id).toList(); + return _db.writeTxn(() => _db.eTags.deleteAllById(ids)); + } /// Syncs remote albums to the database /// returns `true` if there were any changes @@ -324,15 +362,15 @@ class SyncService { // update shared users final List sharedUsers = album.sharedUsers.toList(growable: false); sharedUsers.sort((a, b) => a.id.compareTo(b.id)); - dto.sharedUsers.sort((a, b) => a.id.compareTo(b.id)); + dto.albumUsers.sort((a, b) => a.user.id.compareTo(b.user.id)); final List userIdsToAdd = []; final List usersToUnlink = []; diffSortedListsSync( - dto.sharedUsers, + dto.albumUsers, sharedUsers, - compare: (UserResponseDto a, User b) => a.id.compareTo(b.id), + compare: (AlbumUserResponseDto a, User b) => a.user.id.compareTo(b.id), both: (a, b) => false, - onlyFirst: (UserResponseDto a) => userIdsToAdd.add(a.id), + onlyFirst: (AlbumUserResponseDto a) => userIdsToAdd.add(a.user.id), onlySecond: (User a) => usersToUnlink.add(a), ); @@ -867,7 +905,7 @@ bool _hasAlbumResponseDtoChanged(AlbumResponseDto dto, Album a) { dto.albumName != a.name || dto.albumThumbnailAssetId != a.thumbnail.value?.remoteId || dto.shared != a.shared || - dto.sharedUsers.length != a.sharedUsers.length || + dto.albumUsers.length != a.sharedUsers.length || !dto.updatedAt.isAtSameMomentAs(a.modifiedAt) || !isAtSameMomentAs(dto.startDate, a.startDate) || !isAtSameMomentAs(dto.endDate, a.endDate) || diff --git a/mobile/lib/services/user.service.dart b/mobile/lib/services/user.service.dart index b6e5521def..81100f1624 100644 --- a/mobile/lib/services/user.service.dart +++ b/mobile/lib/services/user.service.dart @@ -70,7 +70,7 @@ class UserService { } } - Future refreshUsers() async { + Future?> getUsersFromServer() async { final List? users = await _getAllUsers(isAll: true); final List? sharedBy = await _partnerService.getPartners(PartnerDirection.sharedBy); @@ -79,7 +79,7 @@ class UserService { if (users == null || sharedBy == null || sharedWith == null) { _log.warning("Failed to refresh users"); - return false; + return null; } users.sortBy((u) => u.id); @@ -108,6 +108,12 @@ class UserService { onlySecond: (_) {}, ); + return users; + } + + Future refreshUsers() async { + final users = await getUsersFromServer(); + if (users == null) return false; return _syncService.syncUsersFromServer(users); } } diff --git a/mobile/lib/shared/cache/custom_image_cache.dart b/mobile/lib/utils/cache/custom_image_cache.dart similarity index 100% rename from mobile/lib/shared/cache/custom_image_cache.dart rename to mobile/lib/utils/cache/custom_image_cache.dart diff --git a/mobile/lib/shared/cache/widgets_binding.dart b/mobile/lib/utils/cache/widgets_binding.dart similarity index 100% rename from mobile/lib/shared/cache/widgets_binding.dart rename to mobile/lib/utils/cache/widgets_binding.dart diff --git a/mobile/lib/widgets/settings/utils/app_settings_update_hook.dart b/mobile/lib/utils/hooks/app_settings_update_hook.dart similarity index 100% rename from mobile/lib/widgets/settings/utils/app_settings_update_hook.dart rename to mobile/lib/utils/hooks/app_settings_update_hook.dart diff --git a/mobile/lib/shared/ui/hooks/blurhash_hook.dart b/mobile/lib/utils/hooks/blurhash_hook.dart similarity index 100% rename from mobile/lib/shared/ui/hooks/blurhash_hook.dart rename to mobile/lib/utils/hooks/blurhash_hook.dart diff --git a/mobile/lib/widgets/asset_viewer/hooks/chewiew_controller_hook.dart b/mobile/lib/utils/hooks/chewiew_controller_hook.dart similarity index 97% rename from mobile/lib/widgets/asset_viewer/hooks/chewiew_controller_hook.dart rename to mobile/lib/utils/hooks/chewiew_controller_hook.dart index 5daeb389ec..08c30b2770 100644 --- a/mobile/lib/widgets/asset_viewer/hooks/chewiew_controller_hook.dart +++ b/mobile/lib/utils/hooks/chewiew_controller_hook.dart @@ -17,6 +17,7 @@ ChewieController useChewieController({ bool allowFullScreen = false, bool allowedScreenSleep = false, bool showControls = true, + bool loopVideo = false, Widget? customControls, Widget? placeholder, Duration hideControlsTimer = const Duration(seconds: 1), @@ -36,6 +37,7 @@ ChewieController useChewieController({ hideControlsTimer: hideControlsTimer, showControlsOnInitialize: showControlsOnInitialize, showControls: showControls, + loopVideo: loopVideo, allowedScreenSleep: allowedScreenSleep, onPlaying: onPlaying, onPaused: onPaused, @@ -53,6 +55,7 @@ class _ChewieControllerHook extends Hook { final bool allowFullScreen; final bool allowedScreenSleep; final bool showControls; + final bool loopVideo; final Widget? customControls; final Widget? placeholder; final Duration hideControlsTimer; @@ -71,6 +74,7 @@ class _ChewieControllerHook extends Hook { this.allowFullScreen = false, this.allowedScreenSleep = false, this.showControls = true, + this.loopVideo = false, this.customControls, this.placeholder, this.hideControlsTimer = const Duration(seconds: 3), @@ -94,6 +98,7 @@ class _ChewieControllerHookState allowFullScreen: hook.allowFullScreen, allowedScreenSleep: hook.allowedScreenSleep, showControls: hook.showControls, + looping: hook.loopVideo, customControls: hook.customControls, placeholder: hook.placeholder, hideControlsTimer: hook.hideControlsTimer, diff --git a/mobile/lib/shared/ui/hooks/timer_hook.dart b/mobile/lib/utils/hooks/timer_hook.dart similarity index 100% rename from mobile/lib/shared/ui/hooks/timer_hook.dart rename to mobile/lib/utils/hooks/timer_hook.dart diff --git a/mobile/lib/utils/image_url_builder.dart b/mobile/lib/utils/image_url_builder.dart index f830aa39e2..5d5719313e 100644 --- a/mobile/lib/utils/image_url_builder.dart +++ b/mobile/lib/utils/image_url_builder.dart @@ -77,5 +77,5 @@ String getThumbnailUrlForRemoteId( } String getFaceThumbnailUrl(final String personId) { - return '${Store.get(StoreKey.serverEndpoint)}/person/$personId/thumbnail'; + return '${Store.get(StoreKey.serverEndpoint)}/people/$personId/thumbnail'; } diff --git a/mobile/lib/utils/immich_app_theme.dart b/mobile/lib/utils/immich_app_theme.dart index 3d550ca17a..32a26439d5 100644 --- a/mobile/lib/utils/immich_app_theme.dart +++ b/mobile/lib/utils/immich_app_theme.dart @@ -121,12 +121,12 @@ final ThemeData immichLightTheme = ThemeData( ), navigationBarTheme: NavigationBarThemeData( indicatorColor: Colors.indigo.withOpacity(0.15), - iconTheme: MaterialStatePropertyAll( + iconTheme: WidgetStatePropertyAll( IconThemeData(color: Colors.grey[700]), ), backgroundColor: immichBackgroundColor, surfaceTintColor: Colors.transparent, - labelTextStyle: MaterialStatePropertyAll( + labelTextStyle: WidgetStatePropertyAll( TextStyle( fontSize: 13, fontWeight: FontWeight.w500, @@ -249,12 +249,12 @@ final ThemeData immichDarkTheme = ThemeData( ), navigationBarTheme: NavigationBarThemeData( indicatorColor: immichDarkThemePrimaryColor.withOpacity(0.4), - iconTheme: MaterialStatePropertyAll( + iconTheme: WidgetStatePropertyAll( IconThemeData(color: Colors.grey[500]), ), backgroundColor: Colors.grey[900], surfaceTintColor: Colors.transparent, - labelTextStyle: MaterialStatePropertyAll( + labelTextStyle: WidgetStatePropertyAll( TextStyle( fontSize: 13, fontWeight: FontWeight.w500, diff --git a/mobile/lib/utils/migration.dart b/mobile/lib/utils/migration.dart index d73a4cd317..2b02a5ff8f 100644 --- a/mobile/lib/utils/migration.dart +++ b/mobile/lib/utils/migration.dart @@ -4,17 +4,12 @@ import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/utils/db.dart'; import 'package:isar/isar.dart'; +const int targetVersion = 6; + Future migrateDatabaseIfNeeded(Isar db) async { final int version = Store.get(StoreKey.version, 1); - switch (version) { - case 1: - await _migrateTo(db, 2); - case 2: - await _migrateTo(db, 3); - case 3: - await _migrateTo(db, 4); - case 4: - await _migrateTo(db, 5); + if (version < targetVersion) { + _migrateTo(db, targetVersion); } } diff --git a/mobile/lib/utils/capitalize_first_letter.dart b/mobile/lib/utils/string_helper.dart similarity index 75% rename from mobile/lib/utils/capitalize_first_letter.dart rename to mobile/lib/utils/string_helper.dart index c1fbb40f8d..201d141531 100644 --- a/mobile/lib/utils/capitalize_first_letter.dart +++ b/mobile/lib/utils/string_helper.dart @@ -3,3 +3,5 @@ extension StringExtension on String { return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; } } + +String s(num count) => (count == 1 ? '' : 's'); diff --git a/mobile/lib/widgets/album/album_viewer_appbar.dart b/mobile/lib/widgets/album/album_viewer_appbar.dart index 5521f50e35..6fb58f8082 100644 --- a/mobile/lib/widgets/album/album_viewer_appbar.dart +++ b/mobile/lib/widgets/album/album_viewer_appbar.dart @@ -275,7 +275,7 @@ class AlbumViewerAppbar extends HookConsumerWidget ); } else { return IconButton( - onPressed: () async => await context.popRoute(), + onPressed: () async => await context.maybePop(), icon: const Icon(Icons.arrow_back_ios_rounded), splashRadius: 25, ); diff --git a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart index 30b880bc8b..f9c63059b7 100644 --- a/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart +++ b/mobile/lib/widgets/asset_viewer/bottom_gallery_bar.dart @@ -110,7 +110,7 @@ class BottomGalleryBar extends ConsumerWidget { if (isDeleted && isParent) { if (totalAssets == 1) { // Handle only one asset - context.popRoute(); + context.maybePop(); } else { // Go to next page otherwise controller.nextPage( @@ -181,7 +181,7 @@ class BottomGalleryBar extends ConsumerWidget { stackElements.elementAt(stackIndex), ); ctx.pop(); - context.popRoute(); + context.maybePop(); }, title: const Text( "viewer_stack_use_as_main_asset", @@ -208,7 +208,7 @@ class BottomGalleryBar extends ConsumerWidget { childrenToRemove: [asset], ); ctx.pop(); - context.popRoute(); + context.maybePop(); } else { await ref.read(assetStackServiceProvider).updateStack( asset, @@ -236,7 +236,7 @@ class BottomGalleryBar extends ConsumerWidget { childrenToRemove: stack, ); ctx.pop(); - context.popRoute(); + context.maybePop(); }, title: const Text( "viewer_unstack", @@ -267,7 +267,7 @@ class BottomGalleryBar extends ConsumerWidget { handleArchive() { ref.read(assetProvider.notifier).toggleArchive([asset]); if (isParent) { - context.popRoute(); + context.maybePop(); return; } removeAssetFromStack(); diff --git a/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart b/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart index 2e1e7f8e64..ebef229dd6 100644 --- a/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart +++ b/mobile/lib/widgets/asset_viewer/custom_video_player_controls.dart @@ -6,7 +6,7 @@ import 'package:immich_mobile/providers/asset_viewer/video_player_controls_provi import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart'; import 'package:immich_mobile/widgets/asset_viewer/center_play_button.dart'; import 'package:immich_mobile/widgets/common/delayed_loading_indicator.dart'; -import 'package:immich_mobile/shared/ui/hooks/timer_hook.dart'; +import 'package:immich_mobile/utils/hooks/timer_hook.dart'; class CustomVideoPlayerControls extends HookConsumerWidget { final Duration hideTimerDuration; diff --git a/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart b/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart index 6406725b21..70fd5e3b89 100644 --- a/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart +++ b/mobile/lib/widgets/asset_viewer/top_control_app_bar.dart @@ -161,7 +161,7 @@ class TopControlAppBar extends HookConsumerWidget { Widget buildBackButton() { return IconButton( onPressed: () { - context.popRoute(); + context.maybePop(); }, icon: Icon( Icons.arrow_back_ios_new_rounded, diff --git a/mobile/lib/widgets/asset_viewer/video_player.dart b/mobile/lib/widgets/asset_viewer/video_player.dart index 56cb22ea74..ebf158b59a 100644 --- a/mobile/lib/widgets/asset_viewer/video_player.dart +++ b/mobile/lib/widgets/asset_viewer/video_player.dart @@ -1,7 +1,7 @@ import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/widgets/asset_viewer/hooks/chewiew_controller_hook.dart'; +import 'package:immich_mobile/utils/hooks/chewiew_controller_hook.dart'; import 'package:immich_mobile/widgets/asset_viewer/custom_video_player_controls.dart'; import 'package:video_player/video_player.dart'; @@ -12,6 +12,7 @@ class VideoPlayerViewer extends HookConsumerWidget { final Duration hideControlsTimer; final bool showControls; final bool showDownloadingIndicator; + final bool loopVideo; const VideoPlayerViewer({ super.key, @@ -21,6 +22,7 @@ class VideoPlayerViewer extends HookConsumerWidget { required this.hideControlsTimer, required this.showControls, required this.showDownloadingIndicator, + required this.loopVideo, }); @override @@ -36,6 +38,7 @@ class VideoPlayerViewer extends HookConsumerWidget { ), showControls: showControls && !isMotionVideo, hideControlsTimer: hideControlsTimer, + loopVideo: loopVideo, ); return Chewie( diff --git a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart index 75d3966b97..fbcfd64713 100644 --- a/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart +++ b/mobile/lib/widgets/common/app_bar_dialog/app_bar_dialog.dart @@ -31,7 +31,7 @@ class ImmichAppBarDialog extends HookConsumerWidget { useEffect( () { - ref.read(backupProvider.notifier).updateServerInfo(); + ref.read(backupProvider.notifier).updateDiskInfo(); ref.read(currentUserProvider.notifier).refresh(); return null; }, diff --git a/mobile/lib/widgets/common/date_time_picker.dart b/mobile/lib/widgets/common/date_time_picker.dart index adc2092f87..746917d3fb 100644 --- a/mobile/lib/widgets/common/date_time_picker.dart +++ b/mobile/lib/widgets/common/date_time_picker.dart @@ -164,7 +164,7 @@ class _DateTimePicker extends HookWidget { color: context.primaryColor, ), menuStyle: const MenuStyle( - fixedSize: MaterialStatePropertyAll(Size.fromWidth(350)), + fixedSize: WidgetStatePropertyAll(Size.fromWidth(350)), alignment: Alignment(-1.25, 0.5), ), onSelected: (value) => tzOffset.value = value!, @@ -175,7 +175,7 @@ class _DateTimePicker extends HookWidget { value: t, label: t.display, style: ButtonStyle( - textStyle: MaterialStatePropertyAll( + textStyle: WidgetStatePropertyAll( context.textTheme.bodyMedium, ), ), diff --git a/mobile/lib/widgets/common/immich_thumbnail.dart b/mobile/lib/widgets/common/immich_thumbnail.dart index 0f15c0a11f..2ebead0083 100644 --- a/mobile/lib/widgets/common/immich_thumbnail.dart +++ b/mobile/lib/widgets/common/immich_thumbnail.dart @@ -5,7 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:immich_mobile/providers/image/immich_local_thumbnail_provider.dart'; import 'package:immich_mobile/providers/image/immich_remote_thumbnail_provider.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; -import 'package:immich_mobile/shared/ui/hooks/blurhash_hook.dart'; +import 'package:immich_mobile/utils/hooks/blurhash_hook.dart'; import 'package:immich_mobile/widgets/common/immich_image.dart'; import 'package:immich_mobile/widgets/common/thumbhash_placeholder.dart'; import 'package:octo_image/octo_image.dart'; diff --git a/mobile/lib/widgets/common/location_picker.dart b/mobile/lib/widgets/common/location_picker.dart index 425bdb15bf..3be3ed428a 100644 --- a/mobile/lib/widgets/common/location_picker.dart +++ b/mobile/lib/widgets/common/location_picker.dart @@ -79,7 +79,7 @@ class _LocationPicker extends HookWidget { ).tr(), ), TextButton( - onPressed: () => context.popRoute(latlng), + onPressed: () => context.maybePop(latlng), child: Text( "action_common_update", style: context.textTheme.bodyMedium?.copyWith( @@ -215,7 +215,7 @@ class _ManualPicker extends HookWidget { decorationText: "location_picker_longitude", hintText: "location_picker_longitude_hint", errorText: "location_picker_longitude_error", - focusNode: latitiudeFocusNode, + focusNode: longitudeFocusNode, validator: _validateLong, onUpdated: onLongitudeEditingCompleted, ), diff --git a/mobile/lib/widgets/common/user_avatar.dart b/mobile/lib/widgets/common/user_avatar.dart index c61a3adbeb..8dfe00b2b9 100644 --- a/mobile/lib/widgets/common/user_avatar.dart +++ b/mobile/lib/widgets/common/user_avatar.dart @@ -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)}/user/profile-image/${u.id}"; + "${Store.get(StoreKey.serverEndpoint)}/users/${u.id}/profile-image"; final nameFirstLetter = u.name.isNotEmpty ? u.name[0] : ""; return CircleAvatar( radius: radius, diff --git a/mobile/lib/widgets/common/user_circle_avatar.dart b/mobile/lib/widgets/common/user_circle_avatar.dart index 1f8529a80a..9dd924d98e 100644 --- a/mobile/lib/widgets/common/user_circle_avatar.dart +++ b/mobile/lib/widgets/common/user_circle_avatar.dart @@ -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)}/user/profile-image/${user.id}?d=${Random().nextInt(1024)}'; + '${Store.get(StoreKey.serverEndpoint)}/users/${user.id}/profile-image?d=${Random().nextInt(1024)}'; final textIcon = Text( user.name[0].toUpperCase(), diff --git a/mobile/lib/widgets/map/map_app_bar.dart b/mobile/lib/widgets/map/map_app_bar.dart index b9d11b0996..42bc598915 100644 --- a/mobile/lib/widgets/map/map_app_bar.dart +++ b/mobile/lib/widgets/map/map_app_bar.dart @@ -50,7 +50,7 @@ class _NonSelectionRow extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( - onPressed: () => context.popRoute(), + onPressed: () => context.maybePop(), style: ElevatedButton.styleFrom( shape: const CircleBorder(), ), diff --git a/mobile/lib/widgets/memories/memory_bottom_info.dart b/mobile/lib/widgets/memories/memory_bottom_info.dart index 408bdc909a..84f4cb6c72 100644 --- a/mobile/lib/widgets/memories/memory_bottom_info.dart +++ b/mobile/lib/widgets/memories/memory_bottom_info.dart @@ -43,7 +43,7 @@ class MemoryBottomInfo extends StatelessWidget { MaterialButton( minWidth: 0, onPressed: () { - context.popRoute(); + context.maybePop(); scrollToDateNotifierProvider .scrollToDate(memory.assets[0].fileCreatedAt); }, diff --git a/mobile/lib/widgets/memories/memory_card.dart b/mobile/lib/widgets/memories/memory_card.dart index df64b2fddb..fb7cc882a0 100644 --- a/mobile/lib/widgets/memories/memory_card.dart +++ b/mobile/lib/widgets/memories/memory_card.dart @@ -5,7 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/pages/common/video_viewer.page.dart'; -import 'package:immich_mobile/shared/ui/hooks/blurhash_hook.dart'; +import 'package:immich_mobile/utils/hooks/blurhash_hook.dart'; import 'package:immich_mobile/widgets/common/immich_image.dart'; class MemoryCard extends StatelessWidget { diff --git a/mobile/lib/widgets/search/search_filter/camera_picker.dart b/mobile/lib/widgets/search/search_filter/camera_picker.dart index fc7f1090d7..ea347141a7 100644 --- a/mobile/lib/widgets/search/search_filter/camera_picker.dart +++ b/mobile/lib/widgets/search/search_filter/camera_picker.dart @@ -40,7 +40,7 @@ class CameraPicker extends HookConsumerWidget { ); final menuStyle = MenuStyle( - shape: MaterialStatePropertyAll( + shape: WidgetStatePropertyAll( RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), diff --git a/mobile/lib/widgets/search/search_filter/location_picker.dart b/mobile/lib/widgets/search/search_filter/location_picker.dart index 05b55a7403..3aee57c3ca 100644 --- a/mobile/lib/widgets/search/search_filter/location_picker.dart +++ b/mobile/lib/widgets/search/search_filter/location_picker.dart @@ -56,7 +56,7 @@ class LocationPicker extends HookConsumerWidget { ); final menuStyle = MenuStyle( - shape: MaterialStatePropertyAll( + shape: WidgetStatePropertyAll( RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), diff --git a/mobile/lib/widgets/settings/advanced_settings.dart b/mobile/lib/widgets/settings/advanced_settings.dart index e79c50bc81..b0727feb0c 100644 --- a/mobile/lib/widgets/settings/advanced_settings.dart +++ b/mobile/lib/widgets/settings/advanced_settings.dart @@ -6,7 +6,7 @@ import 'package:immich_mobile/widgets/settings/local_storage_settings.dart'; import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/providers/user.provider.dart'; diff --git a/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart b/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart index 8e63e61e1c..5b09ae8b72 100644 --- a/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart +++ b/mobile/lib/widgets/settings/asset_list_settings/asset_list_group_settings.dart @@ -6,7 +6,7 @@ import 'package:immich_mobile/providers/app_settings.provider.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/widgets/settings/settings_radio_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class GroupSettings extends HookConsumerWidget { const GroupSettings({ diff --git a/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart b/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart index 1224b14d15..4584b7e688 100644 --- a/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart +++ b/mobile/lib/widgets/settings/asset_list_settings/asset_list_layout_settings.dart @@ -6,7 +6,7 @@ import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class LayoutSettings extends HookConsumerWidget { const LayoutSettings({ diff --git a/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart b/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart index 9545533d95..cd12ea3eb2 100644 --- a/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart +++ b/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart @@ -6,7 +6,7 @@ import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/widgets/settings/asset_list_settings/asset_list_group_settings.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; import 'asset_list_layout_settings.dart'; class AssetListSettings extends HookConsumerWidget { diff --git a/mobile/lib/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart b/mobile/lib/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart new file mode 100644 index 0000000000..23dca85b6f --- /dev/null +++ b/mobile/lib/widgets/settings/asset_viewer_settings/asset_viewer_settings.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart'; +import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; +import 'video_viewer_settings.dart'; + +class AssetViewerSettings extends StatelessWidget { + const AssetViewerSettings({ + super.key, + }); + + @override + Widget build(BuildContext context) { + final assetViewerSetting = [ + const ImageViewerQualitySetting(), + const VideoViewerSettings(), + ]; + + return SettingsSubPageScaffold( + settings: assetViewerSetting, + showDivider: true, + ); + } +} diff --git a/mobile/lib/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart b/mobile/lib/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart new file mode 100644 index 0000000000..444977d9a2 --- /dev/null +++ b/mobile/lib/widgets/settings/asset_viewer_settings/image_viewer_quality_setting.dart @@ -0,0 +1,47 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; +import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; +import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; + +class ImageViewerQualitySetting extends HookConsumerWidget { + const ImageViewerQualitySetting({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isPreview = useAppSettingsState(AppSettingsEnum.loadPreview); + final isOriginal = useAppSettingsState(AppSettingsEnum.loadOriginal); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SettingsSubTitle(title: "setting_image_viewer_title".tr()), + ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 20), + title: Text( + 'setting_image_viewer_help', + style: context.textTheme.bodyMedium, + ).tr(), + ), + SettingsSwitchListTile( + valueNotifier: isPreview, + title: "setting_image_viewer_preview_title".tr(), + subtitle: "setting_image_viewer_preview_subtitle".tr(), + onChanged: (_) => ref.invalidate(appSettingsServiceProvider), + ), + SettingsSwitchListTile( + valueNotifier: isOriginal, + title: "setting_image_viewer_original_title".tr(), + subtitle: "setting_image_viewer_original_subtitle".tr(), + onChanged: (_) => ref.invalidate(appSettingsServiceProvider), + ), + ], + ); + } +} diff --git a/mobile/lib/widgets/settings/asset_viewer_settings/video_viewer_settings.dart b/mobile/lib/widgets/settings/asset_viewer_settings/video_viewer_settings.dart new file mode 100644 index 0000000000..e21c49bb06 --- /dev/null +++ b/mobile/lib/widgets/settings/asset_viewer_settings/video_viewer_settings.dart @@ -0,0 +1,32 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/services/app_settings.service.dart'; +import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; +import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; + +class VideoViewerSettings extends HookConsumerWidget { + const VideoViewerSettings({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final useLoopVideo = useAppSettingsState(AppSettingsEnum.loopVideo); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SettingsSubTitle(title: "setting_video_viewer_title".tr()), + SettingsSwitchListTile( + valueNotifier: useLoopVideo, + title: "setting_video_viewer_looping_title".tr(), + subtitle: "setting_video_viewer_looping_subtitle".tr(), + onChanged: (_) => ref.invalidate(appSettingsServiceProvider), + ), + ], + ); + } +} diff --git a/mobile/lib/widgets/settings/backup_settings/backup_settings.dart b/mobile/lib/widgets/settings/backup_settings/backup_settings.dart index 19e031b082..25bcf2d06e 100644 --- a/mobile/lib/widgets/settings/backup_settings/backup_settings.dart +++ b/mobile/lib/widgets/settings/backup_settings/backup_settings.dart @@ -9,7 +9,7 @@ import 'package:immich_mobile/widgets/settings/backup_settings/foreground_settin import 'package:immich_mobile/widgets/settings/settings_button_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart'; class BackupSettings extends HookConsumerWidget { diff --git a/mobile/lib/widgets/settings/image_viewer_quality_setting.dart b/mobile/lib/widgets/settings/image_viewer_quality_setting.dart deleted file mode 100644 index af39249e4b..0000000000 --- a/mobile/lib/widgets/settings/image_viewer_quality_setting.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/services/app_settings.service.dart'; -import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; -import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; - -class ImageViewerQualitySetting extends HookWidget { - const ImageViewerQualitySetting({ - super.key, - }); - - @override - Widget build(BuildContext context) { - final isPreview = useAppSettingsState(AppSettingsEnum.loadPreview); - final isOriginal = useAppSettingsState(AppSettingsEnum.loadOriginal); - - final viewerSettings = [ - ListTile( - title: Text( - 'setting_image_viewer_help', - style: context.textTheme.bodyMedium, - ).tr(), - ), - SettingsSwitchListTile( - valueNotifier: isPreview, - title: "setting_image_viewer_preview_title".tr(), - subtitle: "setting_image_viewer_preview_subtitle".tr(), - ), - SettingsSwitchListTile( - valueNotifier: isOriginal, - title: "setting_image_viewer_original_title".tr(), - subtitle: "setting_image_viewer_original_subtitle".tr(), - ), - ]; - - return SettingsSubPageScaffold(settings: viewerSettings); - } -} diff --git a/mobile/lib/widgets/settings/language_settings.dart b/mobile/lib/widgets/settings/language_settings.dart index 4569888541..378d32085e 100644 --- a/mobile/lib/widgets/settings/language_settings.dart +++ b/mobile/lib/widgets/settings/language_settings.dart @@ -34,12 +34,12 @@ class LanguageSettings extends HookConsumerWidget { contentPadding: const EdgeInsets.only(left: 16), ), menuStyle: MenuStyle( - shape: MaterialStatePropertyAll( + shape: WidgetStatePropertyAll( RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), ), - backgroundColor: MaterialStatePropertyAll( + backgroundColor: WidgetStatePropertyAll( context.isDarkTheme ? Colors.grey[900]! : context.scaffoldBackgroundColor, diff --git a/mobile/lib/widgets/settings/notification_setting.dart b/mobile/lib/widgets/settings/notification_setting.dart index c07a80c97a..b7276107e0 100644 --- a/mobile/lib/widgets/settings/notification_setting.dart +++ b/mobile/lib/widgets/settings/notification_setting.dart @@ -8,7 +8,7 @@ import 'package:immich_mobile/widgets/settings/settings_button_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; import 'package:permission_handler/permission_handler.dart'; class NotificationSetting extends HookConsumerWidget { diff --git a/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart b/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart index 7935002c05..90a123bfbd 100644 --- a/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart +++ b/mobile/lib/widgets/settings/preference_settings/haptic_setting.dart @@ -5,7 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; class HapticSetting extends HookConsumerWidget { const HapticSetting({ diff --git a/mobile/lib/widgets/settings/preference_settings/theme_setting.dart b/mobile/lib/widgets/settings/preference_settings/theme_setting.dart index 7bec8fdd45..5780054428 100644 --- a/mobile/lib/widgets/settings/preference_settings/theme_setting.dart +++ b/mobile/lib/widgets/settings/preference_settings/theme_setting.dart @@ -5,7 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/widgets/settings/settings_sub_title.dart'; import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart'; -import 'package:immich_mobile/widgets/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart'; import 'package:immich_mobile/utils/immich_app_theme.dart'; class ThemeSetting extends HookConsumerWidget { diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES deleted file mode 100644 index b2323c3158..0000000000 --- a/mobile/openapi/.openapi-generator/FILES +++ /dev/null @@ -1,652 +0,0 @@ -.gitignore -.openapi-generator-ignore -.travis.yml -README.md -analysis_options.yaml -doc/APIKeyApi.md -doc/APIKeyCreateDto.md -doc/APIKeyCreateResponseDto.md -doc/APIKeyResponseDto.md -doc/APIKeyUpdateDto.md -doc/ActivityApi.md -doc/ActivityCreateDto.md -doc/ActivityResponseDto.md -doc/ActivityStatisticsResponseDto.md -doc/AddUsersDto.md -doc/AdminOnboardingUpdateDto.md -doc/AlbumApi.md -doc/AlbumCountResponseDto.md -doc/AlbumResponseDto.md -doc/AlbumUserAddDto.md -doc/AlbumUserCreateDto.md -doc/AlbumUserResponseDto.md -doc/AlbumUserRole.md -doc/AllJobStatusResponseDto.md -doc/AssetApi.md -doc/AssetBulkDeleteDto.md -doc/AssetBulkUpdateDto.md -doc/AssetBulkUploadCheckDto.md -doc/AssetBulkUploadCheckItem.md -doc/AssetBulkUploadCheckResponseDto.md -doc/AssetBulkUploadCheckResult.md -doc/AssetDeltaSyncDto.md -doc/AssetDeltaSyncResponseDto.md -doc/AssetFaceResponseDto.md -doc/AssetFaceUpdateDto.md -doc/AssetFaceUpdateItem.md -doc/AssetFaceWithoutPersonResponseDto.md -doc/AssetFileUploadResponseDto.md -doc/AssetFullSyncDto.md -doc/AssetIdsDto.md -doc/AssetIdsResponseDto.md -doc/AssetJobName.md -doc/AssetJobsDto.md -doc/AssetOrder.md -doc/AssetResponseDto.md -doc/AssetStatsResponseDto.md -doc/AssetTypeEnum.md -doc/AudioCodec.md -doc/AuditApi.md -doc/AuditDeletesResponseDto.md -doc/AuthenticationApi.md -doc/BulkIdResponseDto.md -doc/BulkIdsDto.md -doc/CLIPConfig.md -doc/CLIPMode.md -doc/CQMode.md -doc/ChangePasswordDto.md -doc/CheckExistingAssetsDto.md -doc/CheckExistingAssetsResponseDto.md -doc/Colorspace.md -doc/CreateAlbumDto.md -doc/CreateLibraryDto.md -doc/CreateProfileImageResponseDto.md -doc/CreateTagDto.md -doc/CreateUserDto.md -doc/DeleteUserDto.md -doc/DownloadApi.md -doc/DownloadArchiveInfo.md -doc/DownloadInfoDto.md -doc/DownloadResponseDto.md -doc/EntityType.md -doc/ExifResponseDto.md -doc/FaceApi.md -doc/FaceDto.md -doc/FileChecksumDto.md -doc/FileChecksumResponseDto.md -doc/FileReportApi.md -doc/FileReportDto.md -doc/FileReportFixDto.md -doc/FileReportItemDto.md -doc/ImageFormat.md -doc/JobApi.md -doc/JobCommand.md -doc/JobCommandDto.md -doc/JobCountsDto.md -doc/JobName.md -doc/JobSettingsDto.md -doc/JobStatusDto.md -doc/LibraryApi.md -doc/LibraryResponseDto.md -doc/LibraryStatsResponseDto.md -doc/LibraryType.md -doc/LogLevel.md -doc/LoginCredentialDto.md -doc/LoginResponseDto.md -doc/LogoutResponseDto.md -doc/MapMarkerResponseDto.md -doc/MapTheme.md -doc/MemoryApi.md -doc/MemoryCreateDto.md -doc/MemoryLaneResponseDto.md -doc/MemoryResponseDto.md -doc/MemoryType.md -doc/MemoryUpdateDto.md -doc/MergePersonDto.md -doc/MetadataSearchDto.md -doc/ModelType.md -doc/OAuthApi.md -doc/OAuthAuthorizeResponseDto.md -doc/OAuthCallbackDto.md -doc/OAuthConfigDto.md -doc/OnThisDayDto.md -doc/PartnerApi.md -doc/PartnerResponseDto.md -doc/PathEntityType.md -doc/PathType.md -doc/PeopleResponseDto.md -doc/PeopleUpdateDto.md -doc/PeopleUpdateItem.md -doc/PeopleWithFacesResponseDto.md -doc/PersonApi.md -doc/PersonCreateDto.md -doc/PersonResponseDto.md -doc/PersonStatisticsResponseDto.md -doc/PersonUpdateDto.md -doc/PersonWithFacesResponseDto.md -doc/PlacesResponseDto.md -doc/QueueStatusDto.md -doc/ReactionLevel.md -doc/ReactionType.md -doc/RecognitionConfig.md -doc/ReverseGeocodingStateResponseDto.md -doc/ScanLibraryDto.md -doc/SearchAlbumResponseDto.md -doc/SearchApi.md -doc/SearchAssetResponseDto.md -doc/SearchExploreItem.md -doc/SearchExploreResponseDto.md -doc/SearchFacetCountResponseDto.md -doc/SearchFacetResponseDto.md -doc/SearchResponseDto.md -doc/SearchSuggestionType.md -doc/ServerConfigDto.md -doc/ServerFeaturesDto.md -doc/ServerInfoApi.md -doc/ServerInfoResponseDto.md -doc/ServerMediaTypesResponseDto.md -doc/ServerPingResponse.md -doc/ServerStatsResponseDto.md -doc/ServerThemeDto.md -doc/ServerVersionResponseDto.md -doc/SessionResponseDto.md -doc/SessionsApi.md -doc/SharedLinkApi.md -doc/SharedLinkCreateDto.md -doc/SharedLinkEditDto.md -doc/SharedLinkResponseDto.md -doc/SharedLinkType.md -doc/SignUpDto.md -doc/SmartInfoResponseDto.md -doc/SmartSearchDto.md -doc/SyncApi.md -doc/SystemConfigApi.md -doc/SystemConfigDto.md -doc/SystemConfigFFmpegDto.md -doc/SystemConfigImageDto.md -doc/SystemConfigJobDto.md -doc/SystemConfigLibraryDto.md -doc/SystemConfigLibraryScanDto.md -doc/SystemConfigLibraryWatchDto.md -doc/SystemConfigLoggingDto.md -doc/SystemConfigMachineLearningDto.md -doc/SystemConfigMapDto.md -doc/SystemConfigNewVersionCheckDto.md -doc/SystemConfigNotificationsDto.md -doc/SystemConfigOAuthDto.md -doc/SystemConfigPasswordLoginDto.md -doc/SystemConfigReverseGeocodingDto.md -doc/SystemConfigServerDto.md -doc/SystemConfigSmtpDto.md -doc/SystemConfigSmtpTransportDto.md -doc/SystemConfigStorageTemplateDto.md -doc/SystemConfigTemplateStorageOptionDto.md -doc/SystemConfigThemeDto.md -doc/SystemConfigTrashDto.md -doc/SystemConfigUserDto.md -doc/SystemMetadataApi.md -doc/TagApi.md -doc/TagResponseDto.md -doc/TagTypeEnum.md -doc/ThumbnailFormat.md -doc/TimeBucketResponseDto.md -doc/TimeBucketSize.md -doc/TimelineApi.md -doc/ToneMapping.md -doc/TranscodeHWAccel.md -doc/TranscodePolicy.md -doc/TrashApi.md -doc/UpdateAlbumDto.md -doc/UpdateAlbumUserDto.md -doc/UpdateAssetDto.md -doc/UpdateLibraryDto.md -doc/UpdatePartnerDto.md -doc/UpdateStackParentDto.md -doc/UpdateTagDto.md -doc/UpdateUserDto.md -doc/UsageByUserDto.md -doc/UserApi.md -doc/UserAvatarColor.md -doc/UserDto.md -doc/UserResponseDto.md -doc/UserStatus.md -doc/ValidateAccessTokenResponseDto.md -doc/ValidateLibraryDto.md -doc/ValidateLibraryImportPathResponseDto.md -doc/ValidateLibraryResponseDto.md -doc/VideoCodec.md -git_push.sh -lib/api.dart -lib/api/activity_api.dart -lib/api/album_api.dart -lib/api/api_key_api.dart -lib/api/asset_api.dart -lib/api/audit_api.dart -lib/api/authentication_api.dart -lib/api/download_api.dart -lib/api/face_api.dart -lib/api/file_report_api.dart -lib/api/job_api.dart -lib/api/library_api.dart -lib/api/memory_api.dart -lib/api/o_auth_api.dart -lib/api/partner_api.dart -lib/api/person_api.dart -lib/api/search_api.dart -lib/api/server_info_api.dart -lib/api/sessions_api.dart -lib/api/shared_link_api.dart -lib/api/sync_api.dart -lib/api/system_config_api.dart -lib/api/system_metadata_api.dart -lib/api/tag_api.dart -lib/api/timeline_api.dart -lib/api/trash_api.dart -lib/api/user_api.dart -lib/api_client.dart -lib/api_exception.dart -lib/api_helper.dart -lib/auth/api_key_auth.dart -lib/auth/authentication.dart -lib/auth/http_basic_auth.dart -lib/auth/http_bearer_auth.dart -lib/auth/oauth.dart -lib/model/activity_create_dto.dart -lib/model/activity_response_dto.dart -lib/model/activity_statistics_response_dto.dart -lib/model/add_users_dto.dart -lib/model/admin_onboarding_update_dto.dart -lib/model/album_count_response_dto.dart -lib/model/album_response_dto.dart -lib/model/album_user_add_dto.dart -lib/model/album_user_create_dto.dart -lib/model/album_user_response_dto.dart -lib/model/album_user_role.dart -lib/model/all_job_status_response_dto.dart -lib/model/api_key_create_dto.dart -lib/model/api_key_create_response_dto.dart -lib/model/api_key_response_dto.dart -lib/model/api_key_update_dto.dart -lib/model/asset_bulk_delete_dto.dart -lib/model/asset_bulk_update_dto.dart -lib/model/asset_bulk_upload_check_dto.dart -lib/model/asset_bulk_upload_check_item.dart -lib/model/asset_bulk_upload_check_response_dto.dart -lib/model/asset_bulk_upload_check_result.dart -lib/model/asset_delta_sync_dto.dart -lib/model/asset_delta_sync_response_dto.dart -lib/model/asset_face_response_dto.dart -lib/model/asset_face_update_dto.dart -lib/model/asset_face_update_item.dart -lib/model/asset_face_without_person_response_dto.dart -lib/model/asset_file_upload_response_dto.dart -lib/model/asset_full_sync_dto.dart -lib/model/asset_ids_dto.dart -lib/model/asset_ids_response_dto.dart -lib/model/asset_job_name.dart -lib/model/asset_jobs_dto.dart -lib/model/asset_order.dart -lib/model/asset_response_dto.dart -lib/model/asset_stats_response_dto.dart -lib/model/asset_type_enum.dart -lib/model/audio_codec.dart -lib/model/audit_deletes_response_dto.dart -lib/model/bulk_id_response_dto.dart -lib/model/bulk_ids_dto.dart -lib/model/change_password_dto.dart -lib/model/check_existing_assets_dto.dart -lib/model/check_existing_assets_response_dto.dart -lib/model/clip_config.dart -lib/model/clip_mode.dart -lib/model/colorspace.dart -lib/model/cq_mode.dart -lib/model/create_album_dto.dart -lib/model/create_library_dto.dart -lib/model/create_profile_image_response_dto.dart -lib/model/create_tag_dto.dart -lib/model/create_user_dto.dart -lib/model/delete_user_dto.dart -lib/model/download_archive_info.dart -lib/model/download_info_dto.dart -lib/model/download_response_dto.dart -lib/model/entity_type.dart -lib/model/exif_response_dto.dart -lib/model/face_dto.dart -lib/model/file_checksum_dto.dart -lib/model/file_checksum_response_dto.dart -lib/model/file_report_dto.dart -lib/model/file_report_fix_dto.dart -lib/model/file_report_item_dto.dart -lib/model/image_format.dart -lib/model/job_command.dart -lib/model/job_command_dto.dart -lib/model/job_counts_dto.dart -lib/model/job_name.dart -lib/model/job_settings_dto.dart -lib/model/job_status_dto.dart -lib/model/library_response_dto.dart -lib/model/library_stats_response_dto.dart -lib/model/library_type.dart -lib/model/log_level.dart -lib/model/login_credential_dto.dart -lib/model/login_response_dto.dart -lib/model/logout_response_dto.dart -lib/model/map_marker_response_dto.dart -lib/model/map_theme.dart -lib/model/memory_create_dto.dart -lib/model/memory_lane_response_dto.dart -lib/model/memory_response_dto.dart -lib/model/memory_type.dart -lib/model/memory_update_dto.dart -lib/model/merge_person_dto.dart -lib/model/metadata_search_dto.dart -lib/model/model_type.dart -lib/model/o_auth_authorize_response_dto.dart -lib/model/o_auth_callback_dto.dart -lib/model/o_auth_config_dto.dart -lib/model/on_this_day_dto.dart -lib/model/partner_response_dto.dart -lib/model/path_entity_type.dart -lib/model/path_type.dart -lib/model/people_response_dto.dart -lib/model/people_update_dto.dart -lib/model/people_update_item.dart -lib/model/people_with_faces_response_dto.dart -lib/model/person_create_dto.dart -lib/model/person_response_dto.dart -lib/model/person_statistics_response_dto.dart -lib/model/person_update_dto.dart -lib/model/person_with_faces_response_dto.dart -lib/model/places_response_dto.dart -lib/model/queue_status_dto.dart -lib/model/reaction_level.dart -lib/model/reaction_type.dart -lib/model/recognition_config.dart -lib/model/reverse_geocoding_state_response_dto.dart -lib/model/scan_library_dto.dart -lib/model/search_album_response_dto.dart -lib/model/search_asset_response_dto.dart -lib/model/search_explore_item.dart -lib/model/search_explore_response_dto.dart -lib/model/search_facet_count_response_dto.dart -lib/model/search_facet_response_dto.dart -lib/model/search_response_dto.dart -lib/model/search_suggestion_type.dart -lib/model/server_config_dto.dart -lib/model/server_features_dto.dart -lib/model/server_info_response_dto.dart -lib/model/server_media_types_response_dto.dart -lib/model/server_ping_response.dart -lib/model/server_stats_response_dto.dart -lib/model/server_theme_dto.dart -lib/model/server_version_response_dto.dart -lib/model/session_response_dto.dart -lib/model/shared_link_create_dto.dart -lib/model/shared_link_edit_dto.dart -lib/model/shared_link_response_dto.dart -lib/model/shared_link_type.dart -lib/model/sign_up_dto.dart -lib/model/smart_info_response_dto.dart -lib/model/smart_search_dto.dart -lib/model/system_config_dto.dart -lib/model/system_config_f_fmpeg_dto.dart -lib/model/system_config_image_dto.dart -lib/model/system_config_job_dto.dart -lib/model/system_config_library_dto.dart -lib/model/system_config_library_scan_dto.dart -lib/model/system_config_library_watch_dto.dart -lib/model/system_config_logging_dto.dart -lib/model/system_config_machine_learning_dto.dart -lib/model/system_config_map_dto.dart -lib/model/system_config_new_version_check_dto.dart -lib/model/system_config_notifications_dto.dart -lib/model/system_config_o_auth_dto.dart -lib/model/system_config_password_login_dto.dart -lib/model/system_config_reverse_geocoding_dto.dart -lib/model/system_config_server_dto.dart -lib/model/system_config_smtp_dto.dart -lib/model/system_config_smtp_transport_dto.dart -lib/model/system_config_storage_template_dto.dart -lib/model/system_config_template_storage_option_dto.dart -lib/model/system_config_theme_dto.dart -lib/model/system_config_trash_dto.dart -lib/model/system_config_user_dto.dart -lib/model/tag_response_dto.dart -lib/model/tag_type_enum.dart -lib/model/thumbnail_format.dart -lib/model/time_bucket_response_dto.dart -lib/model/time_bucket_size.dart -lib/model/tone_mapping.dart -lib/model/transcode_hw_accel.dart -lib/model/transcode_policy.dart -lib/model/update_album_dto.dart -lib/model/update_album_user_dto.dart -lib/model/update_asset_dto.dart -lib/model/update_library_dto.dart -lib/model/update_partner_dto.dart -lib/model/update_stack_parent_dto.dart -lib/model/update_tag_dto.dart -lib/model/update_user_dto.dart -lib/model/usage_by_user_dto.dart -lib/model/user_avatar_color.dart -lib/model/user_dto.dart -lib/model/user_response_dto.dart -lib/model/user_status.dart -lib/model/validate_access_token_response_dto.dart -lib/model/validate_library_dto.dart -lib/model/validate_library_import_path_response_dto.dart -lib/model/validate_library_response_dto.dart -lib/model/video_codec.dart -pubspec.yaml -test/activity_api_test.dart -test/activity_create_dto_test.dart -test/activity_response_dto_test.dart -test/activity_statistics_response_dto_test.dart -test/add_users_dto_test.dart -test/admin_onboarding_update_dto_test.dart -test/album_api_test.dart -test/album_count_response_dto_test.dart -test/album_response_dto_test.dart -test/album_user_add_dto_test.dart -test/album_user_create_dto_test.dart -test/album_user_response_dto_test.dart -test/album_user_role_test.dart -test/all_job_status_response_dto_test.dart -test/api_key_api_test.dart -test/api_key_create_dto_test.dart -test/api_key_create_response_dto_test.dart -test/api_key_response_dto_test.dart -test/api_key_update_dto_test.dart -test/asset_api_test.dart -test/asset_bulk_delete_dto_test.dart -test/asset_bulk_update_dto_test.dart -test/asset_bulk_upload_check_dto_test.dart -test/asset_bulk_upload_check_item_test.dart -test/asset_bulk_upload_check_response_dto_test.dart -test/asset_bulk_upload_check_result_test.dart -test/asset_delta_sync_dto_test.dart -test/asset_delta_sync_response_dto_test.dart -test/asset_face_response_dto_test.dart -test/asset_face_update_dto_test.dart -test/asset_face_update_item_test.dart -test/asset_face_without_person_response_dto_test.dart -test/asset_file_upload_response_dto_test.dart -test/asset_full_sync_dto_test.dart -test/asset_ids_dto_test.dart -test/asset_ids_response_dto_test.dart -test/asset_job_name_test.dart -test/asset_jobs_dto_test.dart -test/asset_order_test.dart -test/asset_response_dto_test.dart -test/asset_stats_response_dto_test.dart -test/asset_type_enum_test.dart -test/audio_codec_test.dart -test/audit_api_test.dart -test/audit_deletes_response_dto_test.dart -test/authentication_api_test.dart -test/bulk_id_response_dto_test.dart -test/bulk_ids_dto_test.dart -test/change_password_dto_test.dart -test/check_existing_assets_dto_test.dart -test/check_existing_assets_response_dto_test.dart -test/clip_config_test.dart -test/clip_mode_test.dart -test/colorspace_test.dart -test/cq_mode_test.dart -test/create_album_dto_test.dart -test/create_library_dto_test.dart -test/create_profile_image_response_dto_test.dart -test/create_tag_dto_test.dart -test/create_user_dto_test.dart -test/delete_user_dto_test.dart -test/download_api_test.dart -test/download_archive_info_test.dart -test/download_info_dto_test.dart -test/download_response_dto_test.dart -test/entity_type_test.dart -test/exif_response_dto_test.dart -test/face_api_test.dart -test/face_dto_test.dart -test/file_checksum_dto_test.dart -test/file_checksum_response_dto_test.dart -test/file_report_api_test.dart -test/file_report_dto_test.dart -test/file_report_fix_dto_test.dart -test/file_report_item_dto_test.dart -test/image_format_test.dart -test/job_api_test.dart -test/job_command_dto_test.dart -test/job_command_test.dart -test/job_counts_dto_test.dart -test/job_name_test.dart -test/job_settings_dto_test.dart -test/job_status_dto_test.dart -test/library_api_test.dart -test/library_response_dto_test.dart -test/library_stats_response_dto_test.dart -test/library_type_test.dart -test/log_level_test.dart -test/login_credential_dto_test.dart -test/login_response_dto_test.dart -test/logout_response_dto_test.dart -test/map_marker_response_dto_test.dart -test/map_theme_test.dart -test/memory_api_test.dart -test/memory_create_dto_test.dart -test/memory_lane_response_dto_test.dart -test/memory_response_dto_test.dart -test/memory_type_test.dart -test/memory_update_dto_test.dart -test/merge_person_dto_test.dart -test/metadata_search_dto_test.dart -test/model_type_test.dart -test/o_auth_api_test.dart -test/o_auth_authorize_response_dto_test.dart -test/o_auth_callback_dto_test.dart -test/o_auth_config_dto_test.dart -test/on_this_day_dto_test.dart -test/partner_api_test.dart -test/partner_response_dto_test.dart -test/path_entity_type_test.dart -test/path_type_test.dart -test/people_response_dto_test.dart -test/people_update_dto_test.dart -test/people_update_item_test.dart -test/people_with_faces_response_dto_test.dart -test/person_api_test.dart -test/person_create_dto_test.dart -test/person_response_dto_test.dart -test/person_statistics_response_dto_test.dart -test/person_update_dto_test.dart -test/person_with_faces_response_dto_test.dart -test/places_response_dto_test.dart -test/queue_status_dto_test.dart -test/reaction_level_test.dart -test/reaction_type_test.dart -test/recognition_config_test.dart -test/reverse_geocoding_state_response_dto_test.dart -test/scan_library_dto_test.dart -test/search_album_response_dto_test.dart -test/search_api_test.dart -test/search_asset_response_dto_test.dart -test/search_explore_item_test.dart -test/search_explore_response_dto_test.dart -test/search_facet_count_response_dto_test.dart -test/search_facet_response_dto_test.dart -test/search_response_dto_test.dart -test/search_suggestion_type_test.dart -test/server_config_dto_test.dart -test/server_features_dto_test.dart -test/server_info_api_test.dart -test/server_info_response_dto_test.dart -test/server_media_types_response_dto_test.dart -test/server_ping_response_test.dart -test/server_stats_response_dto_test.dart -test/server_theme_dto_test.dart -test/server_version_response_dto_test.dart -test/session_response_dto_test.dart -test/sessions_api_test.dart -test/shared_link_api_test.dart -test/shared_link_create_dto_test.dart -test/shared_link_edit_dto_test.dart -test/shared_link_response_dto_test.dart -test/shared_link_type_test.dart -test/sign_up_dto_test.dart -test/smart_info_response_dto_test.dart -test/smart_search_dto_test.dart -test/sync_api_test.dart -test/system_config_api_test.dart -test/system_config_dto_test.dart -test/system_config_f_fmpeg_dto_test.dart -test/system_config_image_dto_test.dart -test/system_config_job_dto_test.dart -test/system_config_library_dto_test.dart -test/system_config_library_scan_dto_test.dart -test/system_config_library_watch_dto_test.dart -test/system_config_logging_dto_test.dart -test/system_config_machine_learning_dto_test.dart -test/system_config_map_dto_test.dart -test/system_config_new_version_check_dto_test.dart -test/system_config_notifications_dto_test.dart -test/system_config_o_auth_dto_test.dart -test/system_config_password_login_dto_test.dart -test/system_config_reverse_geocoding_dto_test.dart -test/system_config_server_dto_test.dart -test/system_config_smtp_dto_test.dart -test/system_config_smtp_transport_dto_test.dart -test/system_config_storage_template_dto_test.dart -test/system_config_template_storage_option_dto_test.dart -test/system_config_theme_dto_test.dart -test/system_config_trash_dto_test.dart -test/system_config_user_dto_test.dart -test/system_metadata_api_test.dart -test/tag_api_test.dart -test/tag_response_dto_test.dart -test/tag_type_enum_test.dart -test/thumbnail_format_test.dart -test/time_bucket_response_dto_test.dart -test/time_bucket_size_test.dart -test/timeline_api_test.dart -test/tone_mapping_test.dart -test/transcode_hw_accel_test.dart -test/transcode_policy_test.dart -test/trash_api_test.dart -test/update_album_dto_test.dart -test/update_album_user_dto_test.dart -test/update_asset_dto_test.dart -test/update_library_dto_test.dart -test/update_partner_dto_test.dart -test/update_stack_parent_dto_test.dart -test/update_tag_dto_test.dart -test/update_user_dto_test.dart -test/usage_by_user_dto_test.dart -test/user_api_test.dart -test/user_avatar_color_test.dart -test/user_dto_test.dart -test/user_response_dto_test.dart -test/user_status_test.dart -test/validate_access_token_response_dto_test.dart -test/validate_library_dto_test.dart -test/validate_library_import_path_response_dto_test.dart -test/validate_library_response_dto_test.dart -test/video_codec_test.dart diff --git a/mobile/openapi/.openapi-generator/VERSION b/mobile/openapi/.openapi-generator/VERSION index 4b49d9bb63..18bb4182dd 100644 --- a/mobile/openapi/.openapi-generator/VERSION +++ b/mobile/openapi/.openapi-generator/VERSION @@ -1 +1 @@ -7.2.0 \ No newline at end of file +7.5.0 diff --git a/mobile/openapi/doc/APIKeyApi.md b/mobile/openapi/doc/APIKeyApi.md deleted file mode 100644 index 69b0917bb2..0000000000 --- a/mobile/openapi/doc/APIKeyApi.md +++ /dev/null @@ -1,290 +0,0 @@ -# openapi.api.APIKeyApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**createApiKey**](APIKeyApi.md#createapikey) | **POST** /api-key | -[**deleteApiKey**](APIKeyApi.md#deleteapikey) | **DELETE** /api-key/{id} | -[**getApiKey**](APIKeyApi.md#getapikey) | **GET** /api-key/{id} | -[**getApiKeys**](APIKeyApi.md#getapikeys) | **GET** /api-key | -[**updateApiKey**](APIKeyApi.md#updateapikey) | **PUT** /api-key/{id} | - - -# **createApiKey** -> APIKeyCreateResponseDto createApiKey(aPIKeyCreateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = APIKeyApi(); -final aPIKeyCreateDto = APIKeyCreateDto(); // APIKeyCreateDto | - -try { - final result = api_instance.createApiKey(aPIKeyCreateDto); - print(result); -} catch (e) { - print('Exception when calling APIKeyApi->createApiKey: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **aPIKeyCreateDto** | [**APIKeyCreateDto**](APIKeyCreateDto.md)| | - -### Return type - -[**APIKeyCreateResponseDto**](APIKeyCreateResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteApiKey** -> deleteApiKey(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = APIKeyApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.deleteApiKey(id); -} catch (e) { - print('Exception when calling APIKeyApi->deleteApiKey: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getApiKey** -> APIKeyResponseDto getApiKey(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = APIKeyApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getApiKey(id); - print(result); -} catch (e) { - print('Exception when calling APIKeyApi->getApiKey: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**APIKeyResponseDto**](APIKeyResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getApiKeys** -> List getApiKeys() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = APIKeyApi(); - -try { - final result = api_instance.getApiKeys(); - print(result); -} catch (e) { - print('Exception when calling APIKeyApi->getApiKeys: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](APIKeyResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateApiKey** -> APIKeyResponseDto updateApiKey(id, aPIKeyUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = APIKeyApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final aPIKeyUpdateDto = APIKeyUpdateDto(); // APIKeyUpdateDto | - -try { - final result = api_instance.updateApiKey(id, aPIKeyUpdateDto); - print(result); -} catch (e) { - print('Exception when calling APIKeyApi->updateApiKey: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **aPIKeyUpdateDto** | [**APIKeyUpdateDto**](APIKeyUpdateDto.md)| | - -### Return type - -[**APIKeyResponseDto**](APIKeyResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/APIKeyCreateDto.md b/mobile/openapi/doc/APIKeyCreateDto.md deleted file mode 100644 index 0355e3654f..0000000000 --- a/mobile/openapi/doc/APIKeyCreateDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.APIKeyCreateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**name** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/APIKeyCreateResponseDto.md b/mobile/openapi/doc/APIKeyCreateResponseDto.md deleted file mode 100644 index 3b29bf9402..0000000000 --- a/mobile/openapi/doc/APIKeyCreateResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.APIKeyCreateResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**apiKey** | [**APIKeyResponseDto**](APIKeyResponseDto.md) | | -**secret** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/APIKeyResponseDto.md b/mobile/openapi/doc/APIKeyResponseDto.md deleted file mode 100644 index c40947fa74..0000000000 --- a/mobile/openapi/doc/APIKeyResponseDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.APIKeyResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**createdAt** | [**DateTime**](DateTime.md) | | -**id** | **String** | | -**name** | **String** | | -**updatedAt** | [**DateTime**](DateTime.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/APIKeyUpdateDto.md b/mobile/openapi/doc/APIKeyUpdateDto.md deleted file mode 100644 index d5a72ed860..0000000000 --- a/mobile/openapi/doc/APIKeyUpdateDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.APIKeyUpdateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**name** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ActivityApi.md b/mobile/openapi/doc/ActivityApi.md deleted file mode 100644 index 1552e30863..0000000000 --- a/mobile/openapi/doc/ActivityApi.md +++ /dev/null @@ -1,246 +0,0 @@ -# openapi.api.ActivityApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**createActivity**](ActivityApi.md#createactivity) | **POST** /activity | -[**deleteActivity**](ActivityApi.md#deleteactivity) | **DELETE** /activity/{id} | -[**getActivities**](ActivityApi.md#getactivities) | **GET** /activity | -[**getActivityStatistics**](ActivityApi.md#getactivitystatistics) | **GET** /activity/statistics | - - -# **createActivity** -> ActivityResponseDto createActivity(activityCreateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = ActivityApi(); -final activityCreateDto = ActivityCreateDto(); // ActivityCreateDto | - -try { - final result = api_instance.createActivity(activityCreateDto); - print(result); -} catch (e) { - print('Exception when calling ActivityApi->createActivity: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **activityCreateDto** | [**ActivityCreateDto**](ActivityCreateDto.md)| | - -### Return type - -[**ActivityResponseDto**](ActivityResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteActivity** -> deleteActivity(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = ActivityApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.deleteActivity(id); -} catch (e) { - print('Exception when calling ActivityApi->deleteActivity: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getActivities** -> List getActivities(albumId, assetId, level, type, userId) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = ActivityApi(); -final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final assetId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final level = ; // ReactionLevel | -final type = ; // ReactionType | -final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getActivities(albumId, assetId, level, type, userId); - print(result); -} catch (e) { - print('Exception when calling ActivityApi->getActivities: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **albumId** | **String**| | - **assetId** | **String**| | [optional] - **level** | [**ReactionLevel**](.md)| | [optional] - **type** | [**ReactionType**](.md)| | [optional] - **userId** | **String**| | [optional] - -### Return type - -[**List**](ActivityResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getActivityStatistics** -> ActivityStatisticsResponseDto getActivityStatistics(albumId, assetId) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = ActivityApi(); -final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final assetId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getActivityStatistics(albumId, assetId); - print(result); -} catch (e) { - print('Exception when calling ActivityApi->getActivityStatistics: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **albumId** | **String**| | - **assetId** | **String**| | [optional] - -### Return type - -[**ActivityStatisticsResponseDto**](ActivityStatisticsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/ActivityCreateDto.md b/mobile/openapi/doc/ActivityCreateDto.md deleted file mode 100644 index 32cfdb5c71..0000000000 --- a/mobile/openapi/doc/ActivityCreateDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.ActivityCreateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albumId** | **String** | | -**assetId** | **String** | | [optional] -**comment** | **String** | | [optional] -**type** | [**ReactionType**](ReactionType.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ActivityResponseDto.md b/mobile/openapi/doc/ActivityResponseDto.md deleted file mode 100644 index 3b8589b61e..0000000000 --- a/mobile/openapi/doc/ActivityResponseDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.ActivityResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetId** | **String** | | -**comment** | **String** | | [optional] -**createdAt** | [**DateTime**](DateTime.md) | | -**id** | **String** | | -**type** | **String** | | -**user** | [**UserDto**](UserDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ActivityStatisticsResponseDto.md b/mobile/openapi/doc/ActivityStatisticsResponseDto.md deleted file mode 100644 index 00583aea97..0000000000 --- a/mobile/openapi/doc/ActivityStatisticsResponseDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.ActivityStatisticsResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**comments** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AddUsersDto.md b/mobile/openapi/doc/AddUsersDto.md deleted file mode 100644 index 5547c5a70b..0000000000 --- a/mobile/openapi/doc/AddUsersDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AddUsersDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albumUsers** | [**List**](AlbumUserAddDto.md) | | [default to const []] -**sharedUserIds** | **List** | This property was deprecated in v1.102.0 | [optional] [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AdminOnboardingUpdateDto.md b/mobile/openapi/doc/AdminOnboardingUpdateDto.md deleted file mode 100644 index b250843019..0000000000 --- a/mobile/openapi/doc/AdminOnboardingUpdateDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.AdminOnboardingUpdateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**isOnboarded** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AlbumApi.md b/mobile/openapi/doc/AlbumApi.md deleted file mode 100644 index 2cd6cb29b0..0000000000 --- a/mobile/openapi/doc/AlbumApi.md +++ /dev/null @@ -1,644 +0,0 @@ -# openapi.api.AlbumApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**addAssetsToAlbum**](AlbumApi.md#addassetstoalbum) | **PUT** /album/{id}/assets | -[**addUsersToAlbum**](AlbumApi.md#adduserstoalbum) | **PUT** /album/{id}/users | -[**createAlbum**](AlbumApi.md#createalbum) | **POST** /album | -[**deleteAlbum**](AlbumApi.md#deletealbum) | **DELETE** /album/{id} | -[**getAlbumCount**](AlbumApi.md#getalbumcount) | **GET** /album/count | -[**getAlbumInfo**](AlbumApi.md#getalbuminfo) | **GET** /album/{id} | -[**getAllAlbums**](AlbumApi.md#getallalbums) | **GET** /album | -[**removeAssetFromAlbum**](AlbumApi.md#removeassetfromalbum) | **DELETE** /album/{id}/assets | -[**removeUserFromAlbum**](AlbumApi.md#removeuserfromalbum) | **DELETE** /album/{id}/user/{userId} | -[**updateAlbumInfo**](AlbumApi.md#updatealbuminfo) | **PATCH** /album/{id} | -[**updateAlbumUser**](AlbumApi.md#updatealbumuser) | **PUT** /album/{id}/user/{userId} | - - -# **addAssetsToAlbum** -> List addAssetsToAlbum(id, bulkIdsDto, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final bulkIdsDto = BulkIdsDto(); // BulkIdsDto | -final key = key_example; // String | - -try { - final result = api_instance.addAssetsToAlbum(id, bulkIdsDto, key); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->addAssetsToAlbum: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **bulkIdsDto** | [**BulkIdsDto**](BulkIdsDto.md)| | - **key** | **String**| | [optional] - -### Return type - -[**List**](BulkIdResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **addUsersToAlbum** -> AlbumResponseDto addUsersToAlbum(id, addUsersDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final addUsersDto = AddUsersDto(); // AddUsersDto | - -try { - final result = api_instance.addUsersToAlbum(id, addUsersDto); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->addUsersToAlbum: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **addUsersDto** | [**AddUsersDto**](AddUsersDto.md)| | - -### Return type - -[**AlbumResponseDto**](AlbumResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **createAlbum** -> AlbumResponseDto createAlbum(createAlbumDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final createAlbumDto = CreateAlbumDto(); // CreateAlbumDto | - -try { - final result = api_instance.createAlbum(createAlbumDto); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->createAlbum: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **createAlbumDto** | [**CreateAlbumDto**](CreateAlbumDto.md)| | - -### Return type - -[**AlbumResponseDto**](AlbumResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteAlbum** -> deleteAlbum(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.deleteAlbum(id); -} catch (e) { - print('Exception when calling AlbumApi->deleteAlbum: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAlbumCount** -> AlbumCountResponseDto getAlbumCount() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); - -try { - final result = api_instance.getAlbumCount(); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->getAlbumCount: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**AlbumCountResponseDto**](AlbumCountResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAlbumInfo** -> AlbumResponseDto getAlbumInfo(id, key, withoutAssets) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final key = key_example; // String | -final withoutAssets = true; // bool | - -try { - final result = api_instance.getAlbumInfo(id, key, withoutAssets); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->getAlbumInfo: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **key** | **String**| | [optional] - **withoutAssets** | **bool**| | [optional] - -### Return type - -[**AlbumResponseDto**](AlbumResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllAlbums** -> List getAllAlbums(assetId, shared) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final assetId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | Only returns albums that contain the asset Ignores the shared parameter undefined: get all albums -final shared = true; // bool | - -try { - final result = api_instance.getAllAlbums(assetId, shared); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->getAllAlbums: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetId** | **String**| Only returns albums that contain the asset Ignores the shared parameter undefined: get all albums | [optional] - **shared** | **bool**| | [optional] - -### Return type - -[**List**](AlbumResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **removeAssetFromAlbum** -> List removeAssetFromAlbum(id, bulkIdsDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final bulkIdsDto = BulkIdsDto(); // BulkIdsDto | - -try { - final result = api_instance.removeAssetFromAlbum(id, bulkIdsDto); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->removeAssetFromAlbum: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **bulkIdsDto** | [**BulkIdsDto**](BulkIdsDto.md)| | - -### Return type - -[**List**](BulkIdResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **removeUserFromAlbum** -> removeUserFromAlbum(id, userId) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final userId = userId_example; // String | - -try { - api_instance.removeUserFromAlbum(id, userId); -} catch (e) { - print('Exception when calling AlbumApi->removeUserFromAlbum: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **userId** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateAlbumInfo** -> AlbumResponseDto updateAlbumInfo(id, updateAlbumDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final updateAlbumDto = UpdateAlbumDto(); // UpdateAlbumDto | - -try { - final result = api_instance.updateAlbumInfo(id, updateAlbumDto); - print(result); -} catch (e) { - print('Exception when calling AlbumApi->updateAlbumInfo: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **updateAlbumDto** | [**UpdateAlbumDto**](UpdateAlbumDto.md)| | - -### Return type - -[**AlbumResponseDto**](AlbumResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateAlbumUser** -> updateAlbumUser(id, userId, updateAlbumUserDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AlbumApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final userId = userId_example; // String | -final updateAlbumUserDto = UpdateAlbumUserDto(); // UpdateAlbumUserDto | - -try { - api_instance.updateAlbumUser(id, userId, updateAlbumUserDto); -} catch (e) { - print('Exception when calling AlbumApi->updateAlbumUser: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **userId** | **String**| | - **updateAlbumUserDto** | [**UpdateAlbumUserDto**](UpdateAlbumUserDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/AlbumCountResponseDto.md b/mobile/openapi/doc/AlbumCountResponseDto.md deleted file mode 100644 index 20e496b274..0000000000 --- a/mobile/openapi/doc/AlbumCountResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.AlbumCountResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**notShared** | **int** | | -**owned** | **int** | | -**shared** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AlbumResponseDto.md b/mobile/openapi/doc/AlbumResponseDto.md deleted file mode 100644 index 0152396c25..0000000000 --- a/mobile/openapi/doc/AlbumResponseDto.md +++ /dev/null @@ -1,33 +0,0 @@ -# openapi.model.AlbumResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albumName** | **String** | | -**albumThumbnailAssetId** | **String** | | -**albumUsers** | [**List**](AlbumUserResponseDto.md) | | [default to const []] -**assetCount** | **int** | | -**assets** | [**List**](AssetResponseDto.md) | | [default to const []] -**createdAt** | [**DateTime**](DateTime.md) | | -**description** | **String** | | -**endDate** | [**DateTime**](DateTime.md) | | [optional] -**hasSharedLink** | **bool** | | -**id** | **String** | | -**isActivityEnabled** | **bool** | | -**lastModifiedAssetTimestamp** | [**DateTime**](DateTime.md) | | [optional] -**order** | [**AssetOrder**](AssetOrder.md) | | [optional] -**owner** | [**UserResponseDto**](UserResponseDto.md) | | -**ownerId** | **String** | | -**shared** | **bool** | | -**sharedUsers** | [**List**](UserResponseDto.md) | This property was deprecated in v1.102.0 | [default to const []] -**startDate** | [**DateTime**](DateTime.md) | | [optional] -**updatedAt** | [**DateTime**](DateTime.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AlbumUserAddDto.md b/mobile/openapi/doc/AlbumUserAddDto.md deleted file mode 100644 index aae7c9eb6c..0000000000 --- a/mobile/openapi/doc/AlbumUserAddDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AlbumUserAddDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**role** | [**AlbumUserRole**](AlbumUserRole.md) | | [optional] -**userId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AlbumUserCreateDto.md b/mobile/openapi/doc/AlbumUserCreateDto.md deleted file mode 100644 index 78acbc476b..0000000000 --- a/mobile/openapi/doc/AlbumUserCreateDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AlbumUserCreateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**role** | [**AlbumUserRole**](AlbumUserRole.md) | | -**userId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AlbumUserResponseDto.md b/mobile/openapi/doc/AlbumUserResponseDto.md deleted file mode 100644 index 3f59d3142f..0000000000 --- a/mobile/openapi/doc/AlbumUserResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AlbumUserResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**role** | [**AlbumUserRole**](AlbumUserRole.md) | | -**user** | [**UserResponseDto**](UserResponseDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AlbumUserRole.md b/mobile/openapi/doc/AlbumUserRole.md deleted file mode 100644 index d0f64ef3ec..0000000000 --- a/mobile/openapi/doc/AlbumUserRole.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.AlbumUserRole - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AllJobStatusResponseDto.md b/mobile/openapi/doc/AllJobStatusResponseDto.md deleted file mode 100644 index fe2f536595..0000000000 --- a/mobile/openapi/doc/AllJobStatusResponseDto.md +++ /dev/null @@ -1,27 +0,0 @@ -# openapi.model.AllJobStatusResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**backgroundTask** | [**JobStatusDto**](JobStatusDto.md) | | -**faceDetection** | [**JobStatusDto**](JobStatusDto.md) | | -**facialRecognition** | [**JobStatusDto**](JobStatusDto.md) | | -**library_** | [**JobStatusDto**](JobStatusDto.md) | | -**metadataExtraction** | [**JobStatusDto**](JobStatusDto.md) | | -**migration** | [**JobStatusDto**](JobStatusDto.md) | | -**notifications** | [**JobStatusDto**](JobStatusDto.md) | | -**search** | [**JobStatusDto**](JobStatusDto.md) | | -**sidecar** | [**JobStatusDto**](JobStatusDto.md) | | -**smartSearch** | [**JobStatusDto**](JobStatusDto.md) | | -**storageTemplateMigration** | [**JobStatusDto**](JobStatusDto.md) | | -**thumbnailGeneration** | [**JobStatusDto**](JobStatusDto.md) | | -**videoConversion** | [**JobStatusDto**](JobStatusDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetApi.md b/mobile/openapi/doc/AssetApi.md deleted file mode 100644 index d710ef926a..0000000000 --- a/mobile/openapi/doc/AssetApi.md +++ /dev/null @@ -1,1039 +0,0 @@ -# openapi.api.AssetApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**checkBulkUpload**](AssetApi.md#checkbulkupload) | **POST** /asset/bulk-upload-check | -[**checkExistingAssets**](AssetApi.md#checkexistingassets) | **POST** /asset/exist | -[**deleteAssets**](AssetApi.md#deleteassets) | **DELETE** /asset | -[**getAllAssets**](AssetApi.md#getallassets) | **GET** /asset | -[**getAllUserAssetsByDeviceId**](AssetApi.md#getalluserassetsbydeviceid) | **GET** /asset/device/{deviceId} | -[**getAssetInfo**](AssetApi.md#getassetinfo) | **GET** /asset/{id} | -[**getAssetStatistics**](AssetApi.md#getassetstatistics) | **GET** /asset/statistics | -[**getAssetThumbnail**](AssetApi.md#getassetthumbnail) | **GET** /asset/thumbnail/{id} | -[**getMapMarkers**](AssetApi.md#getmapmarkers) | **GET** /asset/map-marker | -[**getMemoryLane**](AssetApi.md#getmemorylane) | **GET** /asset/memory-lane | -[**getRandom**](AssetApi.md#getrandom) | **GET** /asset/random | -[**runAssetJobs**](AssetApi.md#runassetjobs) | **POST** /asset/jobs | -[**serveFile**](AssetApi.md#servefile) | **GET** /asset/file/{id} | -[**updateAsset**](AssetApi.md#updateasset) | **PUT** /asset/{id} | -[**updateAssets**](AssetApi.md#updateassets) | **PUT** /asset | -[**updateStackParent**](AssetApi.md#updatestackparent) | **PUT** /asset/stack/parent | -[**uploadFile**](AssetApi.md#uploadfile) | **POST** /asset/upload | - - -# **checkBulkUpload** -> AssetBulkUploadCheckResponseDto checkBulkUpload(assetBulkUploadCheckDto) - - - -Checks if assets exist by checksums - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final assetBulkUploadCheckDto = AssetBulkUploadCheckDto(); // AssetBulkUploadCheckDto | - -try { - final result = api_instance.checkBulkUpload(assetBulkUploadCheckDto); - print(result); -} catch (e) { - print('Exception when calling AssetApi->checkBulkUpload: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetBulkUploadCheckDto** | [**AssetBulkUploadCheckDto**](AssetBulkUploadCheckDto.md)| | - -### Return type - -[**AssetBulkUploadCheckResponseDto**](AssetBulkUploadCheckResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **checkExistingAssets** -> CheckExistingAssetsResponseDto checkExistingAssets(checkExistingAssetsDto) - - - -Checks if multiple assets exist on the server and returns all existing - used by background backup - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final checkExistingAssetsDto = CheckExistingAssetsDto(); // CheckExistingAssetsDto | - -try { - final result = api_instance.checkExistingAssets(checkExistingAssetsDto); - print(result); -} catch (e) { - print('Exception when calling AssetApi->checkExistingAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **checkExistingAssetsDto** | [**CheckExistingAssetsDto**](CheckExistingAssetsDto.md)| | - -### Return type - -[**CheckExistingAssetsResponseDto**](CheckExistingAssetsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteAssets** -> deleteAssets(assetBulkDeleteDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final assetBulkDeleteDto = AssetBulkDeleteDto(); // AssetBulkDeleteDto | - -try { - api_instance.deleteAssets(assetBulkDeleteDto); -} catch (e) { - print('Exception when calling AssetApi->deleteAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetBulkDeleteDto** | [**AssetBulkDeleteDto**](AssetBulkDeleteDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllAssets** -> List getAllAssets(ifNoneMatch, isArchived, isFavorite, skip, take, updatedAfter, updatedBefore, userId) - - - -Get all AssetEntity belong to the user - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final ifNoneMatch = ifNoneMatch_example; // String | ETag of data already cached on the client -final isArchived = true; // bool | -final isFavorite = true; // bool | -final skip = 56; // int | -final take = 56; // int | -final updatedAfter = 2013-10-20T19:20:30+01:00; // DateTime | -final updatedBefore = 2013-10-20T19:20:30+01:00; // DateTime | -final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getAllAssets(ifNoneMatch, isArchived, isFavorite, skip, take, updatedAfter, updatedBefore, userId); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getAllAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **ifNoneMatch** | **String**| ETag of data already cached on the client | [optional] - **isArchived** | **bool**| | [optional] - **isFavorite** | **bool**| | [optional] - **skip** | **int**| | [optional] - **take** | **int**| | [optional] - **updatedAfter** | **DateTime**| | [optional] - **updatedBefore** | **DateTime**| | [optional] - **userId** | **String**| | [optional] - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllUserAssetsByDeviceId** -> List getAllUserAssetsByDeviceId(deviceId) - - - -Get all asset of a device that are in the database, ID only. - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final deviceId = deviceId_example; // String | - -try { - final result = api_instance.getAllUserAssetsByDeviceId(deviceId); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getAllUserAssetsByDeviceId: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **deviceId** | **String**| | - -### Return type - -**List** - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAssetInfo** -> AssetResponseDto getAssetInfo(id, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final key = key_example; // String | - -try { - final result = api_instance.getAssetInfo(id, key); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getAssetInfo: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **key** | **String**| | [optional] - -### Return type - -[**AssetResponseDto**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAssetStatistics** -> AssetStatsResponseDto getAssetStatistics(isArchived, isFavorite, isTrashed) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final isArchived = true; // bool | -final isFavorite = true; // bool | -final isTrashed = true; // bool | - -try { - final result = api_instance.getAssetStatistics(isArchived, isFavorite, isTrashed); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getAssetStatistics: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **isArchived** | **bool**| | [optional] - **isFavorite** | **bool**| | [optional] - **isTrashed** | **bool**| | [optional] - -### Return type - -[**AssetStatsResponseDto**](AssetStatsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAssetThumbnail** -> MultipartFile getAssetThumbnail(id, format, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final format = ; // ThumbnailFormat | -final key = key_example; // String | - -try { - final result = api_instance.getAssetThumbnail(id, format, key); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getAssetThumbnail: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **format** | [**ThumbnailFormat**](.md)| | [optional] - **key** | **String**| | [optional] - -### Return type - -[**MultipartFile**](MultipartFile.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/octet-stream - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getMapMarkers** -> List getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final fileCreatedAfter = 2013-10-20T19:20:30+01:00; // DateTime | -final fileCreatedBefore = 2013-10-20T19:20:30+01:00; // DateTime | -final isArchived = true; // bool | -final isFavorite = true; // bool | -final withPartners = true; // bool | - -try { - final result = api_instance.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getMapMarkers: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **fileCreatedAfter** | **DateTime**| | [optional] - **fileCreatedBefore** | **DateTime**| | [optional] - **isArchived** | **bool**| | [optional] - **isFavorite** | **bool**| | [optional] - **withPartners** | **bool**| | [optional] - -### Return type - -[**List**](MapMarkerResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getMemoryLane** -> List getMemoryLane(day, month) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final day = 56; // int | -final month = 56; // int | - -try { - final result = api_instance.getMemoryLane(day, month); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getMemoryLane: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **day** | **int**| | - **month** | **int**| | - -### Return type - -[**List**](MemoryLaneResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getRandom** -> List getRandom(count) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final count = 8.14; // num | - -try { - final result = api_instance.getRandom(count); - print(result); -} catch (e) { - print('Exception when calling AssetApi->getRandom: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **count** | **num**| | [optional] - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **runAssetJobs** -> runAssetJobs(assetJobsDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final assetJobsDto = AssetJobsDto(); // AssetJobsDto | - -try { - api_instance.runAssetJobs(assetJobsDto); -} catch (e) { - print('Exception when calling AssetApi->runAssetJobs: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetJobsDto** | [**AssetJobsDto**](AssetJobsDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **serveFile** -> MultipartFile serveFile(id, isThumb, isWeb, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final isThumb = true; // bool | -final isWeb = true; // bool | -final key = key_example; // String | - -try { - final result = api_instance.serveFile(id, isThumb, isWeb, key); - print(result); -} catch (e) { - print('Exception when calling AssetApi->serveFile: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **isThumb** | **bool**| | [optional] - **isWeb** | **bool**| | [optional] - **key** | **String**| | [optional] - -### Return type - -[**MultipartFile**](MultipartFile.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/octet-stream - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateAsset** -> AssetResponseDto updateAsset(id, updateAssetDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final updateAssetDto = UpdateAssetDto(); // UpdateAssetDto | - -try { - final result = api_instance.updateAsset(id, updateAssetDto); - print(result); -} catch (e) { - print('Exception when calling AssetApi->updateAsset: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **updateAssetDto** | [**UpdateAssetDto**](UpdateAssetDto.md)| | - -### Return type - -[**AssetResponseDto**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateAssets** -> updateAssets(assetBulkUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final assetBulkUpdateDto = AssetBulkUpdateDto(); // AssetBulkUpdateDto | - -try { - api_instance.updateAssets(assetBulkUpdateDto); -} catch (e) { - print('Exception when calling AssetApi->updateAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetBulkUpdateDto** | [**AssetBulkUpdateDto**](AssetBulkUpdateDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateStackParent** -> updateStackParent(updateStackParentDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final updateStackParentDto = UpdateStackParentDto(); // UpdateStackParentDto | - -try { - api_instance.updateStackParent(updateStackParentDto); -} catch (e) { - print('Exception when calling AssetApi->updateStackParent: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **updateStackParentDto** | [**UpdateStackParentDto**](UpdateStackParentDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **uploadFile** -> AssetFileUploadResponseDto uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, xImmichChecksum, duration, isArchived, isFavorite, isOffline, isVisible, libraryId, livePhotoData, sidecarData) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AssetApi(); -final assetData = BINARY_DATA_HERE; // MultipartFile | -final deviceAssetId = deviceAssetId_example; // String | -final deviceId = deviceId_example; // String | -final fileCreatedAt = 2013-10-20T19:20:30+01:00; // DateTime | -final fileModifiedAt = 2013-10-20T19:20:30+01:00; // DateTime | -final key = key_example; // String | -final xImmichChecksum = xImmichChecksum_example; // String | sha1 checksum that can be used for duplicate detection before the file is uploaded -final duration = duration_example; // String | -final isArchived = true; // bool | -final isFavorite = true; // bool | -final isOffline = true; // bool | -final isVisible = true; // bool | -final libraryId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final livePhotoData = BINARY_DATA_HERE; // MultipartFile | -final sidecarData = BINARY_DATA_HERE; // MultipartFile | - -try { - final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key, xImmichChecksum, duration, isArchived, isFavorite, isOffline, isVisible, libraryId, livePhotoData, sidecarData); - print(result); -} catch (e) { - print('Exception when calling AssetApi->uploadFile: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetData** | **MultipartFile**| | - **deviceAssetId** | **String**| | - **deviceId** | **String**| | - **fileCreatedAt** | **DateTime**| | - **fileModifiedAt** | **DateTime**| | - **key** | **String**| | [optional] - **xImmichChecksum** | **String**| sha1 checksum that can be used for duplicate detection before the file is uploaded | [optional] - **duration** | **String**| | [optional] - **isArchived** | **bool**| | [optional] - **isFavorite** | **bool**| | [optional] - **isOffline** | **bool**| | [optional] - **isVisible** | **bool**| | [optional] - **libraryId** | **String**| | [optional] - **livePhotoData** | **MultipartFile**| | [optional] - **sidecarData** | **MultipartFile**| | [optional] - -### Return type - -[**AssetFileUploadResponseDto**](AssetFileUploadResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: multipart/form-data - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/AssetBulkDeleteDto.md b/mobile/openapi/doc/AssetBulkDeleteDto.md deleted file mode 100644 index ff38a456e2..0000000000 --- a/mobile/openapi/doc/AssetBulkDeleteDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AssetBulkDeleteDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**force** | **bool** | | [optional] -**ids** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetBulkUpdateDto.md b/mobile/openapi/doc/AssetBulkUpdateDto.md deleted file mode 100644 index 40ebe6a411..0000000000 --- a/mobile/openapi/doc/AssetBulkUpdateDto.md +++ /dev/null @@ -1,22 +0,0 @@ -# openapi.model.AssetBulkUpdateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**dateTimeOriginal** | **String** | | [optional] -**ids** | **List** | | [default to const []] -**isArchived** | **bool** | | [optional] -**isFavorite** | **bool** | | [optional] -**latitude** | **num** | | [optional] -**longitude** | **num** | | [optional] -**removeParent** | **bool** | | [optional] -**stackParentId** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetBulkUploadCheckDto.md b/mobile/openapi/doc/AssetBulkUploadCheckDto.md deleted file mode 100644 index e3d8419ec7..0000000000 --- a/mobile/openapi/doc/AssetBulkUploadCheckDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.AssetBulkUploadCheckDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assets** | [**List**](AssetBulkUploadCheckItem.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetBulkUploadCheckItem.md b/mobile/openapi/doc/AssetBulkUploadCheckItem.md deleted file mode 100644 index edc739a652..0000000000 --- a/mobile/openapi/doc/AssetBulkUploadCheckItem.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AssetBulkUploadCheckItem - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**checksum** | **String** | base64 or hex encoded sha1 hash | -**id** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetBulkUploadCheckResponseDto.md b/mobile/openapi/doc/AssetBulkUploadCheckResponseDto.md deleted file mode 100644 index 5cdea7d3b8..0000000000 --- a/mobile/openapi/doc/AssetBulkUploadCheckResponseDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.AssetBulkUploadCheckResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**results** | [**List**](AssetBulkUploadCheckResult.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetBulkUploadCheckResult.md b/mobile/openapi/doc/AssetBulkUploadCheckResult.md deleted file mode 100644 index c22f6c249e..0000000000 --- a/mobile/openapi/doc/AssetBulkUploadCheckResult.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.AssetBulkUploadCheckResult - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**action** | **String** | | -**assetId** | **String** | | [optional] -**id** | **String** | | -**reason** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetDeltaSyncDto.md b/mobile/openapi/doc/AssetDeltaSyncDto.md deleted file mode 100644 index b38329fe96..0000000000 --- a/mobile/openapi/doc/AssetDeltaSyncDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AssetDeltaSyncDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**updatedAfter** | [**DateTime**](DateTime.md) | | -**userIds** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetDeltaSyncResponseDto.md b/mobile/openapi/doc/AssetDeltaSyncResponseDto.md deleted file mode 100644 index 527203a4b8..0000000000 --- a/mobile/openapi/doc/AssetDeltaSyncResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.AssetDeltaSyncResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**deleted** | **List** | | [default to const []] -**needsFullSync** | **bool** | | -**upserted** | [**List**](AssetResponseDto.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetFaceResponseDto.md b/mobile/openapi/doc/AssetFaceResponseDto.md deleted file mode 100644 index 00ded8b476..0000000000 --- a/mobile/openapi/doc/AssetFaceResponseDto.md +++ /dev/null @@ -1,22 +0,0 @@ -# openapi.model.AssetFaceResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**boundingBoxX1** | **int** | | -**boundingBoxX2** | **int** | | -**boundingBoxY1** | **int** | | -**boundingBoxY2** | **int** | | -**id** | **String** | | -**imageHeight** | **int** | | -**imageWidth** | **int** | | -**person** | [**PersonResponseDto**](PersonResponseDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetFaceUpdateDto.md b/mobile/openapi/doc/AssetFaceUpdateDto.md deleted file mode 100644 index eb4e4d3872..0000000000 --- a/mobile/openapi/doc/AssetFaceUpdateDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.AssetFaceUpdateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**data** | [**List**](AssetFaceUpdateItem.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetFaceUpdateItem.md b/mobile/openapi/doc/AssetFaceUpdateItem.md deleted file mode 100644 index 6a98288ed3..0000000000 --- a/mobile/openapi/doc/AssetFaceUpdateItem.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AssetFaceUpdateItem - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetId** | **String** | | -**personId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetFaceWithoutPersonResponseDto.md b/mobile/openapi/doc/AssetFaceWithoutPersonResponseDto.md deleted file mode 100644 index 5d421dbeff..0000000000 --- a/mobile/openapi/doc/AssetFaceWithoutPersonResponseDto.md +++ /dev/null @@ -1,21 +0,0 @@ -# openapi.model.AssetFaceWithoutPersonResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**boundingBoxX1** | **int** | | -**boundingBoxX2** | **int** | | -**boundingBoxY1** | **int** | | -**boundingBoxY2** | **int** | | -**id** | **String** | | -**imageHeight** | **int** | | -**imageWidth** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetFileUploadResponseDto.md b/mobile/openapi/doc/AssetFileUploadResponseDto.md deleted file mode 100644 index a698529ac7..0000000000 --- a/mobile/openapi/doc/AssetFileUploadResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AssetFileUploadResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**duplicate** | **bool** | | -**id** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetFullSyncDto.md b/mobile/openapi/doc/AssetFullSyncDto.md deleted file mode 100644 index 8635fee222..0000000000 --- a/mobile/openapi/doc/AssetFullSyncDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.AssetFullSyncDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**lastCreationDate** | [**DateTime**](DateTime.md) | | [optional] -**lastId** | **String** | | [optional] -**limit** | **int** | | -**updatedUntil** | [**DateTime**](DateTime.md) | | -**userId** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetIdsDto.md b/mobile/openapi/doc/AssetIdsDto.md deleted file mode 100644 index 002c3ee5e6..0000000000 --- a/mobile/openapi/doc/AssetIdsDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.AssetIdsDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetIds** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetIdsResponseDto.md b/mobile/openapi/doc/AssetIdsResponseDto.md deleted file mode 100644 index 8a9eba650c..0000000000 --- a/mobile/openapi/doc/AssetIdsResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.AssetIdsResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetId** | **String** | | -**error** | **String** | | [optional] -**success** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetJobName.md b/mobile/openapi/doc/AssetJobName.md deleted file mode 100644 index d9612705ac..0000000000 --- a/mobile/openapi/doc/AssetJobName.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.AssetJobName - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetJobsDto.md b/mobile/openapi/doc/AssetJobsDto.md deleted file mode 100644 index e1d04388a1..0000000000 --- a/mobile/openapi/doc/AssetJobsDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AssetJobsDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetIds** | **List** | | [default to const []] -**name** | [**AssetJobName**](AssetJobName.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetOrder.md b/mobile/openapi/doc/AssetOrder.md deleted file mode 100644 index d1460775e0..0000000000 --- a/mobile/openapi/doc/AssetOrder.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.AssetOrder - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetResponseDto.md b/mobile/openapi/doc/AssetResponseDto.md deleted file mode 100644 index f5d1fa3037..0000000000 --- a/mobile/openapi/doc/AssetResponseDto.md +++ /dev/null @@ -1,46 +0,0 @@ -# openapi.model.AssetResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**checksum** | **String** | base64 encoded sha1 hash | -**deviceAssetId** | **String** | | -**deviceId** | **String** | | -**duration** | **String** | | -**exifInfo** | [**ExifResponseDto**](ExifResponseDto.md) | | [optional] -**fileCreatedAt** | [**DateTime**](DateTime.md) | | -**fileModifiedAt** | [**DateTime**](DateTime.md) | | -**hasMetadata** | **bool** | | -**id** | **String** | | -**isArchived** | **bool** | | -**isExternal** | **bool** | This property was deprecated in v1.104.0 | [optional] -**isFavorite** | **bool** | | -**isOffline** | **bool** | | -**isReadOnly** | **bool** | This property was deprecated in v1.104.0 | [optional] -**isTrashed** | **bool** | | -**libraryId** | **String** | | -**livePhotoVideoId** | **String** | | [optional] -**localDateTime** | [**DateTime**](DateTime.md) | | -**originalFileName** | **String** | | -**originalPath** | **String** | | -**owner** | [**UserResponseDto**](UserResponseDto.md) | | [optional] -**ownerId** | **String** | | -**people** | [**PeopleWithFacesResponseDto**](PeopleWithFacesResponseDto.md) | | [optional] -**resized** | **bool** | | -**smartInfo** | [**SmartInfoResponseDto**](SmartInfoResponseDto.md) | | [optional] -**stack** | [**List**](AssetResponseDto.md) | | [optional] [default to const []] -**stackCount** | **int** | | -**stackParentId** | **String** | | [optional] -**tags** | [**List**](TagResponseDto.md) | | [optional] [default to const []] -**thumbhash** | **String** | | -**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | | -**updatedAt** | [**DateTime**](DateTime.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetStatsResponseDto.md b/mobile/openapi/doc/AssetStatsResponseDto.md deleted file mode 100644 index 370b7c059b..0000000000 --- a/mobile/openapi/doc/AssetStatsResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.AssetStatsResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**images** | **int** | | -**total** | **int** | | -**videos** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AssetTypeEnum.md b/mobile/openapi/doc/AssetTypeEnum.md deleted file mode 100644 index 8d514b090e..0000000000 --- a/mobile/openapi/doc/AssetTypeEnum.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.AssetTypeEnum - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AudioCodec.md b/mobile/openapi/doc/AudioCodec.md deleted file mode 100644 index eef8591857..0000000000 --- a/mobile/openapi/doc/AudioCodec.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.AudioCodec - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AuditApi.md b/mobile/openapi/doc/AuditApi.md deleted file mode 100644 index 2c768c40d1..0000000000 --- a/mobile/openapi/doc/AuditApi.md +++ /dev/null @@ -1,73 +0,0 @@ -# openapi.api.AuditApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getAuditDeletes**](AuditApi.md#getauditdeletes) | **GET** /audit/deletes | - - -# **getAuditDeletes** -> AuditDeletesResponseDto getAuditDeletes(after, entityType, userId) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AuditApi(); -final after = 2013-10-20T19:20:30+01:00; // DateTime | -final entityType = ; // EntityType | -final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getAuditDeletes(after, entityType, userId); - print(result); -} catch (e) { - print('Exception when calling AuditApi->getAuditDeletes: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **after** | **DateTime**| | - **entityType** | [**EntityType**](.md)| | - **userId** | **String**| | [optional] - -### Return type - -[**AuditDeletesResponseDto**](AuditDeletesResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/AuditDeletesResponseDto.md b/mobile/openapi/doc/AuditDeletesResponseDto.md deleted file mode 100644 index c7c9594f1b..0000000000 --- a/mobile/openapi/doc/AuditDeletesResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.AuditDeletesResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**ids** | **List** | | [default to const []] -**needsFullSync** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/AuthenticationApi.md b/mobile/openapi/doc/AuthenticationApi.md deleted file mode 100644 index 02fb94a092..0000000000 --- a/mobile/openapi/doc/AuthenticationApi.md +++ /dev/null @@ -1,257 +0,0 @@ -# openapi.api.AuthenticationApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**changePassword**](AuthenticationApi.md#changepassword) | **POST** /auth/change-password | -[**login**](AuthenticationApi.md#login) | **POST** /auth/login | -[**logout**](AuthenticationApi.md#logout) | **POST** /auth/logout | -[**signUpAdmin**](AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up | -[**validateAccessToken**](AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | - - -# **changePassword** -> UserResponseDto changePassword(changePasswordDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AuthenticationApi(); -final changePasswordDto = ChangePasswordDto(); // ChangePasswordDto | - -try { - final result = api_instance.changePassword(changePasswordDto); - print(result); -} catch (e) { - print('Exception when calling AuthenticationApi->changePassword: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **changePasswordDto** | [**ChangePasswordDto**](ChangePasswordDto.md)| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **login** -> LoginResponseDto login(loginCredentialDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = AuthenticationApi(); -final loginCredentialDto = LoginCredentialDto(); // LoginCredentialDto | - -try { - final result = api_instance.login(loginCredentialDto); - print(result); -} catch (e) { - print('Exception when calling AuthenticationApi->login: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **loginCredentialDto** | [**LoginCredentialDto**](LoginCredentialDto.md)| | - -### Return type - -[**LoginResponseDto**](LoginResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **logout** -> LogoutResponseDto logout() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AuthenticationApi(); - -try { - final result = api_instance.logout(); - print(result); -} catch (e) { - print('Exception when calling AuthenticationApi->logout: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**LogoutResponseDto**](LogoutResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **signUpAdmin** -> UserResponseDto signUpAdmin(signUpDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = AuthenticationApi(); -final signUpDto = SignUpDto(); // SignUpDto | - -try { - final result = api_instance.signUpAdmin(signUpDto); - print(result); -} catch (e) { - print('Exception when calling AuthenticationApi->signUpAdmin: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **signUpDto** | [**SignUpDto**](SignUpDto.md)| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **validateAccessToken** -> ValidateAccessTokenResponseDto validateAccessToken() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = AuthenticationApi(); - -try { - final result = api_instance.validateAccessToken(); - print(result); -} catch (e) { - print('Exception when calling AuthenticationApi->validateAccessToken: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ValidateAccessTokenResponseDto**](ValidateAccessTokenResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/BulkIdResponseDto.md b/mobile/openapi/doc/BulkIdResponseDto.md deleted file mode 100644 index 27ad767e6e..0000000000 --- a/mobile/openapi/doc/BulkIdResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.BulkIdResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**error** | **String** | | [optional] -**id** | **String** | | -**success** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/BulkIdsDto.md b/mobile/openapi/doc/BulkIdsDto.md deleted file mode 100644 index 71f1badd60..0000000000 --- a/mobile/openapi/doc/BulkIdsDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.BulkIdsDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**ids** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CLIPConfig.md b/mobile/openapi/doc/CLIPConfig.md deleted file mode 100644 index 13c2d56ae3..0000000000 --- a/mobile/openapi/doc/CLIPConfig.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.CLIPConfig - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | -**mode** | [**CLIPMode**](CLIPMode.md) | | [optional] -**modelName** | **String** | | -**modelType** | [**ModelType**](ModelType.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CLIPMode.md b/mobile/openapi/doc/CLIPMode.md deleted file mode 100644 index 09c048a89c..0000000000 --- a/mobile/openapi/doc/CLIPMode.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.CLIPMode - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CQMode.md b/mobile/openapi/doc/CQMode.md deleted file mode 100644 index 0375443a1f..0000000000 --- a/mobile/openapi/doc/CQMode.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.CQMode - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ChangePasswordDto.md b/mobile/openapi/doc/ChangePasswordDto.md deleted file mode 100644 index ff23b2a822..0000000000 --- a/mobile/openapi/doc/ChangePasswordDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.ChangePasswordDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**newPassword** | **String** | | -**password** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CheckExistingAssetsDto.md b/mobile/openapi/doc/CheckExistingAssetsDto.md deleted file mode 100644 index 878e200fdf..0000000000 --- a/mobile/openapi/doc/CheckExistingAssetsDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.CheckExistingAssetsDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**deviceAssetIds** | **List** | | [default to const []] -**deviceId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CheckExistingAssetsResponseDto.md b/mobile/openapi/doc/CheckExistingAssetsResponseDto.md deleted file mode 100644 index c9486005fd..0000000000 --- a/mobile/openapi/doc/CheckExistingAssetsResponseDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.CheckExistingAssetsResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**existingIds** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/Colorspace.md b/mobile/openapi/doc/Colorspace.md deleted file mode 100644 index 6f49da91f6..0000000000 --- a/mobile/openapi/doc/Colorspace.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.Colorspace - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CreateAlbumDto.md b/mobile/openapi/doc/CreateAlbumDto.md deleted file mode 100644 index 34035d4af6..0000000000 --- a/mobile/openapi/doc/CreateAlbumDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.CreateAlbumDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albumName** | **String** | | -**albumUsers** | [**List**](AlbumUserCreateDto.md) | This property was added in v1.104.0 | [optional] [default to const []] -**assetIds** | **List** | | [optional] [default to const []] -**description** | **String** | | [optional] -**sharedWithUserIds** | **List** | This property was deprecated in v1.104.0 | [optional] [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CreateLibraryDto.md b/mobile/openapi/doc/CreateLibraryDto.md deleted file mode 100644 index 01a2a0f917..0000000000 --- a/mobile/openapi/doc/CreateLibraryDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.CreateLibraryDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**exclusionPatterns** | **List** | | [optional] [default to const []] -**importPaths** | **List** | | [optional] [default to const []] -**isVisible** | **bool** | | [optional] -**name** | **String** | | [optional] -**ownerId** | **String** | | -**type** | [**LibraryType**](LibraryType.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CreateProfileImageResponseDto.md b/mobile/openapi/doc/CreateProfileImageResponseDto.md deleted file mode 100644 index 968f262b39..0000000000 --- a/mobile/openapi/doc/CreateProfileImageResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.CreateProfileImageResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**profileImagePath** | **String** | | -**userId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CreateTagDto.md b/mobile/openapi/doc/CreateTagDto.md deleted file mode 100644 index 729b39de3f..0000000000 --- a/mobile/openapi/doc/CreateTagDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.CreateTagDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**name** | **String** | | -**type** | [**TagTypeEnum**](TagTypeEnum.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/CreateUserDto.md b/mobile/openapi/doc/CreateUserDto.md deleted file mode 100644 index 477f1f08d2..0000000000 --- a/mobile/openapi/doc/CreateUserDto.md +++ /dev/null @@ -1,22 +0,0 @@ -# openapi.model.CreateUserDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**email** | **String** | | -**memoriesEnabled** | **bool** | | [optional] -**name** | **String** | | -**notify** | **bool** | | [optional] -**password** | **String** | | -**quotaSizeInBytes** | **int** | | [optional] -**shouldChangePassword** | **bool** | | [optional] -**storageLabel** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/DeleteUserDto.md b/mobile/openapi/doc/DeleteUserDto.md deleted file mode 100644 index 50894b6167..0000000000 --- a/mobile/openapi/doc/DeleteUserDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.DeleteUserDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**force** | **bool** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/DownloadApi.md b/mobile/openapi/doc/DownloadApi.md deleted file mode 100644 index cc5cde5c15..0000000000 --- a/mobile/openapi/doc/DownloadApi.md +++ /dev/null @@ -1,187 +0,0 @@ -# openapi.api.DownloadApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**downloadArchive**](DownloadApi.md#downloadarchive) | **POST** /download/archive | -[**downloadFile**](DownloadApi.md#downloadfile) | **POST** /download/asset/{id} | -[**getDownloadInfo**](DownloadApi.md#getdownloadinfo) | **POST** /download/info | - - -# **downloadArchive** -> MultipartFile downloadArchive(assetIdsDto, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = DownloadApi(); -final assetIdsDto = AssetIdsDto(); // AssetIdsDto | -final key = key_example; // String | - -try { - final result = api_instance.downloadArchive(assetIdsDto, key); - print(result); -} catch (e) { - print('Exception when calling DownloadApi->downloadArchive: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetIdsDto** | [**AssetIdsDto**](AssetIdsDto.md)| | - **key** | **String**| | [optional] - -### Return type - -[**MultipartFile**](MultipartFile.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/octet-stream - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **downloadFile** -> MultipartFile downloadFile(id, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = DownloadApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final key = key_example; // String | - -try { - final result = api_instance.downloadFile(id, key); - print(result); -} catch (e) { - print('Exception when calling DownloadApi->downloadFile: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **key** | **String**| | [optional] - -### Return type - -[**MultipartFile**](MultipartFile.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/octet-stream - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getDownloadInfo** -> DownloadResponseDto getDownloadInfo(downloadInfoDto, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = DownloadApi(); -final downloadInfoDto = DownloadInfoDto(); // DownloadInfoDto | -final key = key_example; // String | - -try { - final result = api_instance.getDownloadInfo(downloadInfoDto, key); - print(result); -} catch (e) { - print('Exception when calling DownloadApi->getDownloadInfo: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **downloadInfoDto** | [**DownloadInfoDto**](DownloadInfoDto.md)| | - **key** | **String**| | [optional] - -### Return type - -[**DownloadResponseDto**](DownloadResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/DownloadArchiveInfo.md b/mobile/openapi/doc/DownloadArchiveInfo.md deleted file mode 100644 index 9094270f0e..0000000000 --- a/mobile/openapi/doc/DownloadArchiveInfo.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.DownloadArchiveInfo - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetIds** | **List** | | [default to const []] -**size** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/DownloadInfoDto.md b/mobile/openapi/doc/DownloadInfoDto.md deleted file mode 100644 index 14d5d1e712..0000000000 --- a/mobile/openapi/doc/DownloadInfoDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.DownloadInfoDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albumId** | **String** | | [optional] -**archiveSize** | **int** | | [optional] -**assetIds** | **List** | | [optional] [default to const []] -**userId** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/DownloadResponseDto.md b/mobile/openapi/doc/DownloadResponseDto.md deleted file mode 100644 index 085d69a4e8..0000000000 --- a/mobile/openapi/doc/DownloadResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.DownloadResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**archives** | [**List**](DownloadArchiveInfo.md) | | [default to const []] -**totalSize** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/EntityType.md b/mobile/openapi/doc/EntityType.md deleted file mode 100644 index a01b3cf5e3..0000000000 --- a/mobile/openapi/doc/EntityType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.EntityType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ExifResponseDto.md b/mobile/openapi/doc/ExifResponseDto.md deleted file mode 100644 index 065495dcd0..0000000000 --- a/mobile/openapi/doc/ExifResponseDto.md +++ /dev/null @@ -1,35 +0,0 @@ -# openapi.model.ExifResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**city** | **String** | | [optional] -**country** | **String** | | [optional] -**dateTimeOriginal** | [**DateTime**](DateTime.md) | | [optional] -**description** | **String** | | [optional] -**exifImageHeight** | **num** | | [optional] -**exifImageWidth** | **num** | | [optional] -**exposureTime** | **String** | | [optional] -**fNumber** | **num** | | [optional] -**fileSizeInByte** | **int** | | [optional] -**focalLength** | **num** | | [optional] -**iso** | **num** | | [optional] -**latitude** | **num** | | [optional] -**lensModel** | **String** | | [optional] -**longitude** | **num** | | [optional] -**make** | **String** | | [optional] -**model** | **String** | | [optional] -**modifyDate** | [**DateTime**](DateTime.md) | | [optional] -**orientation** | **String** | | [optional] -**projectionType** | **String** | | [optional] -**state** | **String** | | [optional] -**timeZone** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/FaceApi.md b/mobile/openapi/doc/FaceApi.md deleted file mode 100644 index a58e2a029b..0000000000 --- a/mobile/openapi/doc/FaceApi.md +++ /dev/null @@ -1,183 +0,0 @@ -# openapi.api.FaceApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getFaces**](FaceApi.md#getfaces) | **GET** /face | -[**reassignFacesById**](FaceApi.md#reassignfacesbyid) | **PUT** /face/{id} | -[**unassignFace**](FaceApi.md#unassignface) | **DELETE** /face/{id} | - - -# **getFaces** -> List getFaces(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = FaceApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getFaces(id); - print(result); -} catch (e) { - print('Exception when calling FaceApi->getFaces: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**List**](AssetFaceResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **reassignFacesById** -> PersonResponseDto reassignFacesById(id, faceDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = FaceApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final faceDto = FaceDto(); // FaceDto | - -try { - final result = api_instance.reassignFacesById(id, faceDto); - print(result); -} catch (e) { - print('Exception when calling FaceApi->reassignFacesById: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **faceDto** | [**FaceDto**](FaceDto.md)| | - -### Return type - -[**PersonResponseDto**](PersonResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **unassignFace** -> AssetFaceResponseDto unassignFace(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = FaceApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.unassignFace(id); - print(result); -} catch (e) { - print('Exception when calling FaceApi->unassignFace: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**AssetFaceResponseDto**](AssetFaceResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/FaceDto.md b/mobile/openapi/doc/FaceDto.md deleted file mode 100644 index 21144a34ed..0000000000 --- a/mobile/openapi/doc/FaceDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.FaceDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**id** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/FileChecksumDto.md b/mobile/openapi/doc/FileChecksumDto.md deleted file mode 100644 index b7070431fc..0000000000 --- a/mobile/openapi/doc/FileChecksumDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.FileChecksumDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**filenames** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/FileChecksumResponseDto.md b/mobile/openapi/doc/FileChecksumResponseDto.md deleted file mode 100644 index 9cdea7280a..0000000000 --- a/mobile/openapi/doc/FileChecksumResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.FileChecksumResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**checksum** | **String** | | -**filename** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/FileReportApi.md b/mobile/openapi/doc/FileReportApi.md deleted file mode 100644 index b722c86041..0000000000 --- a/mobile/openapi/doc/FileReportApi.md +++ /dev/null @@ -1,176 +0,0 @@ -# openapi.api.FileReportApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**fixAuditFiles**](FileReportApi.md#fixauditfiles) | **POST** /report/fix | -[**getAuditFiles**](FileReportApi.md#getauditfiles) | **GET** /report | -[**getFileChecksums**](FileReportApi.md#getfilechecksums) | **POST** /report/checksum | - - -# **fixAuditFiles** -> fixAuditFiles(fileReportFixDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = FileReportApi(); -final fileReportFixDto = FileReportFixDto(); // FileReportFixDto | - -try { - api_instance.fixAuditFiles(fileReportFixDto); -} catch (e) { - print('Exception when calling FileReportApi->fixAuditFiles: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **fileReportFixDto** | [**FileReportFixDto**](FileReportFixDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAuditFiles** -> FileReportDto getAuditFiles() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = FileReportApi(); - -try { - final result = api_instance.getAuditFiles(); - print(result); -} catch (e) { - print('Exception when calling FileReportApi->getAuditFiles: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**FileReportDto**](FileReportDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getFileChecksums** -> List getFileChecksums(fileChecksumDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = FileReportApi(); -final fileChecksumDto = FileChecksumDto(); // FileChecksumDto | - -try { - final result = api_instance.getFileChecksums(fileChecksumDto); - print(result); -} catch (e) { - print('Exception when calling FileReportApi->getFileChecksums: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **fileChecksumDto** | [**FileChecksumDto**](FileChecksumDto.md)| | - -### Return type - -[**List**](FileChecksumResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/FileReportDto.md b/mobile/openapi/doc/FileReportDto.md deleted file mode 100644 index c6fd73e2d0..0000000000 --- a/mobile/openapi/doc/FileReportDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.FileReportDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**extras** | **List** | | [default to const []] -**orphans** | [**List**](FileReportItemDto.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/FileReportFixDto.md b/mobile/openapi/doc/FileReportFixDto.md deleted file mode 100644 index 58135dcb03..0000000000 --- a/mobile/openapi/doc/FileReportFixDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.FileReportFixDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**items** | [**List**](FileReportItemDto.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/FileReportItemDto.md b/mobile/openapi/doc/FileReportItemDto.md deleted file mode 100644 index 8ba2b0a343..0000000000 --- a/mobile/openapi/doc/FileReportItemDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.FileReportItemDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**checksum** | **String** | | [optional] -**entityId** | **String** | | -**entityType** | [**PathEntityType**](PathEntityType.md) | | -**pathType** | [**PathType**](PathType.md) | | -**pathValue** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ImageFormat.md b/mobile/openapi/doc/ImageFormat.md deleted file mode 100644 index 312e501c17..0000000000 --- a/mobile/openapi/doc/ImageFormat.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.ImageFormat - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/JobApi.md b/mobile/openapi/doc/JobApi.md deleted file mode 100644 index c50adbead5..0000000000 --- a/mobile/openapi/doc/JobApi.md +++ /dev/null @@ -1,123 +0,0 @@ -# openapi.api.JobApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getAllJobsStatus**](JobApi.md#getalljobsstatus) | **GET** /jobs | -[**sendJobCommand**](JobApi.md#sendjobcommand) | **PUT** /jobs/{id} | - - -# **getAllJobsStatus** -> AllJobStatusResponseDto getAllJobsStatus() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = JobApi(); - -try { - final result = api_instance.getAllJobsStatus(); - print(result); -} catch (e) { - print('Exception when calling JobApi->getAllJobsStatus: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**AllJobStatusResponseDto**](AllJobStatusResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **sendJobCommand** -> JobStatusDto sendJobCommand(id, jobCommandDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = JobApi(); -final id = ; // JobName | -final jobCommandDto = JobCommandDto(); // JobCommandDto | - -try { - final result = api_instance.sendJobCommand(id, jobCommandDto); - print(result); -} catch (e) { - print('Exception when calling JobApi->sendJobCommand: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | [**JobName**](.md)| | - **jobCommandDto** | [**JobCommandDto**](JobCommandDto.md)| | - -### Return type - -[**JobStatusDto**](JobStatusDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/JobCommand.md b/mobile/openapi/doc/JobCommand.md deleted file mode 100644 index 620e0439a5..0000000000 --- a/mobile/openapi/doc/JobCommand.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.JobCommand - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/JobCommandDto.md b/mobile/openapi/doc/JobCommandDto.md deleted file mode 100644 index 49dc499f46..0000000000 --- a/mobile/openapi/doc/JobCommandDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.JobCommandDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**command** | [**JobCommand**](JobCommand.md) | | -**force** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/JobCountsDto.md b/mobile/openapi/doc/JobCountsDto.md deleted file mode 100644 index 25154690ab..0000000000 --- a/mobile/openapi/doc/JobCountsDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.JobCountsDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**active** | **int** | | -**completed** | **int** | | -**delayed** | **int** | | -**failed** | **int** | | -**paused** | **int** | | -**waiting** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/JobName.md b/mobile/openapi/doc/JobName.md deleted file mode 100644 index 43fb27c794..0000000000 --- a/mobile/openapi/doc/JobName.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.JobName - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/JobSettingsDto.md b/mobile/openapi/doc/JobSettingsDto.md deleted file mode 100644 index 4c849feaae..0000000000 --- a/mobile/openapi/doc/JobSettingsDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.JobSettingsDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**concurrency** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/JobStatusDto.md b/mobile/openapi/doc/JobStatusDto.md deleted file mode 100644 index ba85c3b25b..0000000000 --- a/mobile/openapi/doc/JobStatusDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.JobStatusDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**jobCounts** | [**JobCountsDto**](JobCountsDto.md) | | -**queueStatus** | [**QueueStatusDto**](QueueStatusDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/LibraryApi.md b/mobile/openapi/doc/LibraryApi.md deleted file mode 100644 index 8a204788bb..0000000000 --- a/mobile/openapi/doc/LibraryApi.md +++ /dev/null @@ -1,520 +0,0 @@ -# openapi.api.LibraryApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**createLibrary**](LibraryApi.md#createlibrary) | **POST** /library | -[**deleteLibrary**](LibraryApi.md#deletelibrary) | **DELETE** /library/{id} | -[**getAllLibraries**](LibraryApi.md#getalllibraries) | **GET** /library | -[**getLibrary**](LibraryApi.md#getlibrary) | **GET** /library/{id} | -[**getLibraryStatistics**](LibraryApi.md#getlibrarystatistics) | **GET** /library/{id}/statistics | -[**removeOfflineFiles**](LibraryApi.md#removeofflinefiles) | **POST** /library/{id}/removeOffline | -[**scanLibrary**](LibraryApi.md#scanlibrary) | **POST** /library/{id}/scan | -[**updateLibrary**](LibraryApi.md#updatelibrary) | **PUT** /library/{id} | -[**validate**](LibraryApi.md#validate) | **POST** /library/{id}/validate | - - -# **createLibrary** -> LibraryResponseDto createLibrary(createLibraryDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final createLibraryDto = CreateLibraryDto(); // CreateLibraryDto | - -try { - final result = api_instance.createLibrary(createLibraryDto); - print(result); -} catch (e) { - print('Exception when calling LibraryApi->createLibrary: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **createLibraryDto** | [**CreateLibraryDto**](CreateLibraryDto.md)| | - -### Return type - -[**LibraryResponseDto**](LibraryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteLibrary** -> deleteLibrary(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.deleteLibrary(id); -} catch (e) { - print('Exception when calling LibraryApi->deleteLibrary: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllLibraries** -> List getAllLibraries(type) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final type = ; // LibraryType | - -try { - final result = api_instance.getAllLibraries(type); - print(result); -} catch (e) { - print('Exception when calling LibraryApi->getAllLibraries: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **type** | [**LibraryType**](.md)| | [optional] - -### Return type - -[**List**](LibraryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getLibrary** -> LibraryResponseDto getLibrary(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getLibrary(id); - print(result); -} catch (e) { - print('Exception when calling LibraryApi->getLibrary: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**LibraryResponseDto**](LibraryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getLibraryStatistics** -> LibraryStatsResponseDto getLibraryStatistics(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getLibraryStatistics(id); - print(result); -} catch (e) { - print('Exception when calling LibraryApi->getLibraryStatistics: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**LibraryStatsResponseDto**](LibraryStatsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **removeOfflineFiles** -> removeOfflineFiles(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.removeOfflineFiles(id); -} catch (e) { - print('Exception when calling LibraryApi->removeOfflineFiles: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **scanLibrary** -> scanLibrary(id, scanLibraryDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final scanLibraryDto = ScanLibraryDto(); // ScanLibraryDto | - -try { - api_instance.scanLibrary(id, scanLibraryDto); -} catch (e) { - print('Exception when calling LibraryApi->scanLibrary: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **scanLibraryDto** | [**ScanLibraryDto**](ScanLibraryDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateLibrary** -> LibraryResponseDto updateLibrary(id, updateLibraryDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final updateLibraryDto = UpdateLibraryDto(); // UpdateLibraryDto | - -try { - final result = api_instance.updateLibrary(id, updateLibraryDto); - print(result); -} catch (e) { - print('Exception when calling LibraryApi->updateLibrary: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **updateLibraryDto** | [**UpdateLibraryDto**](UpdateLibraryDto.md)| | - -### Return type - -[**LibraryResponseDto**](LibraryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **validate** -> ValidateLibraryResponseDto validate(id, validateLibraryDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = LibraryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final validateLibraryDto = ValidateLibraryDto(); // ValidateLibraryDto | - -try { - final result = api_instance.validate(id, validateLibraryDto); - print(result); -} catch (e) { - print('Exception when calling LibraryApi->validate: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **validateLibraryDto** | [**ValidateLibraryDto**](ValidateLibraryDto.md)| | - -### Return type - -[**ValidateLibraryResponseDto**](ValidateLibraryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/LibraryResponseDto.md b/mobile/openapi/doc/LibraryResponseDto.md deleted file mode 100644 index e7283c11b6..0000000000 --- a/mobile/openapi/doc/LibraryResponseDto.md +++ /dev/null @@ -1,24 +0,0 @@ -# openapi.model.LibraryResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetCount** | **int** | | -**createdAt** | [**DateTime**](DateTime.md) | | -**exclusionPatterns** | **List** | | [default to const []] -**id** | **String** | | -**importPaths** | **List** | | [default to const []] -**name** | **String** | | -**ownerId** | **String** | | -**refreshedAt** | [**DateTime**](DateTime.md) | | -**type** | [**LibraryType**](LibraryType.md) | | -**updatedAt** | [**DateTime**](DateTime.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/LibraryStatsResponseDto.md b/mobile/openapi/doc/LibraryStatsResponseDto.md deleted file mode 100644 index 18c9fdb121..0000000000 --- a/mobile/openapi/doc/LibraryStatsResponseDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.LibraryStatsResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**photos** | **int** | | [default to 0] -**total** | **int** | | [default to 0] -**usage** | **int** | | [default to 0] -**videos** | **int** | | [default to 0] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/LibraryType.md b/mobile/openapi/doc/LibraryType.md deleted file mode 100644 index 0bd5a3a14b..0000000000 --- a/mobile/openapi/doc/LibraryType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.LibraryType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/LogLevel.md b/mobile/openapi/doc/LogLevel.md deleted file mode 100644 index 84b40e5d80..0000000000 --- a/mobile/openapi/doc/LogLevel.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.LogLevel - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/LoginCredentialDto.md b/mobile/openapi/doc/LoginCredentialDto.md deleted file mode 100644 index bf8eb3d21e..0000000000 --- a/mobile/openapi/doc/LoginCredentialDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.LoginCredentialDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**email** | **String** | | -**password** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/LoginResponseDto.md b/mobile/openapi/doc/LoginResponseDto.md deleted file mode 100644 index bd37dc4200..0000000000 --- a/mobile/openapi/doc/LoginResponseDto.md +++ /dev/null @@ -1,21 +0,0 @@ -# openapi.model.LoginResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**accessToken** | **String** | | -**isAdmin** | **bool** | | -**name** | **String** | | -**profileImagePath** | **String** | | -**shouldChangePassword** | **bool** | | -**userEmail** | **String** | | -**userId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/LogoutResponseDto.md b/mobile/openapi/doc/LogoutResponseDto.md deleted file mode 100644 index 4231190bb2..0000000000 --- a/mobile/openapi/doc/LogoutResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.LogoutResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**redirectUri** | **String** | | -**successful** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MapMarkerResponseDto.md b/mobile/openapi/doc/MapMarkerResponseDto.md deleted file mode 100644 index 81d8224dbf..0000000000 --- a/mobile/openapi/doc/MapMarkerResponseDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.MapMarkerResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**city** | **String** | | -**country** | **String** | | -**id** | **String** | | -**lat** | **double** | | -**lon** | **double** | | -**state** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MapTheme.md b/mobile/openapi/doc/MapTheme.md deleted file mode 100644 index 29fd8d9983..0000000000 --- a/mobile/openapi/doc/MapTheme.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.MapTheme - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MemoryApi.md b/mobile/openapi/doc/MemoryApi.md deleted file mode 100644 index 5795669a50..0000000000 --- a/mobile/openapi/doc/MemoryApi.md +++ /dev/null @@ -1,406 +0,0 @@ -# openapi.api.MemoryApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**addMemoryAssets**](MemoryApi.md#addmemoryassets) | **PUT** /memories/{id}/assets | -[**createMemory**](MemoryApi.md#creatememory) | **POST** /memories | -[**deleteMemory**](MemoryApi.md#deletememory) | **DELETE** /memories/{id} | -[**getMemory**](MemoryApi.md#getmemory) | **GET** /memories/{id} | -[**removeMemoryAssets**](MemoryApi.md#removememoryassets) | **DELETE** /memories/{id}/assets | -[**searchMemories**](MemoryApi.md#searchmemories) | **GET** /memories | -[**updateMemory**](MemoryApi.md#updatememory) | **PUT** /memories/{id} | - - -# **addMemoryAssets** -> List addMemoryAssets(id, bulkIdsDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = MemoryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final bulkIdsDto = BulkIdsDto(); // BulkIdsDto | - -try { - final result = api_instance.addMemoryAssets(id, bulkIdsDto); - print(result); -} catch (e) { - print('Exception when calling MemoryApi->addMemoryAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **bulkIdsDto** | [**BulkIdsDto**](BulkIdsDto.md)| | - -### Return type - -[**List**](BulkIdResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **createMemory** -> MemoryResponseDto createMemory(memoryCreateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = MemoryApi(); -final memoryCreateDto = MemoryCreateDto(); // MemoryCreateDto | - -try { - final result = api_instance.createMemory(memoryCreateDto); - print(result); -} catch (e) { - print('Exception when calling MemoryApi->createMemory: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **memoryCreateDto** | [**MemoryCreateDto**](MemoryCreateDto.md)| | - -### Return type - -[**MemoryResponseDto**](MemoryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteMemory** -> deleteMemory(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = MemoryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.deleteMemory(id); -} catch (e) { - print('Exception when calling MemoryApi->deleteMemory: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getMemory** -> MemoryResponseDto getMemory(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = MemoryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getMemory(id); - print(result); -} catch (e) { - print('Exception when calling MemoryApi->getMemory: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**MemoryResponseDto**](MemoryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **removeMemoryAssets** -> List removeMemoryAssets(id, bulkIdsDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = MemoryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final bulkIdsDto = BulkIdsDto(); // BulkIdsDto | - -try { - final result = api_instance.removeMemoryAssets(id, bulkIdsDto); - print(result); -} catch (e) { - print('Exception when calling MemoryApi->removeMemoryAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **bulkIdsDto** | [**BulkIdsDto**](BulkIdsDto.md)| | - -### Return type - -[**List**](BulkIdResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **searchMemories** -> List searchMemories() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = MemoryApi(); - -try { - final result = api_instance.searchMemories(); - print(result); -} catch (e) { - print('Exception when calling MemoryApi->searchMemories: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](MemoryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateMemory** -> MemoryResponseDto updateMemory(id, memoryUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = MemoryApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final memoryUpdateDto = MemoryUpdateDto(); // MemoryUpdateDto | - -try { - final result = api_instance.updateMemory(id, memoryUpdateDto); - print(result); -} catch (e) { - print('Exception when calling MemoryApi->updateMemory: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **memoryUpdateDto** | [**MemoryUpdateDto**](MemoryUpdateDto.md)| | - -### Return type - -[**MemoryResponseDto**](MemoryResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/MemoryCreateDto.md b/mobile/openapi/doc/MemoryCreateDto.md deleted file mode 100644 index e0b0ef5a54..0000000000 --- a/mobile/openapi/doc/MemoryCreateDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.MemoryCreateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assetIds** | **List** | | [optional] [default to const []] -**data** | [**OnThisDayDto**](OnThisDayDto.md) | | -**isSaved** | **bool** | | [optional] -**memoryAt** | [**DateTime**](DateTime.md) | | -**seenAt** | [**DateTime**](DateTime.md) | | [optional] -**type** | [**MemoryType**](MemoryType.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MemoryLaneResponseDto.md b/mobile/openapi/doc/MemoryLaneResponseDto.md deleted file mode 100644 index 7d08b512cc..0000000000 --- a/mobile/openapi/doc/MemoryLaneResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.MemoryLaneResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assets** | [**List**](AssetResponseDto.md) | | [default to const []] -**title** | **String** | This property was deprecated in v1.100.0 | -**yearsAgo** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MemoryResponseDto.md b/mobile/openapi/doc/MemoryResponseDto.md deleted file mode 100644 index 59a8363119..0000000000 --- a/mobile/openapi/doc/MemoryResponseDto.md +++ /dev/null @@ -1,25 +0,0 @@ -# openapi.model.MemoryResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assets** | [**List**](AssetResponseDto.md) | | [default to const []] -**createdAt** | [**DateTime**](DateTime.md) | | -**data** | [**OnThisDayDto**](OnThisDayDto.md) | | -**deletedAt** | [**DateTime**](DateTime.md) | | [optional] -**id** | **String** | | -**isSaved** | **bool** | | -**memoryAt** | [**DateTime**](DateTime.md) | | -**ownerId** | **String** | | -**seenAt** | [**DateTime**](DateTime.md) | | [optional] -**type** | **String** | | -**updatedAt** | [**DateTime**](DateTime.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MemoryType.md b/mobile/openapi/doc/MemoryType.md deleted file mode 100644 index c8dea25bed..0000000000 --- a/mobile/openapi/doc/MemoryType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.MemoryType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MemoryUpdateDto.md b/mobile/openapi/doc/MemoryUpdateDto.md deleted file mode 100644 index 7a48e84e88..0000000000 --- a/mobile/openapi/doc/MemoryUpdateDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.MemoryUpdateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**isSaved** | **bool** | | [optional] -**memoryAt** | [**DateTime**](DateTime.md) | | [optional] -**seenAt** | [**DateTime**](DateTime.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MergePersonDto.md b/mobile/openapi/doc/MergePersonDto.md deleted file mode 100644 index 606f389de1..0000000000 --- a/mobile/openapi/doc/MergePersonDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.MergePersonDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**ids** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/MetadataSearchDto.md b/mobile/openapi/doc/MetadataSearchDto.md deleted file mode 100644 index d6eb2c34be..0000000000 --- a/mobile/openapi/doc/MetadataSearchDto.md +++ /dev/null @@ -1,57 +0,0 @@ -# openapi.model.MetadataSearchDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**checksum** | **String** | | [optional] -**city** | **String** | | [optional] -**country** | **String** | | [optional] -**createdAfter** | [**DateTime**](DateTime.md) | | [optional] -**createdBefore** | [**DateTime**](DateTime.md) | | [optional] -**deviceAssetId** | **String** | | [optional] -**deviceId** | **String** | | [optional] -**encodedVideoPath** | **String** | | [optional] -**id** | **String** | | [optional] -**isArchived** | **bool** | | [optional] -**isEncoded** | **bool** | | [optional] -**isFavorite** | **bool** | | [optional] -**isMotion** | **bool** | | [optional] -**isNotInAlbum** | **bool** | | [optional] -**isOffline** | **bool** | | [optional] -**isVisible** | **bool** | | [optional] -**lensModel** | **String** | | [optional] -**libraryId** | **String** | | [optional] -**make** | **String** | | [optional] -**model** | **String** | | [optional] -**order** | [**AssetOrder**](AssetOrder.md) | | [optional] -**originalFileName** | **String** | | [optional] -**originalPath** | **String** | | [optional] -**page** | **num** | | [optional] -**personIds** | **List** | | [optional] [default to const []] -**previewPath** | **String** | | [optional] -**resizePath** | **String** | This property was deprecated in v1.100.0 | [optional] -**size** | **num** | | [optional] -**state** | **String** | | [optional] -**takenAfter** | [**DateTime**](DateTime.md) | | [optional] -**takenBefore** | [**DateTime**](DateTime.md) | | [optional] -**thumbnailPath** | **String** | | [optional] -**trashedAfter** | [**DateTime**](DateTime.md) | | [optional] -**trashedBefore** | [**DateTime**](DateTime.md) | | [optional] -**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | | [optional] -**updatedAfter** | [**DateTime**](DateTime.md) | | [optional] -**updatedBefore** | [**DateTime**](DateTime.md) | | [optional] -**webpPath** | **String** | This property was deprecated in v1.100.0 | [optional] -**withArchived** | **bool** | | [optional] [default to false] -**withDeleted** | **bool** | | [optional] -**withExif** | **bool** | | [optional] -**withPeople** | **bool** | | [optional] -**withStacked** | **bool** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ModelType.md b/mobile/openapi/doc/ModelType.md deleted file mode 100644 index ea48554b97..0000000000 --- a/mobile/openapi/doc/ModelType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.ModelType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/OAuthApi.md b/mobile/openapi/doc/OAuthApi.md deleted file mode 100644 index ce36f7163a..0000000000 --- a/mobile/openapi/doc/OAuthApi.md +++ /dev/null @@ -1,242 +0,0 @@ -# openapi.api.OAuthApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**finishOAuth**](OAuthApi.md#finishoauth) | **POST** /oauth/callback | -[**linkOAuthAccount**](OAuthApi.md#linkoauthaccount) | **POST** /oauth/link | -[**redirectOAuthToMobile**](OAuthApi.md#redirectoauthtomobile) | **GET** /oauth/mobile-redirect | -[**startOAuth**](OAuthApi.md#startoauth) | **POST** /oauth/authorize | -[**unlinkOAuthAccount**](OAuthApi.md#unlinkoauthaccount) | **POST** /oauth/unlink | - - -# **finishOAuth** -> LoginResponseDto finishOAuth(oAuthCallbackDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = OAuthApi(); -final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto | - -try { - final result = api_instance.finishOAuth(oAuthCallbackDto); - print(result); -} catch (e) { - print('Exception when calling OAuthApi->finishOAuth: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **oAuthCallbackDto** | [**OAuthCallbackDto**](OAuthCallbackDto.md)| | - -### Return type - -[**LoginResponseDto**](LoginResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **linkOAuthAccount** -> UserResponseDto linkOAuthAccount(oAuthCallbackDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = OAuthApi(); -final oAuthCallbackDto = OAuthCallbackDto(); // OAuthCallbackDto | - -try { - final result = api_instance.linkOAuthAccount(oAuthCallbackDto); - print(result); -} catch (e) { - print('Exception when calling OAuthApi->linkOAuthAccount: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **oAuthCallbackDto** | [**OAuthCallbackDto**](OAuthCallbackDto.md)| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **redirectOAuthToMobile** -> redirectOAuthToMobile() - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = OAuthApi(); - -try { - api_instance.redirectOAuthToMobile(); -} catch (e) { - print('Exception when calling OAuthApi->redirectOAuthToMobile: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -void (empty response body) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **startOAuth** -> OAuthAuthorizeResponseDto startOAuth(oAuthConfigDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = OAuthApi(); -final oAuthConfigDto = OAuthConfigDto(); // OAuthConfigDto | - -try { - final result = api_instance.startOAuth(oAuthConfigDto); - print(result); -} catch (e) { - print('Exception when calling OAuthApi->startOAuth: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **oAuthConfigDto** | [**OAuthConfigDto**](OAuthConfigDto.md)| | - -### Return type - -[**OAuthAuthorizeResponseDto**](OAuthAuthorizeResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **unlinkOAuthAccount** -> UserResponseDto unlinkOAuthAccount() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = OAuthApi(); - -try { - final result = api_instance.unlinkOAuthAccount(); - print(result); -} catch (e) { - print('Exception when calling OAuthApi->unlinkOAuthAccount: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/OAuthAuthorizeResponseDto.md b/mobile/openapi/doc/OAuthAuthorizeResponseDto.md deleted file mode 100644 index fe32d2b85f..0000000000 --- a/mobile/openapi/doc/OAuthAuthorizeResponseDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.OAuthAuthorizeResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**url** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/OAuthCallbackDto.md b/mobile/openapi/doc/OAuthCallbackDto.md deleted file mode 100644 index 0627ea834b..0000000000 --- a/mobile/openapi/doc/OAuthCallbackDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.OAuthCallbackDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**url** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/OAuthConfigDto.md b/mobile/openapi/doc/OAuthConfigDto.md deleted file mode 100644 index 0683026ddd..0000000000 --- a/mobile/openapi/doc/OAuthConfigDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.OAuthConfigDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**redirectUri** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/OnThisDayDto.md b/mobile/openapi/doc/OnThisDayDto.md deleted file mode 100644 index 178b4482bc..0000000000 --- a/mobile/openapi/doc/OnThisDayDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.OnThisDayDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**year** | **num** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PartnerApi.md b/mobile/openapi/doc/PartnerApi.md deleted file mode 100644 index 5b4624e0aa..0000000000 --- a/mobile/openapi/doc/PartnerApi.md +++ /dev/null @@ -1,238 +0,0 @@ -# openapi.api.PartnerApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**createPartner**](PartnerApi.md#createpartner) | **POST** /partner/{id} | -[**getPartners**](PartnerApi.md#getpartners) | **GET** /partner | -[**removePartner**](PartnerApi.md#removepartner) | **DELETE** /partner/{id} | -[**updatePartner**](PartnerApi.md#updatepartner) | **PUT** /partner/{id} | - - -# **createPartner** -> PartnerResponseDto createPartner(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PartnerApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.createPartner(id); - print(result); -} catch (e) { - print('Exception when calling PartnerApi->createPartner: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**PartnerResponseDto**](PartnerResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getPartners** -> List getPartners(direction) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PartnerApi(); -final direction = direction_example; // String | - -try { - final result = api_instance.getPartners(direction); - print(result); -} catch (e) { - print('Exception when calling PartnerApi->getPartners: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **direction** | **String**| | - -### Return type - -[**List**](PartnerResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **removePartner** -> removePartner(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PartnerApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.removePartner(id); -} catch (e) { - print('Exception when calling PartnerApi->removePartner: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updatePartner** -> PartnerResponseDto updatePartner(id, updatePartnerDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PartnerApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final updatePartnerDto = UpdatePartnerDto(); // UpdatePartnerDto | - -try { - final result = api_instance.updatePartner(id, updatePartnerDto); - print(result); -} catch (e) { - print('Exception when calling PartnerApi->updatePartner: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **updatePartnerDto** | [**UpdatePartnerDto**](UpdatePartnerDto.md)| | - -### Return type - -[**PartnerResponseDto**](PartnerResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/PartnerResponseDto.md b/mobile/openapi/doc/PartnerResponseDto.md deleted file mode 100644 index 5d0c4ddf37..0000000000 --- a/mobile/openapi/doc/PartnerResponseDto.md +++ /dev/null @@ -1,31 +0,0 @@ -# openapi.model.PartnerResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**avatarColor** | [**UserAvatarColor**](UserAvatarColor.md) | | -**createdAt** | [**DateTime**](DateTime.md) | | -**deletedAt** | [**DateTime**](DateTime.md) | | -**email** | **String** | | -**id** | **String** | | -**inTimeline** | **bool** | | [optional] -**isAdmin** | **bool** | | -**memoriesEnabled** | **bool** | | [optional] -**name** | **String** | | -**oauthId** | **String** | | -**profileImagePath** | **String** | | -**quotaSizeInBytes** | **int** | | -**quotaUsageInBytes** | **int** | | -**shouldChangePassword** | **bool** | | -**status** | [**UserStatus**](UserStatus.md) | | -**storageLabel** | **String** | | -**updatedAt** | [**DateTime**](DateTime.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PathEntityType.md b/mobile/openapi/doc/PathEntityType.md deleted file mode 100644 index 12783a48f0..0000000000 --- a/mobile/openapi/doc/PathEntityType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.PathEntityType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PathType.md b/mobile/openapi/doc/PathType.md deleted file mode 100644 index 48e9443688..0000000000 --- a/mobile/openapi/doc/PathType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.PathType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PeopleResponseDto.md b/mobile/openapi/doc/PeopleResponseDto.md deleted file mode 100644 index 78f9b2207c..0000000000 --- a/mobile/openapi/doc/PeopleResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.PeopleResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**hidden** | **int** | | -**people** | [**List**](PersonResponseDto.md) | | [default to const []] -**total** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PeopleUpdateDto.md b/mobile/openapi/doc/PeopleUpdateDto.md deleted file mode 100644 index 8a3538b0b5..0000000000 --- a/mobile/openapi/doc/PeopleUpdateDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.PeopleUpdateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**people** | [**List**](PeopleUpdateItem.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PeopleUpdateItem.md b/mobile/openapi/doc/PeopleUpdateItem.md deleted file mode 100644 index 381b4a1e19..0000000000 --- a/mobile/openapi/doc/PeopleUpdateItem.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.PeopleUpdateItem - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**birthDate** | [**DateTime**](DateTime.md) | Person date of birth. Note: the mobile app cannot currently set the birth date to null. | [optional] -**featureFaceAssetId** | **String** | Asset is used to get the feature face thumbnail. | [optional] -**id** | **String** | Person id. | -**isHidden** | **bool** | Person visibility | [optional] -**name** | **String** | Person name. | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PersonApi.md b/mobile/openapi/doc/PersonApi.md deleted file mode 100644 index 3ceaf812b4..0000000000 --- a/mobile/openapi/doc/PersonApi.md +++ /dev/null @@ -1,621 +0,0 @@ -# openapi.api.PersonApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**createPerson**](PersonApi.md#createperson) | **POST** /person | -[**getAllPeople**](PersonApi.md#getallpeople) | **GET** /person | -[**getPerson**](PersonApi.md#getperson) | **GET** /person/{id} | -[**getPersonAssets**](PersonApi.md#getpersonassets) | **GET** /person/{id}/assets | -[**getPersonStatistics**](PersonApi.md#getpersonstatistics) | **GET** /person/{id}/statistics | -[**getPersonThumbnail**](PersonApi.md#getpersonthumbnail) | **GET** /person/{id}/thumbnail | -[**mergePerson**](PersonApi.md#mergeperson) | **POST** /person/{id}/merge | -[**reassignFaces**](PersonApi.md#reassignfaces) | **PUT** /person/{id}/reassign | -[**unassignFaces**](PersonApi.md#unassignfaces) | **DELETE** /person | -[**updatePeople**](PersonApi.md#updatepeople) | **PUT** /person | -[**updatePerson**](PersonApi.md#updateperson) | **PUT** /person/{id} | - - -# **createPerson** -> PersonResponseDto createPerson(personCreateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final personCreateDto = PersonCreateDto(); // PersonCreateDto | - -try { - final result = api_instance.createPerson(personCreateDto); - print(result); -} catch (e) { - print('Exception when calling PersonApi->createPerson: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **personCreateDto** | [**PersonCreateDto**](PersonCreateDto.md)| | - -### Return type - -[**PersonResponseDto**](PersonResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllPeople** -> PeopleResponseDto getAllPeople(withHidden) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final withHidden = true; // bool | - -try { - final result = api_instance.getAllPeople(withHidden); - print(result); -} catch (e) { - print('Exception when calling PersonApi->getAllPeople: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **withHidden** | **bool**| | [optional] - -### Return type - -[**PeopleResponseDto**](PeopleResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getPerson** -> PersonResponseDto getPerson(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getPerson(id); - print(result); -} catch (e) { - print('Exception when calling PersonApi->getPerson: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**PersonResponseDto**](PersonResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getPersonAssets** -> List getPersonAssets(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getPersonAssets(id); - print(result); -} catch (e) { - print('Exception when calling PersonApi->getPersonAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getPersonStatistics** -> PersonStatisticsResponseDto getPersonStatistics(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getPersonStatistics(id); - print(result); -} catch (e) { - print('Exception when calling PersonApi->getPersonStatistics: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**PersonStatisticsResponseDto**](PersonStatisticsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getPersonThumbnail** -> MultipartFile getPersonThumbnail(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getPersonThumbnail(id); - print(result); -} catch (e) { - print('Exception when calling PersonApi->getPersonThumbnail: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**MultipartFile**](MultipartFile.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/octet-stream - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **mergePerson** -> List mergePerson(id, mergePersonDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final mergePersonDto = MergePersonDto(); // MergePersonDto | - -try { - final result = api_instance.mergePerson(id, mergePersonDto); - print(result); -} catch (e) { - print('Exception when calling PersonApi->mergePerson: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **mergePersonDto** | [**MergePersonDto**](MergePersonDto.md)| | - -### Return type - -[**List**](BulkIdResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **reassignFaces** -> List reassignFaces(id, assetFaceUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final assetFaceUpdateDto = AssetFaceUpdateDto(); // AssetFaceUpdateDto | - -try { - final result = api_instance.reassignFaces(id, assetFaceUpdateDto); - print(result); -} catch (e) { - print('Exception when calling PersonApi->reassignFaces: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **assetFaceUpdateDto** | [**AssetFaceUpdateDto**](AssetFaceUpdateDto.md)| | - -### Return type - -[**List**](PersonResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **unassignFaces** -> List unassignFaces(assetFaceUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = PersonApi(); -final assetFaceUpdateDto = AssetFaceUpdateDto(); // AssetFaceUpdateDto | - -try { - final result = api_instance.unassignFaces(assetFaceUpdateDto); - print(result); -} catch (e) { - print('Exception when calling PersonApi->unassignFaces: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetFaceUpdateDto** | [**AssetFaceUpdateDto**](AssetFaceUpdateDto.md)| | - -### Return type - -[**List**](BulkIdResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updatePeople** -> List updatePeople(peopleUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final peopleUpdateDto = PeopleUpdateDto(); // PeopleUpdateDto | - -try { - final result = api_instance.updatePeople(peopleUpdateDto); - print(result); -} catch (e) { - print('Exception when calling PersonApi->updatePeople: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **peopleUpdateDto** | [**PeopleUpdateDto**](PeopleUpdateDto.md)| | - -### Return type - -[**List**](BulkIdResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updatePerson** -> PersonResponseDto updatePerson(id, personUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = PersonApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final personUpdateDto = PersonUpdateDto(); // PersonUpdateDto | - -try { - final result = api_instance.updatePerson(id, personUpdateDto); - print(result); -} catch (e) { - print('Exception when calling PersonApi->updatePerson: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **personUpdateDto** | [**PersonUpdateDto**](PersonUpdateDto.md)| | - -### Return type - -[**PersonResponseDto**](PersonResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/PersonCreateDto.md b/mobile/openapi/doc/PersonCreateDto.md deleted file mode 100644 index 427c23382e..0000000000 --- a/mobile/openapi/doc/PersonCreateDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.PersonCreateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**birthDate** | [**DateTime**](DateTime.md) | Person date of birth. Note: the mobile app cannot currently set the birth date to null. | [optional] -**isHidden** | **bool** | Person visibility | [optional] -**name** | **String** | Person name. | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PersonResponseDto.md b/mobile/openapi/doc/PersonResponseDto.md deleted file mode 100644 index c2acbacd1b..0000000000 --- a/mobile/openapi/doc/PersonResponseDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.PersonResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**birthDate** | [**DateTime**](DateTime.md) | | -**id** | **String** | | -**isHidden** | **bool** | | -**name** | **String** | | -**thumbnailPath** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PersonStatisticsResponseDto.md b/mobile/openapi/doc/PersonStatisticsResponseDto.md deleted file mode 100644 index 2dda35b11a..0000000000 --- a/mobile/openapi/doc/PersonStatisticsResponseDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.PersonStatisticsResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**assets** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PersonUpdateDto.md b/mobile/openapi/doc/PersonUpdateDto.md deleted file mode 100644 index f8633e48f9..0000000000 --- a/mobile/openapi/doc/PersonUpdateDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.PersonUpdateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**birthDate** | [**DateTime**](DateTime.md) | Person date of birth. Note: the mobile app cannot currently set the birth date to null. | [optional] -**featureFaceAssetId** | **String** | Asset is used to get the feature face thumbnail. | [optional] -**isHidden** | **bool** | Person visibility | [optional] -**name** | **String** | Person name. | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PersonWithFacesResponseDto.md b/mobile/openapi/doc/PersonWithFacesResponseDto.md deleted file mode 100644 index ddef73618c..0000000000 --- a/mobile/openapi/doc/PersonWithFacesResponseDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.PersonWithFacesResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**birthDate** | [**DateTime**](DateTime.md) | | -**faces** | [**List**](AssetFaceWithoutPersonResponseDto.md) | | [default to const []] -**id** | **String** | | -**isHidden** | **bool** | | -**name** | **String** | | -**thumbnailPath** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/PlacesResponseDto.md b/mobile/openapi/doc/PlacesResponseDto.md deleted file mode 100644 index a4bf36493c..0000000000 --- a/mobile/openapi/doc/PlacesResponseDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.PlacesResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**admin1name** | **String** | | [optional] -**admin2name** | **String** | | [optional] -**latitude** | **num** | | -**longitude** | **num** | | -**name** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/QueueStatusDto.md b/mobile/openapi/doc/QueueStatusDto.md deleted file mode 100644 index ca3475678d..0000000000 --- a/mobile/openapi/doc/QueueStatusDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.QueueStatusDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**isActive** | **bool** | | -**isPaused** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ReactionLevel.md b/mobile/openapi/doc/ReactionLevel.md deleted file mode 100644 index a53955cb0a..0000000000 --- a/mobile/openapi/doc/ReactionLevel.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.ReactionLevel - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ReactionType.md b/mobile/openapi/doc/ReactionType.md deleted file mode 100644 index 0cc41e23a9..0000000000 --- a/mobile/openapi/doc/ReactionType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.ReactionType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/RecognitionConfig.md b/mobile/openapi/doc/RecognitionConfig.md deleted file mode 100644 index a5f8573e2c..0000000000 --- a/mobile/openapi/doc/RecognitionConfig.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.RecognitionConfig - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | -**maxDistance** | **double** | | -**minFaces** | **int** | | -**minScore** | **double** | | -**modelName** | **String** | | -**modelType** | [**ModelType**](ModelType.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ReverseGeocodingStateResponseDto.md b/mobile/openapi/doc/ReverseGeocodingStateResponseDto.md deleted file mode 100644 index 87f8aa8ab7..0000000000 --- a/mobile/openapi/doc/ReverseGeocodingStateResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.ReverseGeocodingStateResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**lastImportFileName** | **String** | | -**lastUpdate** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ScanLibraryDto.md b/mobile/openapi/doc/ScanLibraryDto.md deleted file mode 100644 index e2c489d852..0000000000 --- a/mobile/openapi/doc/ScanLibraryDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.ScanLibraryDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**refreshAllFiles** | **bool** | | [optional] -**refreshModifiedFiles** | **bool** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchAlbumResponseDto.md b/mobile/openapi/doc/SearchAlbumResponseDto.md deleted file mode 100644 index b7897c1263..0000000000 --- a/mobile/openapi/doc/SearchAlbumResponseDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.SearchAlbumResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**count** | **int** | | -**facets** | [**List**](SearchFacetResponseDto.md) | | [default to const []] -**items** | [**List**](AlbumResponseDto.md) | | [default to const []] -**total** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchApi.md b/mobile/openapi/doc/SearchApi.md deleted file mode 100644 index b55bd067c2..0000000000 --- a/mobile/openapi/doc/SearchApi.md +++ /dev/null @@ -1,407 +0,0 @@ -# openapi.api.SearchApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getAssetsByCity**](SearchApi.md#getassetsbycity) | **GET** /search/cities | -[**getExploreData**](SearchApi.md#getexploredata) | **GET** /search/explore | -[**getSearchSuggestions**](SearchApi.md#getsearchsuggestions) | **GET** /search/suggestions | -[**searchMetadata**](SearchApi.md#searchmetadata) | **POST** /search/metadata | -[**searchPerson**](SearchApi.md#searchperson) | **GET** /search/person | -[**searchPlaces**](SearchApi.md#searchplaces) | **GET** /search/places | -[**searchSmart**](SearchApi.md#searchsmart) | **POST** /search/smart | - - -# **getAssetsByCity** -> List getAssetsByCity() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SearchApi(); - -try { - final result = api_instance.getAssetsByCity(); - print(result); -} catch (e) { - print('Exception when calling SearchApi->getAssetsByCity: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getExploreData** -> List getExploreData() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SearchApi(); - -try { - final result = api_instance.getExploreData(); - print(result); -} catch (e) { - print('Exception when calling SearchApi->getExploreData: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](SearchExploreResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getSearchSuggestions** -> List getSearchSuggestions(type, country, make, model, state) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SearchApi(); -final type = ; // SearchSuggestionType | -final country = country_example; // String | -final make = make_example; // String | -final model = model_example; // String | -final state = state_example; // String | - -try { - final result = api_instance.getSearchSuggestions(type, country, make, model, state); - print(result); -} catch (e) { - print('Exception when calling SearchApi->getSearchSuggestions: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **type** | [**SearchSuggestionType**](.md)| | - **country** | **String**| | [optional] - **make** | **String**| | [optional] - **model** | **String**| | [optional] - **state** | **String**| | [optional] - -### Return type - -**List** - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **searchMetadata** -> SearchResponseDto searchMetadata(metadataSearchDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SearchApi(); -final metadataSearchDto = MetadataSearchDto(); // MetadataSearchDto | - -try { - final result = api_instance.searchMetadata(metadataSearchDto); - print(result); -} catch (e) { - print('Exception when calling SearchApi->searchMetadata: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **metadataSearchDto** | [**MetadataSearchDto**](MetadataSearchDto.md)| | - -### Return type - -[**SearchResponseDto**](SearchResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **searchPerson** -> List searchPerson(name, withHidden) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SearchApi(); -final name = name_example; // String | -final withHidden = true; // bool | - -try { - final result = api_instance.searchPerson(name, withHidden); - print(result); -} catch (e) { - print('Exception when calling SearchApi->searchPerson: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **name** | **String**| | - **withHidden** | **bool**| | [optional] - -### Return type - -[**List**](PersonResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **searchPlaces** -> List searchPlaces(name) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SearchApi(); -final name = name_example; // String | - -try { - final result = api_instance.searchPlaces(name); - print(result); -} catch (e) { - print('Exception when calling SearchApi->searchPlaces: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **name** | **String**| | - -### Return type - -[**List**](PlacesResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **searchSmart** -> SearchResponseDto searchSmart(smartSearchDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SearchApi(); -final smartSearchDto = SmartSearchDto(); // SmartSearchDto | - -try { - final result = api_instance.searchSmart(smartSearchDto); - print(result); -} catch (e) { - print('Exception when calling SearchApi->searchSmart: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **smartSearchDto** | [**SmartSearchDto**](SmartSearchDto.md)| | - -### Return type - -[**SearchResponseDto**](SearchResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/SearchAssetResponseDto.md b/mobile/openapi/doc/SearchAssetResponseDto.md deleted file mode 100644 index 5b55a559dc..0000000000 --- a/mobile/openapi/doc/SearchAssetResponseDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.SearchAssetResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**count** | **int** | | -**facets** | [**List**](SearchFacetResponseDto.md) | | [default to const []] -**items** | [**List**](AssetResponseDto.md) | | [default to const []] -**nextPage** | **String** | | -**total** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchExploreItem.md b/mobile/openapi/doc/SearchExploreItem.md deleted file mode 100644 index 9ac85893ef..0000000000 --- a/mobile/openapi/doc/SearchExploreItem.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SearchExploreItem - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**data** | [**AssetResponseDto**](AssetResponseDto.md) | | -**value** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchExploreResponseDto.md b/mobile/openapi/doc/SearchExploreResponseDto.md deleted file mode 100644 index 0185b3651b..0000000000 --- a/mobile/openapi/doc/SearchExploreResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SearchExploreResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**fieldName** | **String** | | -**items** | [**List**](SearchExploreItem.md) | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchFacetCountResponseDto.md b/mobile/openapi/doc/SearchFacetCountResponseDto.md deleted file mode 100644 index b9188b003c..0000000000 --- a/mobile/openapi/doc/SearchFacetCountResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SearchFacetCountResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**count** | **int** | | -**value** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchFacetResponseDto.md b/mobile/openapi/doc/SearchFacetResponseDto.md deleted file mode 100644 index 39868d06c8..0000000000 --- a/mobile/openapi/doc/SearchFacetResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SearchFacetResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**counts** | [**List**](SearchFacetCountResponseDto.md) | | [default to const []] -**fieldName** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchResponseDto.md b/mobile/openapi/doc/SearchResponseDto.md deleted file mode 100644 index 3b8ce07fdd..0000000000 --- a/mobile/openapi/doc/SearchResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SearchResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albums** | [**SearchAlbumResponseDto**](SearchAlbumResponseDto.md) | | -**assets** | [**SearchAssetResponseDto**](SearchAssetResponseDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SearchSuggestionType.md b/mobile/openapi/doc/SearchSuggestionType.md deleted file mode 100644 index e37b3f0de5..0000000000 --- a/mobile/openapi/doc/SearchSuggestionType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.SearchSuggestionType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerConfigDto.md b/mobile/openapi/doc/ServerConfigDto.md deleted file mode 100644 index 7261965bfb..0000000000 --- a/mobile/openapi/doc/ServerConfigDto.md +++ /dev/null @@ -1,21 +0,0 @@ -# openapi.model.ServerConfigDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**externalDomain** | **String** | | -**isInitialized** | **bool** | | -**isOnboarded** | **bool** | | -**loginPageMessage** | **String** | | -**oauthButtonText** | **String** | | -**trashDays** | **int** | | -**userDeleteDelay** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerFeaturesDto.md b/mobile/openapi/doc/ServerFeaturesDto.md deleted file mode 100644 index 6c32b1265c..0000000000 --- a/mobile/openapi/doc/ServerFeaturesDto.md +++ /dev/null @@ -1,26 +0,0 @@ -# openapi.model.ServerFeaturesDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**configFile** | **bool** | | -**email** | **bool** | | -**facialRecognition** | **bool** | | -**map** | **bool** | | -**oauth** | **bool** | | -**oauthAutoLaunch** | **bool** | | -**passwordLogin** | **bool** | | -**reverseGeocoding** | **bool** | | -**search** | **bool** | | -**sidecar** | **bool** | | -**smartSearch** | **bool** | | -**trash** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerInfoApi.md b/mobile/openapi/doc/ServerInfoApi.md deleted file mode 100644 index e8121a8001..0000000000 --- a/mobile/openapi/doc/ServerInfoApi.md +++ /dev/null @@ -1,345 +0,0 @@ -# openapi.api.ServerInfoApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getServerConfig**](ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | -[**getServerFeatures**](ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | -[**getServerInfo**](ServerInfoApi.md#getserverinfo) | **GET** /server-info | -[**getServerStatistics**](ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics | -[**getServerVersion**](ServerInfoApi.md#getserverversion) | **GET** /server-info/version | -[**getSupportedMediaTypes**](ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types | -[**getTheme**](ServerInfoApi.md#gettheme) | **GET** /server-info/theme | -[**pingServer**](ServerInfoApi.md#pingserver) | **GET** /server-info/ping | - - -# **getServerConfig** -> ServerConfigDto getServerConfig() - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getServerConfig(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getServerConfig: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerConfigDto**](ServerConfigDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getServerFeatures** -> ServerFeaturesDto getServerFeatures() - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getServerFeatures(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getServerFeatures: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerFeaturesDto**](ServerFeaturesDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getServerInfo** -> ServerInfoResponseDto getServerInfo() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getServerInfo(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getServerInfo: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerInfoResponseDto**](ServerInfoResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getServerStatistics** -> ServerStatsResponseDto getServerStatistics() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getServerStatistics(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getServerStatistics: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerStatsResponseDto**](ServerStatsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getServerVersion** -> ServerVersionResponseDto getServerVersion() - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getServerVersion(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getServerVersion: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerVersionResponseDto**](ServerVersionResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getSupportedMediaTypes** -> ServerMediaTypesResponseDto getSupportedMediaTypes() - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getSupportedMediaTypes(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getSupportedMediaTypes: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerMediaTypesResponseDto**](ServerMediaTypesResponseDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getTheme** -> ServerThemeDto getTheme() - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.getTheme(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->getTheme: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerThemeDto**](ServerThemeDto.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **pingServer** -> ServerPingResponse pingServer() - - - -### Example -```dart -import 'package:openapi/api.dart'; - -final api_instance = ServerInfoApi(); - -try { - final result = api_instance.pingServer(); - print(result); -} catch (e) { - print('Exception when calling ServerInfoApi->pingServer: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ServerPingResponse**](ServerPingResponse.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/ServerInfoResponseDto.md b/mobile/openapi/doc/ServerInfoResponseDto.md deleted file mode 100644 index eeabb45bf2..0000000000 --- a/mobile/openapi/doc/ServerInfoResponseDto.md +++ /dev/null @@ -1,21 +0,0 @@ -# openapi.model.ServerInfoResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**diskAvailable** | **String** | | -**diskAvailableRaw** | **int** | | -**diskSize** | **String** | | -**diskSizeRaw** | **int** | | -**diskUsagePercentage** | **double** | | -**diskUse** | **String** | | -**diskUseRaw** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerMediaTypesResponseDto.md b/mobile/openapi/doc/ServerMediaTypesResponseDto.md deleted file mode 100644 index d4c247e684..0000000000 --- a/mobile/openapi/doc/ServerMediaTypesResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.ServerMediaTypesResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**image** | **List** | | [default to const []] -**sidecar** | **List** | | [default to const []] -**video** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerPingResponse.md b/mobile/openapi/doc/ServerPingResponse.md deleted file mode 100644 index 97a79869fc..0000000000 --- a/mobile/openapi/doc/ServerPingResponse.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.ServerPingResponse - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**res** | **String** | | [readonly] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerStatsResponseDto.md b/mobile/openapi/doc/ServerStatsResponseDto.md deleted file mode 100644 index 59af9f2862..0000000000 --- a/mobile/openapi/doc/ServerStatsResponseDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.ServerStatsResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**photos** | **int** | | [default to 0] -**usage** | **int** | | [default to 0] -**usageByUser** | [**List**](UsageByUserDto.md) | | [default to const []] -**videos** | **int** | | [default to 0] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerThemeDto.md b/mobile/openapi/doc/ServerThemeDto.md deleted file mode 100644 index 506f60b793..0000000000 --- a/mobile/openapi/doc/ServerThemeDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.ServerThemeDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**customCss** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ServerVersionResponseDto.md b/mobile/openapi/doc/ServerVersionResponseDto.md deleted file mode 100644 index b48291f12f..0000000000 --- a/mobile/openapi/doc/ServerVersionResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.ServerVersionResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**major** | **int** | | -**minor** | **int** | | -**patch_** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SessionResponseDto.md b/mobile/openapi/doc/SessionResponseDto.md deleted file mode 100644 index 9d1a11cbce..0000000000 --- a/mobile/openapi/doc/SessionResponseDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.SessionResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**createdAt** | **String** | | -**current** | **bool** | | -**deviceOS** | **String** | | -**deviceType** | **String** | | -**id** | **String** | | -**updatedAt** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SessionsApi.md b/mobile/openapi/doc/SessionsApi.md deleted file mode 100644 index d082a8cfed..0000000000 --- a/mobile/openapi/doc/SessionsApi.md +++ /dev/null @@ -1,171 +0,0 @@ -# openapi.api.SessionsApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**deleteAllSessions**](SessionsApi.md#deleteallsessions) | **DELETE** /sessions | -[**deleteSession**](SessionsApi.md#deletesession) | **DELETE** /sessions/{id} | -[**getSessions**](SessionsApi.md#getsessions) | **GET** /sessions | - - -# **deleteAllSessions** -> deleteAllSessions() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SessionsApi(); - -try { - api_instance.deleteAllSessions(); -} catch (e) { - print('Exception when calling SessionsApi->deleteAllSessions: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteSession** -> deleteSession(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SessionsApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.deleteSession(id); -} catch (e) { - print('Exception when calling SessionsApi->deleteSession: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getSessions** -> List getSessions() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SessionsApi(); - -try { - final result = api_instance.getSessions(); - print(result); -} catch (e) { - print('Exception when calling SessionsApi->getSessions: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](SessionResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/SharedLinkApi.md b/mobile/openapi/doc/SharedLinkApi.md deleted file mode 100644 index ff62cf423e..0000000000 --- a/mobile/openapi/doc/SharedLinkApi.md +++ /dev/null @@ -1,470 +0,0 @@ -# openapi.api.SharedLinkApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**addSharedLinkAssets**](SharedLinkApi.md#addsharedlinkassets) | **PUT** /shared-link/{id}/assets | -[**createSharedLink**](SharedLinkApi.md#createsharedlink) | **POST** /shared-link | -[**getAllSharedLinks**](SharedLinkApi.md#getallsharedlinks) | **GET** /shared-link | -[**getMySharedLink**](SharedLinkApi.md#getmysharedlink) | **GET** /shared-link/me | -[**getSharedLinkById**](SharedLinkApi.md#getsharedlinkbyid) | **GET** /shared-link/{id} | -[**removeSharedLink**](SharedLinkApi.md#removesharedlink) | **DELETE** /shared-link/{id} | -[**removeSharedLinkAssets**](SharedLinkApi.md#removesharedlinkassets) | **DELETE** /shared-link/{id}/assets | -[**updateSharedLink**](SharedLinkApi.md#updatesharedlink) | **PATCH** /shared-link/{id} | - - -# **addSharedLinkAssets** -> List addSharedLinkAssets(id, assetIdsDto, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final assetIdsDto = AssetIdsDto(); // AssetIdsDto | -final key = key_example; // String | - -try { - final result = api_instance.addSharedLinkAssets(id, assetIdsDto, key); - print(result); -} catch (e) { - print('Exception when calling SharedLinkApi->addSharedLinkAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **assetIdsDto** | [**AssetIdsDto**](AssetIdsDto.md)| | - **key** | **String**| | [optional] - -### Return type - -[**List**](AssetIdsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **createSharedLink** -> SharedLinkResponseDto createSharedLink(sharedLinkCreateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); -final sharedLinkCreateDto = SharedLinkCreateDto(); // SharedLinkCreateDto | - -try { - final result = api_instance.createSharedLink(sharedLinkCreateDto); - print(result); -} catch (e) { - print('Exception when calling SharedLinkApi->createSharedLink: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **sharedLinkCreateDto** | [**SharedLinkCreateDto**](SharedLinkCreateDto.md)| | - -### Return type - -[**SharedLinkResponseDto**](SharedLinkResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllSharedLinks** -> List getAllSharedLinks() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); - -try { - final result = api_instance.getAllSharedLinks(); - print(result); -} catch (e) { - print('Exception when calling SharedLinkApi->getAllSharedLinks: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](SharedLinkResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getMySharedLink** -> SharedLinkResponseDto getMySharedLink(key, password, token) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); -final key = key_example; // String | -final password = password; // String | -final token = token_example; // String | - -try { - final result = api_instance.getMySharedLink(key, password, token); - print(result); -} catch (e) { - print('Exception when calling SharedLinkApi->getMySharedLink: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **key** | **String**| | [optional] - **password** | **String**| | [optional] - **token** | **String**| | [optional] - -### Return type - -[**SharedLinkResponseDto**](SharedLinkResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getSharedLinkById** -> SharedLinkResponseDto getSharedLinkById(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getSharedLinkById(id); - print(result); -} catch (e) { - print('Exception when calling SharedLinkApi->getSharedLinkById: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**SharedLinkResponseDto**](SharedLinkResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **removeSharedLink** -> removeSharedLink(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.removeSharedLink(id); -} catch (e) { - print('Exception when calling SharedLinkApi->removeSharedLink: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **removeSharedLinkAssets** -> List removeSharedLinkAssets(id, assetIdsDto, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final assetIdsDto = AssetIdsDto(); // AssetIdsDto | -final key = key_example; // String | - -try { - final result = api_instance.removeSharedLinkAssets(id, assetIdsDto, key); - print(result); -} catch (e) { - print('Exception when calling SharedLinkApi->removeSharedLinkAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **assetIdsDto** | [**AssetIdsDto**](AssetIdsDto.md)| | - **key** | **String**| | [optional] - -### Return type - -[**List**](AssetIdsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateSharedLink** -> SharedLinkResponseDto updateSharedLink(id, sharedLinkEditDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SharedLinkApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final sharedLinkEditDto = SharedLinkEditDto(); // SharedLinkEditDto | - -try { - final result = api_instance.updateSharedLink(id, sharedLinkEditDto); - print(result); -} catch (e) { - print('Exception when calling SharedLinkApi->updateSharedLink: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **sharedLinkEditDto** | [**SharedLinkEditDto**](SharedLinkEditDto.md)| | - -### Return type - -[**SharedLinkResponseDto**](SharedLinkResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/SharedLinkCreateDto.md b/mobile/openapi/doc/SharedLinkCreateDto.md deleted file mode 100644 index 78e2089121..0000000000 --- a/mobile/openapi/doc/SharedLinkCreateDto.md +++ /dev/null @@ -1,23 +0,0 @@ -# openapi.model.SharedLinkCreateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albumId** | **String** | | [optional] -**allowDownload** | **bool** | | [optional] [default to true] -**allowUpload** | **bool** | | [optional] -**assetIds** | **List** | | [optional] [default to const []] -**description** | **String** | | [optional] -**expiresAt** | [**DateTime**](DateTime.md) | | [optional] -**password** | **String** | | [optional] -**showMetadata** | **bool** | | [optional] [default to true] -**type** | [**SharedLinkType**](SharedLinkType.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SharedLinkEditDto.md b/mobile/openapi/doc/SharedLinkEditDto.md deleted file mode 100644 index 36af31b475..0000000000 --- a/mobile/openapi/doc/SharedLinkEditDto.md +++ /dev/null @@ -1,21 +0,0 @@ -# openapi.model.SharedLinkEditDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**allowDownload** | **bool** | | [optional] -**allowUpload** | **bool** | | [optional] -**changeExpiryTime** | **bool** | Few clients cannot send null to set the expiryTime to never. Setting this flag and not sending expiryAt is considered as null instead. Clients that can send null values can ignore this. | [optional] -**description** | **String** | | [optional] -**expiresAt** | [**DateTime**](DateTime.md) | | [optional] -**password** | **String** | | [optional] -**showMetadata** | **bool** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SharedLinkResponseDto.md b/mobile/openapi/doc/SharedLinkResponseDto.md deleted file mode 100644 index 89f7c7ac82..0000000000 --- a/mobile/openapi/doc/SharedLinkResponseDto.md +++ /dev/null @@ -1,28 +0,0 @@ -# openapi.model.SharedLinkResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**album** | [**AlbumResponseDto**](AlbumResponseDto.md) | | [optional] -**allowDownload** | **bool** | | -**allowUpload** | **bool** | | -**assets** | [**List**](AssetResponseDto.md) | | [default to const []] -**createdAt** | [**DateTime**](DateTime.md) | | -**description** | **String** | | -**expiresAt** | [**DateTime**](DateTime.md) | | -**id** | **String** | | -**key** | **String** | | -**password** | **String** | | -**showMetadata** | **bool** | | -**token** | **String** | | [optional] -**type** | [**SharedLinkType**](SharedLinkType.md) | | -**userId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SharedLinkType.md b/mobile/openapi/doc/SharedLinkType.md deleted file mode 100644 index 78d7604682..0000000000 --- a/mobile/openapi/doc/SharedLinkType.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.SharedLinkType - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SignUpDto.md b/mobile/openapi/doc/SignUpDto.md deleted file mode 100644 index 9706c7c54c..0000000000 --- a/mobile/openapi/doc/SignUpDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.SignUpDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**email** | **String** | | -**name** | **String** | | -**password** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SmartInfoResponseDto.md b/mobile/openapi/doc/SmartInfoResponseDto.md deleted file mode 100644 index ea8353829d..0000000000 --- a/mobile/openapi/doc/SmartInfoResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SmartInfoResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**objects** | **List** | | [optional] [default to const []] -**tags** | **List** | | [optional] [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SmartSearchDto.md b/mobile/openapi/doc/SmartSearchDto.md deleted file mode 100644 index 145b3b0264..0000000000 --- a/mobile/openapi/doc/SmartSearchDto.md +++ /dev/null @@ -1,45 +0,0 @@ -# openapi.model.SmartSearchDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**city** | **String** | | [optional] -**country** | **String** | | [optional] -**createdAfter** | [**DateTime**](DateTime.md) | | [optional] -**createdBefore** | [**DateTime**](DateTime.md) | | [optional] -**deviceId** | **String** | | [optional] -**isArchived** | **bool** | | [optional] -**isEncoded** | **bool** | | [optional] -**isFavorite** | **bool** | | [optional] -**isMotion** | **bool** | | [optional] -**isNotInAlbum** | **bool** | | [optional] -**isOffline** | **bool** | | [optional] -**isVisible** | **bool** | | [optional] -**lensModel** | **String** | | [optional] -**libraryId** | **String** | | [optional] -**make** | **String** | | [optional] -**model** | **String** | | [optional] -**page** | **num** | | [optional] -**personIds** | **List** | | [optional] [default to const []] -**query** | **String** | | -**size** | **num** | | [optional] -**state** | **String** | | [optional] -**takenAfter** | [**DateTime**](DateTime.md) | | [optional] -**takenBefore** | [**DateTime**](DateTime.md) | | [optional] -**trashedAfter** | [**DateTime**](DateTime.md) | | [optional] -**trashedBefore** | [**DateTime**](DateTime.md) | | [optional] -**type** | [**AssetTypeEnum**](AssetTypeEnum.md) | | [optional] -**updatedAfter** | [**DateTime**](DateTime.md) | | [optional] -**updatedBefore** | [**DateTime**](DateTime.md) | | [optional] -**withArchived** | **bool** | | [optional] [default to false] -**withDeleted** | **bool** | | [optional] -**withExif** | **bool** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SyncApi.md b/mobile/openapi/doc/SyncApi.md deleted file mode 100644 index f750f7d4ba..0000000000 --- a/mobile/openapi/doc/SyncApi.md +++ /dev/null @@ -1,125 +0,0 @@ -# openapi.api.SyncApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getDeltaSync**](SyncApi.md#getdeltasync) | **POST** /sync/delta-sync | -[**getFullSyncForUser**](SyncApi.md#getfullsyncforuser) | **POST** /sync/full-sync | - - -# **getDeltaSync** -> AssetDeltaSyncResponseDto getDeltaSync(assetDeltaSyncDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SyncApi(); -final assetDeltaSyncDto = AssetDeltaSyncDto(); // AssetDeltaSyncDto | - -try { - final result = api_instance.getDeltaSync(assetDeltaSyncDto); - print(result); -} catch (e) { - print('Exception when calling SyncApi->getDeltaSync: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetDeltaSyncDto** | [**AssetDeltaSyncDto**](AssetDeltaSyncDto.md)| | - -### Return type - -[**AssetDeltaSyncResponseDto**](AssetDeltaSyncResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getFullSyncForUser** -> List getFullSyncForUser(assetFullSyncDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SyncApi(); -final assetFullSyncDto = AssetFullSyncDto(); // AssetFullSyncDto | - -try { - final result = api_instance.getFullSyncForUser(assetFullSyncDto); - print(result); -} catch (e) { - print('Exception when calling SyncApi->getFullSyncForUser: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **assetFullSyncDto** | [**AssetFullSyncDto**](AssetFullSyncDto.md)| | - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/SystemConfigApi.md b/mobile/openapi/doc/SystemConfigApi.md deleted file mode 100644 index 2d1ce0da60..0000000000 --- a/mobile/openapi/doc/SystemConfigApi.md +++ /dev/null @@ -1,283 +0,0 @@ -# openapi.api.SystemConfigApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getConfig**](SystemConfigApi.md#getconfig) | **GET** /system-config | -[**getConfigDefaults**](SystemConfigApi.md#getconfigdefaults) | **GET** /system-config/defaults | -[**getMapStyle**](SystemConfigApi.md#getmapstyle) | **GET** /system-config/map/style.json | -[**getStorageTemplateOptions**](SystemConfigApi.md#getstoragetemplateoptions) | **GET** /system-config/storage-template-options | -[**updateConfig**](SystemConfigApi.md#updateconfig) | **PUT** /system-config | - - -# **getConfig** -> SystemConfigDto getConfig() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemConfigApi(); - -try { - final result = api_instance.getConfig(); - print(result); -} catch (e) { - print('Exception when calling SystemConfigApi->getConfig: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**SystemConfigDto**](SystemConfigDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getConfigDefaults** -> SystemConfigDto getConfigDefaults() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemConfigApi(); - -try { - final result = api_instance.getConfigDefaults(); - print(result); -} catch (e) { - print('Exception when calling SystemConfigApi->getConfigDefaults: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**SystemConfigDto**](SystemConfigDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getMapStyle** -> Object getMapStyle(theme, key) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemConfigApi(); -final theme = ; // MapTheme | -final key = key_example; // String | - -try { - final result = api_instance.getMapStyle(theme, key); - print(result); -} catch (e) { - print('Exception when calling SystemConfigApi->getMapStyle: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **theme** | [**MapTheme**](.md)| | - **key** | **String**| | [optional] - -### Return type - -[**Object**](Object.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getStorageTemplateOptions** -> SystemConfigTemplateStorageOptionDto getStorageTemplateOptions() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemConfigApi(); - -try { - final result = api_instance.getStorageTemplateOptions(); - print(result); -} catch (e) { - print('Exception when calling SystemConfigApi->getStorageTemplateOptions: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**SystemConfigTemplateStorageOptionDto**](SystemConfigTemplateStorageOptionDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateConfig** -> SystemConfigDto updateConfig(systemConfigDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemConfigApi(); -final systemConfigDto = SystemConfigDto(); // SystemConfigDto | - -try { - final result = api_instance.updateConfig(systemConfigDto); - print(result); -} catch (e) { - print('Exception when calling SystemConfigApi->updateConfig: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **systemConfigDto** | [**SystemConfigDto**](SystemConfigDto.md)| | - -### Return type - -[**SystemConfigDto**](SystemConfigDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/SystemConfigDto.md b/mobile/openapi/doc/SystemConfigDto.md deleted file mode 100644 index c25d6f11c7..0000000000 --- a/mobile/openapi/doc/SystemConfigDto.md +++ /dev/null @@ -1,31 +0,0 @@ -# openapi.model.SystemConfigDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**ffmpeg** | [**SystemConfigFFmpegDto**](SystemConfigFFmpegDto.md) | | -**image** | [**SystemConfigImageDto**](SystemConfigImageDto.md) | | -**job** | [**SystemConfigJobDto**](SystemConfigJobDto.md) | | -**library_** | [**SystemConfigLibraryDto**](SystemConfigLibraryDto.md) | | -**logging** | [**SystemConfigLoggingDto**](SystemConfigLoggingDto.md) | | -**machineLearning** | [**SystemConfigMachineLearningDto**](SystemConfigMachineLearningDto.md) | | -**map** | [**SystemConfigMapDto**](SystemConfigMapDto.md) | | -**newVersionCheck** | [**SystemConfigNewVersionCheckDto**](SystemConfigNewVersionCheckDto.md) | | -**notifications** | [**SystemConfigNotificationsDto**](SystemConfigNotificationsDto.md) | | -**oauth** | [**SystemConfigOAuthDto**](SystemConfigOAuthDto.md) | | -**passwordLogin** | [**SystemConfigPasswordLoginDto**](SystemConfigPasswordLoginDto.md) | | -**reverseGeocoding** | [**SystemConfigReverseGeocodingDto**](SystemConfigReverseGeocodingDto.md) | | -**server** | [**SystemConfigServerDto**](SystemConfigServerDto.md) | | -**storageTemplate** | [**SystemConfigStorageTemplateDto**](SystemConfigStorageTemplateDto.md) | | -**theme** | [**SystemConfigThemeDto**](SystemConfigThemeDto.md) | | -**trash** | [**SystemConfigTrashDto**](SystemConfigTrashDto.md) | | -**user** | [**SystemConfigUserDto**](SystemConfigUserDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigFFmpegDto.md b/mobile/openapi/doc/SystemConfigFFmpegDto.md deleted file mode 100644 index 05fe1c4437..0000000000 --- a/mobile/openapi/doc/SystemConfigFFmpegDto.md +++ /dev/null @@ -1,34 +0,0 @@ -# openapi.model.SystemConfigFFmpegDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**accel** | [**TranscodeHWAccel**](TranscodeHWAccel.md) | | -**acceptedAudioCodecs** | [**List**](AudioCodec.md) | | [default to const []] -**acceptedVideoCodecs** | [**List**](VideoCodec.md) | | [default to const []] -**bframes** | **int** | | -**cqMode** | [**CQMode**](CQMode.md) | | -**crf** | **int** | | -**gopSize** | **int** | | -**maxBitrate** | **String** | | -**npl** | **int** | | -**preferredHwDevice** | **String** | | -**preset** | **String** | | -**refs** | **int** | | -**targetAudioCodec** | [**AudioCodec**](AudioCodec.md) | | -**targetResolution** | **String** | | -**targetVideoCodec** | [**VideoCodec**](VideoCodec.md) | | -**temporalAQ** | **bool** | | -**threads** | **int** | | -**tonemap** | [**ToneMapping**](ToneMapping.md) | | -**transcode** | [**TranscodePolicy**](TranscodePolicy.md) | | -**twoPass** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigImageDto.md b/mobile/openapi/doc/SystemConfigImageDto.md deleted file mode 100644 index 81e88045d5..0000000000 --- a/mobile/openapi/doc/SystemConfigImageDto.md +++ /dev/null @@ -1,21 +0,0 @@ -# openapi.model.SystemConfigImageDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**colorspace** | [**Colorspace**](Colorspace.md) | | -**extractEmbedded** | **bool** | | -**previewFormat** | [**ImageFormat**](ImageFormat.md) | | -**previewSize** | **int** | | -**quality** | **int** | | -**thumbnailFormat** | [**ImageFormat**](ImageFormat.md) | | -**thumbnailSize** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigJobDto.md b/mobile/openapi/doc/SystemConfigJobDto.md deleted file mode 100644 index 9b39c64de7..0000000000 --- a/mobile/openapi/doc/SystemConfigJobDto.md +++ /dev/null @@ -1,25 +0,0 @@ -# openapi.model.SystemConfigJobDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**backgroundTask** | [**JobSettingsDto**](JobSettingsDto.md) | | -**faceDetection** | [**JobSettingsDto**](JobSettingsDto.md) | | -**library_** | [**JobSettingsDto**](JobSettingsDto.md) | | -**metadataExtraction** | [**JobSettingsDto**](JobSettingsDto.md) | | -**migration** | [**JobSettingsDto**](JobSettingsDto.md) | | -**notifications** | [**JobSettingsDto**](JobSettingsDto.md) | | -**search** | [**JobSettingsDto**](JobSettingsDto.md) | | -**sidecar** | [**JobSettingsDto**](JobSettingsDto.md) | | -**smartSearch** | [**JobSettingsDto**](JobSettingsDto.md) | | -**thumbnailGeneration** | [**JobSettingsDto**](JobSettingsDto.md) | | -**videoConversion** | [**JobSettingsDto**](JobSettingsDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigLibraryDto.md b/mobile/openapi/doc/SystemConfigLibraryDto.md deleted file mode 100644 index 919ac36746..0000000000 --- a/mobile/openapi/doc/SystemConfigLibraryDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SystemConfigLibraryDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**scan** | [**SystemConfigLibraryScanDto**](SystemConfigLibraryScanDto.md) | | -**watch** | [**SystemConfigLibraryWatchDto**](SystemConfigLibraryWatchDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigLibraryScanDto.md b/mobile/openapi/doc/SystemConfigLibraryScanDto.md deleted file mode 100644 index d77bb03ce8..0000000000 --- a/mobile/openapi/doc/SystemConfigLibraryScanDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SystemConfigLibraryScanDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**cronExpression** | **String** | | -**enabled** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigLibraryWatchDto.md b/mobile/openapi/doc/SystemConfigLibraryWatchDto.md deleted file mode 100644 index 43b975e21a..0000000000 --- a/mobile/openapi/doc/SystemConfigLibraryWatchDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.SystemConfigLibraryWatchDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigLoggingDto.md b/mobile/openapi/doc/SystemConfigLoggingDto.md deleted file mode 100644 index d63f4548d3..0000000000 --- a/mobile/openapi/doc/SystemConfigLoggingDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SystemConfigLoggingDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | -**level** | [**LogLevel**](LogLevel.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigMachineLearningDto.md b/mobile/openapi/doc/SystemConfigMachineLearningDto.md deleted file mode 100644 index 7cb61d9601..0000000000 --- a/mobile/openapi/doc/SystemConfigMachineLearningDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.SystemConfigMachineLearningDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**clip** | [**CLIPConfig**](CLIPConfig.md) | | -**enabled** | **bool** | | -**facialRecognition** | [**RecognitionConfig**](RecognitionConfig.md) | | -**url** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigMapDto.md b/mobile/openapi/doc/SystemConfigMapDto.md deleted file mode 100644 index 1846563eb0..0000000000 --- a/mobile/openapi/doc/SystemConfigMapDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.SystemConfigMapDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**darkStyle** | **String** | | -**enabled** | **bool** | | -**lightStyle** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigNewVersionCheckDto.md b/mobile/openapi/doc/SystemConfigNewVersionCheckDto.md deleted file mode 100644 index 18b922de20..0000000000 --- a/mobile/openapi/doc/SystemConfigNewVersionCheckDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.SystemConfigNewVersionCheckDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigNotificationsDto.md b/mobile/openapi/doc/SystemConfigNotificationsDto.md deleted file mode 100644 index 6d91c18c83..0000000000 --- a/mobile/openapi/doc/SystemConfigNotificationsDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.SystemConfigNotificationsDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**smtp** | [**SystemConfigSmtpDto**](SystemConfigSmtpDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigOAuthDto.md b/mobile/openapi/doc/SystemConfigOAuthDto.md deleted file mode 100644 index 43694f6fc2..0000000000 --- a/mobile/openapi/doc/SystemConfigOAuthDto.md +++ /dev/null @@ -1,28 +0,0 @@ -# openapi.model.SystemConfigOAuthDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**autoLaunch** | **bool** | | -**autoRegister** | **bool** | | -**buttonText** | **String** | | -**clientId** | **String** | | -**clientSecret** | **String** | | -**defaultStorageQuota** | **num** | | -**enabled** | **bool** | | -**issuerUrl** | **String** | | -**mobileOverrideEnabled** | **bool** | | -**mobileRedirectUri** | **String** | | -**scope** | **String** | | -**signingAlgorithm** | **String** | | -**storageLabelClaim** | **String** | | -**storageQuotaClaim** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigPasswordLoginDto.md b/mobile/openapi/doc/SystemConfigPasswordLoginDto.md deleted file mode 100644 index 682a3c6447..0000000000 --- a/mobile/openapi/doc/SystemConfigPasswordLoginDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.SystemConfigPasswordLoginDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigReverseGeocodingDto.md b/mobile/openapi/doc/SystemConfigReverseGeocodingDto.md deleted file mode 100644 index 9fca6c2094..0000000000 --- a/mobile/openapi/doc/SystemConfigReverseGeocodingDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.SystemConfigReverseGeocodingDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigServerDto.md b/mobile/openapi/doc/SystemConfigServerDto.md deleted file mode 100644 index ead49eeb4f..0000000000 --- a/mobile/openapi/doc/SystemConfigServerDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SystemConfigServerDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**externalDomain** | **String** | | -**loginPageMessage** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigSmtpDto.md b/mobile/openapi/doc/SystemConfigSmtpDto.md deleted file mode 100644 index 35afe03e75..0000000000 --- a/mobile/openapi/doc/SystemConfigSmtpDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.SystemConfigSmtpDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | -**from** | **String** | | -**replyTo** | **String** | | -**transport** | [**SystemConfigSmtpTransportDto**](SystemConfigSmtpTransportDto.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigSmtpTransportDto.md b/mobile/openapi/doc/SystemConfigSmtpTransportDto.md deleted file mode 100644 index ded067f7ee..0000000000 --- a/mobile/openapi/doc/SystemConfigSmtpTransportDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.SystemConfigSmtpTransportDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**host** | **String** | | -**ignoreCert** | **bool** | | -**password** | **String** | | -**port** | **num** | | -**username** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigStorageTemplateDto.md b/mobile/openapi/doc/SystemConfigStorageTemplateDto.md deleted file mode 100644 index c456480690..0000000000 --- a/mobile/openapi/doc/SystemConfigStorageTemplateDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.SystemConfigStorageTemplateDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**enabled** | **bool** | | -**hashVerificationEnabled** | **bool** | | -**template** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigTemplateStorageOptionDto.md b/mobile/openapi/doc/SystemConfigTemplateStorageOptionDto.md deleted file mode 100644 index 6465fcbef8..0000000000 --- a/mobile/openapi/doc/SystemConfigTemplateStorageOptionDto.md +++ /dev/null @@ -1,22 +0,0 @@ -# openapi.model.SystemConfigTemplateStorageOptionDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**dayOptions** | **List** | | [default to const []] -**hourOptions** | **List** | | [default to const []] -**minuteOptions** | **List** | | [default to const []] -**monthOptions** | **List** | | [default to const []] -**presetOptions** | **List** | | [default to const []] -**secondOptions** | **List** | | [default to const []] -**weekOptions** | **List** | | [default to const []] -**yearOptions** | **List** | | [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigThemeDto.md b/mobile/openapi/doc/SystemConfigThemeDto.md deleted file mode 100644 index bcdbb690cb..0000000000 --- a/mobile/openapi/doc/SystemConfigThemeDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.SystemConfigThemeDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**customCss** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigTrashDto.md b/mobile/openapi/doc/SystemConfigTrashDto.md deleted file mode 100644 index 1cc2de7cfd..0000000000 --- a/mobile/openapi/doc/SystemConfigTrashDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.SystemConfigTrashDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**days** | **int** | | -**enabled** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemConfigUserDto.md b/mobile/openapi/doc/SystemConfigUserDto.md deleted file mode 100644 index c295954a8d..0000000000 --- a/mobile/openapi/doc/SystemConfigUserDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.SystemConfigUserDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**deleteDelay** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/SystemMetadataApi.md b/mobile/openapi/doc/SystemMetadataApi.md deleted file mode 100644 index f8c2347afe..0000000000 --- a/mobile/openapi/doc/SystemMetadataApi.md +++ /dev/null @@ -1,172 +0,0 @@ -# openapi.api.SystemMetadataApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getAdminOnboarding**](SystemMetadataApi.md#getadminonboarding) | **GET** /system-metadata/admin-onboarding | -[**getReverseGeocodingState**](SystemMetadataApi.md#getreversegeocodingstate) | **GET** /system-metadata/reverse-geocoding-state | -[**updateAdminOnboarding**](SystemMetadataApi.md#updateadminonboarding) | **POST** /system-metadata/admin-onboarding | - - -# **getAdminOnboarding** -> AdminOnboardingUpdateDto getAdminOnboarding() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemMetadataApi(); - -try { - final result = api_instance.getAdminOnboarding(); - print(result); -} catch (e) { - print('Exception when calling SystemMetadataApi->getAdminOnboarding: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**AdminOnboardingUpdateDto**](AdminOnboardingUpdateDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getReverseGeocodingState** -> ReverseGeocodingStateResponseDto getReverseGeocodingState() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemMetadataApi(); - -try { - final result = api_instance.getReverseGeocodingState(); - print(result); -} catch (e) { - print('Exception when calling SystemMetadataApi->getReverseGeocodingState: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**ReverseGeocodingStateResponseDto**](ReverseGeocodingStateResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateAdminOnboarding** -> updateAdminOnboarding(adminOnboardingUpdateDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = SystemMetadataApi(); -final adminOnboardingUpdateDto = AdminOnboardingUpdateDto(); // AdminOnboardingUpdateDto | - -try { - api_instance.updateAdminOnboarding(adminOnboardingUpdateDto); -} catch (e) { - print('Exception when calling SystemMetadataApi->updateAdminOnboarding: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **adminOnboardingUpdateDto** | [**AdminOnboardingUpdateDto**](AdminOnboardingUpdateDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/TagApi.md b/mobile/openapi/doc/TagApi.md deleted file mode 100644 index 7c5b3d9a1c..0000000000 --- a/mobile/openapi/doc/TagApi.md +++ /dev/null @@ -1,462 +0,0 @@ -# openapi.api.TagApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**createTag**](TagApi.md#createtag) | **POST** /tag | -[**deleteTag**](TagApi.md#deletetag) | **DELETE** /tag/{id} | -[**getAllTags**](TagApi.md#getalltags) | **GET** /tag | -[**getTagAssets**](TagApi.md#gettagassets) | **GET** /tag/{id}/assets | -[**getTagById**](TagApi.md#gettagbyid) | **GET** /tag/{id} | -[**tagAssets**](TagApi.md#tagassets) | **PUT** /tag/{id}/assets | -[**untagAssets**](TagApi.md#untagassets) | **DELETE** /tag/{id}/assets | -[**updateTag**](TagApi.md#updatetag) | **PATCH** /tag/{id} | - - -# **createTag** -> TagResponseDto createTag(createTagDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); -final createTagDto = CreateTagDto(); // CreateTagDto | - -try { - final result = api_instance.createTag(createTagDto); - print(result); -} catch (e) { - print('Exception when calling TagApi->createTag: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **createTagDto** | [**CreateTagDto**](CreateTagDto.md)| | - -### Return type - -[**TagResponseDto**](TagResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteTag** -> deleteTag(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - api_instance.deleteTag(id); -} catch (e) { - print('Exception when calling TagApi->deleteTag: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllTags** -> List getAllTags() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); - -try { - final result = api_instance.getAllTags(); - print(result); -} catch (e) { - print('Exception when calling TagApi->getAllTags: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](TagResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getTagAssets** -> List getTagAssets(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getTagAssets(id); - print(result); -} catch (e) { - print('Exception when calling TagApi->getTagAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getTagById** -> TagResponseDto getTagById(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getTagById(id); - print(result); -} catch (e) { - print('Exception when calling TagApi->getTagById: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**TagResponseDto**](TagResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **tagAssets** -> List tagAssets(id, assetIdsDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final assetIdsDto = AssetIdsDto(); // AssetIdsDto | - -try { - final result = api_instance.tagAssets(id, assetIdsDto); - print(result); -} catch (e) { - print('Exception when calling TagApi->tagAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **assetIdsDto** | [**AssetIdsDto**](AssetIdsDto.md)| | - -### Return type - -[**List**](AssetIdsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **untagAssets** -> List untagAssets(id, assetIdsDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final assetIdsDto = AssetIdsDto(); // AssetIdsDto | - -try { - final result = api_instance.untagAssets(id, assetIdsDto); - print(result); -} catch (e) { - print('Exception when calling TagApi->untagAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **assetIdsDto** | [**AssetIdsDto**](AssetIdsDto.md)| | - -### Return type - -[**List**](AssetIdsResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateTag** -> TagResponseDto updateTag(id, updateTagDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TagApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final updateTagDto = UpdateTagDto(); // UpdateTagDto | - -try { - final result = api_instance.updateTag(id, updateTagDto); - print(result); -} catch (e) { - print('Exception when calling TagApi->updateTag: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **updateTagDto** | [**UpdateTagDto**](UpdateTagDto.md)| | - -### Return type - -[**TagResponseDto**](TagResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/TagResponseDto.md b/mobile/openapi/doc/TagResponseDto.md deleted file mode 100644 index caa47669f3..0000000000 --- a/mobile/openapi/doc/TagResponseDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.TagResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**id** | **String** | | -**name** | **String** | | -**type** | [**TagTypeEnum**](TagTypeEnum.md) | | -**userId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/TagTypeEnum.md b/mobile/openapi/doc/TagTypeEnum.md deleted file mode 100644 index cede140906..0000000000 --- a/mobile/openapi/doc/TagTypeEnum.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.TagTypeEnum - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ThumbnailFormat.md b/mobile/openapi/doc/ThumbnailFormat.md deleted file mode 100644 index 5cd36c673f..0000000000 --- a/mobile/openapi/doc/ThumbnailFormat.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.ThumbnailFormat - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/TimeBucketResponseDto.md b/mobile/openapi/doc/TimeBucketResponseDto.md deleted file mode 100644 index 83eed89f5d..0000000000 --- a/mobile/openapi/doc/TimeBucketResponseDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.TimeBucketResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**count** | **int** | | -**timeBucket** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/TimeBucketSize.md b/mobile/openapi/doc/TimeBucketSize.md deleted file mode 100644 index e89e68d74f..0000000000 --- a/mobile/openapi/doc/TimeBucketSize.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.TimeBucketSize - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/TimelineApi.md b/mobile/openapi/doc/TimelineApi.md deleted file mode 100644 index e98efe7e23..0000000000 --- a/mobile/openapi/doc/TimelineApi.md +++ /dev/null @@ -1,167 +0,0 @@ -# openapi.api.TimelineApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**getTimeBucket**](TimelineApi.md#gettimebucket) | **GET** /timeline/bucket | -[**getTimeBuckets**](TimelineApi.md#gettimebuckets) | **GET** /timeline/buckets | - - -# **getTimeBucket** -> List getTimeBucket(size, timeBucket, albumId, isArchived, isFavorite, isTrashed, key, order, personId, userId, withPartners, withStacked) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TimelineApi(); -final size = ; // TimeBucketSize | -final timeBucket = timeBucket_example; // String | -final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final isArchived = true; // bool | -final isFavorite = true; // bool | -final isTrashed = true; // bool | -final key = key_example; // String | -final order = ; // AssetOrder | -final personId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final withPartners = true; // bool | -final withStacked = true; // bool | - -try { - final result = api_instance.getTimeBucket(size, timeBucket, albumId, isArchived, isFavorite, isTrashed, key, order, personId, userId, withPartners, withStacked); - print(result); -} catch (e) { - print('Exception when calling TimelineApi->getTimeBucket: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **size** | [**TimeBucketSize**](.md)| | - **timeBucket** | **String**| | - **albumId** | **String**| | [optional] - **isArchived** | **bool**| | [optional] - **isFavorite** | **bool**| | [optional] - **isTrashed** | **bool**| | [optional] - **key** | **String**| | [optional] - **order** | [**AssetOrder**](.md)| | [optional] - **personId** | **String**| | [optional] - **userId** | **String**| | [optional] - **withPartners** | **bool**| | [optional] - **withStacked** | **bool**| | [optional] - -### Return type - -[**List**](AssetResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getTimeBuckets** -> List getTimeBuckets(size, albumId, isArchived, isFavorite, isTrashed, key, order, personId, userId, withPartners, withStacked) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TimelineApi(); -final size = ; // TimeBucketSize | -final albumId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final isArchived = true; // bool | -final isFavorite = true; // bool | -final isTrashed = true; // bool | -final key = key_example; // String | -final order = ; // AssetOrder | -final personId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final userId = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final withPartners = true; // bool | -final withStacked = true; // bool | - -try { - final result = api_instance.getTimeBuckets(size, albumId, isArchived, isFavorite, isTrashed, key, order, personId, userId, withPartners, withStacked); - print(result); -} catch (e) { - print('Exception when calling TimelineApi->getTimeBuckets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **size** | [**TimeBucketSize**](.md)| | - **albumId** | **String**| | [optional] - **isArchived** | **bool**| | [optional] - **isFavorite** | **bool**| | [optional] - **isTrashed** | **bool**| | [optional] - **key** | **String**| | [optional] - **order** | [**AssetOrder**](.md)| | [optional] - **personId** | **String**| | [optional] - **userId** | **String**| | [optional] - **withPartners** | **bool**| | [optional] - **withStacked** | **bool**| | [optional] - -### Return type - -[**List**](TimeBucketResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/ToneMapping.md b/mobile/openapi/doc/ToneMapping.md deleted file mode 100644 index 5f3575c45f..0000000000 --- a/mobile/openapi/doc/ToneMapping.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.ToneMapping - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/TranscodeHWAccel.md b/mobile/openapi/doc/TranscodeHWAccel.md deleted file mode 100644 index c03f561660..0000000000 --- a/mobile/openapi/doc/TranscodeHWAccel.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.TranscodeHWAccel - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/TranscodePolicy.md b/mobile/openapi/doc/TranscodePolicy.md deleted file mode 100644 index bf6b88cd3a..0000000000 --- a/mobile/openapi/doc/TranscodePolicy.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.TranscodePolicy - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/TrashApi.md b/mobile/openapi/doc/TrashApi.md deleted file mode 100644 index d120d4da11..0000000000 --- a/mobile/openapi/doc/TrashApi.md +++ /dev/null @@ -1,170 +0,0 @@ -# openapi.api.TrashApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**emptyTrash**](TrashApi.md#emptytrash) | **POST** /trash/empty | -[**restoreAssets**](TrashApi.md#restoreassets) | **POST** /trash/restore/assets | -[**restoreTrash**](TrashApi.md#restoretrash) | **POST** /trash/restore | - - -# **emptyTrash** -> emptyTrash() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TrashApi(); - -try { - api_instance.emptyTrash(); -} catch (e) { - print('Exception when calling TrashApi->emptyTrash: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **restoreAssets** -> restoreAssets(bulkIdsDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TrashApi(); -final bulkIdsDto = BulkIdsDto(); // BulkIdsDto | - -try { - api_instance.restoreAssets(bulkIdsDto); -} catch (e) { - print('Exception when calling TrashApi->restoreAssets: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **bulkIdsDto** | [**BulkIdsDto**](BulkIdsDto.md)| | - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **restoreTrash** -> restoreTrash() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = TrashApi(); - -try { - api_instance.restoreTrash(); -} catch (e) { - print('Exception when calling TrashApi->restoreTrash: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/UpdateAlbumDto.md b/mobile/openapi/doc/UpdateAlbumDto.md deleted file mode 100644 index 89edf1c6ef..0000000000 --- a/mobile/openapi/doc/UpdateAlbumDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.UpdateAlbumDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**albumName** | **String** | | [optional] -**albumThumbnailAssetId** | **String** | | [optional] -**description** | **String** | | [optional] -**isActivityEnabled** | **bool** | | [optional] -**order** | [**AssetOrder**](AssetOrder.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UpdateAlbumUserDto.md b/mobile/openapi/doc/UpdateAlbumUserDto.md deleted file mode 100644 index 1a1050b4db..0000000000 --- a/mobile/openapi/doc/UpdateAlbumUserDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.UpdateAlbumUserDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**role** | [**AlbumUserRole**](AlbumUserRole.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UpdateAssetDto.md b/mobile/openapi/doc/UpdateAssetDto.md deleted file mode 100644 index cfd8f604d2..0000000000 --- a/mobile/openapi/doc/UpdateAssetDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.UpdateAssetDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**dateTimeOriginal** | **String** | | [optional] -**description** | **String** | | [optional] -**isArchived** | **bool** | | [optional] -**isFavorite** | **bool** | | [optional] -**latitude** | **num** | | [optional] -**longitude** | **num** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UpdateLibraryDto.md b/mobile/openapi/doc/UpdateLibraryDto.md deleted file mode 100644 index 0f0e2652b8..0000000000 --- a/mobile/openapi/doc/UpdateLibraryDto.md +++ /dev/null @@ -1,18 +0,0 @@ -# openapi.model.UpdateLibraryDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**exclusionPatterns** | **List** | | [optional] [default to const []] -**importPaths** | **List** | | [optional] [default to const []] -**isVisible** | **bool** | | [optional] -**name** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UpdatePartnerDto.md b/mobile/openapi/doc/UpdatePartnerDto.md deleted file mode 100644 index b336c419eb..0000000000 --- a/mobile/openapi/doc/UpdatePartnerDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.UpdatePartnerDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**inTimeline** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UpdateStackParentDto.md b/mobile/openapi/doc/UpdateStackParentDto.md deleted file mode 100644 index 750daace0c..0000000000 --- a/mobile/openapi/doc/UpdateStackParentDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.UpdateStackParentDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**newParentId** | **String** | | -**oldParentId** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UpdateTagDto.md b/mobile/openapi/doc/UpdateTagDto.md deleted file mode 100644 index 42aae30b5c..0000000000 --- a/mobile/openapi/doc/UpdateTagDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.UpdateTagDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**name** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UpdateUserDto.md b/mobile/openapi/doc/UpdateUserDto.md deleted file mode 100644 index ef4ebf869b..0000000000 --- a/mobile/openapi/doc/UpdateUserDto.md +++ /dev/null @@ -1,24 +0,0 @@ -# openapi.model.UpdateUserDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**avatarColor** | [**UserAvatarColor**](UserAvatarColor.md) | | [optional] -**email** | **String** | | [optional] -**id** | **String** | | -**isAdmin** | **bool** | | [optional] -**memoriesEnabled** | **bool** | | [optional] -**name** | **String** | | [optional] -**password** | **String** | | [optional] -**quotaSizeInBytes** | **int** | | [optional] -**shouldChangePassword** | **bool** | | [optional] -**storageLabel** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UsageByUserDto.md b/mobile/openapi/doc/UsageByUserDto.md deleted file mode 100644 index 0eb2382b65..0000000000 --- a/mobile/openapi/doc/UsageByUserDto.md +++ /dev/null @@ -1,20 +0,0 @@ -# openapi.model.UsageByUserDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**photos** | **int** | | -**quotaSizeInBytes** | **int** | | -**usage** | **int** | | -**userId** | **String** | | -**userName** | **String** | | -**videos** | **int** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UserApi.md b/mobile/openapi/doc/UserApi.md deleted file mode 100644 index 61df5d4de0..0000000000 --- a/mobile/openapi/doc/UserApi.md +++ /dev/null @@ -1,566 +0,0 @@ -# openapi.api.UserApi - -## Load the API package -```dart -import 'package:openapi/api.dart'; -``` - -All URIs are relative to */api* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**createProfileImage**](UserApi.md#createprofileimage) | **POST** /user/profile-image | -[**createUser**](UserApi.md#createuser) | **POST** /user | -[**deleteProfileImage**](UserApi.md#deleteprofileimage) | **DELETE** /user/profile-image | -[**deleteUser**](UserApi.md#deleteuser) | **DELETE** /user/{id} | -[**getAllUsers**](UserApi.md#getallusers) | **GET** /user | -[**getMyUserInfo**](UserApi.md#getmyuserinfo) | **GET** /user/me | -[**getProfileImage**](UserApi.md#getprofileimage) | **GET** /user/profile-image/{id} | -[**getUserById**](UserApi.md#getuserbyid) | **GET** /user/info/{id} | -[**restoreUser**](UserApi.md#restoreuser) | **POST** /user/{id}/restore | -[**updateUser**](UserApi.md#updateuser) | **PUT** /user | - - -# **createProfileImage** -> CreateProfileImageResponseDto createProfileImage(file) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final file = BINARY_DATA_HERE; // MultipartFile | - -try { - final result = api_instance.createProfileImage(file); - print(result); -} catch (e) { - print('Exception when calling UserApi->createProfileImage: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **file** | **MultipartFile**| | - -### Return type - -[**CreateProfileImageResponseDto**](CreateProfileImageResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: multipart/form-data - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **createUser** -> UserResponseDto createUser(createUserDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final createUserDto = CreateUserDto(); // CreateUserDto | - -try { - final result = api_instance.createUser(createUserDto); - print(result); -} catch (e) { - print('Exception when calling UserApi->createUser: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **createUserDto** | [**CreateUserDto**](CreateUserDto.md)| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteProfileImage** -> deleteProfileImage() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); - -try { - api_instance.deleteProfileImage(); -} catch (e) { - print('Exception when calling UserApi->deleteProfileImage: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -void (empty response body) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **deleteUser** -> UserResponseDto deleteUser(id, deleteUserDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | -final deleteUserDto = DeleteUserDto(); // DeleteUserDto | - -try { - final result = api_instance.deleteUser(id, deleteUserDto); - print(result); -} catch (e) { - print('Exception when calling UserApi->deleteUser: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - **deleteUserDto** | [**DeleteUserDto**](DeleteUserDto.md)| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getAllUsers** -> List getAllUsers(isAll) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final isAll = true; // bool | - -try { - final result = api_instance.getAllUsers(isAll); - print(result); -} catch (e) { - print('Exception when calling UserApi->getAllUsers: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **isAll** | **bool**| | - -### Return type - -[**List**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getMyUserInfo** -> UserResponseDto getMyUserInfo() - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); - -try { - final result = api_instance.getMyUserInfo(); - print(result); -} catch (e) { - print('Exception when calling UserApi->getMyUserInfo: $e\n'); -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getProfileImage** -> MultipartFile getProfileImage(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getProfileImage(id); - print(result); -} catch (e) { - print('Exception when calling UserApi->getProfileImage: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**MultipartFile**](MultipartFile.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/octet-stream - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **getUserById** -> UserResponseDto getUserById(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.getUserById(id); - print(result); -} catch (e) { - print('Exception when calling UserApi->getUserById: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **restoreUser** -> UserResponseDto restoreUser(id) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final id = 38400000-8cf0-11bd-b23e-10b96e4ef00d; // String | - -try { - final result = api_instance.restoreUser(id); - print(result); -} catch (e) { - print('Exception when calling UserApi->restoreUser: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **String**| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **updateUser** -> UserResponseDto updateUser(updateUserDto) - - - -### Example -```dart -import 'package:openapi/api.dart'; -// TODO Configure API key authorization: cookie -//defaultApiClient.getAuthentication('cookie').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('cookie').apiKeyPrefix = 'Bearer'; -// TODO Configure API key authorization: api_key -//defaultApiClient.getAuthentication('api_key').apiKey = 'YOUR_API_KEY'; -// uncomment below to setup prefix (e.g. Bearer) for API key, if needed -//defaultApiClient.getAuthentication('api_key').apiKeyPrefix = 'Bearer'; -// TODO Configure HTTP Bearer authorization: bearer -// Case 1. Use String Token -//defaultApiClient.getAuthentication('bearer').setAccessToken('YOUR_ACCESS_TOKEN'); -// Case 2. Use Function which generate token. -// String yourTokenGeneratorFunction() { ... } -//defaultApiClient.getAuthentication('bearer').setAccessToken(yourTokenGeneratorFunction); - -final api_instance = UserApi(); -final updateUserDto = UpdateUserDto(); // UpdateUserDto | - -try { - final result = api_instance.updateUser(updateUserDto); - print(result); -} catch (e) { - print('Exception when calling UserApi->updateUser: $e\n'); -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **updateUserDto** | [**UpdateUserDto**](UpdateUserDto.md)| | - -### Return type - -[**UserResponseDto**](UserResponseDto.md) - -### Authorization - -[cookie](../README.md#cookie), [api_key](../README.md#api_key), [bearer](../README.md#bearer) - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - diff --git a/mobile/openapi/doc/UserAvatarColor.md b/mobile/openapi/doc/UserAvatarColor.md deleted file mode 100644 index a07350de12..0000000000 --- a/mobile/openapi/doc/UserAvatarColor.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.UserAvatarColor - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UserDto.md b/mobile/openapi/doc/UserDto.md deleted file mode 100644 index 7e5770f840..0000000000 --- a/mobile/openapi/doc/UserDto.md +++ /dev/null @@ -1,19 +0,0 @@ -# openapi.model.UserDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**avatarColor** | [**UserAvatarColor**](UserAvatarColor.md) | | -**email** | **String** | | -**id** | **String** | | -**name** | **String** | | -**profileImagePath** | **String** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UserResponseDto.md b/mobile/openapi/doc/UserResponseDto.md deleted file mode 100644 index 69d85fbbd4..0000000000 --- a/mobile/openapi/doc/UserResponseDto.md +++ /dev/null @@ -1,30 +0,0 @@ -# openapi.model.UserResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**avatarColor** | [**UserAvatarColor**](UserAvatarColor.md) | | -**createdAt** | [**DateTime**](DateTime.md) | | -**deletedAt** | [**DateTime**](DateTime.md) | | -**email** | **String** | | -**id** | **String** | | -**isAdmin** | **bool** | | -**memoriesEnabled** | **bool** | | [optional] -**name** | **String** | | -**oauthId** | **String** | | -**profileImagePath** | **String** | | -**quotaSizeInBytes** | **int** | | -**quotaUsageInBytes** | **int** | | -**shouldChangePassword** | **bool** | | -**status** | [**UserStatus**](UserStatus.md) | | -**storageLabel** | **String** | | -**updatedAt** | [**DateTime**](DateTime.md) | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/UserStatus.md b/mobile/openapi/doc/UserStatus.md deleted file mode 100644 index 02abb4eff9..0000000000 --- a/mobile/openapi/doc/UserStatus.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.UserStatus - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ValidateAccessTokenResponseDto.md b/mobile/openapi/doc/ValidateAccessTokenResponseDto.md deleted file mode 100644 index 60e1e02cbf..0000000000 --- a/mobile/openapi/doc/ValidateAccessTokenResponseDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.ValidateAccessTokenResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**authStatus** | **bool** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ValidateLibraryDto.md b/mobile/openapi/doc/ValidateLibraryDto.md deleted file mode 100644 index 13c74a6a66..0000000000 --- a/mobile/openapi/doc/ValidateLibraryDto.md +++ /dev/null @@ -1,16 +0,0 @@ -# openapi.model.ValidateLibraryDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**exclusionPatterns** | **List** | | [optional] [default to const []] -**importPaths** | **List** | | [optional] [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ValidateLibraryImportPathResponseDto.md b/mobile/openapi/doc/ValidateLibraryImportPathResponseDto.md deleted file mode 100644 index 1ebcb04efd..0000000000 --- a/mobile/openapi/doc/ValidateLibraryImportPathResponseDto.md +++ /dev/null @@ -1,17 +0,0 @@ -# openapi.model.ValidateLibraryImportPathResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**importPath** | **String** | | -**isValid** | **bool** | | [default to false] -**message** | **String** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/ValidateLibraryResponseDto.md b/mobile/openapi/doc/ValidateLibraryResponseDto.md deleted file mode 100644 index 7b22fdfe90..0000000000 --- a/mobile/openapi/doc/ValidateLibraryResponseDto.md +++ /dev/null @@ -1,15 +0,0 @@ -# openapi.model.ValidateLibraryResponseDto - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**importPaths** | [**List**](ValidateLibraryImportPathResponseDto.md) | | [optional] [default to const []] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/doc/VideoCodec.md b/mobile/openapi/doc/VideoCodec.md deleted file mode 100644 index 7b7d957989..0000000000 --- a/mobile/openapi/doc/VideoCodec.md +++ /dev/null @@ -1,14 +0,0 @@ -# openapi.model.VideoCodec - -## Load the model package -```dart -import 'package:openapi/api.dart'; -``` - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/mobile/openapi/lib/api/activity_api.dart b/mobile/openapi/lib/api/activity_api.dart index 5d42af87b9..52dceadc72 100644 --- a/mobile/openapi/lib/api/activity_api.dart +++ b/mobile/openapi/lib/api/activity_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,13 +16,13 @@ class ActivityApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /activity' operation and returns the [Response]. + /// Performs an HTTP 'POST /activities' operation and returns the [Response]. /// Parameters: /// /// * [ActivityCreateDto] activityCreateDto (required): Future createActivityWithHttpInfo(ActivityCreateDto activityCreateDto,) async { // ignore: prefer_const_declarations - final path = r'/activity'; + final path = r'/activities'; // ignore: prefer_final_locals Object? postBody = activityCreateDto; @@ -63,13 +63,13 @@ class ActivityApi { return null; } - /// Performs an HTTP 'DELETE /activity/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /activities/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future deleteActivityWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/activity/{id}' + final path = r'/activities/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -103,7 +103,7 @@ class ActivityApi { } } - /// Performs an HTTP 'GET /activity' operation and returns the [Response]. + /// Performs an HTTP 'GET /activities' operation and returns the [Response]. /// Parameters: /// /// * [String] albumId (required): @@ -117,7 +117,7 @@ class ActivityApi { /// * [String] userId: Future getActivitiesWithHttpInfo(String albumId, { String? assetId, ReactionLevel? level, ReactionType? type, String? userId, }) async { // ignore: prefer_const_declarations - final path = r'/activity'; + final path = r'/activities'; // ignore: prefer_final_locals Object? postBody; @@ -183,7 +183,7 @@ class ActivityApi { return null; } - /// Performs an HTTP 'GET /activity/statistics' operation and returns the [Response]. + /// Performs an HTTP 'GET /activities/statistics' operation and returns the [Response]. /// Parameters: /// /// * [String] albumId (required): @@ -191,7 +191,7 @@ class ActivityApi { /// * [String] assetId: Future getActivityStatisticsWithHttpInfo(String albumId, { String? assetId, }) async { // ignore: prefer_const_declarations - final path = r'/activity/statistics'; + final path = r'/activities/statistics'; // ignore: prefer_final_locals Object? postBody; diff --git a/mobile/openapi/lib/api/album_api.dart b/mobile/openapi/lib/api/album_api.dart index 4596eff88b..dbc8648a37 100644 --- a/mobile/openapi/lib/api/album_api.dart +++ b/mobile/openapi/lib/api/album_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,7 +16,7 @@ class AlbumApi { final ApiClient apiClient; - /// Performs an HTTP 'PUT /album/{id}/assets' operation and returns the [Response]. + /// Performs an HTTP 'PUT /albums/{id}/assets' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -26,7 +26,7 @@ class AlbumApi { /// * [String] key: Future addAssetsToAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto, { String? key, }) async { // ignore: prefer_const_declarations - final path = r'/album/{id}/assets' + final path = r'/albums/{id}/assets' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -79,7 +79,7 @@ class AlbumApi { return null; } - /// Performs an HTTP 'PUT /album/{id}/users' operation and returns the [Response]. + /// Performs an HTTP 'PUT /albums/{id}/users' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -87,7 +87,7 @@ class AlbumApi { /// * [AddUsersDto] addUsersDto (required): Future addUsersToAlbumWithHttpInfo(String id, AddUsersDto addUsersDto,) async { // ignore: prefer_const_declarations - final path = r'/album/{id}/users' + final path = r'/albums/{id}/users' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -131,13 +131,13 @@ class AlbumApi { return null; } - /// Performs an HTTP 'POST /album' operation and returns the [Response]. + /// Performs an HTTP 'POST /albums' operation and returns the [Response]. /// Parameters: /// /// * [CreateAlbumDto] createAlbumDto (required): Future createAlbumWithHttpInfo(CreateAlbumDto createAlbumDto,) async { // ignore: prefer_const_declarations - final path = r'/album'; + final path = r'/albums'; // ignore: prefer_final_locals Object? postBody = createAlbumDto; @@ -178,13 +178,13 @@ class AlbumApi { return null; } - /// Performs an HTTP 'DELETE /album/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /albums/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future deleteAlbumWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/album/{id}' + final path = r'/albums/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -218,10 +218,10 @@ class AlbumApi { } } - /// Performs an HTTP 'GET /album/count' operation and returns the [Response]. + /// Performs an HTTP 'GET /albums/count' operation and returns the [Response]. Future getAlbumCountWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/album/count'; + final path = r'/albums/count'; // ignore: prefer_final_locals Object? postBody; @@ -259,7 +259,7 @@ class AlbumApi { return null; } - /// Performs an HTTP 'GET /album/{id}' operation and returns the [Response]. + /// Performs an HTTP 'GET /albums/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -269,7 +269,7 @@ class AlbumApi { /// * [bool] withoutAssets: Future getAlbumInfoWithHttpInfo(String id, { String? key, bool? withoutAssets, }) async { // ignore: prefer_const_declarations - final path = r'/album/{id}' + final path = r'/albums/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -322,7 +322,7 @@ class AlbumApi { return null; } - /// Performs an HTTP 'GET /album' operation and returns the [Response]. + /// Performs an HTTP 'GET /albums' operation and returns the [Response]. /// Parameters: /// /// * [String] assetId: @@ -331,7 +331,7 @@ class AlbumApi { /// * [bool] shared: Future getAllAlbumsWithHttpInfo({ String? assetId, bool? shared, }) async { // ignore: prefer_const_declarations - final path = r'/album'; + final path = r'/albums'; // ignore: prefer_final_locals Object? postBody; @@ -385,7 +385,7 @@ class AlbumApi { return null; } - /// Performs an HTTP 'DELETE /album/{id}/assets' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /albums/{id}/assets' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -393,7 +393,7 @@ class AlbumApi { /// * [BulkIdsDto] bulkIdsDto (required): Future removeAssetFromAlbumWithHttpInfo(String id, BulkIdsDto bulkIdsDto,) async { // ignore: prefer_const_declarations - final path = r'/album/{id}/assets' + final path = r'/albums/{id}/assets' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -440,7 +440,7 @@ class AlbumApi { return null; } - /// Performs an HTTP 'DELETE /album/{id}/user/{userId}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /albums/{id}/user/{userId}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -448,7 +448,7 @@ class AlbumApi { /// * [String] userId (required): Future removeUserFromAlbumWithHttpInfo(String id, String userId,) async { // ignore: prefer_const_declarations - final path = r'/album/{id}/user/{userId}' + final path = r'/albums/{id}/user/{userId}' .replaceAll('{id}', id) .replaceAll('{userId}', userId); @@ -485,7 +485,7 @@ class AlbumApi { } } - /// Performs an HTTP 'PATCH /album/{id}' operation and returns the [Response]. + /// Performs an HTTP 'PATCH /albums/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -493,7 +493,7 @@ class AlbumApi { /// * [UpdateAlbumDto] updateAlbumDto (required): Future updateAlbumInfoWithHttpInfo(String id, UpdateAlbumDto updateAlbumDto,) async { // ignore: prefer_const_declarations - final path = r'/album/{id}' + final path = r'/albums/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -537,7 +537,7 @@ class AlbumApi { return null; } - /// Performs an HTTP 'PUT /album/{id}/user/{userId}' operation and returns the [Response]. + /// Performs an HTTP 'PUT /albums/{id}/user/{userId}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -547,7 +547,7 @@ class AlbumApi { /// * [UpdateAlbumUserDto] updateAlbumUserDto (required): Future updateAlbumUserWithHttpInfo(String id, String userId, UpdateAlbumUserDto updateAlbumUserDto,) async { // ignore: prefer_const_declarations - final path = r'/album/{id}/user/{userId}' + final path = r'/albums/{id}/user/{userId}' .replaceAll('{id}', id) .replaceAll('{userId}', userId); diff --git a/mobile/openapi/lib/api/api_key_api.dart b/mobile/openapi/lib/api/api_key_api.dart index 29e50a8865..03c6605706 100644 --- a/mobile/openapi/lib/api/api_key_api.dart +++ b/mobile/openapi/lib/api/api_key_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,13 +16,13 @@ class APIKeyApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /api-key' operation and returns the [Response]. + /// Performs an HTTP 'POST /api-keys' operation and returns the [Response]. /// Parameters: /// /// * [APIKeyCreateDto] aPIKeyCreateDto (required): Future createApiKeyWithHttpInfo(APIKeyCreateDto aPIKeyCreateDto,) async { // ignore: prefer_const_declarations - final path = r'/api-key'; + final path = r'/api-keys'; // ignore: prefer_final_locals Object? postBody = aPIKeyCreateDto; @@ -63,13 +63,13 @@ class APIKeyApi { return null; } - /// Performs an HTTP 'DELETE /api-key/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /api-keys/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future deleteApiKeyWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/api-key/{id}' + final path = r'/api-keys/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -103,13 +103,13 @@ class APIKeyApi { } } - /// Performs an HTTP 'GET /api-key/{id}' operation and returns the [Response]. + /// Performs an HTTP 'GET /api-keys/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getApiKeyWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/api-key/{id}' + final path = r'/api-keys/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -151,10 +151,10 @@ class APIKeyApi { return null; } - /// Performs an HTTP 'GET /api-key' operation and returns the [Response]. + /// Performs an HTTP 'GET /api-keys' operation and returns the [Response]. Future getApiKeysWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/api-key'; + final path = r'/api-keys'; // ignore: prefer_final_locals Object? postBody; @@ -195,7 +195,7 @@ class APIKeyApi { return null; } - /// Performs an HTTP 'PUT /api-key/{id}' operation and returns the [Response]. + /// Performs an HTTP 'PUT /api-keys/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -203,7 +203,7 @@ class APIKeyApi { /// * [APIKeyUpdateDto] aPIKeyUpdateDto (required): Future updateApiKeyWithHttpInfo(String id, APIKeyUpdateDto aPIKeyUpdateDto,) async { // ignore: prefer_const_declarations - final path = r'/api-key/{id}' + final path = r'/api-keys/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals diff --git a/mobile/openapi/lib/api/asset_api.dart b/mobile/openapi/lib/api/asset_api.dart index 6515046869..58af13bd3d 100644 --- a/mobile/openapi/lib/api/asset_api.dart +++ b/mobile/openapi/lib/api/asset_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -159,117 +159,6 @@ 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 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 = []; - final headerParams = {}; - final formParams = {}; - - 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 = []; - - - 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?> 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') as List) - .cast() - .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]. @@ -522,7 +411,9 @@ class AssetApi { /// * [bool] isFavorite: /// /// * [bool] withPartners: - Future getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, }) async { + /// + /// * [bool] withSharedAlbums: + Future getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, bool? withSharedAlbums, }) async { // ignore: prefer_const_declarations final path = r'/asset/map-marker'; @@ -548,6 +439,9 @@ class AssetApi { if (withPartners != null) { queryParams.addAll(_queryParams('', 'withPartners', withPartners)); } + if (withSharedAlbums != null) { + queryParams.addAll(_queryParams('', 'withSharedAlbums', withSharedAlbums)); + } const contentTypes = []; @@ -574,8 +468,10 @@ class AssetApi { /// * [bool] isFavorite: /// /// * [bool] withPartners: - Future?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, }) async { - final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, withPartners: withPartners, ); + /// + /// * [bool] withSharedAlbums: + Future?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, bool? withSharedAlbums, }) async { + final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, withPartners: withPartners, withSharedAlbums: withSharedAlbums, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -703,6 +599,121 @@ 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 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 = []; + final headerParams = {}; + final formParams = {}; + + if (key != null) { + queryParams.addAll(_queryParams('', 'key', key)); + } + + const contentTypes = ['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 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: /// @@ -970,12 +981,10 @@ class AssetApi { /// /// * [bool] isVisible: /// - /// * [String] libraryId: - /// /// * [MultipartFile] livePhotoData: /// /// * [MultipartFile] sidecarData: - Future uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? xImmichChecksum, String? duration, bool? isArchived, bool? isFavorite, bool? isOffline, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async { + Future uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? xImmichChecksum, String? duration, bool? isArchived, bool? isFavorite, bool? isOffline, bool? isVisible, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async { // ignore: prefer_const_declarations final path = r'/asset/upload'; @@ -1039,10 +1048,6 @@ class AssetApi { hasFields = true; mp.fields[r'isVisible'] = parameterToString(isVisible); } - if (libraryId != null) { - hasFields = true; - mp.fields[r'libraryId'] = parameterToString(libraryId); - } if (livePhotoData != null) { hasFields = true; mp.fields[r'livePhotoData'] = livePhotoData.field; @@ -1095,13 +1100,11 @@ class AssetApi { /// /// * [bool] isVisible: /// - /// * [String] libraryId: - /// /// * [MultipartFile] livePhotoData: /// /// * [MultipartFile] sidecarData: - Future uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? xImmichChecksum, String? duration, bool? isArchived, bool? isFavorite, bool? isOffline, bool? isVisible, String? libraryId, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async { - final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, xImmichChecksum: xImmichChecksum, duration: duration, isArchived: isArchived, isFavorite: isFavorite, isOffline: isOffline, isVisible: isVisible, libraryId: libraryId, livePhotoData: livePhotoData, sidecarData: sidecarData, ); + Future uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String? key, String? xImmichChecksum, String? duration, bool? isArchived, bool? isFavorite, bool? isOffline, bool? isVisible, MultipartFile? livePhotoData, MultipartFile? sidecarData, }) async { + final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, key: key, xImmichChecksum: xImmichChecksum, duration: duration, isArchived: isArchived, isFavorite: isFavorite, isOffline: isOffline, isVisible: isVisible, livePhotoData: livePhotoData, sidecarData: sidecarData, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/lib/api/audit_api.dart b/mobile/openapi/lib/api/audit_api.dart index 83dde34da7..f6d71eafdb 100644 --- a/mobile/openapi/lib/api/audit_api.dart +++ b/mobile/openapi/lib/api/audit_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/authentication_api.dart b/mobile/openapi/lib/api/authentication_api.dart index 62f8be353a..c2aa50e7e7 100644 --- a/mobile/openapi/lib/api/authentication_api.dart +++ b/mobile/openapi/lib/api/authentication_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/download_api.dart b/mobile/openapi/lib/api/download_api.dart index fa157366a8..2676313fae 100644 --- a/mobile/openapi/lib/api/download_api.dart +++ b/mobile/openapi/lib/api/download_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/duplicate_api.dart b/mobile/openapi/lib/api/duplicate_api.dart new file mode 100644 index 0000000000..ef71108b86 --- /dev/null +++ b/mobile/openapi/lib/api/duplicate_api.dart @@ -0,0 +1,62 @@ +// +// 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 DuplicateApi { + DuplicateApi([ApiClient? apiClient]) : apiClient = apiClient ?? defaultApiClient; + + final ApiClient apiClient; + + /// Performs an HTTP 'GET /duplicates' operation and returns the [Response]. + Future getAssetDuplicatesWithHttpInfo() async { + // ignore: prefer_const_declarations + final path = r'/duplicates'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'GET', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + Future?> getAssetDuplicates() async { + final response = await getAssetDuplicatesWithHttpInfo(); + 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') as List) + .cast() + .toList(growable: false); + + } + return null; + } +} diff --git a/mobile/openapi/lib/api/file_report_api.dart b/mobile/openapi/lib/api/file_report_api.dart index df307e12c7..a52f02d43b 100644 --- a/mobile/openapi/lib/api/file_report_api.dart +++ b/mobile/openapi/lib/api/file_report_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,13 +16,13 @@ class FileReportApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /report/fix' operation and returns the [Response]. + /// Performs an HTTP 'POST /reports/fix' operation and returns the [Response]. /// Parameters: /// /// * [FileReportFixDto] fileReportFixDto (required): Future fixAuditFilesWithHttpInfo(FileReportFixDto fileReportFixDto,) async { // ignore: prefer_const_declarations - final path = r'/report/fix'; + final path = r'/reports/fix'; // ignore: prefer_final_locals Object? postBody = fileReportFixDto; @@ -55,10 +55,10 @@ class FileReportApi { } } - /// Performs an HTTP 'GET /report' operation and returns the [Response]. + /// Performs an HTTP 'GET /reports' operation and returns the [Response]. Future getAuditFilesWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/report'; + final path = r'/reports'; // ignore: prefer_final_locals Object? postBody; @@ -96,13 +96,13 @@ class FileReportApi { return null; } - /// Performs an HTTP 'POST /report/checksum' operation and returns the [Response]. + /// Performs an HTTP 'POST /reports/checksum' operation and returns the [Response]. /// Parameters: /// /// * [FileChecksumDto] fileChecksumDto (required): Future getFileChecksumsWithHttpInfo(FileChecksumDto fileChecksumDto,) async { // ignore: prefer_const_declarations - final path = r'/report/checksum'; + final path = r'/reports/checksum'; // ignore: prefer_final_locals Object? postBody = fileChecksumDto; diff --git a/mobile/openapi/lib/api/job_api.dart b/mobile/openapi/lib/api/job_api.dart index 6e1aa3c192..d7be8237d7 100644 --- a/mobile/openapi/lib/api/job_api.dart +++ b/mobile/openapi/lib/api/job_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/library_api.dart b/mobile/openapi/lib/api/library_api.dart index befd0aeeff..e634dae836 100644 --- a/mobile/openapi/lib/api/library_api.dart +++ b/mobile/openapi/lib/api/library_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,13 +16,13 @@ class LibraryApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /library' operation and returns the [Response]. + /// Performs an HTTP 'POST /libraries' operation and returns the [Response]. /// Parameters: /// /// * [CreateLibraryDto] createLibraryDto (required): Future createLibraryWithHttpInfo(CreateLibraryDto createLibraryDto,) async { // ignore: prefer_const_declarations - final path = r'/library'; + final path = r'/libraries'; // ignore: prefer_final_locals Object? postBody = createLibraryDto; @@ -63,13 +63,13 @@ class LibraryApi { return null; } - /// Performs an HTTP 'DELETE /library/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /libraries/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future deleteLibraryWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/library/{id}' + final path = r'/libraries/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -103,13 +103,10 @@ class LibraryApi { } } - /// Performs an HTTP 'GET /library' operation and returns the [Response]. - /// Parameters: - /// - /// * [LibraryType] type: - Future getAllLibrariesWithHttpInfo({ LibraryType? type, }) async { + /// Performs an HTTP 'GET /libraries' operation and returns the [Response]. + Future getAllLibrariesWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/library'; + final path = r'/libraries'; // ignore: prefer_final_locals Object? postBody; @@ -118,10 +115,6 @@ class LibraryApi { final headerParams = {}; final formParams = {}; - if (type != null) { - queryParams.addAll(_queryParams('', 'type', type)); - } - const contentTypes = []; @@ -136,11 +129,8 @@ class LibraryApi { ); } - /// Parameters: - /// - /// * [LibraryType] type: - Future?> getAllLibraries({ LibraryType? type, }) async { - final response = await getAllLibrariesWithHttpInfo( type: type, ); + Future?> getAllLibraries() async { + final response = await getAllLibrariesWithHttpInfo(); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } @@ -157,13 +147,13 @@ class LibraryApi { return null; } - /// Performs an HTTP 'GET /library/{id}' operation and returns the [Response]. + /// Performs an HTTP 'GET /libraries/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getLibraryWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/library/{id}' + final path = r'/libraries/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -205,13 +195,13 @@ class LibraryApi { return null; } - /// Performs an HTTP 'GET /library/{id}/statistics' operation and returns the [Response]. + /// Performs an HTTP 'GET /libraries/{id}/statistics' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getLibraryStatisticsWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/library/{id}/statistics' + final path = r'/libraries/{id}/statistics' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -253,13 +243,13 @@ class LibraryApi { return null; } - /// Performs an HTTP 'POST /library/{id}/removeOffline' operation and returns the [Response]. + /// Performs an HTTP 'POST /libraries/{id}/removeOffline' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future removeOfflineFilesWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/library/{id}/removeOffline' + final path = r'/libraries/{id}/removeOffline' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -293,7 +283,7 @@ class LibraryApi { } } - /// Performs an HTTP 'POST /library/{id}/scan' operation and returns the [Response]. + /// Performs an HTTP 'POST /libraries/{id}/scan' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -301,7 +291,7 @@ class LibraryApi { /// * [ScanLibraryDto] scanLibraryDto (required): Future scanLibraryWithHttpInfo(String id, ScanLibraryDto scanLibraryDto,) async { // ignore: prefer_const_declarations - final path = r'/library/{id}/scan' + final path = r'/libraries/{id}/scan' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -337,7 +327,7 @@ class LibraryApi { } } - /// Performs an HTTP 'PUT /library/{id}' operation and returns the [Response]. + /// Performs an HTTP 'PUT /libraries/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -345,7 +335,7 @@ class LibraryApi { /// * [UpdateLibraryDto] updateLibraryDto (required): Future updateLibraryWithHttpInfo(String id, UpdateLibraryDto updateLibraryDto,) async { // ignore: prefer_const_declarations - final path = r'/library/{id}' + final path = r'/libraries/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -389,7 +379,7 @@ class LibraryApi { return null; } - /// Performs an HTTP 'POST /library/{id}/validate' operation and returns the [Response]. + /// Performs an HTTP 'POST /libraries/{id}/validate' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -397,7 +387,7 @@ class LibraryApi { /// * [ValidateLibraryDto] validateLibraryDto (required): Future validateWithHttpInfo(String id, ValidateLibraryDto validateLibraryDto,) async { // ignore: prefer_const_declarations - final path = r'/library/{id}/validate' + final path = r'/libraries/{id}/validate' .replaceAll('{id}', id); // ignore: prefer_final_locals diff --git a/mobile/openapi/lib/api/memory_api.dart b/mobile/openapi/lib/api/memory_api.dart index 6b4a619b52..cbf2ad3e88 100644 --- a/mobile/openapi/lib/api/memory_api.dart +++ b/mobile/openapi/lib/api/memory_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/o_auth_api.dart b/mobile/openapi/lib/api/o_auth_api.dart index 0337384798..9c238f01dc 100644 --- a/mobile/openapi/lib/api/o_auth_api.dart +++ b/mobile/openapi/lib/api/o_auth_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/partner_api.dart b/mobile/openapi/lib/api/partner_api.dart index e798c5172e..66ec2b089b 100644 --- a/mobile/openapi/lib/api/partner_api.dart +++ b/mobile/openapi/lib/api/partner_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,13 +16,13 @@ class PartnerApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /partner/{id}' operation and returns the [Response]. + /// Performs an HTTP 'POST /partners/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future createPartnerWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/partner/{id}' + final path = r'/partners/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -64,13 +64,13 @@ class PartnerApi { return null; } - /// Performs an HTTP 'GET /partner' operation and returns the [Response]. + /// Performs an HTTP 'GET /partners' operation and returns the [Response]. /// Parameters: /// /// * [String] direction (required): Future getPartnersWithHttpInfo(String direction,) async { // ignore: prefer_const_declarations - final path = r'/partner'; + final path = r'/partners'; // ignore: prefer_final_locals Object? postBody; @@ -116,13 +116,13 @@ class PartnerApi { return null; } - /// Performs an HTTP 'DELETE /partner/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /partners/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future removePartnerWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/partner/{id}' + final path = r'/partners/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -156,7 +156,7 @@ class PartnerApi { } } - /// Performs an HTTP 'PUT /partner/{id}' operation and returns the [Response]. + /// Performs an HTTP 'PUT /partners/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -164,7 +164,7 @@ class PartnerApi { /// * [UpdatePartnerDto] updatePartnerDto (required): Future updatePartnerWithHttpInfo(String id, UpdatePartnerDto updatePartnerDto,) async { // ignore: prefer_const_declarations - final path = r'/partner/{id}' + final path = r'/partners/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals diff --git a/mobile/openapi/lib/api/search_api.dart b/mobile/openapi/lib/api/search_api.dart index 15654fc066..21af2d57cb 100644 --- a/mobile/openapi/lib/api/search_api.dart +++ b/mobile/openapi/lib/api/search_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/server_info_api.dart b/mobile/openapi/lib/api/server_info_api.dart index b67045add1..76da103b70 100644 --- a/mobile/openapi/lib/api/server_info_api.dart +++ b/mobile/openapi/lib/api/server_info_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -98,47 +98,6 @@ class ServerInfoApi { return null; } - /// Performs an HTTP 'GET /server-info' operation and returns the [Response]. - Future getServerInfoWithHttpInfo() async { - // ignore: prefer_const_declarations - final path = r'/server-info'; - - // ignore: prefer_final_locals - Object? postBody; - - final queryParams = []; - final headerParams = {}; - final formParams = {}; - - const contentTypes = []; - - - return apiClient.invokeAPI( - path, - 'GET', - queryParams, - postBody, - headerParams, - formParams, - contentTypes.isEmpty ? null : contentTypes.first, - ); - } - - Future 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 getServerStatisticsWithHttpInfo() async { // ignore: prefer_const_declarations @@ -221,6 +180,47 @@ class ServerInfoApi { return null; } + /// Performs an HTTP 'GET /server-info/storage' operation and returns the [Response]. + Future getStorageWithHttpInfo() async { + // ignore: prefer_const_declarations + final path = r'/server-info/storage'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'GET', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + Future 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 getSupportedMediaTypesWithHttpInfo() async { // ignore: prefer_const_declarations diff --git a/mobile/openapi/lib/api/sessions_api.dart b/mobile/openapi/lib/api/sessions_api.dart index bc0fed71e1..fcc6cb836f 100644 --- a/mobile/openapi/lib/api/sessions_api.dart +++ b/mobile/openapi/lib/api/sessions_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/shared_link_api.dart b/mobile/openapi/lib/api/shared_link_api.dart index 23ec4bcbae..80a5034dff 100644 --- a/mobile/openapi/lib/api/shared_link_api.dart +++ b/mobile/openapi/lib/api/shared_link_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,7 +16,7 @@ class SharedLinkApi { final ApiClient apiClient; - /// Performs an HTTP 'PUT /shared-link/{id}/assets' operation and returns the [Response]. + /// Performs an HTTP 'PUT /shared-links/{id}/assets' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -26,7 +26,7 @@ class SharedLinkApi { /// * [String] key: Future addSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, }) async { // ignore: prefer_const_declarations - final path = r'/shared-link/{id}/assets' + final path = r'/shared-links/{id}/assets' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -79,13 +79,13 @@ class SharedLinkApi { return null; } - /// Performs an HTTP 'POST /shared-link' operation and returns the [Response]. + /// Performs an HTTP 'POST /shared-links' operation and returns the [Response]. /// Parameters: /// /// * [SharedLinkCreateDto] sharedLinkCreateDto (required): Future createSharedLinkWithHttpInfo(SharedLinkCreateDto sharedLinkCreateDto,) async { // ignore: prefer_const_declarations - final path = r'/shared-link'; + final path = r'/shared-links'; // ignore: prefer_final_locals Object? postBody = sharedLinkCreateDto; @@ -126,10 +126,10 @@ class SharedLinkApi { return null; } - /// Performs an HTTP 'GET /shared-link' operation and returns the [Response]. + /// Performs an HTTP 'GET /shared-links' operation and returns the [Response]. Future getAllSharedLinksWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/shared-link'; + final path = r'/shared-links'; // ignore: prefer_final_locals Object? postBody; @@ -170,7 +170,7 @@ class SharedLinkApi { return null; } - /// Performs an HTTP 'GET /shared-link/me' operation and returns the [Response]. + /// Performs an HTTP 'GET /shared-links/me' operation and returns the [Response]. /// Parameters: /// /// * [String] key: @@ -180,7 +180,7 @@ class SharedLinkApi { /// * [String] token: Future getMySharedLinkWithHttpInfo({ String? key, String? password, String? token, }) async { // ignore: prefer_const_declarations - final path = r'/shared-link/me'; + final path = r'/shared-links/me'; // ignore: prefer_final_locals Object? postBody; @@ -235,13 +235,13 @@ class SharedLinkApi { return null; } - /// Performs an HTTP 'GET /shared-link/{id}' operation and returns the [Response]. + /// Performs an HTTP 'GET /shared-links/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getSharedLinkByIdWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/shared-link/{id}' + final path = r'/shared-links/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -283,13 +283,13 @@ class SharedLinkApi { return null; } - /// Performs an HTTP 'DELETE /shared-link/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /shared-links/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future removeSharedLinkWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/shared-link/{id}' + final path = r'/shared-links/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -323,7 +323,7 @@ class SharedLinkApi { } } - /// Performs an HTTP 'DELETE /shared-link/{id}/assets' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /shared-links/{id}/assets' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -333,7 +333,7 @@ class SharedLinkApi { /// * [String] key: Future removeSharedLinkAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto, { String? key, }) async { // ignore: prefer_const_declarations - final path = r'/shared-link/{id}/assets' + final path = r'/shared-links/{id}/assets' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -386,7 +386,7 @@ class SharedLinkApi { return null; } - /// Performs an HTTP 'PATCH /shared-link/{id}' operation and returns the [Response]. + /// Performs an HTTP 'PATCH /shared-links/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -394,7 +394,7 @@ class SharedLinkApi { /// * [SharedLinkEditDto] sharedLinkEditDto (required): Future updateSharedLinkWithHttpInfo(String id, SharedLinkEditDto sharedLinkEditDto,) async { // ignore: prefer_const_declarations - final path = r'/shared-link/{id}' + final path = r'/shared-links/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals diff --git a/mobile/openapi/lib/api/sync_api.dart b/mobile/openapi/lib/api/sync_api.dart index f131d54e9d..f94eb88081 100644 --- a/mobile/openapi/lib/api/sync_api.dart +++ b/mobile/openapi/lib/api/sync_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/system_config_api.dart b/mobile/openapi/lib/api/system_config_api.dart index 276f8c07df..1a5f381b43 100644 --- a/mobile/openapi/lib/api/system_config_api.dart +++ b/mobile/openapi/lib/api/system_config_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/system_metadata_api.dart b/mobile/openapi/lib/api/system_metadata_api.dart index f3952fda8a..822a54b14f 100644 --- a/mobile/openapi/lib/api/system_metadata_api.dart +++ b/mobile/openapi/lib/api/system_metadata_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/tag_api.dart b/mobile/openapi/lib/api/tag_api.dart index c9b75a7672..961f0cb394 100644 --- a/mobile/openapi/lib/api/tag_api.dart +++ b/mobile/openapi/lib/api/tag_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,13 +16,13 @@ class TagApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /tag' operation and returns the [Response]. + /// Performs an HTTP 'POST /tags' operation and returns the [Response]. /// Parameters: /// /// * [CreateTagDto] createTagDto (required): Future createTagWithHttpInfo(CreateTagDto createTagDto,) async { // ignore: prefer_const_declarations - final path = r'/tag'; + final path = r'/tags'; // ignore: prefer_final_locals Object? postBody = createTagDto; @@ -63,13 +63,13 @@ class TagApi { return null; } - /// Performs an HTTP 'DELETE /tag/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /tags/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future deleteTagWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/tag/{id}' + final path = r'/tags/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -103,10 +103,10 @@ class TagApi { } } - /// Performs an HTTP 'GET /tag' operation and returns the [Response]. + /// Performs an HTTP 'GET /tags' operation and returns the [Response]. Future getAllTagsWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/tag'; + final path = r'/tags'; // ignore: prefer_final_locals Object? postBody; @@ -147,13 +147,13 @@ class TagApi { return null; } - /// Performs an HTTP 'GET /tag/{id}/assets' operation and returns the [Response]. + /// Performs an HTTP 'GET /tags/{id}/assets' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getTagAssetsWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/tag/{id}/assets' + final path = r'/tags/{id}/assets' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -198,13 +198,13 @@ class TagApi { return null; } - /// Performs an HTTP 'GET /tag/{id}' operation and returns the [Response]. + /// Performs an HTTP 'GET /tags/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getTagByIdWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/tag/{id}' + final path = r'/tags/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -246,7 +246,7 @@ class TagApi { return null; } - /// Performs an HTTP 'PUT /tag/{id}/assets' operation and returns the [Response]. + /// Performs an HTTP 'PUT /tags/{id}/assets' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -254,7 +254,7 @@ class TagApi { /// * [AssetIdsDto] assetIdsDto (required): Future tagAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto,) async { // ignore: prefer_const_declarations - final path = r'/tag/{id}/assets' + final path = r'/tags/{id}/assets' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -301,7 +301,7 @@ class TagApi { return null; } - /// Performs an HTTP 'DELETE /tag/{id}/assets' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /tags/{id}/assets' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -309,7 +309,7 @@ class TagApi { /// * [AssetIdsDto] assetIdsDto (required): Future untagAssetsWithHttpInfo(String id, AssetIdsDto assetIdsDto,) async { // ignore: prefer_const_declarations - final path = r'/tag/{id}/assets' + final path = r'/tags/{id}/assets' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -356,7 +356,7 @@ class TagApi { return null; } - /// Performs an HTTP 'PATCH /tag/{id}' operation and returns the [Response]. + /// Performs an HTTP 'PATCH /tags/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -364,7 +364,7 @@ class TagApi { /// * [UpdateTagDto] updateTagDto (required): Future updateTagWithHttpInfo(String id, UpdateTagDto updateTagDto,) async { // ignore: prefer_const_declarations - final path = r'/tag/{id}' + final path = r'/tags/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals diff --git a/mobile/openapi/lib/api/timeline_api.dart b/mobile/openapi/lib/api/timeline_api.dart index 0813f3e00c..4acb98bdf2 100644 --- a/mobile/openapi/lib/api/timeline_api.dart +++ b/mobile/openapi/lib/api/timeline_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/trash_api.dart b/mobile/openapi/lib/api/trash_api.dart index 91f1d1a747..9c346870ec 100644 --- a/mobile/openapi/lib/api/trash_api.dart +++ b/mobile/openapi/lib/api/trash_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api/user_api.dart b/mobile/openapi/lib/api/user_api.dart index 241c1698c3..301169cb9a 100644 --- a/mobile/openapi/lib/api/user_api.dart +++ b/mobile/openapi/lib/api/user_api.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -16,13 +16,13 @@ class UserApi { final ApiClient apiClient; - /// Performs an HTTP 'POST /user/profile-image' operation and returns the [Response]. + /// Performs an HTTP 'POST /users/profile-image' operation and returns the [Response]. /// Parameters: /// /// * [MultipartFile] file (required): Future createProfileImageWithHttpInfo(MultipartFile file,) async { // ignore: prefer_const_declarations - final path = r'/user/profile-image'; + final path = r'/users/profile-image'; // ignore: prefer_final_locals Object? postBody; @@ -73,13 +73,13 @@ class UserApi { return null; } - /// Performs an HTTP 'POST /user' operation and returns the [Response]. + /// Performs an HTTP 'POST /users' operation and returns the [Response]. /// Parameters: /// /// * [CreateUserDto] createUserDto (required): Future createUserWithHttpInfo(CreateUserDto createUserDto,) async { // ignore: prefer_const_declarations - final path = r'/user'; + final path = r'/users'; // ignore: prefer_final_locals Object? postBody = createUserDto; @@ -120,10 +120,10 @@ class UserApi { return null; } - /// Performs an HTTP 'DELETE /user/profile-image' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /users/profile-image' operation and returns the [Response]. Future deleteProfileImageWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/user/profile-image'; + final path = r'/users/profile-image'; // ignore: prefer_final_locals Object? postBody; @@ -153,7 +153,7 @@ class UserApi { } } - /// Performs an HTTP 'DELETE /user/{id}' operation and returns the [Response]. + /// Performs an HTTP 'DELETE /users/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): @@ -161,7 +161,7 @@ class UserApi { /// * [DeleteUserDto] deleteUserDto (required): Future deleteUserWithHttpInfo(String id, DeleteUserDto deleteUserDto,) async { // ignore: prefer_const_declarations - final path = r'/user/{id}' + final path = r'/users/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -205,13 +205,13 @@ class UserApi { return null; } - /// Performs an HTTP 'GET /user' operation and returns the [Response]. + /// Performs an HTTP 'GET /users' operation and returns the [Response]. /// Parameters: /// /// * [bool] isAll (required): Future getAllUsersWithHttpInfo(bool isAll,) async { // ignore: prefer_const_declarations - final path = r'/user'; + final path = r'/users'; // ignore: prefer_final_locals Object? postBody; @@ -257,10 +257,10 @@ class UserApi { return null; } - /// Performs an HTTP 'GET /user/me' operation and returns the [Response]. + /// Performs an HTTP 'GET /users/me' operation and returns the [Response]. Future getMyUserInfoWithHttpInfo() async { // ignore: prefer_const_declarations - final path = r'/user/me'; + final path = r'/users/me'; // ignore: prefer_final_locals Object? postBody; @@ -298,13 +298,13 @@ class UserApi { return null; } - /// Performs an HTTP 'GET /user/profile-image/{id}' operation and returns the [Response]. + /// Performs an HTTP 'GET /users/{id}/profile-image' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getProfileImageWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/user/profile-image/{id}' + final path = r'/users/{id}/profile-image' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -346,13 +346,13 @@ class UserApi { return null; } - /// Performs an HTTP 'GET /user/info/{id}' operation and returns the [Response]. + /// Performs an HTTP 'GET /users/{id}' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future getUserByIdWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/user/info/{id}' + final path = r'/users/{id}' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -394,13 +394,13 @@ class UserApi { return null; } - /// Performs an HTTP 'POST /user/{id}/restore' operation and returns the [Response]. + /// Performs an HTTP 'POST /users/{id}/restore' operation and returns the [Response]. /// Parameters: /// /// * [String] id (required): Future restoreUserWithHttpInfo(String id,) async { // ignore: prefer_const_declarations - final path = r'/user/{id}/restore' + final path = r'/users/{id}/restore' .replaceAll('{id}', id); // ignore: prefer_final_locals @@ -442,13 +442,13 @@ class UserApi { return null; } - /// Performs an HTTP 'PUT /user' operation and returns the [Response]. + /// Performs an HTTP 'PUT /users' operation and returns the [Response]. /// Parameters: /// /// * [UpdateUserDto] updateUserDto (required): Future updateUserWithHttpInfo(UpdateUserDto updateUserDto,) async { // ignore: prefer_const_declarations - final path = r'/user'; + final path = r'/users'; // ignore: prefer_final_locals Object? postBody = updateUserDto; diff --git a/mobile/openapi/lib/api_exception.dart b/mobile/openapi/lib/api_exception.dart index 796f7f7ee7..53077d686d 100644 --- a/mobile/openapi/lib/api_exception.dart +++ b/mobile/openapi/lib/api_exception.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/api_helper.dart b/mobile/openapi/lib/api_helper.dart index 8d92ad1f0a..4a8c774623 100644 --- a/mobile/openapi/lib/api_helper.dart +++ b/mobile/openapi/lib/api_helper.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -61,6 +61,9 @@ 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(); } @@ -91,9 +94,6 @@ String parameterToString(dynamic value) { if (value is JobName) { return JobNameTypeTransformer().encode(value).toString(); } - if (value is LibraryType) { - return LibraryTypeTypeTransformer().encode(value).toString(); - } if (value is LogLevel) { return LogLevelTypeTransformer().encode(value).toString(); } diff --git a/mobile/openapi/lib/auth/api_key_auth.dart b/mobile/openapi/lib/auth/api_key_auth.dart index 84dc2955c2..6c5621798f 100644 --- a/mobile/openapi/lib/auth/api_key_auth.dart +++ b/mobile/openapi/lib/auth/api_key_auth.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/auth/authentication.dart b/mobile/openapi/lib/auth/authentication.dart index 1b1b8ae11e..5377fb6f34 100644 --- a/mobile/openapi/lib/auth/authentication.dart +++ b/mobile/openapi/lib/auth/authentication.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/auth/http_basic_auth.dart b/mobile/openapi/lib/auth/http_basic_auth.dart index dfedaa50d0..5e8b1c4147 100644 --- a/mobile/openapi/lib/auth/http_basic_auth.dart +++ b/mobile/openapi/lib/auth/http_basic_auth.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/auth/http_bearer_auth.dart b/mobile/openapi/lib/auth/http_bearer_auth.dart index eddf3a59cb..847dc056e1 100644 --- a/mobile/openapi/lib/auth/http_bearer_auth.dart +++ b/mobile/openapi/lib/auth/http_bearer_auth.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/auth/oauth.dart b/mobile/openapi/lib/auth/oauth.dart index e9e7d784c3..73fd8202dc 100644 --- a/mobile/openapi/lib/auth/oauth.dart +++ b/mobile/openapi/lib/auth/oauth.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/activity_create_dto.dart b/mobile/openapi/lib/model/activity_create_dto.dart index adda496887..b54fa2ca72 100644 --- a/mobile/openapi/lib/model/activity_create_dto.dart +++ b/mobile/openapi/lib/model/activity_create_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/activity_response_dto.dart b/mobile/openapi/lib/model/activity_response_dto.dart index 83e7884f7a..d276d19e6c 100644 --- a/mobile/openapi/lib/model/activity_response_dto.dart +++ b/mobile/openapi/lib/model/activity_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/activity_statistics_response_dto.dart b/mobile/openapi/lib/model/activity_statistics_response_dto.dart index 2bb4e1d5bf..20d4696b1b 100644 --- a/mobile/openapi/lib/model/activity_statistics_response_dto.dart +++ b/mobile/openapi/lib/model/activity_statistics_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/add_users_dto.dart b/mobile/openapi/lib/model/add_users_dto.dart index ad58577b53..2daa571265 100644 --- a/mobile/openapi/lib/model/add_users_dto.dart +++ b/mobile/openapi/lib/model/add_users_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -14,32 +14,25 @@ class AddUsersDto { /// Returns a new [AddUsersDto] instance. AddUsersDto({ this.albumUsers = const [], - this.sharedUserIds = const [], }); List albumUsers; - /// This property was deprecated in v1.102.0 - List sharedUserIds; - @override bool operator ==(Object other) => identical(this, other) || other is AddUsersDto && - _deepEquality.equals(other.albumUsers, albumUsers) && - _deepEquality.equals(other.sharedUserIds, sharedUserIds); + _deepEquality.equals(other.albumUsers, albumUsers); @override int get hashCode => // ignore: unnecessary_parenthesis - (albumUsers.hashCode) + - (sharedUserIds.hashCode); + (albumUsers.hashCode); @override - String toString() => 'AddUsersDto[albumUsers=$albumUsers, sharedUserIds=$sharedUserIds]'; + String toString() => 'AddUsersDto[albumUsers=$albumUsers]'; Map toJson() { final json = {}; json[r'albumUsers'] = this.albumUsers; - json[r'sharedUserIds'] = this.sharedUserIds; return json; } @@ -52,9 +45,6 @@ class AddUsersDto { return AddUsersDto( albumUsers: AlbumUserAddDto.listFromJson(json[r'albumUsers']), - sharedUserIds: json[r'sharedUserIds'] is Iterable - ? (json[r'sharedUserIds'] as Iterable).cast().toList(growable: false) - : const [], ); } return null; diff --git a/mobile/openapi/lib/model/admin_onboarding_update_dto.dart b/mobile/openapi/lib/model/admin_onboarding_update_dto.dart index 50c4ae090e..2277f0958c 100644 --- a/mobile/openapi/lib/model/admin_onboarding_update_dto.dart +++ b/mobile/openapi/lib/model/admin_onboarding_update_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/album_count_response_dto.dart b/mobile/openapi/lib/model/album_count_response_dto.dart index 62121c1f35..531a17a083 100644 --- a/mobile/openapi/lib/model/album_count_response_dto.dart +++ b/mobile/openapi/lib/model/album_count_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/album_response_dto.dart b/mobile/openapi/lib/model/album_response_dto.dart index 79c75bc58c..c98a95775d 100644 --- a/mobile/openapi/lib/model/album_response_dto.dart +++ b/mobile/openapi/lib/model/album_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -29,7 +29,6 @@ class AlbumResponseDto { required this.owner, required this.ownerId, required this.shared, - this.sharedUsers = const [], this.startDate, required this.updatedAt, }); @@ -84,9 +83,6 @@ class AlbumResponseDto { bool shared; - /// This property was deprecated in v1.102.0 - List 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 @@ -115,7 +111,6 @@ class AlbumResponseDto { other.owner == owner && other.ownerId == ownerId && other.shared == shared && - _deepEquality.equals(other.sharedUsers, sharedUsers) && other.startDate == startDate && other.updatedAt == updatedAt; @@ -138,12 +133,11 @@ 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, sharedUsers=$sharedUsers, 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, startDate=$startDate, updatedAt=$updatedAt]'; Map toJson() { final json = {}; @@ -179,7 +173,6 @@ 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 { @@ -213,7 +206,6 @@ class AlbumResponseDto { owner: UserResponseDto.fromJson(json[r'owner'])!, ownerId: mapValueOfType(json, r'ownerId')!, shared: mapValueOfType(json, r'shared')!, - sharedUsers: UserResponseDto.listFromJson(json[r'sharedUsers']), startDate: mapDateTime(json, r'startDate', r''), updatedAt: mapDateTime(json, r'updatedAt', r'')!, ); @@ -276,7 +268,6 @@ class AlbumResponseDto { 'owner', 'ownerId', 'shared', - 'sharedUsers', 'updatedAt', }; } diff --git a/mobile/openapi/lib/model/album_user_add_dto.dart b/mobile/openapi/lib/model/album_user_add_dto.dart index 0e259828f8..e654a2ff5d 100644 --- a/mobile/openapi/lib/model/album_user_add_dto.dart +++ b/mobile/openapi/lib/model/album_user_add_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/album_user_create_dto.dart b/mobile/openapi/lib/model/album_user_create_dto.dart index 4c8f2ec6d1..708acd472b 100644 --- a/mobile/openapi/lib/model/album_user_create_dto.dart +++ b/mobile/openapi/lib/model/album_user_create_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/album_user_response_dto.dart b/mobile/openapi/lib/model/album_user_response_dto.dart index 896c1cbb8f..8f86cf254e 100644 --- a/mobile/openapi/lib/model/album_user_response_dto.dart +++ b/mobile/openapi/lib/model/album_user_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/album_user_role.dart b/mobile/openapi/lib/model/album_user_role.dart index 991d6d182c..c0d61cd7f5 100644 --- a/mobile/openapi/lib/model/album_user_role.dart +++ b/mobile/openapi/lib/model/album_user_role.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/all_job_status_response_dto.dart b/mobile/openapi/lib/model/all_job_status_response_dto.dart index c7760f043b..1ee5253c38 100644 --- a/mobile/openapi/lib/model/all_job_status_response_dto.dart +++ b/mobile/openapi/lib/model/all_job_status_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -14,6 +14,7 @@ class AllJobStatusResponseDto { /// Returns a new [AllJobStatusResponseDto] instance. AllJobStatusResponseDto({ required this.backgroundTask, + required this.duplicateDetection, required this.faceDetection, required this.facialRecognition, required this.library_, @@ -30,6 +31,8 @@ class AllJobStatusResponseDto { JobStatusDto backgroundTask; + JobStatusDto duplicateDetection; + JobStatusDto faceDetection; JobStatusDto facialRecognition; @@ -57,6 +60,7 @@ class AllJobStatusResponseDto { @override bool operator ==(Object other) => identical(this, other) || other is AllJobStatusResponseDto && other.backgroundTask == backgroundTask && + other.duplicateDetection == duplicateDetection && other.faceDetection == faceDetection && other.facialRecognition == facialRecognition && other.library_ == library_ && @@ -74,6 +78,7 @@ class AllJobStatusResponseDto { int get hashCode => // ignore: unnecessary_parenthesis (backgroundTask.hashCode) + + (duplicateDetection.hashCode) + (faceDetection.hashCode) + (facialRecognition.hashCode) + (library_.hashCode) + @@ -88,11 +93,12 @@ class AllJobStatusResponseDto { (videoConversion.hashCode); @override - String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, faceDetection=$faceDetection, facialRecognition=$facialRecognition, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, notifications=$notifications, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]'; + String toString() => 'AllJobStatusResponseDto[backgroundTask=$backgroundTask, duplicateDetection=$duplicateDetection, faceDetection=$faceDetection, facialRecognition=$facialRecognition, library_=$library_, metadataExtraction=$metadataExtraction, migration=$migration, notifications=$notifications, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, storageTemplateMigration=$storageTemplateMigration, thumbnailGeneration=$thumbnailGeneration, videoConversion=$videoConversion]'; Map toJson() { final json = {}; json[r'backgroundTask'] = this.backgroundTask; + json[r'duplicateDetection'] = this.duplicateDetection; json[r'faceDetection'] = this.faceDetection; json[r'facialRecognition'] = this.facialRecognition; json[r'library'] = this.library_; @@ -117,6 +123,7 @@ class AllJobStatusResponseDto { return AllJobStatusResponseDto( backgroundTask: JobStatusDto.fromJson(json[r'backgroundTask'])!, + duplicateDetection: JobStatusDto.fromJson(json[r'duplicateDetection'])!, faceDetection: JobStatusDto.fromJson(json[r'faceDetection'])!, facialRecognition: JobStatusDto.fromJson(json[r'facialRecognition'])!, library_: JobStatusDto.fromJson(json[r'library'])!, @@ -177,6 +184,7 @@ class AllJobStatusResponseDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'backgroundTask', + 'duplicateDetection', 'faceDetection', 'facialRecognition', 'library', diff --git a/mobile/openapi/lib/model/api_key_create_dto.dart b/mobile/openapi/lib/model/api_key_create_dto.dart index 91cf836b50..f6ff8e5f97 100644 --- a/mobile/openapi/lib/model/api_key_create_dto.dart +++ b/mobile/openapi/lib/model/api_key_create_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/api_key_create_response_dto.dart b/mobile/openapi/lib/model/api_key_create_response_dto.dart index d117d7a5e4..93065654ac 100644 --- a/mobile/openapi/lib/model/api_key_create_response_dto.dart +++ b/mobile/openapi/lib/model/api_key_create_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/api_key_response_dto.dart b/mobile/openapi/lib/model/api_key_response_dto.dart index 157bb83e7e..764d5ec973 100644 --- a/mobile/openapi/lib/model/api_key_response_dto.dart +++ b/mobile/openapi/lib/model/api_key_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/api_key_update_dto.dart b/mobile/openapi/lib/model/api_key_update_dto.dart index c7002482da..318f4936e1 100644 --- a/mobile/openapi/lib/model/api_key_update_dto.dart +++ b/mobile/openapi/lib/model/api_key_update_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_bulk_delete_dto.dart b/mobile/openapi/lib/model/asset_bulk_delete_dto.dart index 7edb777dc9..0f6913a7f4 100644 --- a/mobile/openapi/lib/model/asset_bulk_delete_dto.dart +++ b/mobile/openapi/lib/model/asset_bulk_delete_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_bulk_update_dto.dart b/mobile/openapi/lib/model/asset_bulk_update_dto.dart index 1a100b52ac..dcab64e1f3 100644 --- a/mobile/openapi/lib/model/asset_bulk_update_dto.dart +++ b/mobile/openapi/lib/model/asset_bulk_update_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -14,6 +14,7 @@ class AssetBulkUpdateDto { /// Returns a new [AssetBulkUpdateDto] instance. AssetBulkUpdateDto({ this.dateTimeOriginal, + this.duplicateId, this.ids = const [], this.isArchived, this.isFavorite, @@ -31,6 +32,8 @@ class AssetBulkUpdateDto { /// String? dateTimeOriginal; + String? duplicateId; + List ids; /// @@ -84,6 +87,7 @@ 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 && @@ -96,6 +100,7 @@ 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) + @@ -105,7 +110,7 @@ class AssetBulkUpdateDto { (stackParentId == null ? 0 : stackParentId!.hashCode); @override - String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, removeParent=$removeParent, stackParentId=$stackParentId]'; + String toString() => 'AssetBulkUpdateDto[dateTimeOriginal=$dateTimeOriginal, duplicateId=$duplicateId, ids=$ids, isArchived=$isArchived, isFavorite=$isFavorite, latitude=$latitude, longitude=$longitude, removeParent=$removeParent, stackParentId=$stackParentId]'; Map toJson() { final json = {}; @@ -113,6 +118,11 @@ 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) { @@ -157,6 +167,7 @@ class AssetBulkUpdateDto { return AssetBulkUpdateDto( dateTimeOriginal: mapValueOfType(json, r'dateTimeOriginal'), + duplicateId: mapValueOfType(json, r'duplicateId'), ids: json[r'ids'] is Iterable ? (json[r'ids'] as Iterable).cast().toList(growable: false) : const [], diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart index 9a88201a3f..55ea41b598 100644 --- a/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart +++ b/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart index 0d20bd8b3a..16294cdae6 100644 --- a/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart +++ b/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart index 2c4f821a7b..5bfacbff57 100644 --- a/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart +++ b/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart index ac252baec3..737186e589 100644 --- a/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart +++ b/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_delta_sync_dto.dart b/mobile/openapi/lib/model/asset_delta_sync_dto.dart index c7f3ce618a..a5ee10f33e 100644 --- a/mobile/openapi/lib/model/asset_delta_sync_dto.dart +++ b/mobile/openapi/lib/model/asset_delta_sync_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart b/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart index 5d7679e734..3b14fa68cf 100644 --- a/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart +++ b/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_face_response_dto.dart b/mobile/openapi/lib/model/asset_face_response_dto.dart index 74924f6a5b..812b165caa 100644 --- a/mobile/openapi/lib/model/asset_face_response_dto.dart +++ b/mobile/openapi/lib/model/asset_face_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_face_update_dto.dart b/mobile/openapi/lib/model/asset_face_update_dto.dart index 6c68dc761b..58def49ae1 100644 --- a/mobile/openapi/lib/model/asset_face_update_dto.dart +++ b/mobile/openapi/lib/model/asset_face_update_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_face_update_item.dart b/mobile/openapi/lib/model/asset_face_update_item.dart index 36bf94232c..5ea37ea4db 100644 --- a/mobile/openapi/lib/model/asset_face_update_item.dart +++ b/mobile/openapi/lib/model/asset_face_update_item.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart b/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart index 7049386978..893f8ff353 100644 --- a/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart +++ b/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_file_upload_response_dto.dart b/mobile/openapi/lib/model/asset_file_upload_response_dto.dart index f75ec6addc..f198903a40 100644 --- a/mobile/openapi/lib/model/asset_file_upload_response_dto.dart +++ b/mobile/openapi/lib/model/asset_file_upload_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_full_sync_dto.dart b/mobile/openapi/lib/model/asset_full_sync_dto.dart index fba8d65381..e08bdaddf3 100644 --- a/mobile/openapi/lib/model/asset_full_sync_dto.dart +++ b/mobile/openapi/lib/model/asset_full_sync_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_ids_dto.dart b/mobile/openapi/lib/model/asset_ids_dto.dart index 1b4fceeaa8..c8c7a69b89 100644 --- a/mobile/openapi/lib/model/asset_ids_dto.dart +++ b/mobile/openapi/lib/model/asset_ids_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_ids_response_dto.dart b/mobile/openapi/lib/model/asset_ids_response_dto.dart index 81aef4acac..a642c0924c 100644 --- a/mobile/openapi/lib/model/asset_ids_response_dto.dart +++ b/mobile/openapi/lib/model/asset_ids_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_job_name.dart b/mobile/openapi/lib/model/asset_job_name.dart index 1191e55d84..a5b42f4ee5 100644 --- a/mobile/openapi/lib/model/asset_job_name.dart +++ b/mobile/openapi/lib/model/asset_job_name.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_jobs_dto.dart b/mobile/openapi/lib/model/asset_jobs_dto.dart index 996c42bdb1..16ed2644fd 100644 --- a/mobile/openapi/lib/model/asset_jobs_dto.dart +++ b/mobile/openapi/lib/model/asset_jobs_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_media_response_dto.dart b/mobile/openapi/lib/model/asset_media_response_dto.dart new file mode 100644 index 0000000000..c2801c93cc --- /dev/null +++ b/mobile/openapi/lib/model/asset_media_response_dto.dart @@ -0,0 +1,106 @@ +// +// 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 toJson() { + final json = {}; + 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(); + + return AssetMediaResponseDto( + id: mapValueOfType(json, r'id')!, + status: AssetMediaStatus.fromJson(json[r'status'])!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + 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 mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // 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> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + 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 = { + 'id', + 'status', + }; +} + diff --git a/mobile/openapi/lib/model/asset_media_status.dart b/mobile/openapi/lib/model/asset_media_status.dart new file mode 100644 index 0000000000..ff6f62e33f --- /dev/null +++ b/mobile/openapi/lib/model/asset_media_status.dart @@ -0,0 +1,85 @@ +// +// 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 = [ + replaced, + duplicate, + ]; + + static AssetMediaStatus? fromJson(dynamic value) => AssetMediaStatusTypeTransformer().decode(value); + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + 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; +} + diff --git a/mobile/openapi/lib/model/asset_order.dart b/mobile/openapi/lib/model/asset_order.dart index 9afa72aa27..ca04e2b78f 100644 --- a/mobile/openapi/lib/model/asset_order.dart +++ b/mobile/openapi/lib/model/asset_order.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_stats_response_dto.dart b/mobile/openapi/lib/model/asset_stats_response_dto.dart index d3c5f71ff7..c21d7fdbff 100644 --- a/mobile/openapi/lib/model/asset_stats_response_dto.dart +++ b/mobile/openapi/lib/model/asset_stats_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/asset_type_enum.dart b/mobile/openapi/lib/model/asset_type_enum.dart index ec98d5ca83..1022beb24e 100644 --- a/mobile/openapi/lib/model/asset_type_enum.dart +++ b/mobile/openapi/lib/model/asset_type_enum.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/audio_codec.dart b/mobile/openapi/lib/model/audio_codec.dart index bbc12f8dbc..ca195f7d06 100644 --- a/mobile/openapi/lib/model/audio_codec.dart +++ b/mobile/openapi/lib/model/audio_codec.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/audit_deletes_response_dto.dart b/mobile/openapi/lib/model/audit_deletes_response_dto.dart index 5980a0544e..690a52e811 100644 --- a/mobile/openapi/lib/model/audit_deletes_response_dto.dart +++ b/mobile/openapi/lib/model/audit_deletes_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/bulk_id_response_dto.dart b/mobile/openapi/lib/model/bulk_id_response_dto.dart index 957d906319..ef3cf2e0db 100644 --- a/mobile/openapi/lib/model/bulk_id_response_dto.dart +++ b/mobile/openapi/lib/model/bulk_id_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/bulk_ids_dto.dart b/mobile/openapi/lib/model/bulk_ids_dto.dart index ba2076844d..6942875f0a 100644 --- a/mobile/openapi/lib/model/bulk_ids_dto.dart +++ b/mobile/openapi/lib/model/bulk_ids_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/change_password_dto.dart b/mobile/openapi/lib/model/change_password_dto.dart index 3008f5b1c5..1074aaf74d 100644 --- a/mobile/openapi/lib/model/change_password_dto.dart +++ b/mobile/openapi/lib/model/change_password_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/check_existing_assets_dto.dart b/mobile/openapi/lib/model/check_existing_assets_dto.dart index cf3e4c2eae..49ef36cc09 100644 --- a/mobile/openapi/lib/model/check_existing_assets_dto.dart +++ b/mobile/openapi/lib/model/check_existing_assets_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/check_existing_assets_response_dto.dart b/mobile/openapi/lib/model/check_existing_assets_response_dto.dart index db91cf1f0f..d8b0f43a6d 100644 --- a/mobile/openapi/lib/model/check_existing_assets_response_dto.dart +++ b/mobile/openapi/lib/model/check_existing_assets_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/clip_config.dart b/mobile/openapi/lib/model/clip_config.dart index 367102f3e8..5a1d429aea 100644 --- a/mobile/openapi/lib/model/clip_config.dart +++ b/mobile/openapi/lib/model/clip_config.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/clip_mode.dart b/mobile/openapi/lib/model/clip_mode.dart index f52525c38e..98a38759da 100644 --- a/mobile/openapi/lib/model/clip_mode.dart +++ b/mobile/openapi/lib/model/clip_mode.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/colorspace.dart b/mobile/openapi/lib/model/colorspace.dart index eb2cf3f681..e0c1658be5 100644 --- a/mobile/openapi/lib/model/colorspace.dart +++ b/mobile/openapi/lib/model/colorspace.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/cq_mode.dart b/mobile/openapi/lib/model/cq_mode.dart index cd918ce888..f660fabf1f 100644 --- a/mobile/openapi/lib/model/cq_mode.dart +++ b/mobile/openapi/lib/model/cq_mode.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/create_album_dto.dart b/mobile/openapi/lib/model/create_album_dto.dart index 7af3526a45..fa28b782ac 100644 --- a/mobile/openapi/lib/model/create_album_dto.dart +++ b/mobile/openapi/lib/model/create_album_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -17,12 +17,10 @@ class CreateAlbumDto { this.albumUsers = const [], this.assetIds = const [], this.description, - this.sharedWithUserIds = const [], }); String albumName; - /// This property was added in v1.104.0 List albumUsers; List assetIds; @@ -35,16 +33,12 @@ class CreateAlbumDto { /// String? description; - /// This property was deprecated in v1.104.0 - List 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 && - _deepEquality.equals(other.sharedWithUserIds, sharedWithUserIds); + other.description == description; @override int get hashCode => @@ -52,11 +46,10 @@ class CreateAlbumDto { (albumName.hashCode) + (albumUsers.hashCode) + (assetIds.hashCode) + - (description == null ? 0 : description!.hashCode) + - (sharedWithUserIds.hashCode); + (description == null ? 0 : description!.hashCode); @override - String toString() => 'CreateAlbumDto[albumName=$albumName, albumUsers=$albumUsers, assetIds=$assetIds, description=$description, sharedWithUserIds=$sharedWithUserIds]'; + String toString() => 'CreateAlbumDto[albumName=$albumName, albumUsers=$albumUsers, assetIds=$assetIds, description=$description]'; Map toJson() { final json = {}; @@ -68,7 +61,6 @@ class CreateAlbumDto { } else { // json[r'description'] = null; } - json[r'sharedWithUserIds'] = this.sharedWithUserIds; return json; } @@ -86,9 +78,6 @@ class CreateAlbumDto { ? (json[r'assetIds'] as Iterable).cast().toList(growable: false) : const [], description: mapValueOfType(json, r'description'), - sharedWithUserIds: json[r'sharedWithUserIds'] is Iterable - ? (json[r'sharedWithUserIds'] as Iterable).cast().toList(growable: false) - : const [], ); } return null; diff --git a/mobile/openapi/lib/model/create_library_dto.dart b/mobile/openapi/lib/model/create_library_dto.dart index 93fb89b701..65ceec8e8a 100644 --- a/mobile/openapi/lib/model/create_library_dto.dart +++ b/mobile/openapi/lib/model/create_library_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -15,24 +15,14 @@ class CreateLibraryDto { CreateLibraryDto({ this.exclusionPatterns = const [], this.importPaths = const [], - this.isVisible, this.name, required this.ownerId, - required this.type, }); List exclusionPatterns; List importPaths; - /// - /// 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? isVisible; - /// /// 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 @@ -43,46 +33,34 @@ class CreateLibraryDto { String ownerId; - LibraryType type; - @override bool operator ==(Object other) => identical(this, other) || other is CreateLibraryDto && _deepEquality.equals(other.exclusionPatterns, exclusionPatterns) && _deepEquality.equals(other.importPaths, importPaths) && - other.isVisible == isVisible && other.name == name && - other.ownerId == ownerId && - other.type == type; + other.ownerId == ownerId; @override int get hashCode => // ignore: unnecessary_parenthesis (exclusionPatterns.hashCode) + (importPaths.hashCode) + - (isVisible == null ? 0 : isVisible!.hashCode) + (name == null ? 0 : name!.hashCode) + - (ownerId.hashCode) + - (type.hashCode); + (ownerId.hashCode); @override - String toString() => 'CreateLibraryDto[exclusionPatterns=$exclusionPatterns, importPaths=$importPaths, isVisible=$isVisible, name=$name, ownerId=$ownerId, type=$type]'; + String toString() => 'CreateLibraryDto[exclusionPatterns=$exclusionPatterns, importPaths=$importPaths, name=$name, ownerId=$ownerId]'; Map toJson() { final json = {}; json[r'exclusionPatterns'] = this.exclusionPatterns; json[r'importPaths'] = this.importPaths; - if (this.isVisible != null) { - json[r'isVisible'] = this.isVisible; - } else { - // json[r'isVisible'] = null; - } if (this.name != null) { json[r'name'] = this.name; } else { // json[r'name'] = null; } json[r'ownerId'] = this.ownerId; - json[r'type'] = this.type; return json; } @@ -100,10 +78,8 @@ class CreateLibraryDto { importPaths: json[r'importPaths'] is Iterable ? (json[r'importPaths'] as Iterable).cast().toList(growable: false) : const [], - isVisible: mapValueOfType(json, r'isVisible'), name: mapValueOfType(json, r'name'), ownerId: mapValueOfType(json, r'ownerId')!, - type: LibraryType.fromJson(json[r'type'])!, ); } return null; @@ -152,7 +128,6 @@ class CreateLibraryDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'ownerId', - 'type', }; } diff --git a/mobile/openapi/lib/model/create_profile_image_response_dto.dart b/mobile/openapi/lib/model/create_profile_image_response_dto.dart index 9e628efa8a..c9ae3ea651 100644 --- a/mobile/openapi/lib/model/create_profile_image_response_dto.dart +++ b/mobile/openapi/lib/model/create_profile_image_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/create_tag_dto.dart b/mobile/openapi/lib/model/create_tag_dto.dart index ee4a5fe649..31b194993d 100644 --- a/mobile/openapi/lib/model/create_tag_dto.dart +++ b/mobile/openapi/lib/model/create_tag_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/create_user_dto.dart b/mobile/openapi/lib/model/create_user_dto.dart index 6fbd887d7f..4b0bdd55da 100644 --- a/mobile/openapi/lib/model/create_user_dto.dart +++ b/mobile/openapi/lib/model/create_user_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/delete_user_dto.dart b/mobile/openapi/lib/model/delete_user_dto.dart index d62f40b1ee..a758991fa9 100644 --- a/mobile/openapi/lib/model/delete_user_dto.dart +++ b/mobile/openapi/lib/model/delete_user_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/download_archive_info.dart b/mobile/openapi/lib/model/download_archive_info.dart index 20cf8f9b5f..e324850bdc 100644 --- a/mobile/openapi/lib/model/download_archive_info.dart +++ b/mobile/openapi/lib/model/download_archive_info.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/download_info_dto.dart b/mobile/openapi/lib/model/download_info_dto.dart index 7de463b7cb..4c38769010 100644 --- a/mobile/openapi/lib/model/download_info_dto.dart +++ b/mobile/openapi/lib/model/download_info_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/download_response_dto.dart b/mobile/openapi/lib/model/download_response_dto.dart index 1945491a13..f32cba9253 100644 --- a/mobile/openapi/lib/model/download_response_dto.dart +++ b/mobile/openapi/lib/model/download_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/duplicate_detection_config.dart b/mobile/openapi/lib/model/duplicate_detection_config.dart new file mode 100644 index 0000000000..4565a80c0e --- /dev/null +++ b/mobile/openapi/lib/model/duplicate_detection_config.dart @@ -0,0 +1,108 @@ +// +// 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 DuplicateDetectionConfig { + /// Returns a new [DuplicateDetectionConfig] instance. + DuplicateDetectionConfig({ + required this.enabled, + required this.maxDistance, + }); + + bool enabled; + + /// Minimum value: 0.001 + /// Maximum value: 0.1 + double maxDistance; + + @override + bool operator ==(Object other) => identical(this, other) || other is DuplicateDetectionConfig && + other.enabled == enabled && + other.maxDistance == maxDistance; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (enabled.hashCode) + + (maxDistance.hashCode); + + @override + String toString() => 'DuplicateDetectionConfig[enabled=$enabled, maxDistance=$maxDistance]'; + + Map toJson() { + final json = {}; + json[r'enabled'] = this.enabled; + json[r'maxDistance'] = this.maxDistance; + return json; + } + + /// Returns a new [DuplicateDetectionConfig] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static DuplicateDetectionConfig? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return DuplicateDetectionConfig( + enabled: mapValueOfType(json, r'enabled')!, + maxDistance: mapValueOfType(json, r'maxDistance')!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = DuplicateDetectionConfig.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = DuplicateDetectionConfig.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of DuplicateDetectionConfig-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = DuplicateDetectionConfig.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'enabled', + 'maxDistance', + }; +} + diff --git a/mobile/openapi/lib/model/duplicate_response_dto.dart b/mobile/openapi/lib/model/duplicate_response_dto.dart new file mode 100644 index 0000000000..b93ecfe5f5 --- /dev/null +++ b/mobile/openapi/lib/model/duplicate_response_dto.dart @@ -0,0 +1,106 @@ +// +// 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 DuplicateResponseDto { + /// Returns a new [DuplicateResponseDto] instance. + DuplicateResponseDto({ + this.assets = const [], + required this.duplicateId, + }); + + List assets; + + String duplicateId; + + @override + bool operator ==(Object other) => identical(this, other) || other is DuplicateResponseDto && + _deepEquality.equals(other.assets, assets) && + other.duplicateId == duplicateId; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (assets.hashCode) + + (duplicateId.hashCode); + + @override + String toString() => 'DuplicateResponseDto[assets=$assets, duplicateId=$duplicateId]'; + + Map toJson() { + final json = {}; + json[r'assets'] = this.assets; + json[r'duplicateId'] = this.duplicateId; + return json; + } + + /// Returns a new [DuplicateResponseDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static DuplicateResponseDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return DuplicateResponseDto( + assets: AssetResponseDto.listFromJson(json[r'assets']), + duplicateId: mapValueOfType(json, r'duplicateId')!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = DuplicateResponseDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = DuplicateResponseDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of DuplicateResponseDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = DuplicateResponseDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'assets', + 'duplicateId', + }; +} + diff --git a/mobile/openapi/lib/model/entity_type.dart b/mobile/openapi/lib/model/entity_type.dart index 9309e61a23..93a0d0d3cc 100644 --- a/mobile/openapi/lib/model/entity_type.dart +++ b/mobile/openapi/lib/model/entity_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/exif_response_dto.dart b/mobile/openapi/lib/model/exif_response_dto.dart index f508a5ca58..d29d485a05 100644 --- a/mobile/openapi/lib/model/exif_response_dto.dart +++ b/mobile/openapi/lib/model/exif_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/face_dto.dart b/mobile/openapi/lib/model/face_dto.dart index 4f1417ac1a..4fcc86debf 100644 --- a/mobile/openapi/lib/model/face_dto.dart +++ b/mobile/openapi/lib/model/face_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/file_checksum_dto.dart b/mobile/openapi/lib/model/file_checksum_dto.dart index 2ab0b79ff3..c7e8aa1da6 100644 --- a/mobile/openapi/lib/model/file_checksum_dto.dart +++ b/mobile/openapi/lib/model/file_checksum_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/file_checksum_response_dto.dart b/mobile/openapi/lib/model/file_checksum_response_dto.dart index 17c9f9ee55..d4bae3c273 100644 --- a/mobile/openapi/lib/model/file_checksum_response_dto.dart +++ b/mobile/openapi/lib/model/file_checksum_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/file_report_dto.dart b/mobile/openapi/lib/model/file_report_dto.dart index 517790411e..422215ff6c 100644 --- a/mobile/openapi/lib/model/file_report_dto.dart +++ b/mobile/openapi/lib/model/file_report_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/file_report_fix_dto.dart b/mobile/openapi/lib/model/file_report_fix_dto.dart index 420899a8d0..cf09242b0f 100644 --- a/mobile/openapi/lib/model/file_report_fix_dto.dart +++ b/mobile/openapi/lib/model/file_report_fix_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/file_report_item_dto.dart b/mobile/openapi/lib/model/file_report_item_dto.dart index fd937b04e2..5255005daa 100644 --- a/mobile/openapi/lib/model/file_report_item_dto.dart +++ b/mobile/openapi/lib/model/file_report_item_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/image_format.dart b/mobile/openapi/lib/model/image_format.dart index 570b6ca6e6..479b519e24 100644 --- a/mobile/openapi/lib/model/image_format.dart +++ b/mobile/openapi/lib/model/image_format.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/job_command.dart b/mobile/openapi/lib/model/job_command.dart index 1679776718..46ca7db68f 100644 --- a/mobile/openapi/lib/model/job_command.dart +++ b/mobile/openapi/lib/model/job_command.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/job_command_dto.dart b/mobile/openapi/lib/model/job_command_dto.dart index 00fc4a7e0d..5c56715644 100644 --- a/mobile/openapi/lib/model/job_command_dto.dart +++ b/mobile/openapi/lib/model/job_command_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/job_counts_dto.dart b/mobile/openapi/lib/model/job_counts_dto.dart index 7622673982..cf1d0b457d 100644 --- a/mobile/openapi/lib/model/job_counts_dto.dart +++ b/mobile/openapi/lib/model/job_counts_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/job_name.dart b/mobile/openapi/lib/model/job_name.dart index 771d434c7c..072da76d4c 100644 --- a/mobile/openapi/lib/model/job_name.dart +++ b/mobile/openapi/lib/model/job_name.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -29,6 +29,7 @@ class JobName { static const faceDetection = JobName._(r'faceDetection'); static const facialRecognition = JobName._(r'facialRecognition'); static const smartSearch = JobName._(r'smartSearch'); + static const duplicateDetection = JobName._(r'duplicateDetection'); static const backgroundTask = JobName._(r'backgroundTask'); static const storageTemplateMigration = JobName._(r'storageTemplateMigration'); static const migration = JobName._(r'migration'); @@ -45,6 +46,7 @@ class JobName { faceDetection, facialRecognition, smartSearch, + duplicateDetection, backgroundTask, storageTemplateMigration, migration, @@ -96,6 +98,7 @@ class JobNameTypeTransformer { case r'faceDetection': return JobName.faceDetection; case r'facialRecognition': return JobName.facialRecognition; case r'smartSearch': return JobName.smartSearch; + case r'duplicateDetection': return JobName.duplicateDetection; case r'backgroundTask': return JobName.backgroundTask; case r'storageTemplateMigration': return JobName.storageTemplateMigration; case r'migration': return JobName.migration; diff --git a/mobile/openapi/lib/model/job_settings_dto.dart b/mobile/openapi/lib/model/job_settings_dto.dart index c7c10c267b..9c59d503ca 100644 --- a/mobile/openapi/lib/model/job_settings_dto.dart +++ b/mobile/openapi/lib/model/job_settings_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/job_status_dto.dart b/mobile/openapi/lib/model/job_status_dto.dart index de372a36a9..fd925bd53a 100644 --- a/mobile/openapi/lib/model/job_status_dto.dart +++ b/mobile/openapi/lib/model/job_status_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/library_response_dto.dart b/mobile/openapi/lib/model/library_response_dto.dart index eadd3049fb..e27b489104 100644 --- a/mobile/openapi/lib/model/library_response_dto.dart +++ b/mobile/openapi/lib/model/library_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -21,7 +21,6 @@ class LibraryResponseDto { required this.name, required this.ownerId, required this.refreshedAt, - required this.type, required this.updatedAt, }); @@ -41,8 +40,6 @@ class LibraryResponseDto { DateTime? refreshedAt; - LibraryType type; - DateTime updatedAt; @override @@ -55,7 +52,6 @@ class LibraryResponseDto { other.name == name && other.ownerId == ownerId && other.refreshedAt == refreshedAt && - other.type == type && other.updatedAt == updatedAt; @override @@ -69,11 +65,10 @@ class LibraryResponseDto { (name.hashCode) + (ownerId.hashCode) + (refreshedAt == null ? 0 : refreshedAt!.hashCode) + - (type.hashCode) + (updatedAt.hashCode); @override - String toString() => 'LibraryResponseDto[assetCount=$assetCount, createdAt=$createdAt, exclusionPatterns=$exclusionPatterns, id=$id, importPaths=$importPaths, name=$name, ownerId=$ownerId, refreshedAt=$refreshedAt, type=$type, updatedAt=$updatedAt]'; + String toString() => 'LibraryResponseDto[assetCount=$assetCount, createdAt=$createdAt, exclusionPatterns=$exclusionPatterns, id=$id, importPaths=$importPaths, name=$name, ownerId=$ownerId, refreshedAt=$refreshedAt, updatedAt=$updatedAt]'; Map toJson() { final json = {}; @@ -89,7 +84,6 @@ class LibraryResponseDto { } else { // json[r'refreshedAt'] = null; } - json[r'type'] = this.type; json[r'updatedAt'] = this.updatedAt.toUtc().toIso8601String(); return json; } @@ -114,7 +108,6 @@ class LibraryResponseDto { name: mapValueOfType(json, r'name')!, ownerId: mapValueOfType(json, r'ownerId')!, refreshedAt: mapDateTime(json, r'refreshedAt', r''), - type: LibraryType.fromJson(json[r'type'])!, updatedAt: mapDateTime(json, r'updatedAt', r'')!, ); } @@ -171,7 +164,6 @@ class LibraryResponseDto { 'name', 'ownerId', 'refreshedAt', - 'type', 'updatedAt', }; } diff --git a/mobile/openapi/lib/model/library_stats_response_dto.dart b/mobile/openapi/lib/model/library_stats_response_dto.dart index 36215d094e..8cfb292855 100644 --- a/mobile/openapi/lib/model/library_stats_response_dto.dart +++ b/mobile/openapi/lib/model/library_stats_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/library_type.dart b/mobile/openapi/lib/model/library_type.dart deleted file mode 100644 index 37cfeb5ec4..0000000000 --- a/mobile/openapi/lib/model/library_type.dart +++ /dev/null @@ -1,85 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 LibraryType { - /// Instantiate a new enum with the provided [value]. - const LibraryType._(this.value); - - /// The underlying value of this enum member. - final String value; - - @override - String toString() => value; - - String toJson() => value; - - static const UPLOAD = LibraryType._(r'UPLOAD'); - static const EXTERNAL = LibraryType._(r'EXTERNAL'); - - /// List of all possible values in this [enum][LibraryType]. - static const values = [ - UPLOAD, - EXTERNAL, - ]; - - static LibraryType? fromJson(dynamic value) => LibraryTypeTypeTransformer().decode(value); - - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; - if (json is List && json.isNotEmpty) { - for (final row in json) { - final value = LibraryType.fromJson(row); - if (value != null) { - result.add(value); - } - } - } - return result.toList(growable: growable); - } -} - -/// Transformation class that can [encode] an instance of [LibraryType] to String, -/// and [decode] dynamic data back to [LibraryType]. -class LibraryTypeTypeTransformer { - factory LibraryTypeTypeTransformer() => _instance ??= const LibraryTypeTypeTransformer._(); - - const LibraryTypeTypeTransformer._(); - - String encode(LibraryType data) => data.value; - - /// Decodes a [dynamic value][data] to a LibraryType. - /// - /// 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. - LibraryType? decode(dynamic data, {bool allowNull = true}) { - if (data != null) { - switch (data) { - case r'UPLOAD': return LibraryType.UPLOAD; - case r'EXTERNAL': return LibraryType.EXTERNAL; - default: - if (!allowNull) { - throw ArgumentError('Unknown enum value to decode: $data'); - } - } - } - return null; - } - - /// Singleton [LibraryTypeTypeTransformer] instance. - static LibraryTypeTypeTransformer? _instance; -} - diff --git a/mobile/openapi/lib/model/log_level.dart b/mobile/openapi/lib/model/log_level.dart index 73f9fe5e24..2129096da2 100644 --- a/mobile/openapi/lib/model/log_level.dart +++ b/mobile/openapi/lib/model/log_level.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/login_credential_dto.dart b/mobile/openapi/lib/model/login_credential_dto.dart index 8dc3d9d58f..ac2f511691 100644 --- a/mobile/openapi/lib/model/login_credential_dto.dart +++ b/mobile/openapi/lib/model/login_credential_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/login_response_dto.dart b/mobile/openapi/lib/model/login_response_dto.dart index b116f0c96f..6a0eb2355c 100644 --- a/mobile/openapi/lib/model/login_response_dto.dart +++ b/mobile/openapi/lib/model/login_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/logout_response_dto.dart b/mobile/openapi/lib/model/logout_response_dto.dart index 11fcda7ecf..ca1e8d23bb 100644 --- a/mobile/openapi/lib/model/logout_response_dto.dart +++ b/mobile/openapi/lib/model/logout_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/map_marker_response_dto.dart b/mobile/openapi/lib/model/map_marker_response_dto.dart index 8331f0679c..ca1ec3c8a1 100644 --- a/mobile/openapi/lib/model/map_marker_response_dto.dart +++ b/mobile/openapi/lib/model/map_marker_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/map_theme.dart b/mobile/openapi/lib/model/map_theme.dart index a2e43425b4..e2553790c6 100644 --- a/mobile/openapi/lib/model/map_theme.dart +++ b/mobile/openapi/lib/model/map_theme.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/memory_create_dto.dart b/mobile/openapi/lib/model/memory_create_dto.dart index c48a07c5f0..2efdf88936 100644 --- a/mobile/openapi/lib/model/memory_create_dto.dart +++ b/mobile/openapi/lib/model/memory_create_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/memory_lane_response_dto.dart b/mobile/openapi/lib/model/memory_lane_response_dto.dart index 2f1f659529..4abe607381 100644 --- a/mobile/openapi/lib/model/memory_lane_response_dto.dart +++ b/mobile/openapi/lib/model/memory_lane_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -14,37 +14,30 @@ class MemoryLaneResponseDto { /// Returns a new [MemoryLaneResponseDto] instance. MemoryLaneResponseDto({ this.assets = const [], - required this.title, required this.yearsAgo, }); List 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, title=$title, yearsAgo=$yearsAgo]'; + String toString() => 'MemoryLaneResponseDto[assets=$assets, yearsAgo=$yearsAgo]'; Map toJson() { final json = {}; json[r'assets'] = this.assets; - json[r'title'] = this.title; json[r'yearsAgo'] = this.yearsAgo; return json; } @@ -58,7 +51,6 @@ class MemoryLaneResponseDto { return MemoryLaneResponseDto( assets: AssetResponseDto.listFromJson(json[r'assets']), - title: mapValueOfType(json, r'title')!, yearsAgo: mapValueOfType(json, r'yearsAgo')!, ); } @@ -108,7 +100,6 @@ class MemoryLaneResponseDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'assets', - 'title', 'yearsAgo', }; } diff --git a/mobile/openapi/lib/model/memory_response_dto.dart b/mobile/openapi/lib/model/memory_response_dto.dart index 8671e3c645..06e0e3114b 100644 --- a/mobile/openapi/lib/model/memory_response_dto.dart +++ b/mobile/openapi/lib/model/memory_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/memory_type.dart b/mobile/openapi/lib/model/memory_type.dart index 513b7c2d45..aee7bd1ba1 100644 --- a/mobile/openapi/lib/model/memory_type.dart +++ b/mobile/openapi/lib/model/memory_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/memory_update_dto.dart b/mobile/openapi/lib/model/memory_update_dto.dart index adf42330df..318f4b42ad 100644 --- a/mobile/openapi/lib/model/memory_update_dto.dart +++ b/mobile/openapi/lib/model/memory_update_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/merge_person_dto.dart b/mobile/openapi/lib/model/merge_person_dto.dart index cb3a5f4c3b..ea23042e2c 100644 --- a/mobile/openapi/lib/model/merge_person_dto.dart +++ b/mobile/openapi/lib/model/merge_person_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/metadata_search_dto.dart b/mobile/openapi/lib/model/metadata_search_dto.dart index 6ef3ffcfcd..322373ee58 100644 --- a/mobile/openapi/lib/model/metadata_search_dto.dart +++ b/mobile/openapi/lib/model/metadata_search_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -39,7 +39,6 @@ class MetadataSearchDto { this.page, this.personIds = const [], this.previewPath, - this.resizePath, this.size, this.state, this.takenAfter, @@ -50,7 +49,6 @@ class MetadataSearchDto { this.type, this.updatedAfter, this.updatedBefore, - this.webpPath, this.withArchived = false, this.withDeleted, this.withExif, @@ -261,15 +259,6 @@ 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 /// @@ -352,15 +341,6 @@ 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; /// @@ -423,7 +403,6 @@ 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 && @@ -434,7 +413,6 @@ class MetadataSearchDto { other.type == type && other.updatedAfter == updatedAfter && other.updatedBefore == updatedBefore && - other.webpPath == webpPath && other.withArchived == withArchived && other.withDeleted == withDeleted && other.withExif == withExif && @@ -470,7 +448,6 @@ 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) + @@ -481,7 +458,6 @@ 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) + @@ -489,7 +465,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, 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]'; + 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]'; Map toJson() { final json = {}; @@ -619,11 +595,6 @@ 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 { @@ -673,11 +644,6 @@ 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) { @@ -739,7 +705,6 @@ class MetadataSearchDto { ? (json[r'personIds'] as Iterable).cast().toList(growable: false) : const [], previewPath: mapValueOfType(json, r'previewPath'), - resizePath: mapValueOfType(json, r'resizePath'), size: num.parse('${json[r'size']}'), state: mapValueOfType(json, r'state'), takenAfter: mapDateTime(json, r'takenAfter', r''), @@ -750,7 +715,6 @@ class MetadataSearchDto { type: AssetTypeEnum.fromJson(json[r'type']), updatedAfter: mapDateTime(json, r'updatedAfter', r''), updatedBefore: mapDateTime(json, r'updatedBefore', r''), - webpPath: mapValueOfType(json, r'webpPath'), withArchived: mapValueOfType(json, r'withArchived') ?? false, withDeleted: mapValueOfType(json, r'withDeleted'), withExif: mapValueOfType(json, r'withExif'), diff --git a/mobile/openapi/lib/model/model_type.dart b/mobile/openapi/lib/model/model_type.dart index 4b7c350321..36f7424199 100644 --- a/mobile/openapi/lib/model/model_type.dart +++ b/mobile/openapi/lib/model/model_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart b/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart index f042713cce..ffd017f816 100644 --- a/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart +++ b/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/o_auth_callback_dto.dart b/mobile/openapi/lib/model/o_auth_callback_dto.dart index 0ec446cead..89ad0f60b0 100644 --- a/mobile/openapi/lib/model/o_auth_callback_dto.dart +++ b/mobile/openapi/lib/model/o_auth_callback_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/o_auth_config_dto.dart b/mobile/openapi/lib/model/o_auth_config_dto.dart index a86b5ab714..7d76758864 100644 --- a/mobile/openapi/lib/model/o_auth_config_dto.dart +++ b/mobile/openapi/lib/model/o_auth_config_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/on_this_day_dto.dart b/mobile/openapi/lib/model/on_this_day_dto.dart index 81b13e391b..be170caf85 100644 --- a/mobile/openapi/lib/model/on_this_day_dto.dart +++ b/mobile/openapi/lib/model/on_this_day_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/partner_response_dto.dart b/mobile/openapi/lib/model/partner_response_dto.dart index 37602d04b7..1efd91c346 100644 --- a/mobile/openapi/lib/model/partner_response_dto.dart +++ b/mobile/openapi/lib/model/partner_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/path_entity_type.dart b/mobile/openapi/lib/model/path_entity_type.dart index e1f45f0e83..fdcdae4f1b 100644 --- a/mobile/openapi/lib/model/path_entity_type.dart +++ b/mobile/openapi/lib/model/path_entity_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/path_type.dart b/mobile/openapi/lib/model/path_type.dart index 11cdf41ea1..bfb16c6667 100644 --- a/mobile/openapi/lib/model/path_type.dart +++ b/mobile/openapi/lib/model/path_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/people_response_dto.dart b/mobile/openapi/lib/model/people_response_dto.dart index 02a82cadf1..423ea989d4 100644 --- a/mobile/openapi/lib/model/people_response_dto.dart +++ b/mobile/openapi/lib/model/people_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/people_update_dto.dart b/mobile/openapi/lib/model/people_update_dto.dart index a98934b521..9fcfdc8761 100644 --- a/mobile/openapi/lib/model/people_update_dto.dart +++ b/mobile/openapi/lib/model/people_update_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/people_update_item.dart b/mobile/openapi/lib/model/people_update_item.dart index 565743e11d..8af0a8b11a 100644 --- a/mobile/openapi/lib/model/people_update_item.dart +++ b/mobile/openapi/lib/model/people_update_item.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/person_create_dto.dart b/mobile/openapi/lib/model/person_create_dto.dart index 4811de3efe..9889328dee 100644 --- a/mobile/openapi/lib/model/person_create_dto.dart +++ b/mobile/openapi/lib/model/person_create_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/person_response_dto.dart b/mobile/openapi/lib/model/person_response_dto.dart index 30edc062be..e1f6b44e5b 100644 --- a/mobile/openapi/lib/model/person_response_dto.dart +++ b/mobile/openapi/lib/model/person_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/person_statistics_response_dto.dart b/mobile/openapi/lib/model/person_statistics_response_dto.dart index 17dd4f356b..929fbc29d2 100644 --- a/mobile/openapi/lib/model/person_statistics_response_dto.dart +++ b/mobile/openapi/lib/model/person_statistics_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/person_update_dto.dart b/mobile/openapi/lib/model/person_update_dto.dart index 611efe8171..1af03890a2 100644 --- a/mobile/openapi/lib/model/person_update_dto.dart +++ b/mobile/openapi/lib/model/person_update_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/person_with_faces_response_dto.dart b/mobile/openapi/lib/model/person_with_faces_response_dto.dart index 67ac02ca02..b15e620250 100644 --- a/mobile/openapi/lib/model/person_with_faces_response_dto.dart +++ b/mobile/openapi/lib/model/person_with_faces_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/places_response_dto.dart b/mobile/openapi/lib/model/places_response_dto.dart index a2d8378883..d3e1fc449b 100644 --- a/mobile/openapi/lib/model/places_response_dto.dart +++ b/mobile/openapi/lib/model/places_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/queue_status_dto.dart b/mobile/openapi/lib/model/queue_status_dto.dart index 96775de8e9..7f7d310f6f 100644 --- a/mobile/openapi/lib/model/queue_status_dto.dart +++ b/mobile/openapi/lib/model/queue_status_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/reaction_level.dart b/mobile/openapi/lib/model/reaction_level.dart index 2f96b4b32c..29568b9d11 100644 --- a/mobile/openapi/lib/model/reaction_level.dart +++ b/mobile/openapi/lib/model/reaction_level.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/reaction_type.dart b/mobile/openapi/lib/model/reaction_type.dart index 8ea9afcdb0..4c788138fb 100644 --- a/mobile/openapi/lib/model/reaction_type.dart +++ b/mobile/openapi/lib/model/reaction_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/recognition_config.dart b/mobile/openapi/lib/model/recognition_config.dart index 3d4171bf68..3080023bbd 100644 --- a/mobile/openapi/lib/model/recognition_config.dart +++ b/mobile/openapi/lib/model/recognition_config.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart b/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart index 71e1d3ad99..eb414be984 100644 --- a/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart +++ b/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/scan_library_dto.dart b/mobile/openapi/lib/model/scan_library_dto.dart index 0f5dedf64a..1b31aaaf01 100644 --- a/mobile/openapi/lib/model/scan_library_dto.dart +++ b/mobile/openapi/lib/model/scan_library_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_album_response_dto.dart b/mobile/openapi/lib/model/search_album_response_dto.dart index 7925356102..46ce5273ac 100644 --- a/mobile/openapi/lib/model/search_album_response_dto.dart +++ b/mobile/openapi/lib/model/search_album_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_asset_response_dto.dart b/mobile/openapi/lib/model/search_asset_response_dto.dart index abdbc5d4e3..21ddbbb213 100644 --- a/mobile/openapi/lib/model/search_asset_response_dto.dart +++ b/mobile/openapi/lib/model/search_asset_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_explore_item.dart b/mobile/openapi/lib/model/search_explore_item.dart index 218f7f4c6f..951fdd1bc8 100644 --- a/mobile/openapi/lib/model/search_explore_item.dart +++ b/mobile/openapi/lib/model/search_explore_item.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_explore_response_dto.dart b/mobile/openapi/lib/model/search_explore_response_dto.dart index ad317642d9..5bc601de9e 100644 --- a/mobile/openapi/lib/model/search_explore_response_dto.dart +++ b/mobile/openapi/lib/model/search_explore_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_facet_count_response_dto.dart b/mobile/openapi/lib/model/search_facet_count_response_dto.dart index a53ae6b86c..b40710e525 100644 --- a/mobile/openapi/lib/model/search_facet_count_response_dto.dart +++ b/mobile/openapi/lib/model/search_facet_count_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_facet_response_dto.dart b/mobile/openapi/lib/model/search_facet_response_dto.dart index 30dd1215fa..0784921c6b 100644 --- a/mobile/openapi/lib/model/search_facet_response_dto.dart +++ b/mobile/openapi/lib/model/search_facet_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_response_dto.dart b/mobile/openapi/lib/model/search_response_dto.dart index 2f697f3dd8..9b2b7fd3cf 100644 --- a/mobile/openapi/lib/model/search_response_dto.dart +++ b/mobile/openapi/lib/model/search_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/search_suggestion_type.dart b/mobile/openapi/lib/model/search_suggestion_type.dart index d33b4a69d9..3f905e029d 100644 --- a/mobile/openapi/lib/model/search_suggestion_type.dart +++ b/mobile/openapi/lib/model/search_suggestion_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/server_config_dto.dart b/mobile/openapi/lib/model/server_config_dto.dart index faa167c73a..47cc52fb2c 100644 --- a/mobile/openapi/lib/model/server_config_dto.dart +++ b/mobile/openapi/lib/model/server_config_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/server_features_dto.dart b/mobile/openapi/lib/model/server_features_dto.dart index f9f8233f49..3e5466237a 100644 --- a/mobile/openapi/lib/model/server_features_dto.dart +++ b/mobile/openapi/lib/model/server_features_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -14,6 +14,7 @@ class ServerFeaturesDto { /// Returns a new [ServerFeaturesDto] instance. ServerFeaturesDto({ required this.configFile, + required this.duplicateDetection, required this.email, required this.facialRecognition, required this.map, @@ -29,6 +30,8 @@ class ServerFeaturesDto { bool configFile; + bool duplicateDetection; + bool email; bool facialRecognition; @@ -54,6 +57,7 @@ class ServerFeaturesDto { @override bool operator ==(Object other) => identical(this, other) || other is ServerFeaturesDto && other.configFile == configFile && + other.duplicateDetection == duplicateDetection && other.email == email && other.facialRecognition == facialRecognition && other.map == map && @@ -70,6 +74,7 @@ class ServerFeaturesDto { int get hashCode => // ignore: unnecessary_parenthesis (configFile.hashCode) + + (duplicateDetection.hashCode) + (email.hashCode) + (facialRecognition.hashCode) + (map.hashCode) + @@ -83,11 +88,12 @@ class ServerFeaturesDto { (trash.hashCode); @override - String toString() => 'ServerFeaturesDto[configFile=$configFile, email=$email, facialRecognition=$facialRecognition, map=$map, oauth=$oauth, oauthAutoLaunch=$oauthAutoLaunch, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, trash=$trash]'; + String toString() => 'ServerFeaturesDto[configFile=$configFile, duplicateDetection=$duplicateDetection, email=$email, facialRecognition=$facialRecognition, map=$map, oauth=$oauth, oauthAutoLaunch=$oauthAutoLaunch, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, search=$search, sidecar=$sidecar, smartSearch=$smartSearch, trash=$trash]'; Map toJson() { final json = {}; json[r'configFile'] = this.configFile; + json[r'duplicateDetection'] = this.duplicateDetection; json[r'email'] = this.email; json[r'facialRecognition'] = this.facialRecognition; json[r'map'] = this.map; @@ -111,6 +117,7 @@ class ServerFeaturesDto { return ServerFeaturesDto( configFile: mapValueOfType(json, r'configFile')!, + duplicateDetection: mapValueOfType(json, r'duplicateDetection')!, email: mapValueOfType(json, r'email')!, facialRecognition: mapValueOfType(json, r'facialRecognition')!, map: mapValueOfType(json, r'map')!, @@ -170,6 +177,7 @@ class ServerFeaturesDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'configFile', + 'duplicateDetection', 'email', 'facialRecognition', 'map', diff --git a/mobile/openapi/lib/model/server_media_types_response_dto.dart b/mobile/openapi/lib/model/server_media_types_response_dto.dart index cf5a93bf8c..35ddef1956 100644 --- a/mobile/openapi/lib/model/server_media_types_response_dto.dart +++ b/mobile/openapi/lib/model/server_media_types_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/server_ping_response.dart b/mobile/openapi/lib/model/server_ping_response.dart index 280a50a44b..e23dc15c61 100644 --- a/mobile/openapi/lib/model/server_ping_response.dart +++ b/mobile/openapi/lib/model/server_ping_response.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/server_stats_response_dto.dart b/mobile/openapi/lib/model/server_stats_response_dto.dart index c4afaa348c..6996e49aa5 100644 --- a/mobile/openapi/lib/model/server_stats_response_dto.dart +++ b/mobile/openapi/lib/model/server_stats_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/server_info_response_dto.dart b/mobile/openapi/lib/model/server_storage_response_dto.dart similarity index 71% rename from mobile/openapi/lib/model/server_info_response_dto.dart rename to mobile/openapi/lib/model/server_storage_response_dto.dart index e66cfe44bf..ab0f169e4b 100644 --- a/mobile/openapi/lib/model/server_info_response_dto.dart +++ b/mobile/openapi/lib/model/server_storage_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -10,9 +10,9 @@ part of openapi.api; -class ServerInfoResponseDto { - /// Returns a new [ServerInfoResponseDto] instance. - ServerInfoResponseDto({ +class ServerStorageResponseDto { + /// Returns a new [ServerStorageResponseDto] instance. + ServerStorageResponseDto({ required this.diskAvailable, required this.diskAvailableRaw, required this.diskSize, @@ -37,7 +37,7 @@ class ServerInfoResponseDto { int diskUseRaw; @override - bool operator ==(Object other) => identical(this, other) || other is ServerInfoResponseDto && + bool operator ==(Object other) => identical(this, other) || other is ServerStorageResponseDto && other.diskAvailable == diskAvailable && other.diskAvailableRaw == diskAvailableRaw && other.diskSize == diskSize && @@ -58,7 +58,7 @@ class ServerInfoResponseDto { (diskUseRaw.hashCode); @override - String toString() => 'ServerInfoResponseDto[diskAvailable=$diskAvailable, diskAvailableRaw=$diskAvailableRaw, diskSize=$diskSize, diskSizeRaw=$diskSizeRaw, diskUsagePercentage=$diskUsagePercentage, diskUse=$diskUse, diskUseRaw=$diskUseRaw]'; + String toString() => 'ServerStorageResponseDto[diskAvailable=$diskAvailable, diskAvailableRaw=$diskAvailableRaw, diskSize=$diskSize, diskSizeRaw=$diskSizeRaw, diskUsagePercentage=$diskUsagePercentage, diskUse=$diskUse, diskUseRaw=$diskUseRaw]'; Map toJson() { final json = {}; @@ -72,14 +72,14 @@ class ServerInfoResponseDto { return json; } - /// Returns a new [ServerInfoResponseDto] instance and imports its values from + /// Returns a new [ServerStorageResponseDto] instance and imports its values from /// [value] if it's a [Map], null otherwise. // ignore: prefer_constructors_over_static_methods - static ServerInfoResponseDto? fromJson(dynamic value) { + static ServerStorageResponseDto? fromJson(dynamic value) { if (value is Map) { final json = value.cast(); - return ServerInfoResponseDto( + return ServerStorageResponseDto( diskAvailable: mapValueOfType(json, r'diskAvailable')!, diskAvailableRaw: mapValueOfType(json, r'diskAvailableRaw')!, diskSize: mapValueOfType(json, r'diskSize')!, @@ -92,11 +92,11 @@ class ServerInfoResponseDto { return null; } - static List listFromJson(dynamic json, {bool growable = false,}) { - final result = []; + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; if (json is List && json.isNotEmpty) { for (final row in json) { - final value = ServerInfoResponseDto.fromJson(row); + final value = ServerStorageResponseDto.fromJson(row); if (value != null) { result.add(value); } @@ -105,12 +105,12 @@ class ServerInfoResponseDto { return result.toList(growable: growable); } - static Map mapFromJson(dynamic json) { - final map = {}; + static Map mapFromJson(dynamic json) { + final map = {}; if (json is Map && json.isNotEmpty) { json = json.cast(); // ignore: parameter_assignments for (final entry in json.entries) { - final value = ServerInfoResponseDto.fromJson(entry.value); + final value = ServerStorageResponseDto.fromJson(entry.value); if (value != null) { map[entry.key] = value; } @@ -119,14 +119,14 @@ class ServerInfoResponseDto { return map; } - // maps a json object with a list of ServerInfoResponseDto-objects as value to a dart map - static Map> mapListFromJson(dynamic json, {bool growable = false,}) { - final map = >{}; + // maps a json object with a list of ServerStorageResponseDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; if (json is Map && json.isNotEmpty) { // ignore: parameter_assignments json = json.cast(); for (final entry in json.entries) { - map[entry.key] = ServerInfoResponseDto.listFromJson(entry.value, growable: growable,); + map[entry.key] = ServerStorageResponseDto.listFromJson(entry.value, growable: growable,); } } return map; diff --git a/mobile/openapi/lib/model/server_theme_dto.dart b/mobile/openapi/lib/model/server_theme_dto.dart index e822c33df1..65b9b9163e 100644 --- a/mobile/openapi/lib/model/server_theme_dto.dart +++ b/mobile/openapi/lib/model/server_theme_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/server_version_response_dto.dart b/mobile/openapi/lib/model/server_version_response_dto.dart index 65f76311b8..e507f3372a 100644 --- a/mobile/openapi/lib/model/server_version_response_dto.dart +++ b/mobile/openapi/lib/model/server_version_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/session_response_dto.dart b/mobile/openapi/lib/model/session_response_dto.dart index 6a44fc24bb..82673b3874 100644 --- a/mobile/openapi/lib/model/session_response_dto.dart +++ b/mobile/openapi/lib/model/session_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/shared_link_create_dto.dart b/mobile/openapi/lib/model/shared_link_create_dto.dart index 920e62e52e..623bc3125f 100644 --- a/mobile/openapi/lib/model/shared_link_create_dto.dart +++ b/mobile/openapi/lib/model/shared_link_create_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/shared_link_edit_dto.dart b/mobile/openapi/lib/model/shared_link_edit_dto.dart index ff4e270a8e..2369c85db1 100644 --- a/mobile/openapi/lib/model/shared_link_edit_dto.dart +++ b/mobile/openapi/lib/model/shared_link_edit_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/shared_link_response_dto.dart b/mobile/openapi/lib/model/shared_link_response_dto.dart index b114b9cd6a..018a1a51de 100644 --- a/mobile/openapi/lib/model/shared_link_response_dto.dart +++ b/mobile/openapi/lib/model/shared_link_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/shared_link_type.dart b/mobile/openapi/lib/model/shared_link_type.dart index 317c7037f9..efab97c209 100644 --- a/mobile/openapi/lib/model/shared_link_type.dart +++ b/mobile/openapi/lib/model/shared_link_type.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/sign_up_dto.dart b/mobile/openapi/lib/model/sign_up_dto.dart index b9f5261abe..772749fdba 100644 --- a/mobile/openapi/lib/model/sign_up_dto.dart +++ b/mobile/openapi/lib/model/sign_up_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/smart_info_response_dto.dart b/mobile/openapi/lib/model/smart_info_response_dto.dart index 72e958297a..52e7c108b8 100644 --- a/mobile/openapi/lib/model/smart_info_response_dto.dart +++ b/mobile/openapi/lib/model/smart_info_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/smart_search_dto.dart b/mobile/openapi/lib/model/smart_search_dto.dart index 6b9b17e352..0ff8cf6115 100644 --- a/mobile/openapi/lib/model/smart_search_dto.dart +++ b/mobile/openapi/lib/model/smart_search_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_dto.dart b/mobile/openapi/lib/model/system_config_dto.dart index c4fe990f13..e56169742a 100644 --- a/mobile/openapi/lib/model/system_config_dto.dart +++ b/mobile/openapi/lib/model/system_config_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart b/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart index 758bc37fa4..3c856bcdbe 100644 --- a/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart +++ b/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -14,6 +14,7 @@ class SystemConfigFFmpegDto { /// Returns a new [SystemConfigFFmpegDto] instance. SystemConfigFFmpegDto({ required this.accel, + required this.accelDecode, this.acceptedAudioCodecs = const [], this.acceptedVideoCodecs = const [], required this.bframes, @@ -37,6 +38,8 @@ class SystemConfigFFmpegDto { TranscodeHWAccel accel; + bool accelDecode; + List acceptedAudioCodecs; List acceptedVideoCodecs; @@ -87,6 +90,7 @@ class SystemConfigFFmpegDto { @override bool operator ==(Object other) => identical(this, other) || other is SystemConfigFFmpegDto && other.accel == accel && + other.accelDecode == accelDecode && _deepEquality.equals(other.acceptedAudioCodecs, acceptedAudioCodecs) && _deepEquality.equals(other.acceptedVideoCodecs, acceptedVideoCodecs) && other.bframes == bframes && @@ -111,6 +115,7 @@ class SystemConfigFFmpegDto { int get hashCode => // ignore: unnecessary_parenthesis (accel.hashCode) + + (accelDecode.hashCode) + (acceptedAudioCodecs.hashCode) + (acceptedVideoCodecs.hashCode) + (bframes.hashCode) + @@ -132,11 +137,12 @@ class SystemConfigFFmpegDto { (twoPass.hashCode); @override - String toString() => 'SystemConfigFFmpegDto[accel=$accel, acceptedAudioCodecs=$acceptedAudioCodecs, acceptedVideoCodecs=$acceptedVideoCodecs, bframes=$bframes, cqMode=$cqMode, crf=$crf, gopSize=$gopSize, maxBitrate=$maxBitrate, npl=$npl, preferredHwDevice=$preferredHwDevice, preset=$preset, refs=$refs, targetAudioCodec=$targetAudioCodec, targetResolution=$targetResolution, targetVideoCodec=$targetVideoCodec, temporalAQ=$temporalAQ, threads=$threads, tonemap=$tonemap, transcode=$transcode, twoPass=$twoPass]'; + String toString() => 'SystemConfigFFmpegDto[accel=$accel, accelDecode=$accelDecode, acceptedAudioCodecs=$acceptedAudioCodecs, acceptedVideoCodecs=$acceptedVideoCodecs, bframes=$bframes, cqMode=$cqMode, crf=$crf, gopSize=$gopSize, maxBitrate=$maxBitrate, npl=$npl, preferredHwDevice=$preferredHwDevice, preset=$preset, refs=$refs, targetAudioCodec=$targetAudioCodec, targetResolution=$targetResolution, targetVideoCodec=$targetVideoCodec, temporalAQ=$temporalAQ, threads=$threads, tonemap=$tonemap, transcode=$transcode, twoPass=$twoPass]'; Map toJson() { final json = {}; json[r'accel'] = this.accel; + json[r'accelDecode'] = this.accelDecode; json[r'acceptedAudioCodecs'] = this.acceptedAudioCodecs; json[r'acceptedVideoCodecs'] = this.acceptedVideoCodecs; json[r'bframes'] = this.bframes; @@ -168,6 +174,7 @@ class SystemConfigFFmpegDto { return SystemConfigFFmpegDto( accel: TranscodeHWAccel.fromJson(json[r'accel'])!, + accelDecode: mapValueOfType(json, r'accelDecode')!, acceptedAudioCodecs: AudioCodec.listFromJson(json[r'acceptedAudioCodecs']), acceptedVideoCodecs: VideoCodec.listFromJson(json[r'acceptedVideoCodecs']), bframes: mapValueOfType(json, r'bframes')!, @@ -235,6 +242,7 @@ class SystemConfigFFmpegDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'accel', + 'accelDecode', 'acceptedAudioCodecs', 'acceptedVideoCodecs', 'bframes', diff --git a/mobile/openapi/lib/model/system_config_image_dto.dart b/mobile/openapi/lib/model/system_config_image_dto.dart index 46e598d6be..388949c759 100644 --- a/mobile/openapi/lib/model/system_config_image_dto.dart +++ b/mobile/openapi/lib/model/system_config_image_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_job_dto.dart b/mobile/openapi/lib/model/system_config_job_dto.dart index 0ddf69e465..1bc0f6b29c 100644 --- a/mobile/openapi/lib/model/system_config_job_dto.dart +++ b/mobile/openapi/lib/model/system_config_job_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_library_dto.dart b/mobile/openapi/lib/model/system_config_library_dto.dart index 4f1dad23e6..4f55e33e80 100644 --- a/mobile/openapi/lib/model/system_config_library_dto.dart +++ b/mobile/openapi/lib/model/system_config_library_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_library_scan_dto.dart b/mobile/openapi/lib/model/system_config_library_scan_dto.dart index 971a1e7585..31df272594 100644 --- a/mobile/openapi/lib/model/system_config_library_scan_dto.dart +++ b/mobile/openapi/lib/model/system_config_library_scan_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_library_watch_dto.dart b/mobile/openapi/lib/model/system_config_library_watch_dto.dart index 0bcb6f1771..9d152f366a 100644 --- a/mobile/openapi/lib/model/system_config_library_watch_dto.dart +++ b/mobile/openapi/lib/model/system_config_library_watch_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_logging_dto.dart b/mobile/openapi/lib/model/system_config_logging_dto.dart index 6692fd01fd..60c0be3d2c 100644 --- a/mobile/openapi/lib/model/system_config_logging_dto.dart +++ b/mobile/openapi/lib/model/system_config_logging_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_machine_learning_dto.dart b/mobile/openapi/lib/model/system_config_machine_learning_dto.dart index 7d5e4cba0f..fc3aae1804 100644 --- a/mobile/openapi/lib/model/system_config_machine_learning_dto.dart +++ b/mobile/openapi/lib/model/system_config_machine_learning_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -14,6 +14,7 @@ class SystemConfigMachineLearningDto { /// Returns a new [SystemConfigMachineLearningDto] instance. SystemConfigMachineLearningDto({ required this.clip, + required this.duplicateDetection, required this.enabled, required this.facialRecognition, required this.url, @@ -21,6 +22,8 @@ class SystemConfigMachineLearningDto { CLIPConfig clip; + DuplicateDetectionConfig duplicateDetection; + bool enabled; RecognitionConfig facialRecognition; @@ -30,6 +33,7 @@ class SystemConfigMachineLearningDto { @override bool operator ==(Object other) => identical(this, other) || other is SystemConfigMachineLearningDto && other.clip == clip && + other.duplicateDetection == duplicateDetection && other.enabled == enabled && other.facialRecognition == facialRecognition && other.url == url; @@ -38,16 +42,18 @@ class SystemConfigMachineLearningDto { int get hashCode => // ignore: unnecessary_parenthesis (clip.hashCode) + + (duplicateDetection.hashCode) + (enabled.hashCode) + (facialRecognition.hashCode) + (url.hashCode); @override - String toString() => 'SystemConfigMachineLearningDto[clip=$clip, enabled=$enabled, facialRecognition=$facialRecognition, url=$url]'; + String toString() => 'SystemConfigMachineLearningDto[clip=$clip, duplicateDetection=$duplicateDetection, enabled=$enabled, facialRecognition=$facialRecognition, url=$url]'; Map toJson() { final json = {}; json[r'clip'] = this.clip; + json[r'duplicateDetection'] = this.duplicateDetection; json[r'enabled'] = this.enabled; json[r'facialRecognition'] = this.facialRecognition; json[r'url'] = this.url; @@ -63,6 +69,7 @@ class SystemConfigMachineLearningDto { return SystemConfigMachineLearningDto( clip: CLIPConfig.fromJson(json[r'clip'])!, + duplicateDetection: DuplicateDetectionConfig.fromJson(json[r'duplicateDetection'])!, enabled: mapValueOfType(json, r'enabled')!, facialRecognition: RecognitionConfig.fromJson(json[r'facialRecognition'])!, url: mapValueOfType(json, r'url')!, @@ -114,6 +121,7 @@ class SystemConfigMachineLearningDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'clip', + 'duplicateDetection', 'enabled', 'facialRecognition', 'url', diff --git a/mobile/openapi/lib/model/system_config_map_dto.dart b/mobile/openapi/lib/model/system_config_map_dto.dart index f9f4a4d5de..6631885182 100644 --- a/mobile/openapi/lib/model/system_config_map_dto.dart +++ b/mobile/openapi/lib/model/system_config_map_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_new_version_check_dto.dart b/mobile/openapi/lib/model/system_config_new_version_check_dto.dart index 4ab93dfca3..c7b8c98695 100644 --- a/mobile/openapi/lib/model/system_config_new_version_check_dto.dart +++ b/mobile/openapi/lib/model/system_config_new_version_check_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_notifications_dto.dart b/mobile/openapi/lib/model/system_config_notifications_dto.dart index 0c353b0b0c..22f08b3ab4 100644 --- a/mobile/openapi/lib/model/system_config_notifications_dto.dart +++ b/mobile/openapi/lib/model/system_config_notifications_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_o_auth_dto.dart b/mobile/openapi/lib/model/system_config_o_auth_dto.dart index 1b43f3eb72..a8af9c1132 100644 --- a/mobile/openapi/lib/model/system_config_o_auth_dto.dart +++ b/mobile/openapi/lib/model/system_config_o_auth_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_password_login_dto.dart b/mobile/openapi/lib/model/system_config_password_login_dto.dart index 840206acc9..61896a890c 100644 --- a/mobile/openapi/lib/model/system_config_password_login_dto.dart +++ b/mobile/openapi/lib/model/system_config_password_login_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart b/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart index 9e5ea396d4..2eb586cac6 100644 --- a/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart +++ b/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_server_dto.dart b/mobile/openapi/lib/model/system_config_server_dto.dart index 998aec96e1..ccb48ee61d 100644 --- a/mobile/openapi/lib/model/system_config_server_dto.dart +++ b/mobile/openapi/lib/model/system_config_server_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_smtp_dto.dart b/mobile/openapi/lib/model/system_config_smtp_dto.dart index d8e490473f..6588d244ee 100644 --- a/mobile/openapi/lib/model/system_config_smtp_dto.dart +++ b/mobile/openapi/lib/model/system_config_smtp_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart b/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart index fa8e9f6c0a..63dfdca4cf 100644 --- a/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart +++ b/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_storage_template_dto.dart b/mobile/openapi/lib/model/system_config_storage_template_dto.dart index f8348c33fc..13323aebda 100644 --- a/mobile/openapi/lib/model/system_config_storage_template_dto.dart +++ b/mobile/openapi/lib/model/system_config_storage_template_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart b/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart index 1992530b40..82e0a6f747 100644 --- a/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart +++ b/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_theme_dto.dart b/mobile/openapi/lib/model/system_config_theme_dto.dart index d6897bab37..2f7f4d2f3b 100644 --- a/mobile/openapi/lib/model/system_config_theme_dto.dart +++ b/mobile/openapi/lib/model/system_config_theme_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_trash_dto.dart b/mobile/openapi/lib/model/system_config_trash_dto.dart index 255be5cbda..336019fde4 100644 --- a/mobile/openapi/lib/model/system_config_trash_dto.dart +++ b/mobile/openapi/lib/model/system_config_trash_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/system_config_user_dto.dart b/mobile/openapi/lib/model/system_config_user_dto.dart index 95b9c289e8..c466374460 100644 --- a/mobile/openapi/lib/model/system_config_user_dto.dart +++ b/mobile/openapi/lib/model/system_config_user_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/tag_response_dto.dart b/mobile/openapi/lib/model/tag_response_dto.dart index 566e7a0f18..d371bd1c04 100644 --- a/mobile/openapi/lib/model/tag_response_dto.dart +++ b/mobile/openapi/lib/model/tag_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/tag_type_enum.dart b/mobile/openapi/lib/model/tag_type_enum.dart index a5e4316a2b..3f2e723796 100644 --- a/mobile/openapi/lib/model/tag_type_enum.dart +++ b/mobile/openapi/lib/model/tag_type_enum.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/thumbnail_format.dart b/mobile/openapi/lib/model/thumbnail_format.dart index 506726e3bc..a255fac25e 100644 --- a/mobile/openapi/lib/model/thumbnail_format.dart +++ b/mobile/openapi/lib/model/thumbnail_format.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/time_bucket_response_dto.dart b/mobile/openapi/lib/model/time_bucket_response_dto.dart index da86bc4650..2c86a56b3c 100644 --- a/mobile/openapi/lib/model/time_bucket_response_dto.dart +++ b/mobile/openapi/lib/model/time_bucket_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/time_bucket_size.dart b/mobile/openapi/lib/model/time_bucket_size.dart index 443beab28f..e843b43f43 100644 --- a/mobile/openapi/lib/model/time_bucket_size.dart +++ b/mobile/openapi/lib/model/time_bucket_size.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/tone_mapping.dart b/mobile/openapi/lib/model/tone_mapping.dart index bb6206193a..e05aea2b77 100644 --- a/mobile/openapi/lib/model/tone_mapping.dart +++ b/mobile/openapi/lib/model/tone_mapping.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/transcode_hw_accel.dart b/mobile/openapi/lib/model/transcode_hw_accel.dart index 50428d3954..de5006341e 100644 --- a/mobile/openapi/lib/model/transcode_hw_accel.dart +++ b/mobile/openapi/lib/model/transcode_hw_accel.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/transcode_policy.dart b/mobile/openapi/lib/model/transcode_policy.dart index 7d586bc2dc..6e9617428a 100644 --- a/mobile/openapi/lib/model/transcode_policy.dart +++ b/mobile/openapi/lib/model/transcode_policy.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/update_album_dto.dart b/mobile/openapi/lib/model/update_album_dto.dart index d9408cedfb..f9c9762887 100644 --- a/mobile/openapi/lib/model/update_album_dto.dart +++ b/mobile/openapi/lib/model/update_album_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/update_album_user_dto.dart b/mobile/openapi/lib/model/update_album_user_dto.dart index 8e85349318..f77223acf5 100644 --- a/mobile/openapi/lib/model/update_album_user_dto.dart +++ b/mobile/openapi/lib/model/update_album_user_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/update_asset_dto.dart b/mobile/openapi/lib/model/update_asset_dto.dart index e8402f1bf8..e9a4d8d6b8 100644 --- a/mobile/openapi/lib/model/update_asset_dto.dart +++ b/mobile/openapi/lib/model/update_asset_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/update_library_dto.dart b/mobile/openapi/lib/model/update_library_dto.dart index b870f240fe..85847c0ddf 100644 --- a/mobile/openapi/lib/model/update_library_dto.dart +++ b/mobile/openapi/lib/model/update_library_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first @@ -15,7 +15,6 @@ class UpdateLibraryDto { UpdateLibraryDto({ this.exclusionPatterns = const [], this.importPaths = const [], - this.isVisible, this.name, }); @@ -23,14 +22,6 @@ class UpdateLibraryDto { List importPaths; - /// - /// 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? isVisible; - /// /// 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 @@ -43,7 +34,6 @@ class UpdateLibraryDto { bool operator ==(Object other) => identical(this, other) || other is UpdateLibraryDto && _deepEquality.equals(other.exclusionPatterns, exclusionPatterns) && _deepEquality.equals(other.importPaths, importPaths) && - other.isVisible == isVisible && other.name == name; @override @@ -51,21 +41,15 @@ class UpdateLibraryDto { // ignore: unnecessary_parenthesis (exclusionPatterns.hashCode) + (importPaths.hashCode) + - (isVisible == null ? 0 : isVisible!.hashCode) + (name == null ? 0 : name!.hashCode); @override - String toString() => 'UpdateLibraryDto[exclusionPatterns=$exclusionPatterns, importPaths=$importPaths, isVisible=$isVisible, name=$name]'; + String toString() => 'UpdateLibraryDto[exclusionPatterns=$exclusionPatterns, importPaths=$importPaths, name=$name]'; Map toJson() { final json = {}; json[r'exclusionPatterns'] = this.exclusionPatterns; json[r'importPaths'] = this.importPaths; - if (this.isVisible != null) { - json[r'isVisible'] = this.isVisible; - } else { - // json[r'isVisible'] = null; - } if (this.name != null) { json[r'name'] = this.name; } else { @@ -88,7 +72,6 @@ class UpdateLibraryDto { importPaths: json[r'importPaths'] is Iterable ? (json[r'importPaths'] as Iterable).cast().toList(growable: false) : const [], - isVisible: mapValueOfType(json, r'isVisible'), name: mapValueOfType(json, r'name'), ); } diff --git a/mobile/openapi/lib/model/update_partner_dto.dart b/mobile/openapi/lib/model/update_partner_dto.dart index 8156803c61..f695f99535 100644 --- a/mobile/openapi/lib/model/update_partner_dto.dart +++ b/mobile/openapi/lib/model/update_partner_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/update_stack_parent_dto.dart b/mobile/openapi/lib/model/update_stack_parent_dto.dart index 12fda9d630..4247c2e29f 100644 --- a/mobile/openapi/lib/model/update_stack_parent_dto.dart +++ b/mobile/openapi/lib/model/update_stack_parent_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/update_tag_dto.dart b/mobile/openapi/lib/model/update_tag_dto.dart index 6075bc7963..dfa9b8cfc0 100644 --- a/mobile/openapi/lib/model/update_tag_dto.dart +++ b/mobile/openapi/lib/model/update_tag_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/update_user_dto.dart b/mobile/openapi/lib/model/update_user_dto.dart index 7a8f097975..caa0600793 100644 --- a/mobile/openapi/lib/model/update_user_dto.dart +++ b/mobile/openapi/lib/model/update_user_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/usage_by_user_dto.dart b/mobile/openapi/lib/model/usage_by_user_dto.dart index b9b4fc6c3e..0bbbba00bb 100644 --- a/mobile/openapi/lib/model/usage_by_user_dto.dart +++ b/mobile/openapi/lib/model/usage_by_user_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/user_avatar_color.dart b/mobile/openapi/lib/model/user_avatar_color.dart index a783f8c37e..4cd7dd3204 100644 --- a/mobile/openapi/lib/model/user_avatar_color.dart +++ b/mobile/openapi/lib/model/user_avatar_color.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/user_dto.dart b/mobile/openapi/lib/model/user_dto.dart index 431648605c..1c4c4eb0b4 100644 --- a/mobile/openapi/lib/model/user_dto.dart +++ b/mobile/openapi/lib/model/user_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/user_response_dto.dart b/mobile/openapi/lib/model/user_response_dto.dart index df68128e71..063b3d33b6 100644 --- a/mobile/openapi/lib/model/user_response_dto.dart +++ b/mobile/openapi/lib/model/user_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/user_status.dart b/mobile/openapi/lib/model/user_status.dart index cbbe1b56d9..596abf324e 100644 --- a/mobile/openapi/lib/model/user_status.dart +++ b/mobile/openapi/lib/model/user_status.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/validate_access_token_response_dto.dart b/mobile/openapi/lib/model/validate_access_token_response_dto.dart index f04ca200fc..e970f7e840 100644 --- a/mobile/openapi/lib/model/validate_access_token_response_dto.dart +++ b/mobile/openapi/lib/model/validate_access_token_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/validate_library_dto.dart b/mobile/openapi/lib/model/validate_library_dto.dart index a29a622079..05e122b1a1 100644 --- a/mobile/openapi/lib/model/validate_library_dto.dart +++ b/mobile/openapi/lib/model/validate_library_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart b/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart index 142055f2cd..23aac0b742 100644 --- a/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart +++ b/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/validate_library_response_dto.dart b/mobile/openapi/lib/model/validate_library_response_dto.dart index bb975da23a..b213f9ba98 100644 --- a/mobile/openapi/lib/model/validate_library_response_dto.dart +++ b/mobile/openapi/lib/model/validate_library_response_dto.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/lib/model/video_codec.dart b/mobile/openapi/lib/model/video_codec.dart index 36e1c681a6..307b208757 100644 --- a/mobile/openapi/lib/model/video_codec.dart +++ b/mobile/openapi/lib/model/video_codec.dart @@ -1,7 +1,7 @@ // // AUTO-GENERATED FILE, DO NOT MODIFY! // -// @dart=2.12 +// @dart=2.18 // ignore_for_file: unused_element, unused_import // ignore_for_file: always_put_required_named_parameters_first diff --git a/mobile/openapi/pubspec.yaml b/mobile/openapi/pubspec.yaml index 41ab08885c..f033028432 100644 --- a/mobile/openapi/pubspec.yaml +++ b/mobile/openapi/pubspec.yaml @@ -11,7 +11,7 @@ environment: dependencies: collection: '^1.17.0' http: '>=0.13.0 <0.14.0' - intl: '^0.18.0' + intl: any meta: '^1.1.8' dev_dependencies: - test: '>=1.16.0 <1.18.0' + test: '>=1.21.6 <1.22.0' diff --git a/mobile/openapi/test/activity_api_test.dart b/mobile/openapi/test/activity_api_test.dart deleted file mode 100644 index 05ffd928e0..0000000000 --- a/mobile/openapi/test/activity_api_test.dart +++ /dev/null @@ -1,41 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for ActivityApi -void main() { - // final instance = ActivityApi(); - - group('tests for ActivityApi', () { - //Future createActivity(ActivityCreateDto activityCreateDto) async - test('test createActivity', () async { - // TODO - }); - - //Future deleteActivity(String id) async - test('test deleteActivity', () async { - // TODO - }); - - //Future> getActivities(String albumId, { String assetId, ReactionLevel level, ReactionType type, String userId }) async - test('test getActivities', () async { - // TODO - }); - - //Future getActivityStatistics(String albumId, { String assetId }) async - test('test getActivityStatistics', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/activity_create_dto_test.dart b/mobile/openapi/test/activity_create_dto_test.dart deleted file mode 100644 index 263f1e27d7..0000000000 --- a/mobile/openapi/test/activity_create_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ActivityCreateDto -void main() { - // final instance = ActivityCreateDto(); - - group('test ActivityCreateDto', () { - // String albumId - test('to test the property `albumId`', () async { - // TODO - }); - - // String assetId - test('to test the property `assetId`', () async { - // TODO - }); - - // String comment - test('to test the property `comment`', () async { - // TODO - }); - - // ReactionType type - test('to test the property `type`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/activity_response_dto_test.dart b/mobile/openapi/test/activity_response_dto_test.dart deleted file mode 100644 index 5f70944b60..0000000000 --- a/mobile/openapi/test/activity_response_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ActivityResponseDto -void main() { - // final instance = ActivityResponseDto(); - - group('test ActivityResponseDto', () { - // String assetId - test('to test the property `assetId`', () async { - // TODO - }); - - // String comment - test('to test the property `comment`', () async { - // TODO - }); - - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // String type - test('to test the property `type`', () async { - // TODO - }); - - // UserDto user - test('to test the property `user`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/activity_statistics_response_dto_test.dart b/mobile/openapi/test/activity_statistics_response_dto_test.dart deleted file mode 100644 index 05f8bfdd07..0000000000 --- a/mobile/openapi/test/activity_statistics_response_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ActivityStatisticsResponseDto -void main() { - // final instance = ActivityStatisticsResponseDto(); - - group('test ActivityStatisticsResponseDto', () { - // int comments - test('to test the property `comments`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/add_users_dto_test.dart b/mobile/openapi/test/add_users_dto_test.dart deleted file mode 100644 index b0d66c56d8..0000000000 --- a/mobile/openapi/test/add_users_dto_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AddUsersDto -void main() { - // final instance = AddUsersDto(); - - group('test AddUsersDto', () { - // List albumUsers (default value: const []) - test('to test the property `albumUsers`', () async { - // TODO - }); - - // This property was deprecated in v1.102.0 - // List sharedUserIds (default value: const []) - test('to test the property `sharedUserIds`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/admin_onboarding_update_dto_test.dart b/mobile/openapi/test/admin_onboarding_update_dto_test.dart deleted file mode 100644 index 09cc73e977..0000000000 --- a/mobile/openapi/test/admin_onboarding_update_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AdminOnboardingUpdateDto -void main() { - // final instance = AdminOnboardingUpdateDto(); - - group('test AdminOnboardingUpdateDto', () { - // bool isOnboarded - test('to test the property `isOnboarded`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/album_api_test.dart b/mobile/openapi/test/album_api_test.dart deleted file mode 100644 index 1a6d3ab3bb..0000000000 --- a/mobile/openapi/test/album_api_test.dart +++ /dev/null @@ -1,76 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for AlbumApi -void main() { - // final instance = AlbumApi(); - - group('tests for AlbumApi', () { - //Future> addAssetsToAlbum(String id, BulkIdsDto bulkIdsDto, { String key }) async - test('test addAssetsToAlbum', () async { - // TODO - }); - - //Future addUsersToAlbum(String id, AddUsersDto addUsersDto) async - test('test addUsersToAlbum', () async { - // TODO - }); - - //Future createAlbum(CreateAlbumDto createAlbumDto) async - test('test createAlbum', () async { - // TODO - }); - - //Future deleteAlbum(String id) async - test('test deleteAlbum', () async { - // TODO - }); - - //Future getAlbumCount() async - test('test getAlbumCount', () async { - // TODO - }); - - //Future getAlbumInfo(String id, { String key, bool withoutAssets }) async - test('test getAlbumInfo', () async { - // TODO - }); - - //Future> getAllAlbums({ String assetId, bool shared }) async - test('test getAllAlbums', () async { - // TODO - }); - - //Future> removeAssetFromAlbum(String id, BulkIdsDto bulkIdsDto) async - test('test removeAssetFromAlbum', () async { - // TODO - }); - - //Future removeUserFromAlbum(String id, String userId) async - test('test removeUserFromAlbum', () async { - // TODO - }); - - //Future updateAlbumInfo(String id, UpdateAlbumDto updateAlbumDto) async - test('test updateAlbumInfo', () async { - // TODO - }); - - //Future updateAlbumUser(String id, String userId, UpdateAlbumUserDto updateAlbumUserDto) async - test('test updateAlbumUser', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/album_count_response_dto_test.dart b/mobile/openapi/test/album_count_response_dto_test.dart deleted file mode 100644 index 5da1acb072..0000000000 --- a/mobile/openapi/test/album_count_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AlbumCountResponseDto -void main() { - // final instance = AlbumCountResponseDto(); - - group('test AlbumCountResponseDto', () { - // int notShared - test('to test the property `notShared`', () async { - // TODO - }); - - // int owned - test('to test the property `owned`', () async { - // TODO - }); - - // int shared - test('to test the property `shared`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/album_response_dto_test.dart b/mobile/openapi/test/album_response_dto_test.dart deleted file mode 100644 index b9702165b5..0000000000 --- a/mobile/openapi/test/album_response_dto_test.dart +++ /dev/null @@ -1,118 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AlbumResponseDto -void main() { - // final instance = AlbumResponseDto(); - - group('test AlbumResponseDto', () { - // String albumName - test('to test the property `albumName`', () async { - // TODO - }); - - // String albumThumbnailAssetId - test('to test the property `albumThumbnailAssetId`', () async { - // TODO - }); - - // List albumUsers (default value: const []) - test('to test the property `albumUsers`', () async { - // TODO - }); - - // int assetCount - test('to test the property `assetCount`', () async { - // TODO - }); - - // List assets (default value: const []) - test('to test the property `assets`', () async { - // TODO - }); - - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // DateTime endDate - test('to test the property `endDate`', () async { - // TODO - }); - - // bool hasSharedLink - test('to test the property `hasSharedLink`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isActivityEnabled - test('to test the property `isActivityEnabled`', () async { - // TODO - }); - - // DateTime lastModifiedAssetTimestamp - test('to test the property `lastModifiedAssetTimestamp`', () async { - // TODO - }); - - // AssetOrder order - test('to test the property `order`', () async { - // TODO - }); - - // UserResponseDto owner - test('to test the property `owner`', () async { - // TODO - }); - - // String ownerId - test('to test the property `ownerId`', () async { - // TODO - }); - - // bool shared - test('to test the property `shared`', () async { - // TODO - }); - - // This property was deprecated in v1.102.0 - // List sharedUsers (default value: const []) - test('to test the property `sharedUsers`', () async { - // TODO - }); - - // DateTime startDate - test('to test the property `startDate`', () async { - // TODO - }); - - // DateTime updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/album_user_add_dto_test.dart b/mobile/openapi/test/album_user_add_dto_test.dart deleted file mode 100644 index 3f315ea2bb..0000000000 --- a/mobile/openapi/test/album_user_add_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AlbumUserAddDto -void main() { - // final instance = AlbumUserAddDto(); - - group('test AlbumUserAddDto', () { - // AlbumUserRole role - test('to test the property `role`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/album_user_create_dto_test.dart b/mobile/openapi/test/album_user_create_dto_test.dart deleted file mode 100644 index a1459172f7..0000000000 --- a/mobile/openapi/test/album_user_create_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AlbumUserCreateDto -void main() { - // final instance = AlbumUserCreateDto(); - - group('test AlbumUserCreateDto', () { - // AlbumUserRole role - test('to test the property `role`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/album_user_response_dto_test.dart b/mobile/openapi/test/album_user_response_dto_test.dart deleted file mode 100644 index 19f15a305d..0000000000 --- a/mobile/openapi/test/album_user_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AlbumUserResponseDto -void main() { - // final instance = AlbumUserResponseDto(); - - group('test AlbumUserResponseDto', () { - // AlbumUserRole role - test('to test the property `role`', () async { - // TODO - }); - - // UserResponseDto user - test('to test the property `user`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/album_user_role_test.dart b/mobile/openapi/test/album_user_role_test.dart deleted file mode 100644 index bc09896215..0000000000 --- a/mobile/openapi/test/album_user_role_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AlbumUserRole -void main() { - - group('test AlbumUserRole', () { - - }); - -} diff --git a/mobile/openapi/test/all_job_status_response_dto_test.dart b/mobile/openapi/test/all_job_status_response_dto_test.dart deleted file mode 100644 index 36bebbaf4d..0000000000 --- a/mobile/openapi/test/all_job_status_response_dto_test.dart +++ /dev/null @@ -1,87 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AllJobStatusResponseDto -void main() { - // final instance = AllJobStatusResponseDto(); - - group('test AllJobStatusResponseDto', () { - // JobStatusDto backgroundTask - test('to test the property `backgroundTask`', () async { - // TODO - }); - - // JobStatusDto faceDetection - test('to test the property `faceDetection`', () async { - // TODO - }); - - // JobStatusDto facialRecognition - test('to test the property `facialRecognition`', () async { - // TODO - }); - - // JobStatusDto library_ - test('to test the property `library_`', () async { - // TODO - }); - - // JobStatusDto metadataExtraction - test('to test the property `metadataExtraction`', () async { - // TODO - }); - - // JobStatusDto migration - test('to test the property `migration`', () async { - // TODO - }); - - // JobStatusDto notifications - test('to test the property `notifications`', () async { - // TODO - }); - - // JobStatusDto search - test('to test the property `search`', () async { - // TODO - }); - - // JobStatusDto sidecar - test('to test the property `sidecar`', () async { - // TODO - }); - - // JobStatusDto smartSearch - test('to test the property `smartSearch`', () async { - // TODO - }); - - // JobStatusDto storageTemplateMigration - test('to test the property `storageTemplateMigration`', () async { - // TODO - }); - - // JobStatusDto thumbnailGeneration - test('to test the property `thumbnailGeneration`', () async { - // TODO - }); - - // JobStatusDto videoConversion - test('to test the property `videoConversion`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/api_key_api_test.dart b/mobile/openapi/test/api_key_api_test.dart deleted file mode 100644 index 679abffbd4..0000000000 --- a/mobile/openapi/test/api_key_api_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for APIKeyApi -void main() { - // final instance = APIKeyApi(); - - group('tests for APIKeyApi', () { - //Future createApiKey(APIKeyCreateDto aPIKeyCreateDto) async - test('test createApiKey', () async { - // TODO - }); - - //Future deleteApiKey(String id) async - test('test deleteApiKey', () async { - // TODO - }); - - //Future getApiKey(String id) async - test('test getApiKey', () async { - // TODO - }); - - //Future> getApiKeys() async - test('test getApiKeys', () async { - // TODO - }); - - //Future updateApiKey(String id, APIKeyUpdateDto aPIKeyUpdateDto) async - test('test updateApiKey', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/api_key_create_dto_test.dart b/mobile/openapi/test/api_key_create_dto_test.dart deleted file mode 100644 index a09181ef0f..0000000000 --- a/mobile/openapi/test/api_key_create_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for APIKeyCreateDto -void main() { - // final instance = APIKeyCreateDto(); - - group('test APIKeyCreateDto', () { - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/api_key_create_response_dto_test.dart b/mobile/openapi/test/api_key_create_response_dto_test.dart deleted file mode 100644 index 9d9a8d24ee..0000000000 --- a/mobile/openapi/test/api_key_create_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for APIKeyCreateResponseDto -void main() { - // final instance = APIKeyCreateResponseDto(); - - group('test APIKeyCreateResponseDto', () { - // APIKeyResponseDto apiKey - test('to test the property `apiKey`', () async { - // TODO - }); - - // String secret - test('to test the property `secret`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/api_key_response_dto_test.dart b/mobile/openapi/test/api_key_response_dto_test.dart deleted file mode 100644 index 399a01429a..0000000000 --- a/mobile/openapi/test/api_key_response_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for APIKeyResponseDto -void main() { - // final instance = APIKeyResponseDto(); - - group('test APIKeyResponseDto', () { - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // DateTime updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/api_key_update_dto_test.dart b/mobile/openapi/test/api_key_update_dto_test.dart deleted file mode 100644 index ca7bc2187e..0000000000 --- a/mobile/openapi/test/api_key_update_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for APIKeyUpdateDto -void main() { - // final instance = APIKeyUpdateDto(); - - group('test APIKeyUpdateDto', () { - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_api_test.dart b/mobile/openapi/test/asset_api_test.dart deleted file mode 100644 index 0a278daa32..0000000000 --- a/mobile/openapi/test/asset_api_test.dart +++ /dev/null @@ -1,114 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for AssetApi -void main() { - // final instance = AssetApi(); - - group('tests for AssetApi', () { - // Checks if assets exist by checksums - // - //Future checkBulkUpload(AssetBulkUploadCheckDto assetBulkUploadCheckDto) async - test('test checkBulkUpload', () async { - // TODO - }); - - // Checks if multiple assets exist on the server and returns all existing - used by background backup - // - //Future checkExistingAssets(CheckExistingAssetsDto checkExistingAssetsDto) async - test('test checkExistingAssets', () async { - // TODO - }); - - //Future deleteAssets(AssetBulkDeleteDto assetBulkDeleteDto) async - test('test deleteAssets', () async { - // TODO - }); - - // Get all AssetEntity belong to the user - // - //Future> getAllAssets({ String ifNoneMatch, bool isArchived, bool isFavorite, int skip, int take, DateTime updatedAfter, DateTime updatedBefore, String userId }) async - test('test getAllAssets', () async { - // TODO - }); - - // Get all asset of a device that are in the database, ID only. - // - //Future> getAllUserAssetsByDeviceId(String deviceId) async - test('test getAllUserAssetsByDeviceId', () async { - // TODO - }); - - //Future getAssetInfo(String id, { String key }) async - test('test getAssetInfo', () async { - // TODO - }); - - //Future getAssetStatistics({ bool isArchived, bool isFavorite, bool isTrashed }) async - test('test getAssetStatistics', () async { - // TODO - }); - - //Future getAssetThumbnail(String id, { ThumbnailFormat format, String key }) async - test('test getAssetThumbnail', () async { - // TODO - }); - - //Future> getMapMarkers({ DateTime fileCreatedAfter, DateTime fileCreatedBefore, bool isArchived, bool isFavorite, bool withPartners }) async - test('test getMapMarkers', () async { - // TODO - }); - - //Future> getMemoryLane(int day, int month) async - test('test getMemoryLane', () async { - // TODO - }); - - //Future> getRandom({ num count }) async - test('test getRandom', () async { - // TODO - }); - - //Future runAssetJobs(AssetJobsDto assetJobsDto) async - test('test runAssetJobs', () async { - // TODO - }); - - //Future serveFile(String id, { bool isThumb, bool isWeb, String key }) async - test('test serveFile', () async { - // TODO - }); - - //Future updateAsset(String id, UpdateAssetDto updateAssetDto) async - test('test updateAsset', () async { - // TODO - }); - - //Future updateAssets(AssetBulkUpdateDto assetBulkUpdateDto) async - test('test updateAssets', () async { - // TODO - }); - - //Future updateStackParent(UpdateStackParentDto updateStackParentDto) async - test('test updateStackParent', () async { - // TODO - }); - - //Future uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, { String key, String xImmichChecksum, String duration, bool isArchived, bool isFavorite, bool isOffline, bool isVisible, String libraryId, MultipartFile livePhotoData, MultipartFile sidecarData }) async - test('test uploadFile', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/asset_bulk_delete_dto_test.dart b/mobile/openapi/test/asset_bulk_delete_dto_test.dart deleted file mode 100644 index d4245531f0..0000000000 --- a/mobile/openapi/test/asset_bulk_delete_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetBulkDeleteDto -void main() { - // final instance = AssetBulkDeleteDto(); - - group('test AssetBulkDeleteDto', () { - // bool force - test('to test the property `force`', () async { - // TODO - }); - - // List ids (default value: const []) - test('to test the property `ids`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_bulk_update_dto_test.dart b/mobile/openapi/test/asset_bulk_update_dto_test.dart deleted file mode 100644 index d04bdd8091..0000000000 --- a/mobile/openapi/test/asset_bulk_update_dto_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetBulkUpdateDto -void main() { - // final instance = AssetBulkUpdateDto(); - - group('test AssetBulkUpdateDto', () { - // String dateTimeOriginal - test('to test the property `dateTimeOriginal`', () async { - // TODO - }); - - // List ids (default value: const []) - test('to test the property `ids`', () async { - // TODO - }); - - // bool isArchived - test('to test the property `isArchived`', () async { - // TODO - }); - - // bool isFavorite - test('to test the property `isFavorite`', () async { - // TODO - }); - - // num latitude - test('to test the property `latitude`', () async { - // TODO - }); - - // num longitude - test('to test the property `longitude`', () async { - // TODO - }); - - // bool removeParent - test('to test the property `removeParent`', () async { - // TODO - }); - - // String stackParentId - test('to test the property `stackParentId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_bulk_upload_check_dto_test.dart b/mobile/openapi/test/asset_bulk_upload_check_dto_test.dart deleted file mode 100644 index 830cf2e29e..0000000000 --- a/mobile/openapi/test/asset_bulk_upload_check_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetBulkUploadCheckDto -void main() { - // final instance = AssetBulkUploadCheckDto(); - - group('test AssetBulkUploadCheckDto', () { - // List assets (default value: const []) - test('to test the property `assets`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_bulk_upload_check_item_test.dart b/mobile/openapi/test/asset_bulk_upload_check_item_test.dart deleted file mode 100644 index 9f3e6e72fa..0000000000 --- a/mobile/openapi/test/asset_bulk_upload_check_item_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetBulkUploadCheckItem -void main() { - // final instance = AssetBulkUploadCheckItem(); - - group('test AssetBulkUploadCheckItem', () { - // base64 or hex encoded sha1 hash - // String checksum - test('to test the property `checksum`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_bulk_upload_check_response_dto_test.dart b/mobile/openapi/test/asset_bulk_upload_check_response_dto_test.dart deleted file mode 100644 index 1af1fede08..0000000000 --- a/mobile/openapi/test/asset_bulk_upload_check_response_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetBulkUploadCheckResponseDto -void main() { - // final instance = AssetBulkUploadCheckResponseDto(); - - group('test AssetBulkUploadCheckResponseDto', () { - // List results (default value: const []) - test('to test the property `results`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_bulk_upload_check_result_test.dart b/mobile/openapi/test/asset_bulk_upload_check_result_test.dart deleted file mode 100644 index dd0a28ba57..0000000000 --- a/mobile/openapi/test/asset_bulk_upload_check_result_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetBulkUploadCheckResult -void main() { - // final instance = AssetBulkUploadCheckResult(); - - group('test AssetBulkUploadCheckResult', () { - // String action - test('to test the property `action`', () async { - // TODO - }); - - // String assetId - test('to test the property `assetId`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // String reason - test('to test the property `reason`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_delta_sync_dto_test.dart b/mobile/openapi/test/asset_delta_sync_dto_test.dart deleted file mode 100644 index 41676d610b..0000000000 --- a/mobile/openapi/test/asset_delta_sync_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetDeltaSyncDto -void main() { - // final instance = AssetDeltaSyncDto(); - - group('test AssetDeltaSyncDto', () { - // DateTime updatedAfter - test('to test the property `updatedAfter`', () async { - // TODO - }); - - // List userIds (default value: const []) - test('to test the property `userIds`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_delta_sync_response_dto_test.dart b/mobile/openapi/test/asset_delta_sync_response_dto_test.dart deleted file mode 100644 index 20104c08c6..0000000000 --- a/mobile/openapi/test/asset_delta_sync_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetDeltaSyncResponseDto -void main() { - // final instance = AssetDeltaSyncResponseDto(); - - group('test AssetDeltaSyncResponseDto', () { - // List deleted (default value: const []) - test('to test the property `deleted`', () async { - // TODO - }); - - // bool needsFullSync - test('to test the property `needsFullSync`', () async { - // TODO - }); - - // List upserted (default value: const []) - test('to test the property `upserted`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_face_response_dto_test.dart b/mobile/openapi/test/asset_face_response_dto_test.dart deleted file mode 100644 index cfedbeca9b..0000000000 --- a/mobile/openapi/test/asset_face_response_dto_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetFaceResponseDto -void main() { - // final instance = AssetFaceResponseDto(); - - group('test AssetFaceResponseDto', () { - // int boundingBoxX1 - test('to test the property `boundingBoxX1`', () async { - // TODO - }); - - // int boundingBoxX2 - test('to test the property `boundingBoxX2`', () async { - // TODO - }); - - // int boundingBoxY1 - test('to test the property `boundingBoxY1`', () async { - // TODO - }); - - // int boundingBoxY2 - test('to test the property `boundingBoxY2`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // int imageHeight - test('to test the property `imageHeight`', () async { - // TODO - }); - - // int imageWidth - test('to test the property `imageWidth`', () async { - // TODO - }); - - // PersonResponseDto person - test('to test the property `person`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_face_update_dto_test.dart b/mobile/openapi/test/asset_face_update_dto_test.dart deleted file mode 100644 index 5338a0bad9..0000000000 --- a/mobile/openapi/test/asset_face_update_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetFaceUpdateDto -void main() { - // final instance = AssetFaceUpdateDto(); - - group('test AssetFaceUpdateDto', () { - // List data (default value: const []) - test('to test the property `data`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_face_update_item_test.dart b/mobile/openapi/test/asset_face_update_item_test.dart deleted file mode 100644 index a3ef4c3357..0000000000 --- a/mobile/openapi/test/asset_face_update_item_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetFaceUpdateItem -void main() { - // final instance = AssetFaceUpdateItem(); - - group('test AssetFaceUpdateItem', () { - // String assetId - test('to test the property `assetId`', () async { - // TODO - }); - - // String personId - test('to test the property `personId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_face_without_person_response_dto_test.dart b/mobile/openapi/test/asset_face_without_person_response_dto_test.dart deleted file mode 100644 index 5eb7e5d939..0000000000 --- a/mobile/openapi/test/asset_face_without_person_response_dto_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetFaceWithoutPersonResponseDto -void main() { - // final instance = AssetFaceWithoutPersonResponseDto(); - - group('test AssetFaceWithoutPersonResponseDto', () { - // int boundingBoxX1 - test('to test the property `boundingBoxX1`', () async { - // TODO - }); - - // int boundingBoxX2 - test('to test the property `boundingBoxX2`', () async { - // TODO - }); - - // int boundingBoxY1 - test('to test the property `boundingBoxY1`', () async { - // TODO - }); - - // int boundingBoxY2 - test('to test the property `boundingBoxY2`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // int imageHeight - test('to test the property `imageHeight`', () async { - // TODO - }); - - // int imageWidth - test('to test the property `imageWidth`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_file_upload_response_dto_test.dart b/mobile/openapi/test/asset_file_upload_response_dto_test.dart deleted file mode 100644 index 6d050c589b..0000000000 --- a/mobile/openapi/test/asset_file_upload_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetFileUploadResponseDto -void main() { - // final instance = AssetFileUploadResponseDto(); - - group('test AssetFileUploadResponseDto', () { - // bool duplicate - test('to test the property `duplicate`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_full_sync_dto_test.dart b/mobile/openapi/test/asset_full_sync_dto_test.dart deleted file mode 100644 index cf838ae89e..0000000000 --- a/mobile/openapi/test/asset_full_sync_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetFullSyncDto -void main() { - // final instance = AssetFullSyncDto(); - - group('test AssetFullSyncDto', () { - // DateTime lastCreationDate - test('to test the property `lastCreationDate`', () async { - // TODO - }); - - // String lastId - test('to test the property `lastId`', () async { - // TODO - }); - - // int limit - test('to test the property `limit`', () async { - // TODO - }); - - // DateTime updatedUntil - test('to test the property `updatedUntil`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_ids_dto_test.dart b/mobile/openapi/test/asset_ids_dto_test.dart deleted file mode 100644 index 840f6f5cca..0000000000 --- a/mobile/openapi/test/asset_ids_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetIdsDto -void main() { - // final instance = AssetIdsDto(); - - group('test AssetIdsDto', () { - // List assetIds (default value: const []) - test('to test the property `assetIds`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_ids_response_dto_test.dart b/mobile/openapi/test/asset_ids_response_dto_test.dart deleted file mode 100644 index cb03844cca..0000000000 --- a/mobile/openapi/test/asset_ids_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetIdsResponseDto -void main() { - // final instance = AssetIdsResponseDto(); - - group('test AssetIdsResponseDto', () { - // String assetId - test('to test the property `assetId`', () async { - // TODO - }); - - // String error - test('to test the property `error`', () async { - // TODO - }); - - // bool success - test('to test the property `success`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_job_name_test.dart b/mobile/openapi/test/asset_job_name_test.dart deleted file mode 100644 index dc6313c927..0000000000 --- a/mobile/openapi/test/asset_job_name_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetJobName -void main() { - - group('test AssetJobName', () { - - }); - -} diff --git a/mobile/openapi/test/asset_jobs_dto_test.dart b/mobile/openapi/test/asset_jobs_dto_test.dart deleted file mode 100644 index e114d9fb2c..0000000000 --- a/mobile/openapi/test/asset_jobs_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetJobsDto -void main() { - // final instance = AssetJobsDto(); - - group('test AssetJobsDto', () { - // List assetIds (default value: const []) - test('to test the property `assetIds`', () async { - // TODO - }); - - // AssetJobName name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_order_test.dart b/mobile/openapi/test/asset_order_test.dart deleted file mode 100644 index 4a14908100..0000000000 --- a/mobile/openapi/test/asset_order_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetOrder -void main() { - - group('test AssetOrder', () { - - }); - -} diff --git a/mobile/openapi/test/asset_response_dto_test.dart b/mobile/openapi/test/asset_response_dto_test.dart deleted file mode 100644 index 355f07a047..0000000000 --- a/mobile/openapi/test/asset_response_dto_test.dart +++ /dev/null @@ -1,185 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetResponseDto -void main() { - // final instance = AssetResponseDto(); - - group('test AssetResponseDto', () { - // base64 encoded sha1 hash - // String checksum - test('to test the property `checksum`', () async { - // TODO - }); - - // String deviceAssetId - test('to test the property `deviceAssetId`', () async { - // TODO - }); - - // String deviceId - test('to test the property `deviceId`', () async { - // TODO - }); - - // String duration - test('to test the property `duration`', () async { - // TODO - }); - - // ExifResponseDto exifInfo - test('to test the property `exifInfo`', () async { - // TODO - }); - - // DateTime fileCreatedAt - test('to test the property `fileCreatedAt`', () async { - // TODO - }); - - // DateTime fileModifiedAt - test('to test the property `fileModifiedAt`', () async { - // TODO - }); - - // bool hasMetadata - test('to test the property `hasMetadata`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isArchived - test('to test the property `isArchived`', () async { - // TODO - }); - - // This property was deprecated in v1.104.0 - // bool isExternal - test('to test the property `isExternal`', () async { - // TODO - }); - - // bool isFavorite - test('to test the property `isFavorite`', () async { - // TODO - }); - - // bool isOffline - test('to test the property `isOffline`', () async { - // TODO - }); - - // This property was deprecated in v1.104.0 - // bool isReadOnly - test('to test the property `isReadOnly`', () async { - // TODO - }); - - // bool isTrashed - test('to test the property `isTrashed`', () async { - // TODO - }); - - // String libraryId - test('to test the property `libraryId`', () async { - // TODO - }); - - // String livePhotoVideoId - test('to test the property `livePhotoVideoId`', () async { - // TODO - }); - - // DateTime localDateTime - test('to test the property `localDateTime`', () async { - // TODO - }); - - // String originalFileName - test('to test the property `originalFileName`', () async { - // TODO - }); - - // String originalPath - test('to test the property `originalPath`', () async { - // TODO - }); - - // UserResponseDto owner - test('to test the property `owner`', () async { - // TODO - }); - - // String ownerId - test('to test the property `ownerId`', () async { - // TODO - }); - - // PeopleWithFacesResponseDto people - test('to test the property `people`', () async { - // TODO - }); - - // bool resized - test('to test the property `resized`', () async { - // TODO - }); - - // SmartInfoResponseDto smartInfo - test('to test the property `smartInfo`', () async { - // TODO - }); - - // List stack (default value: const []) - test('to test the property `stack`', () async { - // TODO - }); - - // int stackCount - test('to test the property `stackCount`', () async { - // TODO - }); - - // String stackParentId - test('to test the property `stackParentId`', () async { - // TODO - }); - - // List tags (default value: const []) - test('to test the property `tags`', () async { - // TODO - }); - - // String thumbhash - test('to test the property `thumbhash`', () async { - // TODO - }); - - // AssetTypeEnum type - test('to test the property `type`', () async { - // TODO - }); - - // DateTime updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_stats_response_dto_test.dart b/mobile/openapi/test/asset_stats_response_dto_test.dart deleted file mode 100644 index eaeace92a7..0000000000 --- a/mobile/openapi/test/asset_stats_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetStatsResponseDto -void main() { - // final instance = AssetStatsResponseDto(); - - group('test AssetStatsResponseDto', () { - // int images - test('to test the property `images`', () async { - // TODO - }); - - // int total - test('to test the property `total`', () async { - // TODO - }); - - // int videos - test('to test the property `videos`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/asset_type_enum_test.dart b/mobile/openapi/test/asset_type_enum_test.dart deleted file mode 100644 index a826ee679f..0000000000 --- a/mobile/openapi/test/asset_type_enum_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AssetTypeEnum -void main() { - - group('test AssetTypeEnum', () { - - }); - -} diff --git a/mobile/openapi/test/audio_codec_test.dart b/mobile/openapi/test/audio_codec_test.dart deleted file mode 100644 index a6c61661d6..0000000000 --- a/mobile/openapi/test/audio_codec_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AudioCodec -void main() { - - group('test AudioCodec', () { - - }); - -} diff --git a/mobile/openapi/test/audit_api_test.dart b/mobile/openapi/test/audit_api_test.dart deleted file mode 100644 index 8114283a1a..0000000000 --- a/mobile/openapi/test/audit_api_test.dart +++ /dev/null @@ -1,26 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for AuditApi -void main() { - // final instance = AuditApi(); - - group('tests for AuditApi', () { - //Future getAuditDeletes(DateTime after, EntityType entityType, { String userId }) async - test('test getAuditDeletes', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/audit_deletes_response_dto_test.dart b/mobile/openapi/test/audit_deletes_response_dto_test.dart deleted file mode 100644 index 45dbccc28d..0000000000 --- a/mobile/openapi/test/audit_deletes_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for AuditDeletesResponseDto -void main() { - // final instance = AuditDeletesResponseDto(); - - group('test AuditDeletesResponseDto', () { - // List ids (default value: const []) - test('to test the property `ids`', () async { - // TODO - }); - - // bool needsFullSync - test('to test the property `needsFullSync`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/authentication_api_test.dart b/mobile/openapi/test/authentication_api_test.dart deleted file mode 100644 index dea20ec9b1..0000000000 --- a/mobile/openapi/test/authentication_api_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for AuthenticationApi -void main() { - // final instance = AuthenticationApi(); - - group('tests for AuthenticationApi', () { - //Future changePassword(ChangePasswordDto changePasswordDto) async - test('test changePassword', () async { - // TODO - }); - - //Future login(LoginCredentialDto loginCredentialDto) async - test('test login', () async { - // TODO - }); - - //Future logout() async - test('test logout', () async { - // TODO - }); - - //Future signUpAdmin(SignUpDto signUpDto) async - test('test signUpAdmin', () async { - // TODO - }); - - //Future validateAccessToken() async - test('test validateAccessToken', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/bulk_id_response_dto_test.dart b/mobile/openapi/test/bulk_id_response_dto_test.dart deleted file mode 100644 index 23e13ef507..0000000000 --- a/mobile/openapi/test/bulk_id_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for BulkIdResponseDto -void main() { - // final instance = BulkIdResponseDto(); - - group('test BulkIdResponseDto', () { - // String error - test('to test the property `error`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool success - test('to test the property `success`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/bulk_ids_dto_test.dart b/mobile/openapi/test/bulk_ids_dto_test.dart deleted file mode 100644 index 22b11ec8f0..0000000000 --- a/mobile/openapi/test/bulk_ids_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for BulkIdsDto -void main() { - // final instance = BulkIdsDto(); - - group('test BulkIdsDto', () { - // List ids (default value: const []) - test('to test the property `ids`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/change_password_dto_test.dart b/mobile/openapi/test/change_password_dto_test.dart deleted file mode 100644 index 21ed393bc4..0000000000 --- a/mobile/openapi/test/change_password_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ChangePasswordDto -void main() { - // final instance = ChangePasswordDto(); - - group('test ChangePasswordDto', () { - // String newPassword - test('to test the property `newPassword`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/check_existing_assets_dto_test.dart b/mobile/openapi/test/check_existing_assets_dto_test.dart deleted file mode 100644 index df4c51e707..0000000000 --- a/mobile/openapi/test/check_existing_assets_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CheckExistingAssetsDto -void main() { - // final instance = CheckExistingAssetsDto(); - - group('test CheckExistingAssetsDto', () { - // List deviceAssetIds (default value: const []) - test('to test the property `deviceAssetIds`', () async { - // TODO - }); - - // String deviceId - test('to test the property `deviceId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/check_existing_assets_response_dto_test.dart b/mobile/openapi/test/check_existing_assets_response_dto_test.dart deleted file mode 100644 index 250fec3c62..0000000000 --- a/mobile/openapi/test/check_existing_assets_response_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CheckExistingAssetsResponseDto -void main() { - // final instance = CheckExistingAssetsResponseDto(); - - group('test CheckExistingAssetsResponseDto', () { - // List existingIds (default value: const []) - test('to test the property `existingIds`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/clip_config_test.dart b/mobile/openapi/test/clip_config_test.dart deleted file mode 100644 index 77069e5b98..0000000000 --- a/mobile/openapi/test/clip_config_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CLIPConfig -void main() { - // final instance = CLIPConfig(); - - group('test CLIPConfig', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // CLIPMode mode - test('to test the property `mode`', () async { - // TODO - }); - - // String modelName - test('to test the property `modelName`', () async { - // TODO - }); - - // ModelType modelType - test('to test the property `modelType`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/clip_mode_test.dart b/mobile/openapi/test/clip_mode_test.dart deleted file mode 100644 index 8b6627e7eb..0000000000 --- a/mobile/openapi/test/clip_mode_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CLIPMode -void main() { - - group('test CLIPMode', () { - - }); - -} diff --git a/mobile/openapi/test/colorspace_test.dart b/mobile/openapi/test/colorspace_test.dart deleted file mode 100644 index f689d519ed..0000000000 --- a/mobile/openapi/test/colorspace_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for Colorspace -void main() { - - group('test Colorspace', () { - - }); - -} diff --git a/mobile/openapi/test/cq_mode_test.dart b/mobile/openapi/test/cq_mode_test.dart deleted file mode 100644 index 13d4a7b0c4..0000000000 --- a/mobile/openapi/test/cq_mode_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CQMode -void main() { - - group('test CQMode', () { - - }); - -} diff --git a/mobile/openapi/test/create_album_dto_test.dart b/mobile/openapi/test/create_album_dto_test.dart deleted file mode 100644 index f3dc3c8647..0000000000 --- a/mobile/openapi/test/create_album_dto_test.dart +++ /dev/null @@ -1,49 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CreateAlbumDto -void main() { - // final instance = CreateAlbumDto(); - - group('test CreateAlbumDto', () { - // String albumName - test('to test the property `albumName`', () async { - // TODO - }); - - // This property was added in v1.104.0 - // List albumUsers (default value: const []) - test('to test the property `albumUsers`', () async { - // TODO - }); - - // List assetIds (default value: const []) - test('to test the property `assetIds`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // This property was deprecated in v1.104.0 - // List sharedWithUserIds (default value: const []) - test('to test the property `sharedWithUserIds`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/create_library_dto_test.dart b/mobile/openapi/test/create_library_dto_test.dart deleted file mode 100644 index 1dd77af251..0000000000 --- a/mobile/openapi/test/create_library_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CreateLibraryDto -void main() { - // final instance = CreateLibraryDto(); - - group('test CreateLibraryDto', () { - // List exclusionPatterns (default value: const []) - test('to test the property `exclusionPatterns`', () async { - // TODO - }); - - // List importPaths (default value: const []) - test('to test the property `importPaths`', () async { - // TODO - }); - - // bool isVisible - test('to test the property `isVisible`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String ownerId - test('to test the property `ownerId`', () async { - // TODO - }); - - // LibraryType type - test('to test the property `type`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/create_profile_image_response_dto_test.dart b/mobile/openapi/test/create_profile_image_response_dto_test.dart deleted file mode 100644 index a09fed9504..0000000000 --- a/mobile/openapi/test/create_profile_image_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CreateProfileImageResponseDto -void main() { - // final instance = CreateProfileImageResponseDto(); - - group('test CreateProfileImageResponseDto', () { - // String profileImagePath - test('to test the property `profileImagePath`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/create_tag_dto_test.dart b/mobile/openapi/test/create_tag_dto_test.dart deleted file mode 100644 index 6bffb3200a..0000000000 --- a/mobile/openapi/test/create_tag_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CreateTagDto -void main() { - // final instance = CreateTagDto(); - - group('test CreateTagDto', () { - // String name - test('to test the property `name`', () async { - // TODO - }); - - // TagTypeEnum type - test('to test the property `type`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/create_user_dto_test.dart b/mobile/openapi/test/create_user_dto_test.dart deleted file mode 100644 index 0d474f932c..0000000000 --- a/mobile/openapi/test/create_user_dto_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for CreateUserDto -void main() { - // final instance = CreateUserDto(); - - group('test CreateUserDto', () { - // String email - test('to test the property `email`', () async { - // TODO - }); - - // bool memoriesEnabled - test('to test the property `memoriesEnabled`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // bool notify - test('to test the property `notify`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - // int quotaSizeInBytes - test('to test the property `quotaSizeInBytes`', () async { - // TODO - }); - - // bool shouldChangePassword - test('to test the property `shouldChangePassword`', () async { - // TODO - }); - - // String storageLabel - test('to test the property `storageLabel`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/delete_user_dto_test.dart b/mobile/openapi/test/delete_user_dto_test.dart deleted file mode 100644 index 475681d420..0000000000 --- a/mobile/openapi/test/delete_user_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for DeleteUserDto -void main() { - // final instance = DeleteUserDto(); - - group('test DeleteUserDto', () { - // bool force - test('to test the property `force`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/download_api_test.dart b/mobile/openapi/test/download_api_test.dart deleted file mode 100644 index 09ba5d5e40..0000000000 --- a/mobile/openapi/test/download_api_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for DownloadApi -void main() { - // final instance = DownloadApi(); - - group('tests for DownloadApi', () { - //Future downloadArchive(AssetIdsDto assetIdsDto, { String key }) async - test('test downloadArchive', () async { - // TODO - }); - - //Future downloadFile(String id, { String key }) async - test('test downloadFile', () async { - // TODO - }); - - //Future getDownloadInfo(DownloadInfoDto downloadInfoDto, { String key }) async - test('test getDownloadInfo', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/download_archive_info_test.dart b/mobile/openapi/test/download_archive_info_test.dart deleted file mode 100644 index 53c705a378..0000000000 --- a/mobile/openapi/test/download_archive_info_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for DownloadArchiveInfo -void main() { - // final instance = DownloadArchiveInfo(); - - group('test DownloadArchiveInfo', () { - // List assetIds (default value: const []) - test('to test the property `assetIds`', () async { - // TODO - }); - - // int size - test('to test the property `size`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/download_info_dto_test.dart b/mobile/openapi/test/download_info_dto_test.dart deleted file mode 100644 index 5efd4e11eb..0000000000 --- a/mobile/openapi/test/download_info_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for DownloadInfoDto -void main() { - // final instance = DownloadInfoDto(); - - group('test DownloadInfoDto', () { - // String albumId - test('to test the property `albumId`', () async { - // TODO - }); - - // int archiveSize - test('to test the property `archiveSize`', () async { - // TODO - }); - - // List assetIds (default value: const []) - test('to test the property `assetIds`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/download_response_dto_test.dart b/mobile/openapi/test/download_response_dto_test.dart deleted file mode 100644 index 949c9517aa..0000000000 --- a/mobile/openapi/test/download_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for DownloadResponseDto -void main() { - // final instance = DownloadResponseDto(); - - group('test DownloadResponseDto', () { - // List archives (default value: const []) - test('to test the property `archives`', () async { - // TODO - }); - - // int totalSize - test('to test the property `totalSize`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/entity_type_test.dart b/mobile/openapi/test/entity_type_test.dart deleted file mode 100644 index 81f023308c..0000000000 --- a/mobile/openapi/test/entity_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for EntityType -void main() { - - group('test EntityType', () { - - }); - -} diff --git a/mobile/openapi/test/exif_response_dto_test.dart b/mobile/openapi/test/exif_response_dto_test.dart deleted file mode 100644 index 43d5b2673b..0000000000 --- a/mobile/openapi/test/exif_response_dto_test.dart +++ /dev/null @@ -1,127 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ExifResponseDto -void main() { - // final instance = ExifResponseDto(); - - group('test ExifResponseDto', () { - // String city - test('to test the property `city`', () async { - // TODO - }); - - // String country - test('to test the property `country`', () async { - // TODO - }); - - // DateTime dateTimeOriginal - test('to test the property `dateTimeOriginal`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // num exifImageHeight - test('to test the property `exifImageHeight`', () async { - // TODO - }); - - // num exifImageWidth - test('to test the property `exifImageWidth`', () async { - // TODO - }); - - // String exposureTime - test('to test the property `exposureTime`', () async { - // TODO - }); - - // num fNumber - test('to test the property `fNumber`', () async { - // TODO - }); - - // int fileSizeInByte - test('to test the property `fileSizeInByte`', () async { - // TODO - }); - - // num focalLength - test('to test the property `focalLength`', () async { - // TODO - }); - - // num iso - test('to test the property `iso`', () async { - // TODO - }); - - // num latitude - test('to test the property `latitude`', () async { - // TODO - }); - - // String lensModel - test('to test the property `lensModel`', () async { - // TODO - }); - - // num longitude - test('to test the property `longitude`', () async { - // TODO - }); - - // String make - test('to test the property `make`', () async { - // TODO - }); - - // String model - test('to test the property `model`', () async { - // TODO - }); - - // DateTime modifyDate - test('to test the property `modifyDate`', () async { - // TODO - }); - - // String orientation - test('to test the property `orientation`', () async { - // TODO - }); - - // String projectionType - test('to test the property `projectionType`', () async { - // TODO - }); - - // String state - test('to test the property `state`', () async { - // TODO - }); - - // String timeZone - test('to test the property `timeZone`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/face_api_test.dart b/mobile/openapi/test/face_api_test.dart deleted file mode 100644 index 55c289e041..0000000000 --- a/mobile/openapi/test/face_api_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for FaceApi -void main() { - // final instance = FaceApi(); - - group('tests for FaceApi', () { - //Future> getFaces(String id) async - test('test getFaces', () async { - // TODO - }); - - //Future reassignFacesById(String id, FaceDto faceDto) async - test('test reassignFacesById', () async { - // TODO - }); - - //Future unassignFace(String id) async - test('test unassignFace', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/face_dto_test.dart b/mobile/openapi/test/face_dto_test.dart deleted file mode 100644 index ea8091f2e3..0000000000 --- a/mobile/openapi/test/face_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for FaceDto -void main() { - // final instance = FaceDto(); - - group('test FaceDto', () { - // String id - test('to test the property `id`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/file_checksum_dto_test.dart b/mobile/openapi/test/file_checksum_dto_test.dart deleted file mode 100644 index 6eb3a39023..0000000000 --- a/mobile/openapi/test/file_checksum_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for FileChecksumDto -void main() { - // final instance = FileChecksumDto(); - - group('test FileChecksumDto', () { - // List filenames (default value: const []) - test('to test the property `filenames`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/file_checksum_response_dto_test.dart b/mobile/openapi/test/file_checksum_response_dto_test.dart deleted file mode 100644 index a90fc61649..0000000000 --- a/mobile/openapi/test/file_checksum_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for FileChecksumResponseDto -void main() { - // final instance = FileChecksumResponseDto(); - - group('test FileChecksumResponseDto', () { - // String checksum - test('to test the property `checksum`', () async { - // TODO - }); - - // String filename - test('to test the property `filename`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/file_report_api_test.dart b/mobile/openapi/test/file_report_api_test.dart deleted file mode 100644 index 255c787002..0000000000 --- a/mobile/openapi/test/file_report_api_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for FileReportApi -void main() { - // final instance = FileReportApi(); - - group('tests for FileReportApi', () { - //Future fixAuditFiles(FileReportFixDto fileReportFixDto) async - test('test fixAuditFiles', () async { - // TODO - }); - - //Future getAuditFiles() async - test('test getAuditFiles', () async { - // TODO - }); - - //Future> getFileChecksums(FileChecksumDto fileChecksumDto) async - test('test getFileChecksums', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/file_report_dto_test.dart b/mobile/openapi/test/file_report_dto_test.dart deleted file mode 100644 index a843046683..0000000000 --- a/mobile/openapi/test/file_report_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for FileReportDto -void main() { - // final instance = FileReportDto(); - - group('test FileReportDto', () { - // List extras (default value: const []) - test('to test the property `extras`', () async { - // TODO - }); - - // List orphans (default value: const []) - test('to test the property `orphans`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/file_report_fix_dto_test.dart b/mobile/openapi/test/file_report_fix_dto_test.dart deleted file mode 100644 index 44e7344295..0000000000 --- a/mobile/openapi/test/file_report_fix_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for FileReportFixDto -void main() { - // final instance = FileReportFixDto(); - - group('test FileReportFixDto', () { - // List items (default value: const []) - test('to test the property `items`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/file_report_item_dto_test.dart b/mobile/openapi/test/file_report_item_dto_test.dart deleted file mode 100644 index 7e90322f70..0000000000 --- a/mobile/openapi/test/file_report_item_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for FileReportItemDto -void main() { - // final instance = FileReportItemDto(); - - group('test FileReportItemDto', () { - // String checksum - test('to test the property `checksum`', () async { - // TODO - }); - - // String entityId - test('to test the property `entityId`', () async { - // TODO - }); - - // PathEntityType entityType - test('to test the property `entityType`', () async { - // TODO - }); - - // PathType pathType - test('to test the property `pathType`', () async { - // TODO - }); - - // String pathValue - test('to test the property `pathValue`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/image_format_test.dart b/mobile/openapi/test/image_format_test.dart deleted file mode 100644 index 2bb1512a68..0000000000 --- a/mobile/openapi/test/image_format_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ImageFormat -void main() { - - group('test ImageFormat', () { - - }); - -} diff --git a/mobile/openapi/test/job_api_test.dart b/mobile/openapi/test/job_api_test.dart deleted file mode 100644 index c30811bb05..0000000000 --- a/mobile/openapi/test/job_api_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for JobApi -void main() { - // final instance = JobApi(); - - group('tests for JobApi', () { - //Future getAllJobsStatus() async - test('test getAllJobsStatus', () async { - // TODO - }); - - //Future sendJobCommand(JobName id, JobCommandDto jobCommandDto) async - test('test sendJobCommand', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/job_command_dto_test.dart b/mobile/openapi/test/job_command_dto_test.dart deleted file mode 100644 index 83a27b4d9c..0000000000 --- a/mobile/openapi/test/job_command_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for JobCommandDto -void main() { - // final instance = JobCommandDto(); - - group('test JobCommandDto', () { - // JobCommand command - test('to test the property `command`', () async { - // TODO - }); - - // bool force - test('to test the property `force`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/job_command_test.dart b/mobile/openapi/test/job_command_test.dart deleted file mode 100644 index df6822c9d4..0000000000 --- a/mobile/openapi/test/job_command_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for JobCommand -void main() { - - group('test JobCommand', () { - - }); - -} diff --git a/mobile/openapi/test/job_counts_dto_test.dart b/mobile/openapi/test/job_counts_dto_test.dart deleted file mode 100644 index 43e24df0fc..0000000000 --- a/mobile/openapi/test/job_counts_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for JobCountsDto -void main() { - // final instance = JobCountsDto(); - - group('test JobCountsDto', () { - // int active - test('to test the property `active`', () async { - // TODO - }); - - // int completed - test('to test the property `completed`', () async { - // TODO - }); - - // int delayed - test('to test the property `delayed`', () async { - // TODO - }); - - // int failed - test('to test the property `failed`', () async { - // TODO - }); - - // int paused - test('to test the property `paused`', () async { - // TODO - }); - - // int waiting - test('to test the property `waiting`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/job_name_test.dart b/mobile/openapi/test/job_name_test.dart deleted file mode 100644 index 4c14d76be0..0000000000 --- a/mobile/openapi/test/job_name_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for JobName -void main() { - - group('test JobName', () { - - }); - -} diff --git a/mobile/openapi/test/job_settings_dto_test.dart b/mobile/openapi/test/job_settings_dto_test.dart deleted file mode 100644 index e06900185a..0000000000 --- a/mobile/openapi/test/job_settings_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for JobSettingsDto -void main() { - // final instance = JobSettingsDto(); - - group('test JobSettingsDto', () { - // int concurrency - test('to test the property `concurrency`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/job_status_dto_test.dart b/mobile/openapi/test/job_status_dto_test.dart deleted file mode 100644 index ae353baf0c..0000000000 --- a/mobile/openapi/test/job_status_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for JobStatusDto -void main() { - // final instance = JobStatusDto(); - - group('test JobStatusDto', () { - // JobCountsDto jobCounts - test('to test the property `jobCounts`', () async { - // TODO - }); - - // QueueStatusDto queueStatus - test('to test the property `queueStatus`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/library_api_test.dart b/mobile/openapi/test/library_api_test.dart deleted file mode 100644 index 21afeff544..0000000000 --- a/mobile/openapi/test/library_api_test.dart +++ /dev/null @@ -1,66 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for LibraryApi -void main() { - // final instance = LibraryApi(); - - group('tests for LibraryApi', () { - //Future createLibrary(CreateLibraryDto createLibraryDto) async - test('test createLibrary', () async { - // TODO - }); - - //Future deleteLibrary(String id) async - test('test deleteLibrary', () async { - // TODO - }); - - //Future> getAllLibraries({ LibraryType type }) async - test('test getAllLibraries', () async { - // TODO - }); - - //Future getLibrary(String id) async - test('test getLibrary', () async { - // TODO - }); - - //Future getLibraryStatistics(String id) async - test('test getLibraryStatistics', () async { - // TODO - }); - - //Future removeOfflineFiles(String id) async - test('test removeOfflineFiles', () async { - // TODO - }); - - //Future scanLibrary(String id, ScanLibraryDto scanLibraryDto) async - test('test scanLibrary', () async { - // TODO - }); - - //Future updateLibrary(String id, UpdateLibraryDto updateLibraryDto) async - test('test updateLibrary', () async { - // TODO - }); - - //Future validate(String id, ValidateLibraryDto validateLibraryDto) async - test('test validate', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/library_response_dto_test.dart b/mobile/openapi/test/library_response_dto_test.dart deleted file mode 100644 index 9fd196d1b0..0000000000 --- a/mobile/openapi/test/library_response_dto_test.dart +++ /dev/null @@ -1,72 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for LibraryResponseDto -void main() { - // final instance = LibraryResponseDto(); - - group('test LibraryResponseDto', () { - // int assetCount - test('to test the property `assetCount`', () async { - // TODO - }); - - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // List exclusionPatterns (default value: const []) - test('to test the property `exclusionPatterns`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // List importPaths (default value: const []) - test('to test the property `importPaths`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String ownerId - test('to test the property `ownerId`', () async { - // TODO - }); - - // DateTime refreshedAt - test('to test the property `refreshedAt`', () async { - // TODO - }); - - // LibraryType type - test('to test the property `type`', () async { - // TODO - }); - - // DateTime updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/library_stats_response_dto_test.dart b/mobile/openapi/test/library_stats_response_dto_test.dart deleted file mode 100644 index 91e9bb7040..0000000000 --- a/mobile/openapi/test/library_stats_response_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for LibraryStatsResponseDto -void main() { - // final instance = LibraryStatsResponseDto(); - - group('test LibraryStatsResponseDto', () { - // int photos (default value: 0) - test('to test the property `photos`', () async { - // TODO - }); - - // int total (default value: 0) - test('to test the property `total`', () async { - // TODO - }); - - // int usage (default value: 0) - test('to test the property `usage`', () async { - // TODO - }); - - // int videos (default value: 0) - test('to test the property `videos`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/library_type_test.dart b/mobile/openapi/test/library_type_test.dart deleted file mode 100644 index 991e21c9e2..0000000000 --- a/mobile/openapi/test/library_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for LibraryType -void main() { - - group('test LibraryType', () { - - }); - -} diff --git a/mobile/openapi/test/log_level_test.dart b/mobile/openapi/test/log_level_test.dart deleted file mode 100644 index dfe841bf07..0000000000 --- a/mobile/openapi/test/log_level_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for LogLevel -void main() { - - group('test LogLevel', () { - - }); - -} diff --git a/mobile/openapi/test/login_credential_dto_test.dart b/mobile/openapi/test/login_credential_dto_test.dart deleted file mode 100644 index 9995af7304..0000000000 --- a/mobile/openapi/test/login_credential_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for LoginCredentialDto -void main() { - // final instance = LoginCredentialDto(); - - group('test LoginCredentialDto', () { - // String email - test('to test the property `email`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/login_response_dto_test.dart b/mobile/openapi/test/login_response_dto_test.dart deleted file mode 100644 index a8365ff062..0000000000 --- a/mobile/openapi/test/login_response_dto_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for LoginResponseDto -void main() { - // final instance = LoginResponseDto(); - - group('test LoginResponseDto', () { - // String accessToken - test('to test the property `accessToken`', () async { - // TODO - }); - - // bool isAdmin - test('to test the property `isAdmin`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String profileImagePath - test('to test the property `profileImagePath`', () async { - // TODO - }); - - // bool shouldChangePassword - test('to test the property `shouldChangePassword`', () async { - // TODO - }); - - // String userEmail - test('to test the property `userEmail`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/logout_response_dto_test.dart b/mobile/openapi/test/logout_response_dto_test.dart deleted file mode 100644 index 1d16ab3c6c..0000000000 --- a/mobile/openapi/test/logout_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for LogoutResponseDto -void main() { - // final instance = LogoutResponseDto(); - - group('test LogoutResponseDto', () { - // String redirectUri - test('to test the property `redirectUri`', () async { - // TODO - }); - - // bool successful - test('to test the property `successful`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/map_marker_response_dto_test.dart b/mobile/openapi/test/map_marker_response_dto_test.dart deleted file mode 100644 index 9668260839..0000000000 --- a/mobile/openapi/test/map_marker_response_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MapMarkerResponseDto -void main() { - // final instance = MapMarkerResponseDto(); - - group('test MapMarkerResponseDto', () { - // String city - test('to test the property `city`', () async { - // TODO - }); - - // String country - test('to test the property `country`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // double lat - test('to test the property `lat`', () async { - // TODO - }); - - // double lon - test('to test the property `lon`', () async { - // TODO - }); - - // String state - test('to test the property `state`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/map_theme_test.dart b/mobile/openapi/test/map_theme_test.dart deleted file mode 100644 index 82fa9ff3d8..0000000000 --- a/mobile/openapi/test/map_theme_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MapTheme -void main() { - - group('test MapTheme', () { - - }); - -} diff --git a/mobile/openapi/test/memory_api_test.dart b/mobile/openapi/test/memory_api_test.dart deleted file mode 100644 index 1a930782ea..0000000000 --- a/mobile/openapi/test/memory_api_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for MemoryApi -void main() { - // final instance = MemoryApi(); - - group('tests for MemoryApi', () { - //Future> addMemoryAssets(String id, BulkIdsDto bulkIdsDto) async - test('test addMemoryAssets', () async { - // TODO - }); - - //Future createMemory(MemoryCreateDto memoryCreateDto) async - test('test createMemory', () async { - // TODO - }); - - //Future deleteMemory(String id) async - test('test deleteMemory', () async { - // TODO - }); - - //Future getMemory(String id) async - test('test getMemory', () async { - // TODO - }); - - //Future> removeMemoryAssets(String id, BulkIdsDto bulkIdsDto) async - test('test removeMemoryAssets', () async { - // TODO - }); - - //Future> searchMemories() async - test('test searchMemories', () async { - // TODO - }); - - //Future updateMemory(String id, MemoryUpdateDto memoryUpdateDto) async - test('test updateMemory', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/memory_create_dto_test.dart b/mobile/openapi/test/memory_create_dto_test.dart deleted file mode 100644 index bfb6f09e15..0000000000 --- a/mobile/openapi/test/memory_create_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MemoryCreateDto -void main() { - // final instance = MemoryCreateDto(); - - group('test MemoryCreateDto', () { - // List assetIds (default value: const []) - test('to test the property `assetIds`', () async { - // TODO - }); - - // OnThisDayDto data - test('to test the property `data`', () async { - // TODO - }); - - // bool isSaved - test('to test the property `isSaved`', () async { - // TODO - }); - - // DateTime memoryAt - test('to test the property `memoryAt`', () async { - // TODO - }); - - // DateTime seenAt - test('to test the property `seenAt`', () async { - // TODO - }); - - // MemoryType type - test('to test the property `type`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/memory_lane_response_dto_test.dart b/mobile/openapi/test/memory_lane_response_dto_test.dart deleted file mode 100644 index a48d757e2c..0000000000 --- a/mobile/openapi/test/memory_lane_response_dto_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MemoryLaneResponseDto -void main() { - // final instance = MemoryLaneResponseDto(); - - group('test MemoryLaneResponseDto', () { - // List assets (default value: const []) - test('to test the property `assets`', () async { - // TODO - }); - - // This property was deprecated in v1.100.0 - // String title - test('to test the property `title`', () async { - // TODO - }); - - // int yearsAgo - test('to test the property `yearsAgo`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/memory_response_dto_test.dart b/mobile/openapi/test/memory_response_dto_test.dart deleted file mode 100644 index 90b2e78347..0000000000 --- a/mobile/openapi/test/memory_response_dto_test.dart +++ /dev/null @@ -1,77 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MemoryResponseDto -void main() { - // final instance = MemoryResponseDto(); - - group('test MemoryResponseDto', () { - // List assets (default value: const []) - test('to test the property `assets`', () async { - // TODO - }); - - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // OnThisDayDto data - test('to test the property `data`', () async { - // TODO - }); - - // DateTime deletedAt - test('to test the property `deletedAt`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isSaved - test('to test the property `isSaved`', () async { - // TODO - }); - - // DateTime memoryAt - test('to test the property `memoryAt`', () async { - // TODO - }); - - // String ownerId - test('to test the property `ownerId`', () async { - // TODO - }); - - // DateTime seenAt - test('to test the property `seenAt`', () async { - // TODO - }); - - // String type - test('to test the property `type`', () async { - // TODO - }); - - // DateTime updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/memory_type_test.dart b/mobile/openapi/test/memory_type_test.dart deleted file mode 100644 index 0a6589d9ad..0000000000 --- a/mobile/openapi/test/memory_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MemoryType -void main() { - - group('test MemoryType', () { - - }); - -} diff --git a/mobile/openapi/test/memory_update_dto_test.dart b/mobile/openapi/test/memory_update_dto_test.dart deleted file mode 100644 index 173128e395..0000000000 --- a/mobile/openapi/test/memory_update_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MemoryUpdateDto -void main() { - // final instance = MemoryUpdateDto(); - - group('test MemoryUpdateDto', () { - // bool isSaved - test('to test the property `isSaved`', () async { - // TODO - }); - - // DateTime memoryAt - test('to test the property `memoryAt`', () async { - // TODO - }); - - // DateTime seenAt - test('to test the property `seenAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/merge_person_dto_test.dart b/mobile/openapi/test/merge_person_dto_test.dart deleted file mode 100644 index 4a22063a81..0000000000 --- a/mobile/openapi/test/merge_person_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MergePersonDto -void main() { - // final instance = MergePersonDto(); - - group('test MergePersonDto', () { - // List ids (default value: const []) - test('to test the property `ids`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/metadata_search_dto_test.dart b/mobile/openapi/test/metadata_search_dto_test.dart deleted file mode 100644 index c630fec9a5..0000000000 --- a/mobile/openapi/test/metadata_search_dto_test.dart +++ /dev/null @@ -1,239 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for MetadataSearchDto -void main() { - // final instance = MetadataSearchDto(); - - group('test MetadataSearchDto', () { - // String checksum - test('to test the property `checksum`', () async { - // TODO - }); - - // String city - test('to test the property `city`', () async { - // TODO - }); - - // String country - test('to test the property `country`', () async { - // TODO - }); - - // DateTime createdAfter - test('to test the property `createdAfter`', () async { - // TODO - }); - - // DateTime createdBefore - test('to test the property `createdBefore`', () async { - // TODO - }); - - // String deviceAssetId - test('to test the property `deviceAssetId`', () async { - // TODO - }); - - // String deviceId - test('to test the property `deviceId`', () async { - // TODO - }); - - // String encodedVideoPath - test('to test the property `encodedVideoPath`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isArchived - test('to test the property `isArchived`', () async { - // TODO - }); - - // bool isEncoded - test('to test the property `isEncoded`', () async { - // TODO - }); - - // bool isFavorite - test('to test the property `isFavorite`', () async { - // TODO - }); - - // bool isMotion - test('to test the property `isMotion`', () async { - // TODO - }); - - // bool isNotInAlbum - test('to test the property `isNotInAlbum`', () async { - // TODO - }); - - // bool isOffline - test('to test the property `isOffline`', () async { - // TODO - }); - - // bool isVisible - test('to test the property `isVisible`', () async { - // TODO - }); - - // String lensModel - test('to test the property `lensModel`', () async { - // TODO - }); - - // String libraryId - test('to test the property `libraryId`', () async { - // TODO - }); - - // String make - test('to test the property `make`', () async { - // TODO - }); - - // String model - test('to test the property `model`', () async { - // TODO - }); - - // AssetOrder order - test('to test the property `order`', () async { - // TODO - }); - - // String originalFileName - test('to test the property `originalFileName`', () async { - // TODO - }); - - // String originalPath - test('to test the property `originalPath`', () async { - // TODO - }); - - // num page - test('to test the property `page`', () async { - // TODO - }); - - // List personIds (default value: const []) - test('to test the property `personIds`', () async { - // TODO - }); - - // String previewPath - test('to test the property `previewPath`', () async { - // TODO - }); - - // This property was deprecated in v1.100.0 - // String resizePath - test('to test the property `resizePath`', () async { - // TODO - }); - - // num size - test('to test the property `size`', () async { - // TODO - }); - - // String state - test('to test the property `state`', () async { - // TODO - }); - - // DateTime takenAfter - test('to test the property `takenAfter`', () async { - // TODO - }); - - // DateTime takenBefore - test('to test the property `takenBefore`', () async { - // TODO - }); - - // String thumbnailPath - test('to test the property `thumbnailPath`', () async { - // TODO - }); - - // DateTime trashedAfter - test('to test the property `trashedAfter`', () async { - // TODO - }); - - // DateTime trashedBefore - test('to test the property `trashedBefore`', () async { - // TODO - }); - - // AssetTypeEnum type - test('to test the property `type`', () async { - // TODO - }); - - // DateTime updatedAfter - test('to test the property `updatedAfter`', () async { - // TODO - }); - - // DateTime updatedBefore - test('to test the property `updatedBefore`', () async { - // TODO - }); - - // This property was deprecated in v1.100.0 - // String webpPath - test('to test the property `webpPath`', () async { - // TODO - }); - - // bool withArchived (default value: false) - test('to test the property `withArchived`', () async { - // TODO - }); - - // bool withDeleted - test('to test the property `withDeleted`', () async { - // TODO - }); - - // bool withExif - test('to test the property `withExif`', () async { - // TODO - }); - - // bool withPeople - test('to test the property `withPeople`', () async { - // TODO - }); - - // bool withStacked - test('to test the property `withStacked`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/model_type_test.dart b/mobile/openapi/test/model_type_test.dart deleted file mode 100644 index 17089fcae6..0000000000 --- a/mobile/openapi/test/model_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ModelType -void main() { - - group('test ModelType', () { - - }); - -} diff --git a/mobile/openapi/test/o_auth_api_test.dart b/mobile/openapi/test/o_auth_api_test.dart deleted file mode 100644 index 055963aaec..0000000000 --- a/mobile/openapi/test/o_auth_api_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for OAuthApi -void main() { - // final instance = OAuthApi(); - - group('tests for OAuthApi', () { - //Future finishOAuth(OAuthCallbackDto oAuthCallbackDto) async - test('test finishOAuth', () async { - // TODO - }); - - //Future linkOAuthAccount(OAuthCallbackDto oAuthCallbackDto) async - test('test linkOAuthAccount', () async { - // TODO - }); - - //Future redirectOAuthToMobile() async - test('test redirectOAuthToMobile', () async { - // TODO - }); - - //Future startOAuth(OAuthConfigDto oAuthConfigDto) async - test('test startOAuth', () async { - // TODO - }); - - //Future unlinkOAuthAccount() async - test('test unlinkOAuthAccount', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/o_auth_authorize_response_dto_test.dart b/mobile/openapi/test/o_auth_authorize_response_dto_test.dart deleted file mode 100644 index 76b016642a..0000000000 --- a/mobile/openapi/test/o_auth_authorize_response_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for OAuthAuthorizeResponseDto -void main() { - // final instance = OAuthAuthorizeResponseDto(); - - group('test OAuthAuthorizeResponseDto', () { - // String url - test('to test the property `url`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/o_auth_callback_dto_test.dart b/mobile/openapi/test/o_auth_callback_dto_test.dart deleted file mode 100644 index 701b4666ab..0000000000 --- a/mobile/openapi/test/o_auth_callback_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for OAuthCallbackDto -void main() { - // final instance = OAuthCallbackDto(); - - group('test OAuthCallbackDto', () { - // String url - test('to test the property `url`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/o_auth_config_dto_test.dart b/mobile/openapi/test/o_auth_config_dto_test.dart deleted file mode 100644 index d887635d7a..0000000000 --- a/mobile/openapi/test/o_auth_config_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for OAuthConfigDto -void main() { - // final instance = OAuthConfigDto(); - - group('test OAuthConfigDto', () { - // String redirectUri - test('to test the property `redirectUri`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/on_this_day_dto_test.dart b/mobile/openapi/test/on_this_day_dto_test.dart deleted file mode 100644 index 71379f8bb0..0000000000 --- a/mobile/openapi/test/on_this_day_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for OnThisDayDto -void main() { - // final instance = OnThisDayDto(); - - group('test OnThisDayDto', () { - // num year - test('to test the property `year`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/partner_api_test.dart b/mobile/openapi/test/partner_api_test.dart deleted file mode 100644 index daaf656442..0000000000 --- a/mobile/openapi/test/partner_api_test.dart +++ /dev/null @@ -1,41 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for PartnerApi -void main() { - // final instance = PartnerApi(); - - group('tests for PartnerApi', () { - //Future createPartner(String id) async - test('test createPartner', () async { - // TODO - }); - - //Future> getPartners(String direction) async - test('test getPartners', () async { - // TODO - }); - - //Future removePartner(String id) async - test('test removePartner', () async { - // TODO - }); - - //Future updatePartner(String id, UpdatePartnerDto updatePartnerDto) async - test('test updatePartner', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/partner_response_dto_test.dart b/mobile/openapi/test/partner_response_dto_test.dart deleted file mode 100644 index 2eef7f0c83..0000000000 --- a/mobile/openapi/test/partner_response_dto_test.dart +++ /dev/null @@ -1,107 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PartnerResponseDto -void main() { - // final instance = PartnerResponseDto(); - - group('test PartnerResponseDto', () { - // UserAvatarColor avatarColor - test('to test the property `avatarColor`', () async { - // TODO - }); - - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // DateTime deletedAt - test('to test the property `deletedAt`', () async { - // TODO - }); - - // String email - test('to test the property `email`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool inTimeline - test('to test the property `inTimeline`', () async { - // TODO - }); - - // bool isAdmin - test('to test the property `isAdmin`', () async { - // TODO - }); - - // bool memoriesEnabled - test('to test the property `memoriesEnabled`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String oauthId - test('to test the property `oauthId`', () async { - // TODO - }); - - // String profileImagePath - test('to test the property `profileImagePath`', () async { - // TODO - }); - - // int quotaSizeInBytes - test('to test the property `quotaSizeInBytes`', () async { - // TODO - }); - - // int quotaUsageInBytes - test('to test the property `quotaUsageInBytes`', () async { - // TODO - }); - - // bool shouldChangePassword - test('to test the property `shouldChangePassword`', () async { - // TODO - }); - - // UserStatus status - test('to test the property `status`', () async { - // TODO - }); - - // String storageLabel - test('to test the property `storageLabel`', () async { - // TODO - }); - - // DateTime updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/path_entity_type_test.dart b/mobile/openapi/test/path_entity_type_test.dart deleted file mode 100644 index 7a9c9a714e..0000000000 --- a/mobile/openapi/test/path_entity_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PathEntityType -void main() { - - group('test PathEntityType', () { - - }); - -} diff --git a/mobile/openapi/test/path_type_test.dart b/mobile/openapi/test/path_type_test.dart deleted file mode 100644 index 20862a0ef5..0000000000 --- a/mobile/openapi/test/path_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PathType -void main() { - - group('test PathType', () { - - }); - -} diff --git a/mobile/openapi/test/people_response_dto_test.dart b/mobile/openapi/test/people_response_dto_test.dart deleted file mode 100644 index 94db6eb86b..0000000000 --- a/mobile/openapi/test/people_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PeopleResponseDto -void main() { - // final instance = PeopleResponseDto(); - - group('test PeopleResponseDto', () { - // int hidden - test('to test the property `hidden`', () async { - // TODO - }); - - // List people (default value: const []) - test('to test the property `people`', () async { - // TODO - }); - - // int total - test('to test the property `total`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/people_update_dto_test.dart b/mobile/openapi/test/people_update_dto_test.dart deleted file mode 100644 index 841b6de6d8..0000000000 --- a/mobile/openapi/test/people_update_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PeopleUpdateDto -void main() { - // final instance = PeopleUpdateDto(); - - group('test PeopleUpdateDto', () { - // List people (default value: const []) - test('to test the property `people`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/people_update_item_test.dart b/mobile/openapi/test/people_update_item_test.dart deleted file mode 100644 index 8829352cf6..0000000000 --- a/mobile/openapi/test/people_update_item_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PeopleUpdateItem -void main() { - // final instance = PeopleUpdateItem(); - - group('test PeopleUpdateItem', () { - // Person date of birth. Note: the mobile app cannot currently set the birth date to null. - // DateTime birthDate - test('to test the property `birthDate`', () async { - // TODO - }); - - // Asset is used to get the feature face thumbnail. - // String featureFaceAssetId - test('to test the property `featureFaceAssetId`', () async { - // TODO - }); - - // Person id. - // String id - test('to test the property `id`', () async { - // TODO - }); - - // Person visibility - // bool isHidden - test('to test the property `isHidden`', () async { - // TODO - }); - - // Person name. - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/person_api_test.dart b/mobile/openapi/test/person_api_test.dart deleted file mode 100644 index de36966e5c..0000000000 --- a/mobile/openapi/test/person_api_test.dart +++ /dev/null @@ -1,76 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for PersonApi -void main() { - // final instance = PersonApi(); - - group('tests for PersonApi', () { - //Future createPerson(PersonCreateDto personCreateDto) async - test('test createPerson', () async { - // TODO - }); - - //Future getAllPeople({ bool withHidden }) async - test('test getAllPeople', () async { - // TODO - }); - - //Future getPerson(String id) async - test('test getPerson', () async { - // TODO - }); - - //Future> getPersonAssets(String id) async - test('test getPersonAssets', () async { - // TODO - }); - - //Future getPersonStatistics(String id) async - test('test getPersonStatistics', () async { - // TODO - }); - - //Future getPersonThumbnail(String id) async - test('test getPersonThumbnail', () async { - // TODO - }); - - //Future> mergePerson(String id, MergePersonDto mergePersonDto) async - test('test mergePerson', () async { - // TODO - }); - - //Future> reassignFaces(String id, AssetFaceUpdateDto assetFaceUpdateDto) async - test('test reassignFaces', () async { - // TODO - }); - - //Future> unassignFaces(AssetFaceUpdateDto assetFaceUpdateDto) async - test('test unassignFaces', () async { - // TODO - }); - - //Future> updatePeople(PeopleUpdateDto peopleUpdateDto) async - test('test updatePeople', () async { - // TODO - }); - - //Future updatePerson(String id, PersonUpdateDto personUpdateDto) async - test('test updatePerson', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/person_create_dto_test.dart b/mobile/openapi/test/person_create_dto_test.dart deleted file mode 100644 index 96f1fe6d39..0000000000 --- a/mobile/openapi/test/person_create_dto_test.dart +++ /dev/null @@ -1,40 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PersonCreateDto -void main() { - // final instance = PersonCreateDto(); - - group('test PersonCreateDto', () { - // Person date of birth. Note: the mobile app cannot currently set the birth date to null. - // DateTime birthDate - test('to test the property `birthDate`', () async { - // TODO - }); - - // Person visibility - // bool isHidden - test('to test the property `isHidden`', () async { - // TODO - }); - - // Person name. - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/person_response_dto_test.dart b/mobile/openapi/test/person_response_dto_test.dart deleted file mode 100644 index 0ba7306117..0000000000 --- a/mobile/openapi/test/person_response_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PersonResponseDto -void main() { - // final instance = PersonResponseDto(); - - group('test PersonResponseDto', () { - // DateTime birthDate - test('to test the property `birthDate`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isHidden - test('to test the property `isHidden`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String thumbnailPath - test('to test the property `thumbnailPath`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/person_statistics_response_dto_test.dart b/mobile/openapi/test/person_statistics_response_dto_test.dart deleted file mode 100644 index a58310d933..0000000000 --- a/mobile/openapi/test/person_statistics_response_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PersonStatisticsResponseDto -void main() { - // final instance = PersonStatisticsResponseDto(); - - group('test PersonStatisticsResponseDto', () { - // int assets - test('to test the property `assets`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/person_update_dto_test.dart b/mobile/openapi/test/person_update_dto_test.dart deleted file mode 100644 index 6ed4482cc6..0000000000 --- a/mobile/openapi/test/person_update_dto_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PersonUpdateDto -void main() { - // final instance = PersonUpdateDto(); - - group('test PersonUpdateDto', () { - // Person date of birth. Note: the mobile app cannot currently set the birth date to null. - // DateTime birthDate - test('to test the property `birthDate`', () async { - // TODO - }); - - // Asset is used to get the feature face thumbnail. - // String featureFaceAssetId - test('to test the property `featureFaceAssetId`', () async { - // TODO - }); - - // Person visibility - // bool isHidden - test('to test the property `isHidden`', () async { - // TODO - }); - - // Person name. - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/person_with_faces_response_dto_test.dart b/mobile/openapi/test/person_with_faces_response_dto_test.dart deleted file mode 100644 index 7f7e0f89ac..0000000000 --- a/mobile/openapi/test/person_with_faces_response_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PersonWithFacesResponseDto -void main() { - // final instance = PersonWithFacesResponseDto(); - - group('test PersonWithFacesResponseDto', () { - // DateTime birthDate - test('to test the property `birthDate`', () async { - // TODO - }); - - // List faces (default value: const []) - test('to test the property `faces`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isHidden - test('to test the property `isHidden`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String thumbnailPath - test('to test the property `thumbnailPath`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/places_response_dto_test.dart b/mobile/openapi/test/places_response_dto_test.dart deleted file mode 100644 index 5a320fce64..0000000000 --- a/mobile/openapi/test/places_response_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for PlacesResponseDto -void main() { - // final instance = PlacesResponseDto(); - - group('test PlacesResponseDto', () { - // String admin1name - test('to test the property `admin1name`', () async { - // TODO - }); - - // String admin2name - test('to test the property `admin2name`', () async { - // TODO - }); - - // num latitude - test('to test the property `latitude`', () async { - // TODO - }); - - // num longitude - test('to test the property `longitude`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/queue_status_dto_test.dart b/mobile/openapi/test/queue_status_dto_test.dart deleted file mode 100644 index f85eb9da86..0000000000 --- a/mobile/openapi/test/queue_status_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for QueueStatusDto -void main() { - // final instance = QueueStatusDto(); - - group('test QueueStatusDto', () { - // bool isActive - test('to test the property `isActive`', () async { - // TODO - }); - - // bool isPaused - test('to test the property `isPaused`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/reaction_level_test.dart b/mobile/openapi/test/reaction_level_test.dart deleted file mode 100644 index 6fcba58b1a..0000000000 --- a/mobile/openapi/test/reaction_level_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ReactionLevel -void main() { - - group('test ReactionLevel', () { - - }); - -} diff --git a/mobile/openapi/test/reaction_type_test.dart b/mobile/openapi/test/reaction_type_test.dart deleted file mode 100644 index 4c0dfc5955..0000000000 --- a/mobile/openapi/test/reaction_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ReactionType -void main() { - - group('test ReactionType', () { - - }); - -} diff --git a/mobile/openapi/test/recognition_config_test.dart b/mobile/openapi/test/recognition_config_test.dart deleted file mode 100644 index ec006cf3d9..0000000000 --- a/mobile/openapi/test/recognition_config_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for RecognitionConfig -void main() { - // final instance = RecognitionConfig(); - - group('test RecognitionConfig', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // double maxDistance - test('to test the property `maxDistance`', () async { - // TODO - }); - - // int minFaces - test('to test the property `minFaces`', () async { - // TODO - }); - - // double minScore - test('to test the property `minScore`', () async { - // TODO - }); - - // String modelName - test('to test the property `modelName`', () async { - // TODO - }); - - // ModelType modelType - test('to test the property `modelType`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/reverse_geocoding_state_response_dto_test.dart b/mobile/openapi/test/reverse_geocoding_state_response_dto_test.dart deleted file mode 100644 index 91fdfcfea4..0000000000 --- a/mobile/openapi/test/reverse_geocoding_state_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ReverseGeocodingStateResponseDto -void main() { - // final instance = ReverseGeocodingStateResponseDto(); - - group('test ReverseGeocodingStateResponseDto', () { - // String lastImportFileName - test('to test the property `lastImportFileName`', () async { - // TODO - }); - - // String lastUpdate - test('to test the property `lastUpdate`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/scan_library_dto_test.dart b/mobile/openapi/test/scan_library_dto_test.dart deleted file mode 100644 index 2b3c758670..0000000000 --- a/mobile/openapi/test/scan_library_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ScanLibraryDto -void main() { - // final instance = ScanLibraryDto(); - - group('test ScanLibraryDto', () { - // bool refreshAllFiles - test('to test the property `refreshAllFiles`', () async { - // TODO - }); - - // bool refreshModifiedFiles - test('to test the property `refreshModifiedFiles`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_album_response_dto_test.dart b/mobile/openapi/test/search_album_response_dto_test.dart deleted file mode 100644 index 7002d34b09..0000000000 --- a/mobile/openapi/test/search_album_response_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchAlbumResponseDto -void main() { - // final instance = SearchAlbumResponseDto(); - - group('test SearchAlbumResponseDto', () { - // int count - test('to test the property `count`', () async { - // TODO - }); - - // List facets (default value: const []) - test('to test the property `facets`', () async { - // TODO - }); - - // List items (default value: const []) - test('to test the property `items`', () async { - // TODO - }); - - // int total - test('to test the property `total`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_api_test.dart b/mobile/openapi/test/search_api_test.dart deleted file mode 100644 index a00b1290f4..0000000000 --- a/mobile/openapi/test/search_api_test.dart +++ /dev/null @@ -1,56 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for SearchApi -void main() { - // final instance = SearchApi(); - - group('tests for SearchApi', () { - //Future> getAssetsByCity() async - test('test getAssetsByCity', () async { - // TODO - }); - - //Future> getExploreData() async - test('test getExploreData', () async { - // TODO - }); - - //Future> getSearchSuggestions(SearchSuggestionType type, { String country, String make, String model, String state }) async - test('test getSearchSuggestions', () async { - // TODO - }); - - //Future searchMetadata(MetadataSearchDto metadataSearchDto) async - test('test searchMetadata', () async { - // TODO - }); - - //Future> searchPerson(String name, { bool withHidden }) async - test('test searchPerson', () async { - // TODO - }); - - //Future> searchPlaces(String name) async - test('test searchPlaces', () async { - // TODO - }); - - //Future searchSmart(SmartSearchDto smartSearchDto) async - test('test searchSmart', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/search_asset_response_dto_test.dart b/mobile/openapi/test/search_asset_response_dto_test.dart deleted file mode 100644 index 56e8276171..0000000000 --- a/mobile/openapi/test/search_asset_response_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchAssetResponseDto -void main() { - // final instance = SearchAssetResponseDto(); - - group('test SearchAssetResponseDto', () { - // int count - test('to test the property `count`', () async { - // TODO - }); - - // List facets (default value: const []) - test('to test the property `facets`', () async { - // TODO - }); - - // List items (default value: const []) - test('to test the property `items`', () async { - // TODO - }); - - // String nextPage - test('to test the property `nextPage`', () async { - // TODO - }); - - // int total - test('to test the property `total`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_explore_item_test.dart b/mobile/openapi/test/search_explore_item_test.dart deleted file mode 100644 index 2bc3ad7aee..0000000000 --- a/mobile/openapi/test/search_explore_item_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchExploreItem -void main() { - // final instance = SearchExploreItem(); - - group('test SearchExploreItem', () { - // AssetResponseDto data - test('to test the property `data`', () async { - // TODO - }); - - // String value - test('to test the property `value`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_explore_response_dto_test.dart b/mobile/openapi/test/search_explore_response_dto_test.dart deleted file mode 100644 index ccc82a0d75..0000000000 --- a/mobile/openapi/test/search_explore_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchExploreResponseDto -void main() { - // final instance = SearchExploreResponseDto(); - - group('test SearchExploreResponseDto', () { - // String fieldName - test('to test the property `fieldName`', () async { - // TODO - }); - - // List items (default value: const []) - test('to test the property `items`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_facet_count_response_dto_test.dart b/mobile/openapi/test/search_facet_count_response_dto_test.dart deleted file mode 100644 index fb3caee627..0000000000 --- a/mobile/openapi/test/search_facet_count_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchFacetCountResponseDto -void main() { - // final instance = SearchFacetCountResponseDto(); - - group('test SearchFacetCountResponseDto', () { - // int count - test('to test the property `count`', () async { - // TODO - }); - - // String value - test('to test the property `value`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_facet_response_dto_test.dart b/mobile/openapi/test/search_facet_response_dto_test.dart deleted file mode 100644 index ed5e0d83aa..0000000000 --- a/mobile/openapi/test/search_facet_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchFacetResponseDto -void main() { - // final instance = SearchFacetResponseDto(); - - group('test SearchFacetResponseDto', () { - // List counts (default value: const []) - test('to test the property `counts`', () async { - // TODO - }); - - // String fieldName - test('to test the property `fieldName`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_response_dto_test.dart b/mobile/openapi/test/search_response_dto_test.dart deleted file mode 100644 index 06f8fa7a3a..0000000000 --- a/mobile/openapi/test/search_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchResponseDto -void main() { - // final instance = SearchResponseDto(); - - group('test SearchResponseDto', () { - // SearchAlbumResponseDto albums - test('to test the property `albums`', () async { - // TODO - }); - - // SearchAssetResponseDto assets - test('to test the property `assets`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/search_suggestion_type_test.dart b/mobile/openapi/test/search_suggestion_type_test.dart deleted file mode 100644 index f86a7de90a..0000000000 --- a/mobile/openapi/test/search_suggestion_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SearchSuggestionType -void main() { - - group('test SearchSuggestionType', () { - - }); - -} diff --git a/mobile/openapi/test/server_config_dto_test.dart b/mobile/openapi/test/server_config_dto_test.dart deleted file mode 100644 index f76556c50f..0000000000 --- a/mobile/openapi/test/server_config_dto_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerConfigDto -void main() { - // final instance = ServerConfigDto(); - - group('test ServerConfigDto', () { - // String externalDomain - test('to test the property `externalDomain`', () async { - // TODO - }); - - // bool isInitialized - test('to test the property `isInitialized`', () async { - // TODO - }); - - // bool isOnboarded - test('to test the property `isOnboarded`', () async { - // TODO - }); - - // String loginPageMessage - test('to test the property `loginPageMessage`', () async { - // TODO - }); - - // String oauthButtonText - test('to test the property `oauthButtonText`', () async { - // TODO - }); - - // int trashDays - test('to test the property `trashDays`', () async { - // TODO - }); - - // int userDeleteDelay - test('to test the property `userDeleteDelay`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/server_features_dto_test.dart b/mobile/openapi/test/server_features_dto_test.dart deleted file mode 100644 index b16d4cb6ca..0000000000 --- a/mobile/openapi/test/server_features_dto_test.dart +++ /dev/null @@ -1,82 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerFeaturesDto -void main() { - // final instance = ServerFeaturesDto(); - - group('test ServerFeaturesDto', () { - // bool configFile - test('to test the property `configFile`', () async { - // TODO - }); - - // bool email - test('to test the property `email`', () async { - // TODO - }); - - // bool facialRecognition - test('to test the property `facialRecognition`', () async { - // TODO - }); - - // bool map - test('to test the property `map`', () async { - // TODO - }); - - // bool oauth - test('to test the property `oauth`', () async { - // TODO - }); - - // bool oauthAutoLaunch - test('to test the property `oauthAutoLaunch`', () async { - // TODO - }); - - // bool passwordLogin - test('to test the property `passwordLogin`', () async { - // TODO - }); - - // bool reverseGeocoding - test('to test the property `reverseGeocoding`', () async { - // TODO - }); - - // bool search - test('to test the property `search`', () async { - // TODO - }); - - // bool sidecar - test('to test the property `sidecar`', () async { - // TODO - }); - - // bool smartSearch - test('to test the property `smartSearch`', () async { - // TODO - }); - - // bool trash - test('to test the property `trash`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/server_info_api_test.dart b/mobile/openapi/test/server_info_api_test.dart deleted file mode 100644 index dac465116e..0000000000 --- a/mobile/openapi/test/server_info_api_test.dart +++ /dev/null @@ -1,61 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for ServerInfoApi -void main() { - // final instance = ServerInfoApi(); - - group('tests for ServerInfoApi', () { - //Future getServerConfig() async - test('test getServerConfig', () async { - // TODO - }); - - //Future getServerFeatures() async - test('test getServerFeatures', () async { - // TODO - }); - - //Future getServerInfo() async - test('test getServerInfo', () async { - // TODO - }); - - //Future getServerStatistics() async - test('test getServerStatistics', () async { - // TODO - }); - - //Future getServerVersion() async - test('test getServerVersion', () async { - // TODO - }); - - //Future getSupportedMediaTypes() async - test('test getSupportedMediaTypes', () async { - // TODO - }); - - //Future getTheme() async - test('test getTheme', () async { - // TODO - }); - - //Future pingServer() async - test('test pingServer', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/server_info_response_dto_test.dart b/mobile/openapi/test/server_info_response_dto_test.dart deleted file mode 100644 index e41635ec51..0000000000 --- a/mobile/openapi/test/server_info_response_dto_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerInfoResponseDto -void main() { - // final instance = ServerInfoResponseDto(); - - group('test ServerInfoResponseDto', () { - // String diskAvailable - test('to test the property `diskAvailable`', () async { - // TODO - }); - - // int diskAvailableRaw - test('to test the property `diskAvailableRaw`', () async { - // TODO - }); - - // String diskSize - test('to test the property `diskSize`', () async { - // TODO - }); - - // int diskSizeRaw - test('to test the property `diskSizeRaw`', () async { - // TODO - }); - - // double diskUsagePercentage - test('to test the property `diskUsagePercentage`', () async { - // TODO - }); - - // String diskUse - test('to test the property `diskUse`', () async { - // TODO - }); - - // int diskUseRaw - test('to test the property `diskUseRaw`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/server_media_types_response_dto_test.dart b/mobile/openapi/test/server_media_types_response_dto_test.dart deleted file mode 100644 index 9ae2bfa2d9..0000000000 --- a/mobile/openapi/test/server_media_types_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerMediaTypesResponseDto -void main() { - // final instance = ServerMediaTypesResponseDto(); - - group('test ServerMediaTypesResponseDto', () { - // List image (default value: const []) - test('to test the property `image`', () async { - // TODO - }); - - // List sidecar (default value: const []) - test('to test the property `sidecar`', () async { - // TODO - }); - - // List video (default value: const []) - test('to test the property `video`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/server_ping_response_test.dart b/mobile/openapi/test/server_ping_response_test.dart deleted file mode 100644 index cb72680176..0000000000 --- a/mobile/openapi/test/server_ping_response_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerPingResponse -void main() { - // final instance = ServerPingResponse(); - - group('test ServerPingResponse', () { - // String res - test('to test the property `res`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/server_stats_response_dto_test.dart b/mobile/openapi/test/server_stats_response_dto_test.dart deleted file mode 100644 index fa7e032aa1..0000000000 --- a/mobile/openapi/test/server_stats_response_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerStatsResponseDto -void main() { - // final instance = ServerStatsResponseDto(); - - group('test ServerStatsResponseDto', () { - // int photos (default value: 0) - test('to test the property `photos`', () async { - // TODO - }); - - // int usage (default value: 0) - test('to test the property `usage`', () async { - // TODO - }); - - // List usageByUser (default value: const []) - test('to test the property `usageByUser`', () async { - // TODO - }); - - // int videos (default value: 0) - test('to test the property `videos`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/server_theme_dto_test.dart b/mobile/openapi/test/server_theme_dto_test.dart deleted file mode 100644 index d340b8f55d..0000000000 --- a/mobile/openapi/test/server_theme_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerThemeDto -void main() { - // final instance = ServerThemeDto(); - - group('test ServerThemeDto', () { - // String customCss - test('to test the property `customCss`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/server_version_response_dto_test.dart b/mobile/openapi/test/server_version_response_dto_test.dart deleted file mode 100644 index add42ccd66..0000000000 --- a/mobile/openapi/test/server_version_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ServerVersionResponseDto -void main() { - // final instance = ServerVersionResponseDto(); - - group('test ServerVersionResponseDto', () { - // int major - test('to test the property `major`', () async { - // TODO - }); - - // int minor - test('to test the property `minor`', () async { - // TODO - }); - - // int patch_ - test('to test the property `patch_`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/session_response_dto_test.dart b/mobile/openapi/test/session_response_dto_test.dart deleted file mode 100644 index d704b2e5eb..0000000000 --- a/mobile/openapi/test/session_response_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SessionResponseDto -void main() { - // final instance = SessionResponseDto(); - - group('test SessionResponseDto', () { - // String createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // bool current - test('to test the property `current`', () async { - // TODO - }); - - // String deviceOS - test('to test the property `deviceOS`', () async { - // TODO - }); - - // String deviceType - test('to test the property `deviceType`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // String updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/sessions_api_test.dart b/mobile/openapi/test/sessions_api_test.dart deleted file mode 100644 index 9fc6093c19..0000000000 --- a/mobile/openapi/test/sessions_api_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for SessionsApi -void main() { - // final instance = SessionsApi(); - - group('tests for SessionsApi', () { - //Future deleteAllSessions() async - test('test deleteAllSessions', () async { - // TODO - }); - - //Future deleteSession(String id) async - test('test deleteSession', () async { - // TODO - }); - - //Future> getSessions() async - test('test getSessions', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/shared_link_api_test.dart b/mobile/openapi/test/shared_link_api_test.dart deleted file mode 100644 index ebe5bf199f..0000000000 --- a/mobile/openapi/test/shared_link_api_test.dart +++ /dev/null @@ -1,61 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for SharedLinkApi -void main() { - // final instance = SharedLinkApi(); - - group('tests for SharedLinkApi', () { - //Future> addSharedLinkAssets(String id, AssetIdsDto assetIdsDto, { String key }) async - test('test addSharedLinkAssets', () async { - // TODO - }); - - //Future createSharedLink(SharedLinkCreateDto sharedLinkCreateDto) async - test('test createSharedLink', () async { - // TODO - }); - - //Future> getAllSharedLinks() async - test('test getAllSharedLinks', () async { - // TODO - }); - - //Future getMySharedLink({ String key, String password, String token }) async - test('test getMySharedLink', () async { - // TODO - }); - - //Future getSharedLinkById(String id) async - test('test getSharedLinkById', () async { - // TODO - }); - - //Future removeSharedLink(String id) async - test('test removeSharedLink', () async { - // TODO - }); - - //Future> removeSharedLinkAssets(String id, AssetIdsDto assetIdsDto, { String key }) async - test('test removeSharedLinkAssets', () async { - // TODO - }); - - //Future updateSharedLink(String id, SharedLinkEditDto sharedLinkEditDto) async - test('test updateSharedLink', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/shared_link_create_dto_test.dart b/mobile/openapi/test/shared_link_create_dto_test.dart deleted file mode 100644 index 982d72a140..0000000000 --- a/mobile/openapi/test/shared_link_create_dto_test.dart +++ /dev/null @@ -1,67 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SharedLinkCreateDto -void main() { - // final instance = SharedLinkCreateDto(); - - group('test SharedLinkCreateDto', () { - // String albumId - test('to test the property `albumId`', () async { - // TODO - }); - - // bool allowDownload (default value: true) - test('to test the property `allowDownload`', () async { - // TODO - }); - - // bool allowUpload - test('to test the property `allowUpload`', () async { - // TODO - }); - - // List assetIds (default value: const []) - test('to test the property `assetIds`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // DateTime expiresAt - test('to test the property `expiresAt`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - // bool showMetadata (default value: true) - test('to test the property `showMetadata`', () async { - // TODO - }); - - // SharedLinkType type - test('to test the property `type`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/shared_link_edit_dto_test.dart b/mobile/openapi/test/shared_link_edit_dto_test.dart deleted file mode 100644 index f5c45190c3..0000000000 --- a/mobile/openapi/test/shared_link_edit_dto_test.dart +++ /dev/null @@ -1,58 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SharedLinkEditDto -void main() { - // final instance = SharedLinkEditDto(); - - group('test SharedLinkEditDto', () { - // bool allowDownload - test('to test the property `allowDownload`', () async { - // TODO - }); - - // bool allowUpload - test('to test the property `allowUpload`', () async { - // TODO - }); - - // Few clients cannot send null to set the expiryTime to never. Setting this flag and not sending expiryAt is considered as null instead. Clients that can send null values can ignore this. - // bool changeExpiryTime - test('to test the property `changeExpiryTime`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // DateTime expiresAt - test('to test the property `expiresAt`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - // bool showMetadata - test('to test the property `showMetadata`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/shared_link_response_dto_test.dart b/mobile/openapi/test/shared_link_response_dto_test.dart deleted file mode 100644 index 0eb4ed50a7..0000000000 --- a/mobile/openapi/test/shared_link_response_dto_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SharedLinkResponseDto -void main() { - // final instance = SharedLinkResponseDto(); - - group('test SharedLinkResponseDto', () { - // AlbumResponseDto album - test('to test the property `album`', () async { - // TODO - }); - - // bool allowDownload - test('to test the property `allowDownload`', () async { - // TODO - }); - - // bool allowUpload - test('to test the property `allowUpload`', () async { - // TODO - }); - - // List assets (default value: const []) - test('to test the property `assets`', () async { - // TODO - }); - - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // DateTime expiresAt - test('to test the property `expiresAt`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // String key - test('to test the property `key`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - // bool showMetadata - test('to test the property `showMetadata`', () async { - // TODO - }); - - // String token - test('to test the property `token`', () async { - // TODO - }); - - // SharedLinkType type - test('to test the property `type`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/shared_link_type_test.dart b/mobile/openapi/test/shared_link_type_test.dart deleted file mode 100644 index 6a2c8cdf51..0000000000 --- a/mobile/openapi/test/shared_link_type_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SharedLinkType -void main() { - - group('test SharedLinkType', () { - - }); - -} diff --git a/mobile/openapi/test/sign_up_dto_test.dart b/mobile/openapi/test/sign_up_dto_test.dart deleted file mode 100644 index 3c255f7265..0000000000 --- a/mobile/openapi/test/sign_up_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SignUpDto -void main() { - // final instance = SignUpDto(); - - group('test SignUpDto', () { - // String email - test('to test the property `email`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/smart_info_response_dto_test.dart b/mobile/openapi/test/smart_info_response_dto_test.dart deleted file mode 100644 index 15758d0636..0000000000 --- a/mobile/openapi/test/smart_info_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SmartInfoResponseDto -void main() { - // final instance = SmartInfoResponseDto(); - - group('test SmartInfoResponseDto', () { - // List objects (default value: const []) - test('to test the property `objects`', () async { - // TODO - }); - - // List tags (default value: const []) - test('to test the property `tags`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/smart_search_dto_test.dart b/mobile/openapi/test/smart_search_dto_test.dart deleted file mode 100644 index 6ad95107ba..0000000000 --- a/mobile/openapi/test/smart_search_dto_test.dart +++ /dev/null @@ -1,177 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SmartSearchDto -void main() { - // final instance = SmartSearchDto(); - - group('test SmartSearchDto', () { - // String city - test('to test the property `city`', () async { - // TODO - }); - - // String country - test('to test the property `country`', () async { - // TODO - }); - - // DateTime createdAfter - test('to test the property `createdAfter`', () async { - // TODO - }); - - // DateTime createdBefore - test('to test the property `createdBefore`', () async { - // TODO - }); - - // String deviceId - test('to test the property `deviceId`', () async { - // TODO - }); - - // bool isArchived - test('to test the property `isArchived`', () async { - // TODO - }); - - // bool isEncoded - test('to test the property `isEncoded`', () async { - // TODO - }); - - // bool isFavorite - test('to test the property `isFavorite`', () async { - // TODO - }); - - // bool isMotion - test('to test the property `isMotion`', () async { - // TODO - }); - - // bool isNotInAlbum - test('to test the property `isNotInAlbum`', () async { - // TODO - }); - - // bool isOffline - test('to test the property `isOffline`', () async { - // TODO - }); - - // bool isVisible - test('to test the property `isVisible`', () async { - // TODO - }); - - // String lensModel - test('to test the property `lensModel`', () async { - // TODO - }); - - // String libraryId - test('to test the property `libraryId`', () async { - // TODO - }); - - // String make - test('to test the property `make`', () async { - // TODO - }); - - // String model - test('to test the property `model`', () async { - // TODO - }); - - // num page - test('to test the property `page`', () async { - // TODO - }); - - // List personIds (default value: const []) - test('to test the property `personIds`', () async { - // TODO - }); - - // String query - test('to test the property `query`', () async { - // TODO - }); - - // num size - test('to test the property `size`', () async { - // TODO - }); - - // String state - test('to test the property `state`', () async { - // TODO - }); - - // DateTime takenAfter - test('to test the property `takenAfter`', () async { - // TODO - }); - - // DateTime takenBefore - test('to test the property `takenBefore`', () async { - // TODO - }); - - // DateTime trashedAfter - test('to test the property `trashedAfter`', () async { - // TODO - }); - - // DateTime trashedBefore - test('to test the property `trashedBefore`', () async { - // TODO - }); - - // AssetTypeEnum type - test('to test the property `type`', () async { - // TODO - }); - - // DateTime updatedAfter - test('to test the property `updatedAfter`', () async { - // TODO - }); - - // DateTime updatedBefore - test('to test the property `updatedBefore`', () async { - // TODO - }); - - // bool withArchived (default value: false) - test('to test the property `withArchived`', () async { - // TODO - }); - - // bool withDeleted - test('to test the property `withDeleted`', () async { - // TODO - }); - - // bool withExif - test('to test the property `withExif`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/sync_api_test.dart b/mobile/openapi/test/sync_api_test.dart deleted file mode 100644 index c2f548aeb2..0000000000 --- a/mobile/openapi/test/sync_api_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for SyncApi -void main() { - // final instance = SyncApi(); - - group('tests for SyncApi', () { - //Future getDeltaSync(AssetDeltaSyncDto assetDeltaSyncDto) async - test('test getDeltaSync', () async { - // TODO - }); - - //Future> getFullSyncForUser(AssetFullSyncDto assetFullSyncDto) async - test('test getFullSyncForUser', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/system_config_api_test.dart b/mobile/openapi/test/system_config_api_test.dart deleted file mode 100644 index 0330d6a3d0..0000000000 --- a/mobile/openapi/test/system_config_api_test.dart +++ /dev/null @@ -1,46 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for SystemConfigApi -void main() { - // final instance = SystemConfigApi(); - - group('tests for SystemConfigApi', () { - //Future getConfig() async - test('test getConfig', () async { - // TODO - }); - - //Future getConfigDefaults() async - test('test getConfigDefaults', () async { - // TODO - }); - - //Future getMapStyle(MapTheme theme, { String key }) async - test('test getMapStyle', () async { - // TODO - }); - - //Future getStorageTemplateOptions() async - test('test getStorageTemplateOptions', () async { - // TODO - }); - - //Future updateConfig(SystemConfigDto systemConfigDto) async - test('test updateConfig', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/system_config_dto_test.dart b/mobile/openapi/test/system_config_dto_test.dart deleted file mode 100644 index 3a6eb5523b..0000000000 --- a/mobile/openapi/test/system_config_dto_test.dart +++ /dev/null @@ -1,107 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigDto -void main() { - // final instance = SystemConfigDto(); - - group('test SystemConfigDto', () { - // SystemConfigFFmpegDto ffmpeg - test('to test the property `ffmpeg`', () async { - // TODO - }); - - // SystemConfigImageDto image - test('to test the property `image`', () async { - // TODO - }); - - // SystemConfigJobDto job - test('to test the property `job`', () async { - // TODO - }); - - // SystemConfigLibraryDto library_ - test('to test the property `library_`', () async { - // TODO - }); - - // SystemConfigLoggingDto logging - test('to test the property `logging`', () async { - // TODO - }); - - // SystemConfigMachineLearningDto machineLearning - test('to test the property `machineLearning`', () async { - // TODO - }); - - // SystemConfigMapDto map - test('to test the property `map`', () async { - // TODO - }); - - // SystemConfigNewVersionCheckDto newVersionCheck - test('to test the property `newVersionCheck`', () async { - // TODO - }); - - // SystemConfigNotificationsDto notifications - test('to test the property `notifications`', () async { - // TODO - }); - - // SystemConfigOAuthDto oauth - test('to test the property `oauth`', () async { - // TODO - }); - - // SystemConfigPasswordLoginDto passwordLogin - test('to test the property `passwordLogin`', () async { - // TODO - }); - - // SystemConfigReverseGeocodingDto reverseGeocoding - test('to test the property `reverseGeocoding`', () async { - // TODO - }); - - // SystemConfigServerDto server - test('to test the property `server`', () async { - // TODO - }); - - // SystemConfigStorageTemplateDto storageTemplate - test('to test the property `storageTemplate`', () async { - // TODO - }); - - // SystemConfigThemeDto theme - test('to test the property `theme`', () async { - // TODO - }); - - // SystemConfigTrashDto trash - test('to test the property `trash`', () async { - // TODO - }); - - // SystemConfigUserDto user - test('to test the property `user`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_f_fmpeg_dto_test.dart b/mobile/openapi/test/system_config_f_fmpeg_dto_test.dart deleted file mode 100644 index b0a4f2afb8..0000000000 --- a/mobile/openapi/test/system_config_f_fmpeg_dto_test.dart +++ /dev/null @@ -1,122 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigFFmpegDto -void main() { - // final instance = SystemConfigFFmpegDto(); - - group('test SystemConfigFFmpegDto', () { - // TranscodeHWAccel accel - test('to test the property `accel`', () async { - // TODO - }); - - // List acceptedAudioCodecs (default value: const []) - test('to test the property `acceptedAudioCodecs`', () async { - // TODO - }); - - // List acceptedVideoCodecs (default value: const []) - test('to test the property `acceptedVideoCodecs`', () async { - // TODO - }); - - // int bframes - test('to test the property `bframes`', () async { - // TODO - }); - - // CQMode cqMode - test('to test the property `cqMode`', () async { - // TODO - }); - - // int crf - test('to test the property `crf`', () async { - // TODO - }); - - // int gopSize - test('to test the property `gopSize`', () async { - // TODO - }); - - // String maxBitrate - test('to test the property `maxBitrate`', () async { - // TODO - }); - - // int npl - test('to test the property `npl`', () async { - // TODO - }); - - // String preferredHwDevice - test('to test the property `preferredHwDevice`', () async { - // TODO - }); - - // String preset - test('to test the property `preset`', () async { - // TODO - }); - - // int refs - test('to test the property `refs`', () async { - // TODO - }); - - // AudioCodec targetAudioCodec - test('to test the property `targetAudioCodec`', () async { - // TODO - }); - - // String targetResolution - test('to test the property `targetResolution`', () async { - // TODO - }); - - // VideoCodec targetVideoCodec - test('to test the property `targetVideoCodec`', () async { - // TODO - }); - - // bool temporalAQ - test('to test the property `temporalAQ`', () async { - // TODO - }); - - // int threads - test('to test the property `threads`', () async { - // TODO - }); - - // ToneMapping tonemap - test('to test the property `tonemap`', () async { - // TODO - }); - - // TranscodePolicy transcode - test('to test the property `transcode`', () async { - // TODO - }); - - // bool twoPass - test('to test the property `twoPass`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_image_dto_test.dart b/mobile/openapi/test/system_config_image_dto_test.dart deleted file mode 100644 index b46340455b..0000000000 --- a/mobile/openapi/test/system_config_image_dto_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigImageDto -void main() { - // final instance = SystemConfigImageDto(); - - group('test SystemConfigImageDto', () { - // Colorspace colorspace - test('to test the property `colorspace`', () async { - // TODO - }); - - // bool extractEmbedded - test('to test the property `extractEmbedded`', () async { - // TODO - }); - - // ImageFormat previewFormat - test('to test the property `previewFormat`', () async { - // TODO - }); - - // int previewSize - test('to test the property `previewSize`', () async { - // TODO - }); - - // int quality - test('to test the property `quality`', () async { - // TODO - }); - - // ImageFormat thumbnailFormat - test('to test the property `thumbnailFormat`', () async { - // TODO - }); - - // int thumbnailSize - test('to test the property `thumbnailSize`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_job_dto_test.dart b/mobile/openapi/test/system_config_job_dto_test.dart deleted file mode 100644 index 1bf0fa85ba..0000000000 --- a/mobile/openapi/test/system_config_job_dto_test.dart +++ /dev/null @@ -1,77 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigJobDto -void main() { - // final instance = SystemConfigJobDto(); - - group('test SystemConfigJobDto', () { - // JobSettingsDto backgroundTask - test('to test the property `backgroundTask`', () async { - // TODO - }); - - // JobSettingsDto faceDetection - test('to test the property `faceDetection`', () async { - // TODO - }); - - // JobSettingsDto library_ - test('to test the property `library_`', () async { - // TODO - }); - - // JobSettingsDto metadataExtraction - test('to test the property `metadataExtraction`', () async { - // TODO - }); - - // JobSettingsDto migration - test('to test the property `migration`', () async { - // TODO - }); - - // JobSettingsDto notifications - test('to test the property `notifications`', () async { - // TODO - }); - - // JobSettingsDto search - test('to test the property `search`', () async { - // TODO - }); - - // JobSettingsDto sidecar - test('to test the property `sidecar`', () async { - // TODO - }); - - // JobSettingsDto smartSearch - test('to test the property `smartSearch`', () async { - // TODO - }); - - // JobSettingsDto thumbnailGeneration - test('to test the property `thumbnailGeneration`', () async { - // TODO - }); - - // JobSettingsDto videoConversion - test('to test the property `videoConversion`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_library_dto_test.dart b/mobile/openapi/test/system_config_library_dto_test.dart deleted file mode 100644 index 6b24124591..0000000000 --- a/mobile/openapi/test/system_config_library_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigLibraryDto -void main() { - // final instance = SystemConfigLibraryDto(); - - group('test SystemConfigLibraryDto', () { - // SystemConfigLibraryScanDto scan - test('to test the property `scan`', () async { - // TODO - }); - - // SystemConfigLibraryWatchDto watch - test('to test the property `watch`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_library_scan_dto_test.dart b/mobile/openapi/test/system_config_library_scan_dto_test.dart deleted file mode 100644 index 574013e752..0000000000 --- a/mobile/openapi/test/system_config_library_scan_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigLibraryScanDto -void main() { - // final instance = SystemConfigLibraryScanDto(); - - group('test SystemConfigLibraryScanDto', () { - // String cronExpression - test('to test the property `cronExpression`', () async { - // TODO - }); - - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_library_watch_dto_test.dart b/mobile/openapi/test/system_config_library_watch_dto_test.dart deleted file mode 100644 index 19b5de05fe..0000000000 --- a/mobile/openapi/test/system_config_library_watch_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigLibraryWatchDto -void main() { - // final instance = SystemConfigLibraryWatchDto(); - - group('test SystemConfigLibraryWatchDto', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_logging_dto_test.dart b/mobile/openapi/test/system_config_logging_dto_test.dart deleted file mode 100644 index cc638f5310..0000000000 --- a/mobile/openapi/test/system_config_logging_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigLoggingDto -void main() { - // final instance = SystemConfigLoggingDto(); - - group('test SystemConfigLoggingDto', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // LogLevel level - test('to test the property `level`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_machine_learning_dto_test.dart b/mobile/openapi/test/system_config_machine_learning_dto_test.dart deleted file mode 100644 index 377f25ce09..0000000000 --- a/mobile/openapi/test/system_config_machine_learning_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigMachineLearningDto -void main() { - // final instance = SystemConfigMachineLearningDto(); - - group('test SystemConfigMachineLearningDto', () { - // CLIPConfig clip - test('to test the property `clip`', () async { - // TODO - }); - - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // RecognitionConfig facialRecognition - test('to test the property `facialRecognition`', () async { - // TODO - }); - - // String url - test('to test the property `url`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_map_dto_test.dart b/mobile/openapi/test/system_config_map_dto_test.dart deleted file mode 100644 index b42753d4f4..0000000000 --- a/mobile/openapi/test/system_config_map_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigMapDto -void main() { - // final instance = SystemConfigMapDto(); - - group('test SystemConfigMapDto', () { - // String darkStyle - test('to test the property `darkStyle`', () async { - // TODO - }); - - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // String lightStyle - test('to test the property `lightStyle`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_new_version_check_dto_test.dart b/mobile/openapi/test/system_config_new_version_check_dto_test.dart deleted file mode 100644 index 8711a52456..0000000000 --- a/mobile/openapi/test/system_config_new_version_check_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigNewVersionCheckDto -void main() { - // final instance = SystemConfigNewVersionCheckDto(); - - group('test SystemConfigNewVersionCheckDto', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_notifications_dto_test.dart b/mobile/openapi/test/system_config_notifications_dto_test.dart deleted file mode 100644 index 4c18515ff0..0000000000 --- a/mobile/openapi/test/system_config_notifications_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigNotificationsDto -void main() { - // final instance = SystemConfigNotificationsDto(); - - group('test SystemConfigNotificationsDto', () { - // SystemConfigSmtpDto smtp - test('to test the property `smtp`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_o_auth_dto_test.dart b/mobile/openapi/test/system_config_o_auth_dto_test.dart deleted file mode 100644 index e855ff9608..0000000000 --- a/mobile/openapi/test/system_config_o_auth_dto_test.dart +++ /dev/null @@ -1,92 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigOAuthDto -void main() { - // final instance = SystemConfigOAuthDto(); - - group('test SystemConfigOAuthDto', () { - // bool autoLaunch - test('to test the property `autoLaunch`', () async { - // TODO - }); - - // bool autoRegister - test('to test the property `autoRegister`', () async { - // TODO - }); - - // String buttonText - test('to test the property `buttonText`', () async { - // TODO - }); - - // String clientId - test('to test the property `clientId`', () async { - // TODO - }); - - // String clientSecret - test('to test the property `clientSecret`', () async { - // TODO - }); - - // num defaultStorageQuota - test('to test the property `defaultStorageQuota`', () async { - // TODO - }); - - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // String issuerUrl - test('to test the property `issuerUrl`', () async { - // TODO - }); - - // bool mobileOverrideEnabled - test('to test the property `mobileOverrideEnabled`', () async { - // TODO - }); - - // String mobileRedirectUri - test('to test the property `mobileRedirectUri`', () async { - // TODO - }); - - // String scope - test('to test the property `scope`', () async { - // TODO - }); - - // String signingAlgorithm - test('to test the property `signingAlgorithm`', () async { - // TODO - }); - - // String storageLabelClaim - test('to test the property `storageLabelClaim`', () async { - // TODO - }); - - // String storageQuotaClaim - test('to test the property `storageQuotaClaim`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_password_login_dto_test.dart b/mobile/openapi/test/system_config_password_login_dto_test.dart deleted file mode 100644 index a8d87d1547..0000000000 --- a/mobile/openapi/test/system_config_password_login_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigPasswordLoginDto -void main() { - // final instance = SystemConfigPasswordLoginDto(); - - group('test SystemConfigPasswordLoginDto', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_reverse_geocoding_dto_test.dart b/mobile/openapi/test/system_config_reverse_geocoding_dto_test.dart deleted file mode 100644 index b4aa477df3..0000000000 --- a/mobile/openapi/test/system_config_reverse_geocoding_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigReverseGeocodingDto -void main() { - // final instance = SystemConfigReverseGeocodingDto(); - - group('test SystemConfigReverseGeocodingDto', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_server_dto_test.dart b/mobile/openapi/test/system_config_server_dto_test.dart deleted file mode 100644 index 5d10e0d7a2..0000000000 --- a/mobile/openapi/test/system_config_server_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigServerDto -void main() { - // final instance = SystemConfigServerDto(); - - group('test SystemConfigServerDto', () { - // String externalDomain - test('to test the property `externalDomain`', () async { - // TODO - }); - - // String loginPageMessage - test('to test the property `loginPageMessage`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_smtp_dto_test.dart b/mobile/openapi/test/system_config_smtp_dto_test.dart deleted file mode 100644 index 92332ef5dc..0000000000 --- a/mobile/openapi/test/system_config_smtp_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigSmtpDto -void main() { - // final instance = SystemConfigSmtpDto(); - - group('test SystemConfigSmtpDto', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // String from - test('to test the property `from`', () async { - // TODO - }); - - // String replyTo - test('to test the property `replyTo`', () async { - // TODO - }); - - // SystemConfigSmtpTransportDto transport - test('to test the property `transport`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_smtp_transport_dto_test.dart b/mobile/openapi/test/system_config_smtp_transport_dto_test.dart deleted file mode 100644 index f1b5db0004..0000000000 --- a/mobile/openapi/test/system_config_smtp_transport_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigSmtpTransportDto -void main() { - // final instance = SystemConfigSmtpTransportDto(); - - group('test SystemConfigSmtpTransportDto', () { - // String host - test('to test the property `host`', () async { - // TODO - }); - - // bool ignoreCert - test('to test the property `ignoreCert`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - // num port - test('to test the property `port`', () async { - // TODO - }); - - // String username - test('to test the property `username`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_storage_template_dto_test.dart b/mobile/openapi/test/system_config_storage_template_dto_test.dart deleted file mode 100644 index aa00b78fe4..0000000000 --- a/mobile/openapi/test/system_config_storage_template_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigStorageTemplateDto -void main() { - // final instance = SystemConfigStorageTemplateDto(); - - group('test SystemConfigStorageTemplateDto', () { - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - // bool hashVerificationEnabled - test('to test the property `hashVerificationEnabled`', () async { - // TODO - }); - - // String template - test('to test the property `template`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_template_storage_option_dto_test.dart b/mobile/openapi/test/system_config_template_storage_option_dto_test.dart deleted file mode 100644 index 6082748336..0000000000 --- a/mobile/openapi/test/system_config_template_storage_option_dto_test.dart +++ /dev/null @@ -1,62 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigTemplateStorageOptionDto -void main() { - // final instance = SystemConfigTemplateStorageOptionDto(); - - group('test SystemConfigTemplateStorageOptionDto', () { - // List dayOptions (default value: const []) - test('to test the property `dayOptions`', () async { - // TODO - }); - - // List hourOptions (default value: const []) - test('to test the property `hourOptions`', () async { - // TODO - }); - - // List minuteOptions (default value: const []) - test('to test the property `minuteOptions`', () async { - // TODO - }); - - // List monthOptions (default value: const []) - test('to test the property `monthOptions`', () async { - // TODO - }); - - // List presetOptions (default value: const []) - test('to test the property `presetOptions`', () async { - // TODO - }); - - // List secondOptions (default value: const []) - test('to test the property `secondOptions`', () async { - // TODO - }); - - // List weekOptions (default value: const []) - test('to test the property `weekOptions`', () async { - // TODO - }); - - // List yearOptions (default value: const []) - test('to test the property `yearOptions`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_theme_dto_test.dart b/mobile/openapi/test/system_config_theme_dto_test.dart deleted file mode 100644 index 98e283559e..0000000000 --- a/mobile/openapi/test/system_config_theme_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigThemeDto -void main() { - // final instance = SystemConfigThemeDto(); - - group('test SystemConfigThemeDto', () { - // String customCss - test('to test the property `customCss`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_trash_dto_test.dart b/mobile/openapi/test/system_config_trash_dto_test.dart deleted file mode 100644 index a1b79f1138..0000000000 --- a/mobile/openapi/test/system_config_trash_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigTrashDto -void main() { - // final instance = SystemConfigTrashDto(); - - group('test SystemConfigTrashDto', () { - // int days - test('to test the property `days`', () async { - // TODO - }); - - // bool enabled - test('to test the property `enabled`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_config_user_dto_test.dart b/mobile/openapi/test/system_config_user_dto_test.dart deleted file mode 100644 index d3c7be050d..0000000000 --- a/mobile/openapi/test/system_config_user_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for SystemConfigUserDto -void main() { - // final instance = SystemConfigUserDto(); - - group('test SystemConfigUserDto', () { - // int deleteDelay - test('to test the property `deleteDelay`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/system_metadata_api_test.dart b/mobile/openapi/test/system_metadata_api_test.dart deleted file mode 100644 index bc1ce6f6f3..0000000000 --- a/mobile/openapi/test/system_metadata_api_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for SystemMetadataApi -void main() { - // final instance = SystemMetadataApi(); - - group('tests for SystemMetadataApi', () { - //Future getAdminOnboarding() async - test('test getAdminOnboarding', () async { - // TODO - }); - - //Future getReverseGeocodingState() async - test('test getReverseGeocodingState', () async { - // TODO - }); - - //Future updateAdminOnboarding(AdminOnboardingUpdateDto adminOnboardingUpdateDto) async - test('test updateAdminOnboarding', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/tag_api_test.dart b/mobile/openapi/test/tag_api_test.dart deleted file mode 100644 index 1b4d797448..0000000000 --- a/mobile/openapi/test/tag_api_test.dart +++ /dev/null @@ -1,61 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for TagApi -void main() { - // final instance = TagApi(); - - group('tests for TagApi', () { - //Future createTag(CreateTagDto createTagDto) async - test('test createTag', () async { - // TODO - }); - - //Future deleteTag(String id) async - test('test deleteTag', () async { - // TODO - }); - - //Future> getAllTags() async - test('test getAllTags', () async { - // TODO - }); - - //Future> getTagAssets(String id) async - test('test getTagAssets', () async { - // TODO - }); - - //Future getTagById(String id) async - test('test getTagById', () async { - // TODO - }); - - //Future> tagAssets(String id, AssetIdsDto assetIdsDto) async - test('test tagAssets', () async { - // TODO - }); - - //Future> untagAssets(String id, AssetIdsDto assetIdsDto) async - test('test untagAssets', () async { - // TODO - }); - - //Future updateTag(String id, UpdateTagDto updateTagDto) async - test('test updateTag', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/tag_response_dto_test.dart b/mobile/openapi/test/tag_response_dto_test.dart deleted file mode 100644 index 88f483caf5..0000000000 --- a/mobile/openapi/test/tag_response_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for TagResponseDto -void main() { - // final instance = TagResponseDto(); - - group('test TagResponseDto', () { - // String id - test('to test the property `id`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // TagTypeEnum type - test('to test the property `type`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/tag_type_enum_test.dart b/mobile/openapi/test/tag_type_enum_test.dart deleted file mode 100644 index 07a0389466..0000000000 --- a/mobile/openapi/test/tag_type_enum_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for TagTypeEnum -void main() { - - group('test TagTypeEnum', () { - - }); - -} diff --git a/mobile/openapi/test/thumbnail_format_test.dart b/mobile/openapi/test/thumbnail_format_test.dart deleted file mode 100644 index 9fb4c53878..0000000000 --- a/mobile/openapi/test/thumbnail_format_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ThumbnailFormat -void main() { - - group('test ThumbnailFormat', () { - - }); - -} diff --git a/mobile/openapi/test/time_bucket_response_dto_test.dart b/mobile/openapi/test/time_bucket_response_dto_test.dart deleted file mode 100644 index 9a09f2017d..0000000000 --- a/mobile/openapi/test/time_bucket_response_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for TimeBucketResponseDto -void main() { - // final instance = TimeBucketResponseDto(); - - group('test TimeBucketResponseDto', () { - // int count - test('to test the property `count`', () async { - // TODO - }); - - // String timeBucket - test('to test the property `timeBucket`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/time_bucket_size_test.dart b/mobile/openapi/test/time_bucket_size_test.dart deleted file mode 100644 index 8f0ca35b99..0000000000 --- a/mobile/openapi/test/time_bucket_size_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for TimeBucketSize -void main() { - - group('test TimeBucketSize', () { - - }); - -} diff --git a/mobile/openapi/test/timeline_api_test.dart b/mobile/openapi/test/timeline_api_test.dart deleted file mode 100644 index ae217b2e40..0000000000 --- a/mobile/openapi/test/timeline_api_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for TimelineApi -void main() { - // final instance = TimelineApi(); - - group('tests for TimelineApi', () { - //Future> getTimeBucket(TimeBucketSize size, String timeBucket, { String albumId, bool isArchived, bool isFavorite, bool isTrashed, String key, AssetOrder order, String personId, String userId, bool withPartners, bool withStacked }) async - test('test getTimeBucket', () async { - // TODO - }); - - //Future> getTimeBuckets(TimeBucketSize size, { String albumId, bool isArchived, bool isFavorite, bool isTrashed, String key, AssetOrder order, String personId, String userId, bool withPartners, bool withStacked }) async - test('test getTimeBuckets', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/tone_mapping_test.dart b/mobile/openapi/test/tone_mapping_test.dart deleted file mode 100644 index 0a719125de..0000000000 --- a/mobile/openapi/test/tone_mapping_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ToneMapping -void main() { - - group('test ToneMapping', () { - - }); - -} diff --git a/mobile/openapi/test/transcode_hw_accel_test.dart b/mobile/openapi/test/transcode_hw_accel_test.dart deleted file mode 100644 index c9887c87d5..0000000000 --- a/mobile/openapi/test/transcode_hw_accel_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for TranscodeHWAccel -void main() { - - group('test TranscodeHWAccel', () { - - }); - -} diff --git a/mobile/openapi/test/transcode_policy_test.dart b/mobile/openapi/test/transcode_policy_test.dart deleted file mode 100644 index 4a27e2a881..0000000000 --- a/mobile/openapi/test/transcode_policy_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for TranscodePolicy -void main() { - - group('test TranscodePolicy', () { - - }); - -} diff --git a/mobile/openapi/test/trash_api_test.dart b/mobile/openapi/test/trash_api_test.dart deleted file mode 100644 index e96c254e4f..0000000000 --- a/mobile/openapi/test/trash_api_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for TrashApi -void main() { - // final instance = TrashApi(); - - group('tests for TrashApi', () { - //Future emptyTrash() async - test('test emptyTrash', () async { - // TODO - }); - - //Future restoreAssets(BulkIdsDto bulkIdsDto) async - test('test restoreAssets', () async { - // TODO - }); - - //Future restoreTrash() async - test('test restoreTrash', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/update_album_dto_test.dart b/mobile/openapi/test/update_album_dto_test.dart deleted file mode 100644 index 7f1591a52c..0000000000 --- a/mobile/openapi/test/update_album_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdateAlbumDto -void main() { - // final instance = UpdateAlbumDto(); - - group('test UpdateAlbumDto', () { - // String albumName - test('to test the property `albumName`', () async { - // TODO - }); - - // String albumThumbnailAssetId - test('to test the property `albumThumbnailAssetId`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // bool isActivityEnabled - test('to test the property `isActivityEnabled`', () async { - // TODO - }); - - // AssetOrder order - test('to test the property `order`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/update_album_user_dto_test.dart b/mobile/openapi/test/update_album_user_dto_test.dart deleted file mode 100644 index a42ca38b2c..0000000000 --- a/mobile/openapi/test/update_album_user_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdateAlbumUserDto -void main() { - // final instance = UpdateAlbumUserDto(); - - group('test UpdateAlbumUserDto', () { - // AlbumUserRole role - test('to test the property `role`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/update_asset_dto_test.dart b/mobile/openapi/test/update_asset_dto_test.dart deleted file mode 100644 index 9d9874beb8..0000000000 --- a/mobile/openapi/test/update_asset_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdateAssetDto -void main() { - // final instance = UpdateAssetDto(); - - group('test UpdateAssetDto', () { - // String dateTimeOriginal - test('to test the property `dateTimeOriginal`', () async { - // TODO - }); - - // String description - test('to test the property `description`', () async { - // TODO - }); - - // bool isArchived - test('to test the property `isArchived`', () async { - // TODO - }); - - // bool isFavorite - test('to test the property `isFavorite`', () async { - // TODO - }); - - // num latitude - test('to test the property `latitude`', () async { - // TODO - }); - - // num longitude - test('to test the property `longitude`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/update_library_dto_test.dart b/mobile/openapi/test/update_library_dto_test.dart deleted file mode 100644 index 222eb333bc..0000000000 --- a/mobile/openapi/test/update_library_dto_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdateLibraryDto -void main() { - // final instance = UpdateLibraryDto(); - - group('test UpdateLibraryDto', () { - // List exclusionPatterns (default value: const []) - test('to test the property `exclusionPatterns`', () async { - // TODO - }); - - // List importPaths (default value: const []) - test('to test the property `importPaths`', () async { - // TODO - }); - - // bool isVisible - test('to test the property `isVisible`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/update_partner_dto_test.dart b/mobile/openapi/test/update_partner_dto_test.dart deleted file mode 100644 index ca569914b7..0000000000 --- a/mobile/openapi/test/update_partner_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdatePartnerDto -void main() { - // final instance = UpdatePartnerDto(); - - group('test UpdatePartnerDto', () { - // bool inTimeline - test('to test the property `inTimeline`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/update_stack_parent_dto_test.dart b/mobile/openapi/test/update_stack_parent_dto_test.dart deleted file mode 100644 index 6af71854ec..0000000000 --- a/mobile/openapi/test/update_stack_parent_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdateStackParentDto -void main() { - // final instance = UpdateStackParentDto(); - - group('test UpdateStackParentDto', () { - // String newParentId - test('to test the property `newParentId`', () async { - // TODO - }); - - // String oldParentId - test('to test the property `oldParentId`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/update_tag_dto_test.dart b/mobile/openapi/test/update_tag_dto_test.dart deleted file mode 100644 index 7c67e55d74..0000000000 --- a/mobile/openapi/test/update_tag_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdateTagDto -void main() { - // final instance = UpdateTagDto(); - - group('test UpdateTagDto', () { - // String name - test('to test the property `name`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/update_user_dto_test.dart b/mobile/openapi/test/update_user_dto_test.dart deleted file mode 100644 index 10c506666d..0000000000 --- a/mobile/openapi/test/update_user_dto_test.dart +++ /dev/null @@ -1,72 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UpdateUserDto -void main() { - // final instance = UpdateUserDto(); - - group('test UpdateUserDto', () { - // UserAvatarColor avatarColor - test('to test the property `avatarColor`', () async { - // TODO - }); - - // String email - test('to test the property `email`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isAdmin - test('to test the property `isAdmin`', () async { - // TODO - }); - - // bool memoriesEnabled - test('to test the property `memoriesEnabled`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String password - test('to test the property `password`', () async { - // TODO - }); - - // int quotaSizeInBytes - test('to test the property `quotaSizeInBytes`', () async { - // TODO - }); - - // bool shouldChangePassword - test('to test the property `shouldChangePassword`', () async { - // TODO - }); - - // String storageLabel - test('to test the property `storageLabel`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/usage_by_user_dto_test.dart b/mobile/openapi/test/usage_by_user_dto_test.dart deleted file mode 100644 index 68a9f20846..0000000000 --- a/mobile/openapi/test/usage_by_user_dto_test.dart +++ /dev/null @@ -1,52 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UsageByUserDto -void main() { - // final instance = UsageByUserDto(); - - group('test UsageByUserDto', () { - // int photos - test('to test the property `photos`', () async { - // TODO - }); - - // int quotaSizeInBytes - test('to test the property `quotaSizeInBytes`', () async { - // TODO - }); - - // int usage - test('to test the property `usage`', () async { - // TODO - }); - - // String userId - test('to test the property `userId`', () async { - // TODO - }); - - // String userName - test('to test the property `userName`', () async { - // TODO - }); - - // int videos - test('to test the property `videos`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/user_api_test.dart b/mobile/openapi/test/user_api_test.dart deleted file mode 100644 index 61df36243d..0000000000 --- a/mobile/openapi/test/user_api_test.dart +++ /dev/null @@ -1,71 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - - -/// tests for UserApi -void main() { - // final instance = UserApi(); - - group('tests for UserApi', () { - //Future createProfileImage(MultipartFile file) async - test('test createProfileImage', () async { - // TODO - }); - - //Future createUser(CreateUserDto createUserDto) async - test('test createUser', () async { - // TODO - }); - - //Future deleteProfileImage() async - test('test deleteProfileImage', () async { - // TODO - }); - - //Future deleteUser(String id, DeleteUserDto deleteUserDto) async - test('test deleteUser', () async { - // TODO - }); - - //Future> getAllUsers(bool isAll) async - test('test getAllUsers', () async { - // TODO - }); - - //Future getMyUserInfo() async - test('test getMyUserInfo', () async { - // TODO - }); - - //Future getProfileImage(String id) async - test('test getProfileImage', () async { - // TODO - }); - - //Future getUserById(String id) async - test('test getUserById', () async { - // TODO - }); - - //Future restoreUser(String id) async - test('test restoreUser', () async { - // TODO - }); - - //Future updateUser(UpdateUserDto updateUserDto) async - test('test updateUser', () async { - // TODO - }); - - }); -} diff --git a/mobile/openapi/test/user_avatar_color_test.dart b/mobile/openapi/test/user_avatar_color_test.dart deleted file mode 100644 index 83480b580f..0000000000 --- a/mobile/openapi/test/user_avatar_color_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UserAvatarColor -void main() { - - group('test UserAvatarColor', () { - - }); - -} diff --git a/mobile/openapi/test/user_dto_test.dart b/mobile/openapi/test/user_dto_test.dart deleted file mode 100644 index 20229ff65b..0000000000 --- a/mobile/openapi/test/user_dto_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UserDto -void main() { - // final instance = UserDto(); - - group('test UserDto', () { - // UserAvatarColor avatarColor - test('to test the property `avatarColor`', () async { - // TODO - }); - - // String email - test('to test the property `email`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String profileImagePath - test('to test the property `profileImagePath`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/user_response_dto_test.dart b/mobile/openapi/test/user_response_dto_test.dart deleted file mode 100644 index 71fa57f488..0000000000 --- a/mobile/openapi/test/user_response_dto_test.dart +++ /dev/null @@ -1,102 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UserResponseDto -void main() { - // final instance = UserResponseDto(); - - group('test UserResponseDto', () { - // UserAvatarColor avatarColor - test('to test the property `avatarColor`', () async { - // TODO - }); - - // DateTime createdAt - test('to test the property `createdAt`', () async { - // TODO - }); - - // DateTime deletedAt - test('to test the property `deletedAt`', () async { - // TODO - }); - - // String email - test('to test the property `email`', () async { - // TODO - }); - - // String id - test('to test the property `id`', () async { - // TODO - }); - - // bool isAdmin - test('to test the property `isAdmin`', () async { - // TODO - }); - - // bool memoriesEnabled - test('to test the property `memoriesEnabled`', () async { - // TODO - }); - - // String name - test('to test the property `name`', () async { - // TODO - }); - - // String oauthId - test('to test the property `oauthId`', () async { - // TODO - }); - - // String profileImagePath - test('to test the property `profileImagePath`', () async { - // TODO - }); - - // int quotaSizeInBytes - test('to test the property `quotaSizeInBytes`', () async { - // TODO - }); - - // int quotaUsageInBytes - test('to test the property `quotaUsageInBytes`', () async { - // TODO - }); - - // bool shouldChangePassword - test('to test the property `shouldChangePassword`', () async { - // TODO - }); - - // UserStatus status - test('to test the property `status`', () async { - // TODO - }); - - // String storageLabel - test('to test the property `storageLabel`', () async { - // TODO - }); - - // DateTime updatedAt - test('to test the property `updatedAt`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/user_status_test.dart b/mobile/openapi/test/user_status_test.dart deleted file mode 100644 index 88abba0459..0000000000 --- a/mobile/openapi/test/user_status_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for UserStatus -void main() { - - group('test UserStatus', () { - - }); - -} diff --git a/mobile/openapi/test/validate_access_token_response_dto_test.dart b/mobile/openapi/test/validate_access_token_response_dto_test.dart deleted file mode 100644 index fff824700c..0000000000 --- a/mobile/openapi/test/validate_access_token_response_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ValidateAccessTokenResponseDto -void main() { - // final instance = ValidateAccessTokenResponseDto(); - - group('test ValidateAccessTokenResponseDto', () { - // bool authStatus - test('to test the property `authStatus`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/validate_library_dto_test.dart b/mobile/openapi/test/validate_library_dto_test.dart deleted file mode 100644 index 8d4922ee4a..0000000000 --- a/mobile/openapi/test/validate_library_dto_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ValidateLibraryDto -void main() { - // final instance = ValidateLibraryDto(); - - group('test ValidateLibraryDto', () { - // List exclusionPatterns (default value: const []) - test('to test the property `exclusionPatterns`', () async { - // TODO - }); - - // List importPaths (default value: const []) - test('to test the property `importPaths`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/validate_library_import_path_response_dto_test.dart b/mobile/openapi/test/validate_library_import_path_response_dto_test.dart deleted file mode 100644 index a118698a13..0000000000 --- a/mobile/openapi/test/validate_library_import_path_response_dto_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ValidateLibraryImportPathResponseDto -void main() { - // final instance = ValidateLibraryImportPathResponseDto(); - - group('test ValidateLibraryImportPathResponseDto', () { - // String importPath - test('to test the property `importPath`', () async { - // TODO - }); - - // bool isValid (default value: false) - test('to test the property `isValid`', () async { - // TODO - }); - - // String message - test('to test the property `message`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/validate_library_response_dto_test.dart b/mobile/openapi/test/validate_library_response_dto_test.dart deleted file mode 100644 index 6750809066..0000000000 --- a/mobile/openapi/test/validate_library_response_dto_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for ValidateLibraryResponseDto -void main() { - // final instance = ValidateLibraryResponseDto(); - - group('test ValidateLibraryResponseDto', () { - // List importPaths (default value: const []) - test('to test the property `importPaths`', () async { - // TODO - }); - - - }); - -} diff --git a/mobile/openapi/test/video_codec_test.dart b/mobile/openapi/test/video_codec_test.dart deleted file mode 100644 index 8c1e4a17ff..0000000000 --- a/mobile/openapi/test/video_codec_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// -// AUTO-GENERATED FILE, DO NOT MODIFY! -// -// @dart=2.12 - -// 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 - -import 'package:openapi/api.dart'; -import 'package:test/test.dart'; - -// tests for VideoCodec -void main() { - - group('test VideoCodec', () { - - }); - -} diff --git a/mobile/pubspec.lock b/mobile/pubspec.lock index 54648fd20b..b1c1db2e1e 100644 --- a/mobile/pubspec.lock +++ b/mobile/pubspec.lock @@ -61,18 +61,18 @@ packages: dependency: "direct main" description: name: auto_route - sha256: "82f8df1d177416bc6b7a449127d0270ff1f0f633a91f2ceb7a85d4f07c3affa1" + sha256: "6cad3f408863ffff2b5757967c802b18415dac4acb1b40c5cdd45d0a26e5080f" url: "https://pub.dev" source: hosted - version: "7.8.4" + version: "8.1.3" auto_route_generator: dependency: "direct dev" description: name: auto_route_generator - sha256: "11067a3bcd643812518fe26c0c9ec073990286cabfd9d74b6da9ef9b913c4d22" + sha256: ba28133d3a3bf0a66772bcc98dade5843753cd9f1a8fb4802b842895515b67d3 url: "https://pub.dev" source: hosted - version: "7.3.2" + version: "8.0.0" boolean_selector: dependency: transitive description: @@ -381,10 +381,10 @@ packages: dependency: "direct main" description: name: easy_localization - sha256: de63e3b422adfc97f256cbb3f8cf12739b6a4993d390f3cadb3f51837afaefe5 + sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.7" easy_logger: dependency: transitive description: @@ -503,10 +503,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "4.0.0" flutter_local_notifications: dependency: "direct main" description: @@ -699,10 +699,10 @@ packages: dependency: transitive description: name: hotreloader - sha256: "94ee21a60ea2836500799f3af035dc3212b1562027f1e0031c14e087f0231449" + sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "4.2.0" html: dependency: transitive description: @@ -816,10 +816,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -872,34 +872,34 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.0.0" logging: dependency: "direct main" description: @@ -1503,10 +1503,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.0" thumbhash: dependency: "direct main" description: @@ -1703,10 +1703,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.1" wakelock_plus: dependency: "direct main" description: @@ -1805,4 +1805,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.16.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 847256dbbb..ed6afd7ff7 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -2,7 +2,7 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone publish_to: 'none' -version: 1.103.1+137 +version: 1.105.1+140 environment: sdk: '>=3.3.0 <4.0.0' @@ -21,8 +21,8 @@ dependencies: riverpod_annotation: ^2.3.3 cached_network_image: ^3.3.1 flutter_cache_manager: ^3.3.1 - intl: ^0.18.0 - auto_route: ^7.8.4 + intl: ^0.19.0 + auto_route: ^8.0.2 fluttertoast: ^8.2.4 video_player: ^2.8.2 chewie: ^1.7.4 @@ -86,9 +86,9 @@ dependency_overrides: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^3.0.1 + flutter_lints: ^4.0.0 build_runner: ^2.4.8 - auto_route_generator: ^7.3.2 + auto_route_generator: ^8.0.0 flutter_launcher_icons: ^0.13.1 flutter_native_splash: ^2.3.9 isar_generator: ^3.1.0+1 diff --git a/mobile/test/modules/activity/activities_page_test.dart b/mobile/test/modules/activity/activities_page_test.dart index 9f410b2e26..a5dda5dc44 100644 --- a/mobile/test/modules/activity/activities_page_test.dart +++ b/mobile/test/modules/activity/activities_page_test.dart @@ -1,5 +1,6 @@ @Skip('currently failing due to mock HTTP client to download ISAR binaries') @Tags(['widget']) +library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/mobile/test/modules/activity/activity_text_field_test.dart b/mobile/test/modules/activity/activity_text_field_test.dart index 84c98fd3ff..caa742873a 100644 --- a/mobile/test/modules/activity/activity_text_field_test.dart +++ b/mobile/test/modules/activity/activity_text_field_test.dart @@ -1,5 +1,6 @@ @Skip('currently failing due to mock HTTP client to download ISAR binaries') @Tags(['widget']) +library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/mobile/test/modules/activity/activity_tile_test.dart b/mobile/test/modules/activity/activity_tile_test.dart index d6fd0d5efd..f64eea851a 100644 --- a/mobile/test/modules/activity/activity_tile_test.dart +++ b/mobile/test/modules/activity/activity_tile_test.dart @@ -1,5 +1,6 @@ @Skip('currently failing due to mock HTTP client to download ISAR binaries') @Tags(['widget']) +library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/mobile/test/modules/activity/dismissible_activity_test.dart b/mobile/test/modules/activity/dismissible_activity_test.dart index fabdace13f..494a89db83 100644 --- a/mobile/test/modules/activity/dismissible_activity_test.dart +++ b/mobile/test/modules/activity/dismissible_activity_test.dart @@ -1,4 +1,5 @@ @Tags(['widget']) +library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/mobile/test/modules/map/map_theme_override_test.dart b/mobile/test/modules/map/map_theme_override_test.dart index 831b46c343..f399625ac2 100644 --- a/mobile/test/modules/map/map_theme_override_test.dart +++ b/mobile/test/modules/map/map_theme_override_test.dart @@ -1,4 +1,5 @@ @Tags(['widget']) +library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/mobile/test/modules/shared/sync_service_test.dart b/mobile/test/modules/shared/sync_service_test.dart index 735cc57a1b..24f0c443ba 100644 --- a/mobile/test/modules/shared/sync_service_test.dart +++ b/mobile/test/modules/shared/sync_service_test.dart @@ -75,8 +75,12 @@ void main() { makeAsset(checksum: "c", remoteId: "1-1"), ]; expect(db.assets.countSync(), 5); - final bool c1 = - await s.syncRemoteAssetsToDb(owner, _failDiff, (u) => remoteAssets); + final bool c1 = await s.syncRemoteAssetsToDb( + users: [owner], + getChangedAssets: _failDiff, + loadAssets: (u, d) => remoteAssets, + refreshUsers: () => [owner], + ); expect(c1, isFalse); expect(db.assets.countSync(), 5); }); @@ -92,8 +96,12 @@ void main() { makeAsset(checksum: "g", remoteId: "3-1"), ]; expect(db.assets.countSync(), 5); - final bool c1 = - await s.syncRemoteAssetsToDb(owner, _failDiff, (u) => remoteAssets); + final bool c1 = await s.syncRemoteAssetsToDb( + users: [owner], + getChangedAssets: _failDiff, + loadAssets: (u, d) => remoteAssets, + refreshUsers: () => [owner], + ); expect(c1, isTrue); expect(db.assets.countSync(), 7); }); @@ -109,23 +117,39 @@ void main() { makeAsset(checksum: "j", remoteId: "2-1d"), ]; expect(db.assets.countSync(), 5); - final bool c1 = - await s.syncRemoteAssetsToDb(owner, _failDiff, (u) => remoteAssets); + final bool c1 = await s.syncRemoteAssetsToDb( + users: [owner], + getChangedAssets: _failDiff, + loadAssets: (u, d) => remoteAssets, + refreshUsers: () => [owner], + ); expect(c1, isTrue); expect(db.assets.countSync(), 8); - final bool c2 = - await s.syncRemoteAssetsToDb(owner, _failDiff, (u) => remoteAssets); + final bool c2 = await s.syncRemoteAssetsToDb( + users: [owner], + getChangedAssets: _failDiff, + loadAssets: (u, d) => remoteAssets, + refreshUsers: () => [owner], + ); expect(c2, isFalse); expect(db.assets.countSync(), 8); remoteAssets.removeAt(4); - final bool c3 = - await s.syncRemoteAssetsToDb(owner, _failDiff, (u) => remoteAssets); + final bool c3 = await s.syncRemoteAssetsToDb( + users: [owner], + getChangedAssets: _failDiff, + loadAssets: (u, d) => remoteAssets, + refreshUsers: () => [owner], + ); expect(c3, isTrue); expect(db.assets.countSync(), 7); remoteAssets.add(makeAsset(checksum: "k", remoteId: "2-1e")); remoteAssets.add(makeAsset(checksum: "l", remoteId: "2-2")); - final bool c4 = - await s.syncRemoteAssetsToDb(owner, _failDiff, (u) => remoteAssets); + final bool c4 = await s.syncRemoteAssetsToDb( + users: [owner], + getChangedAssets: _failDiff, + loadAssets: (u, d) => remoteAssets, + refreshUsers: () => [owner], + ); expect(c4, isTrue); expect(db.assets.countSync(), 9); }); @@ -140,9 +164,10 @@ void main() { toUpsert[0].isFavorite = true; final List toDelete = ["2-1", "1-1"]; final bool c = await s.syncRemoteAssetsToDb( - owner, - (user, since) async => (toUpsert, toDelete), - (user) => throw Exception(), + users: [owner], + getChangedAssets: (user, since) async => (toUpsert, toDelete), + loadAssets: (user, date) => throw Exception(), + refreshUsers: () => throw Exception(), ); expect(c, isTrue); expect(db.assets.countSync(), 6); @@ -150,5 +175,8 @@ void main() { }); } -Future<(List?, List?)> _failDiff(User user, DateTime time) => +Future<(List?, List?)> _failDiff( + List user, + DateTime time, +) => Future.value((null, null)); diff --git a/mobile/test/widget_tester_extensions.dart b/mobile/test/widget_tester_extensions.dart index c054a32501..7d5b266224 100644 --- a/mobile/test/widget_tester_extensions.dart +++ b/mobile/test/widget_tester_extensions.dart @@ -23,8 +23,8 @@ extension PumpConsumerWidget on WidgetTester { home: Material(child: widget), ), ), - duration, - phase, + duration: duration, + phase: phase, ); } } diff --git a/open-api/bin/generate-open-api.sh b/open-api/bin/generate-open-api.sh index c972a4c806..a00d57d0ae 100755 --- a/open-api/bin/generate-open-api.sh +++ b/open-api/bin/generate-open-api.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -OPENAPI_GENERATOR_VERSION=v7.2.0 +OPENAPI_GENERATOR_VERSION=v7.5.0 # usage: ./bin/generate-open-api.sh @@ -24,7 +24,8 @@ function typescript { npm --prefix typescript-sdk ci && npm --prefix typescript-sdk run build } -node ./bin/sync-spec-version.js +# requires server to be built +npm run sync:open-api --prefix=../server if [[ $1 == 'dart' ]]; then dart diff --git a/open-api/bin/sync-spec-version.js b/open-api/bin/sync-spec-version.js deleted file mode 100644 index 98c52413e6..0000000000 --- a/open-api/bin/sync-spec-version.js +++ /dev/null @@ -1,9 +0,0 @@ -const spec = require('../immich-openapi-specs.json'); -const pkg = require('../../server/package.json'); -const path = require('path'); -const fs = require('fs'); -spec.info.version = pkg.version; -fs.writeFileSync( - path.join(__dirname, '../immich-openapi-specs.json'), - JSON.stringify(spec, null, 2) -); diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 36602cbe2d..cefcff2d82 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "paths": { - "/activity": { + "/activities": { "get": { "operationId": "getActivities", "parameters": [ @@ -75,9 +75,7 @@ "api_key": [] } ], - "tags": [ - "Activity" - ] + "tags": ["Activity"] }, "post": { "operationId": "createActivity", @@ -115,12 +113,10 @@ "api_key": [] } ], - "tags": [ - "Activity" - ] + "tags": ["Activity"] } }, - "/activity/statistics": { + "/activities/statistics": { "get": { "operationId": "getActivityStatistics", "parameters": [ @@ -166,12 +162,10 @@ "api_key": [] } ], - "tags": [ - "Activity" - ] + "tags": ["Activity"] } }, - "/activity/{id}": { + "/activities/{id}": { "delete": { "operationId": "deleteActivity", "parameters": [ @@ -201,12 +195,10 @@ "api_key": [] } ], - "tags": [ - "Activity" - ] + "tags": ["Activity"] } }, - "/album": { + "/albums": { "get": { "operationId": "getAllAlbums", "parameters": [ @@ -255,9 +247,7 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] }, "post": { "operationId": "createAlbum", @@ -295,12 +285,10 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] } }, - "/album/count": { + "/albums/count": { "get": { "operationId": "getAlbumCount", "parameters": [], @@ -327,12 +315,10 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] } }, - "/album/{id}": { + "/albums/{id}": { "delete": { "operationId": "deleteAlbum", "parameters": [ @@ -362,9 +348,7 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] }, "get": { "operationId": "getAlbumInfo", @@ -418,9 +402,7 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] }, "patch": { "operationId": "updateAlbumInfo", @@ -468,12 +450,10 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] } }, - "/album/{id}/assets": { + "/albums/{id}/assets": { "delete": { "operationId": "removeAssetFromAlbum", "parameters": [ @@ -523,9 +503,7 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] }, "put": { "operationId": "addAssetsToAlbum", @@ -584,12 +562,10 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] } }, - "/album/{id}/user/{userId}": { + "/albums/{id}/user/{userId}": { "delete": { "operationId": "removeUserFromAlbum", "parameters": [ @@ -627,9 +603,7 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] }, "put": { "operationId": "updateAlbumUser", @@ -678,12 +652,10 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] } }, - "/album/{id}/users": { + "/albums/{id}/users": { "put": { "operationId": "addUsersToAlbum", "parameters": [ @@ -730,12 +702,10 @@ "api_key": [] } ], - "tags": [ - "Album" - ] + "tags": ["Album"] } }, - "/api-key": { + "/api-keys": { "get": { "operationId": "getApiKeys", "parameters": [], @@ -765,9 +735,7 @@ "api_key": [] } ], - "tags": [ - "API Key" - ] + "tags": ["API Key"] }, "post": { "operationId": "createApiKey", @@ -805,12 +773,10 @@ "api_key": [] } ], - "tags": [ - "API Key" - ] + "tags": ["API Key"] } }, - "/api-key/{id}": { + "/api-keys/{id}": { "delete": { "operationId": "deleteApiKey", "parameters": [ @@ -840,9 +806,7 @@ "api_key": [] } ], - "tags": [ - "API Key" - ] + "tags": ["API Key"] }, "get": { "operationId": "getApiKey", @@ -880,9 +844,7 @@ "api_key": [] } ], - "tags": [ - "API Key" - ] + "tags": ["API Key"] }, "put": { "operationId": "updateApiKey", @@ -930,9 +892,7 @@ "api_key": [] } ], - "tags": [ - "API Key" - ] + "tags": ["API Key"] } }, "/asset": { @@ -965,112 +925,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] - }, - "get": { - "description": "Get all AssetEntity belong to the user", - "operationId": "getAllAssets", - "parameters": [ - { - "name": "if-none-match", - "in": "header", - "description": "ETag of data already cached on the client", - "required": false, - "schema": { - "type": "string" - } - }, - { - "name": "isArchived", - "required": false, - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "isFavorite", - "required": false, - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "skip", - "required": false, - "in": "query", - "schema": { - "type": "integer" - } - }, - { - "name": "take", - "required": false, - "in": "query", - "schema": { - "type": "integer" - } - }, - { - "name": "updatedAfter", - "required": false, - "in": "query", - "schema": { - "format": "date-time", - "type": "string" - } - }, - { - "name": "updatedBefore", - "required": false, - "in": "query", - "schema": { - "format": "date-time", - "type": "string" - } - }, - { - "name": "userId", - "required": false, - "in": "query", - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/AssetResponseDto" - }, - "type": "array" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] }, "put": { "operationId": "updateAssets", @@ -1101,9 +956,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/bulk-upload-check": { @@ -1144,9 +997,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/device/{deviceId}": { @@ -1189,9 +1040,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/exist": { @@ -1232,9 +1081,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/file/{id}": { @@ -1301,9 +1148,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/jobs": { @@ -1336,9 +1181,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/map-marker": { @@ -1386,6 +1229,14 @@ "schema": { "type": "boolean" } + }, + { + "name": "withSharedAlbums", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { @@ -1414,9 +1265,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/memory-lane": { @@ -1470,9 +1319,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/random": { @@ -1515,9 +1362,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/stack/parent": { @@ -1550,9 +1395,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/statistics": { @@ -1607,9 +1450,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/thumbnail/{id}": { @@ -1666,9 +1507,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/upload": { @@ -1727,9 +1566,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] } }, "/asset/{id}": { @@ -1777,9 +1614,7 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] }, "put": { "operationId": "updateAsset", @@ -1827,9 +1662,69 @@ "api_key": [] } ], - "tags": [ - "Asset" - ] + "tags": ["Asset"] + } + }, + "/asset/{id}/file": { + "put": { + "description": "Replace the asset with new file, without changing its id", + "operationId": "replaceAsset", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "type": "string" + } + }, + { + "name": "key", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/AssetMediaReplaceDto" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetMediaResponseDto" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": ["Asset"], + "x-immich-lifecycle": { + "addedAt": "v1.106.0" + } } }, "/audit/deletes": { @@ -1886,9 +1781,7 @@ "api_key": [] } ], - "tags": [ - "Audit" - ] + "tags": ["Audit"] } }, "/auth/admin-sign-up": { @@ -1917,9 +1810,7 @@ "description": "" } }, - "tags": [ - "Authentication" - ] + "tags": ["Authentication"] } }, "/auth/change-password": { @@ -1959,9 +1850,7 @@ "api_key": [] } ], - "tags": [ - "Authentication" - ] + "tags": ["Authentication"] } }, "/auth/login": { @@ -1990,9 +1879,7 @@ "description": "" } }, - "tags": [ - "Authentication" - ] + "tags": ["Authentication"] } }, "/auth/logout": { @@ -2022,9 +1909,7 @@ "api_key": [] } ], - "tags": [ - "Authentication" - ] + "tags": ["Authentication"] } }, "/auth/validateToken": { @@ -2054,9 +1939,7 @@ "api_key": [] } ], - "tags": [ - "Authentication" - ] + "tags": ["Authentication"] } }, "/download/archive": { @@ -2106,9 +1989,7 @@ "api_key": [] } ], - "tags": [ - "Download" - ] + "tags": ["Download"] } }, "/download/asset/{id}": { @@ -2157,9 +2038,7 @@ "api_key": [] } ], - "tags": [ - "Download" - ] + "tags": ["Download"] } }, "/download/info": { @@ -2208,12 +2087,43 @@ "api_key": [] } ], - "tags": [ - "Download" - ] + "tags": ["Download"] } }, - "/face": { + "/duplicates": { + "get": { + "operationId": "getAssetDuplicates", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/DuplicateResponseDto" + }, + "type": "array" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": ["Duplicate"] + } + }, + "/faces": { "get": { "operationId": "getFaces", "parameters": [ @@ -2253,52 +2163,10 @@ "api_key": [] } ], - "tags": [ - "Face" - ] + "tags": ["Face"] } }, - "/face/{id}": { - "delete": { - "operationId": "unassignFace", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AssetFaceResponseDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "Face" - ] - }, + "/faces/{id}": { "put": { "operationId": "reassignFacesById", "parameters": [ @@ -2345,9 +2213,7 @@ "api_key": [] } ], - "tags": [ - "Face" - ] + "tags": ["Face"] } }, "/jobs": { @@ -2377,9 +2243,7 @@ "api_key": [] } ], - "tags": [ - "Job" - ] + "tags": ["Job"] } }, "/jobs/{id}": { @@ -2428,24 +2292,13 @@ "api_key": [] } ], - "tags": [ - "Job" - ] + "tags": ["Job"] } }, - "/library": { + "/libraries": { "get": { "operationId": "getAllLibraries", - "parameters": [ - { - "name": "type", - "required": false, - "in": "query", - "schema": { - "$ref": "#/components/schemas/LibraryType" - } - } - ], + "parameters": [], "responses": { "200": { "content": { @@ -2472,9 +2325,7 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] }, "post": { "operationId": "createLibrary", @@ -2512,12 +2363,10 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] } }, - "/library/{id}": { + "/libraries/{id}": { "delete": { "operationId": "deleteLibrary", "parameters": [ @@ -2547,9 +2396,7 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] }, "get": { "operationId": "getLibrary", @@ -2587,9 +2434,7 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] }, "put": { "operationId": "updateLibrary", @@ -2637,12 +2482,10 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] } }, - "/library/{id}/removeOffline": { + "/libraries/{id}/removeOffline": { "post": { "operationId": "removeOfflineFiles", "parameters": [ @@ -2672,12 +2515,10 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] } }, - "/library/{id}/scan": { + "/libraries/{id}/scan": { "post": { "operationId": "scanLibrary", "parameters": [ @@ -2717,12 +2558,10 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] } }, - "/library/{id}/statistics": { + "/libraries/{id}/statistics": { "get": { "operationId": "getLibraryStatistics", "parameters": [ @@ -2759,12 +2598,10 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] } }, - "/library/{id}/validate": { + "/libraries/{id}/validate": { "post": { "operationId": "validate", "parameters": [ @@ -2811,9 +2648,7 @@ "api_key": [] } ], - "tags": [ - "Library" - ] + "tags": ["Library"] } }, "/memories": { @@ -2846,9 +2681,7 @@ "api_key": [] } ], - "tags": [ - "Memory" - ] + "tags": ["Memory"] }, "post": { "operationId": "createMemory", @@ -2886,9 +2719,7 @@ "api_key": [] } ], - "tags": [ - "Memory" - ] + "tags": ["Memory"] } }, "/memories/{id}": { @@ -2921,9 +2752,7 @@ "api_key": [] } ], - "tags": [ - "Memory" - ] + "tags": ["Memory"] }, "get": { "operationId": "getMemory", @@ -2961,9 +2790,7 @@ "api_key": [] } ], - "tags": [ - "Memory" - ] + "tags": ["Memory"] }, "put": { "operationId": "updateMemory", @@ -3011,9 +2838,7 @@ "api_key": [] } ], - "tags": [ - "Memory" - ] + "tags": ["Memory"] } }, "/memories/{id}/assets": { @@ -3066,9 +2891,7 @@ "api_key": [] } ], - "tags": [ - "Memory" - ] + "tags": ["Memory"] }, "put": { "operationId": "addMemoryAssets", @@ -3119,9 +2942,7 @@ "api_key": [] } ], - "tags": [ - "Memory" - ] + "tags": ["Memory"] } }, "/oauth/authorize": { @@ -3150,9 +2971,7 @@ "description": "" } }, - "tags": [ - "OAuth" - ] + "tags": ["OAuth"] } }, "/oauth/callback": { @@ -3181,9 +3000,7 @@ "description": "" } }, - "tags": [ - "OAuth" - ] + "tags": ["OAuth"] } }, "/oauth/link": { @@ -3223,9 +3040,7 @@ "api_key": [] } ], - "tags": [ - "OAuth" - ] + "tags": ["OAuth"] } }, "/oauth/mobile-redirect": { @@ -3237,9 +3052,7 @@ "description": "" } }, - "tags": [ - "OAuth" - ] + "tags": ["OAuth"] } }, "/oauth/unlink": { @@ -3269,12 +3082,10 @@ "api_key": [] } ], - "tags": [ - "OAuth" - ] + "tags": ["OAuth"] } }, - "/partner": { + "/partners": { "get": { "operationId": "getPartners", "parameters": [ @@ -3283,10 +3094,7 @@ "required": true, "in": "query", "schema": { - "enum": [ - "shared-by", - "shared-with" - ], + "enum": ["shared-by", "shared-with"], "type": "string" } } @@ -3317,12 +3125,10 @@ "api_key": [] } ], - "tags": [ - "Partner" - ] + "tags": ["Partner"] } }, - "/partner/{id}": { + "/partners/{id}": { "delete": { "operationId": "removePartner", "parameters": [ @@ -3352,9 +3158,7 @@ "api_key": [] } ], - "tags": [ - "Partner" - ] + "tags": ["Partner"] }, "post": { "operationId": "createPartner", @@ -3392,9 +3196,7 @@ "api_key": [] } ], - "tags": [ - "Partner" - ] + "tags": ["Partner"] }, "put": { "operationId": "updatePartner", @@ -3442,44 +3244,10 @@ "api_key": [] } ], - "tags": [ - "Partner" - ] + "tags": ["Partner"] } }, - "/person": { - "delete": { - "operationId": "unassignFaces", - "parameters": [], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AssetFaceUpdateDto" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/BulkIdResponseDto" - }, - "type": "array" - } - } - }, - "description": "" - } - }, - "tags": [ - "Person" - ] - }, + "/people": { "get": { "operationId": "getAllPeople", "parameters": [ @@ -3515,9 +3283,7 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] }, "post": { "operationId": "createPerson", @@ -3555,9 +3321,7 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] }, "put": { "operationId": "updatePeople", @@ -3598,12 +3362,10 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] } }, - "/person/{id}": { + "/people/{id}": { "get": { "operationId": "getPerson", "parameters": [ @@ -3640,9 +3402,7 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] }, "put": { "operationId": "updatePerson", @@ -3690,12 +3450,10 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] } }, - "/person/{id}/assets": { + "/people/{id}/assets": { "get": { "operationId": "getPersonAssets", "parameters": [ @@ -3735,12 +3493,10 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] } }, - "/person/{id}/merge": { + "/people/{id}/merge": { "post": { "operationId": "mergePerson", "parameters": [ @@ -3790,12 +3546,10 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] } }, - "/person/{id}/reassign": { + "/people/{id}/reassign": { "put": { "operationId": "reassignFaces", "parameters": [ @@ -3845,12 +3599,10 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] } }, - "/person/{id}/statistics": { + "/people/{id}/statistics": { "get": { "operationId": "getPersonStatistics", "parameters": [ @@ -3887,12 +3639,10 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] } }, - "/person/{id}/thumbnail": { + "/people/{id}/thumbnail": { "get": { "operationId": "getPersonThumbnail", "parameters": [ @@ -3930,12 +3680,10 @@ "api_key": [] } ], - "tags": [ - "Person" - ] + "tags": ["Person"] } }, - "/report": { + "/reports": { "get": { "operationId": "getAuditFiles", "parameters": [], @@ -3962,12 +3710,10 @@ "api_key": [] } ], - "tags": [ - "File Report" - ] + "tags": ["File Report"] } }, - "/report/checksum": { + "/reports/checksum": { "post": { "operationId": "getFileChecksums", "parameters": [], @@ -4007,12 +3753,10 @@ "api_key": [] } ], - "tags": [ - "File Report" - ] + "tags": ["File Report"] } }, - "/report/fix": { + "/reports/fix": { "post": { "operationId": "fixAuditFiles", "parameters": [], @@ -4042,9 +3786,7 @@ "api_key": [] } ], - "tags": [ - "File Report" - ] + "tags": ["File Report"] } }, "/search/cities": { @@ -4077,9 +3819,7 @@ "api_key": [] } ], - "tags": [ - "Search" - ] + "tags": ["Search"] } }, "/search/explore": { @@ -4112,9 +3852,7 @@ "api_key": [] } ], - "tags": [ - "Search" - ] + "tags": ["Search"] } }, "/search/metadata": { @@ -4154,9 +3892,7 @@ "api_key": [] } ], - "tags": [ - "Search" - ] + "tags": ["Search"] } }, "/search/person": { @@ -4206,9 +3942,7 @@ "api_key": [] } ], - "tags": [ - "Search" - ] + "tags": ["Search"] } }, "/search/places": { @@ -4250,9 +3984,7 @@ "api_key": [] } ], - "tags": [ - "Search" - ] + "tags": ["Search"] } }, "/search/smart": { @@ -4292,9 +4024,7 @@ "api_key": [] } ], - "tags": [ - "Search" - ] + "tags": ["Search"] } }, "/search/suggestions": { @@ -4368,41 +4098,7 @@ "api_key": [] } ], - "tags": [ - "Search" - ] - } - }, - "/server-info": { - "get": { - "operationId": "getServerInfo", - "parameters": [], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerInfoResponseDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "Server Info" - ] + "tags": ["Search"] } }, "/server-info/config": { @@ -4421,9 +4117,7 @@ "description": "" } }, - "tags": [ - "Server Info" - ] + "tags": ["Server Info"] } }, "/server-info/features": { @@ -4442,9 +4136,7 @@ "description": "" } }, - "tags": [ - "Server Info" - ] + "tags": ["Server Info"] } }, "/server-info/media-types": { @@ -4463,9 +4155,7 @@ "description": "" } }, - "tags": [ - "Server Info" - ] + "tags": ["Server Info"] } }, "/server-info/ping": { @@ -4484,9 +4174,7 @@ "description": "" } }, - "tags": [ - "Server Info" - ] + "tags": ["Server Info"] } }, "/server-info/statistics": { @@ -4516,9 +4204,37 @@ "api_key": [] } ], - "tags": [ - "Server Info" - ] + "tags": ["Server Info"] + } + }, + "/server-info/storage": { + "get": { + "operationId": "getStorage", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerStorageResponseDto" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": ["Server Info"] } }, "/server-info/theme": { @@ -4537,9 +4253,7 @@ "description": "" } }, - "tags": [ - "Server Info" - ] + "tags": ["Server Info"] } }, "/server-info/version": { @@ -4558,9 +4272,7 @@ "description": "" } }, - "tags": [ - "Server Info" - ] + "tags": ["Server Info"] } }, "/sessions": { @@ -4583,9 +4295,7 @@ "api_key": [] } ], - "tags": [ - "Sessions" - ] + "tags": ["Sessions"] }, "get": { "operationId": "getSessions", @@ -4616,9 +4326,7 @@ "api_key": [] } ], - "tags": [ - "Sessions" - ] + "tags": ["Sessions"] } }, "/sessions/{id}": { @@ -4651,12 +4359,10 @@ "api_key": [] } ], - "tags": [ - "Sessions" - ] + "tags": ["Sessions"] } }, - "/shared-link": { + "/shared-links": { "get": { "operationId": "getAllSharedLinks", "parameters": [], @@ -4686,9 +4392,7 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] }, "post": { "operationId": "createSharedLink", @@ -4726,12 +4430,10 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] } }, - "/shared-link/me": { + "/shared-links/me": { "get": { "operationId": "getMySharedLink", "parameters": [ @@ -4784,12 +4486,10 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] } }, - "/shared-link/{id}": { + "/shared-links/{id}": { "delete": { "operationId": "removeSharedLink", "parameters": [ @@ -4819,9 +4519,7 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] }, "get": { "operationId": "getSharedLinkById", @@ -4859,9 +4557,7 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] }, "patch": { "operationId": "updateSharedLink", @@ -4909,12 +4605,10 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] } }, - "/shared-link/{id}/assets": { + "/shared-links/{id}/assets": { "delete": { "operationId": "removeSharedLinkAssets", "parameters": [ @@ -4972,9 +4666,7 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] }, "put": { "operationId": "addSharedLinkAssets", @@ -5033,9 +4725,7 @@ "api_key": [] } ], - "tags": [ - "Shared Link" - ] + "tags": ["Shared Link"] } }, "/sync/delta-sync": { @@ -5075,9 +4765,7 @@ "api_key": [] } ], - "tags": [ - "Sync" - ] + "tags": ["Sync"] } }, "/sync/full-sync": { @@ -5120,9 +4808,7 @@ "api_key": [] } ], - "tags": [ - "Sync" - ] + "tags": ["Sync"] } }, "/system-config": { @@ -5152,9 +4838,7 @@ "api_key": [] } ], - "tags": [ - "System Config" - ] + "tags": ["System Config"] }, "put": { "operationId": "updateConfig", @@ -5192,9 +4876,7 @@ "api_key": [] } ], - "tags": [ - "System Config" - ] + "tags": ["System Config"] } }, "/system-config/defaults": { @@ -5224,9 +4906,7 @@ "api_key": [] } ], - "tags": [ - "System Config" - ] + "tags": ["System Config"] } }, "/system-config/map/style.json": { @@ -5273,9 +4953,7 @@ "api_key": [] } ], - "tags": [ - "System Config" - ] + "tags": ["System Config"] } }, "/system-config/storage-template-options": { @@ -5305,9 +4983,7 @@ "api_key": [] } ], - "tags": [ - "System Config" - ] + "tags": ["System Config"] } }, "/system-metadata/admin-onboarding": { @@ -5337,9 +5013,7 @@ "api_key": [] } ], - "tags": [ - "System Metadata" - ] + "tags": ["System Metadata"] }, "post": { "operationId": "updateAdminOnboarding", @@ -5370,9 +5044,7 @@ "api_key": [] } ], - "tags": [ - "System Metadata" - ] + "tags": ["System Metadata"] } }, "/system-metadata/reverse-geocoding-state": { @@ -5402,12 +5074,10 @@ "api_key": [] } ], - "tags": [ - "System Metadata" - ] + "tags": ["System Metadata"] } }, - "/tag": { + "/tags": { "get": { "operationId": "getAllTags", "parameters": [], @@ -5437,9 +5107,7 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] }, "post": { "operationId": "createTag", @@ -5477,12 +5145,10 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] } }, - "/tag/{id}": { + "/tags/{id}": { "delete": { "operationId": "deleteTag", "parameters": [ @@ -5512,9 +5178,7 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] }, "get": { "operationId": "getTagById", @@ -5552,9 +5216,7 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] }, "patch": { "operationId": "updateTag", @@ -5602,12 +5264,10 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] } }, - "/tag/{id}/assets": { + "/tags/{id}/assets": { "delete": { "operationId": "untagAssets", "parameters": [ @@ -5657,9 +5317,7 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] }, "get": { "operationId": "getTagAssets", @@ -5700,9 +5358,7 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] }, "put": { "operationId": "tagAssets", @@ -5753,9 +5409,7 @@ "api_key": [] } ], - "tags": [ - "Tag" - ] + "tags": ["Tag"] } }, "/timeline/bucket": { @@ -5888,9 +5542,7 @@ "api_key": [] } ], - "tags": [ - "Timeline" - ] + "tags": ["Timeline"] } }, "/timeline/buckets": { @@ -6015,9 +5667,7 @@ "api_key": [] } ], - "tags": [ - "Timeline" - ] + "tags": ["Timeline"] } }, "/trash/empty": { @@ -6040,9 +5690,7 @@ "api_key": [] } ], - "tags": [ - "Trash" - ] + "tags": ["Trash"] } }, "/trash/restore": { @@ -6065,9 +5713,7 @@ "api_key": [] } ], - "tags": [ - "Trash" - ] + "tags": ["Trash"] } }, "/trash/restore/assets": { @@ -6100,12 +5746,10 @@ "api_key": [] } ], - "tags": [ - "Trash" - ] + "tags": ["Trash"] } }, - "/user": { + "/users": { "get": { "operationId": "getAllUsers", "parameters": [ @@ -6144,9 +5788,7 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] }, "post": { "operationId": "createUser", @@ -6184,9 +5826,7 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] }, "put": { "operationId": "updateUser", @@ -6224,54 +5864,10 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] } }, - "/user/info/{id}": { - "get": { - "operationId": "getUserById", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserResponseDto" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "User" - ] - } - }, - "/user/me": { + "/users/me": { "get": { "operationId": "getMyUserInfo", "parameters": [], @@ -6298,12 +5894,10 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] } }, - "/user/profile-image": { + "/users/profile-image": { "delete": { "operationId": "deleteProfileImage", "parameters": [], @@ -6323,9 +5917,7 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] }, "post": { "operationId": "createProfileImage", @@ -6364,55 +5956,10 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] } }, - "/user/profile-image/{id}": { - "get": { - "operationId": "getProfileImage", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "format": "uuid", - "type": "string" - } - } - ], - "responses": { - "200": { - "content": { - "application/octet-stream": { - "schema": { - "format": "binary", - "type": "string" - } - } - }, - "description": "" - } - }, - "security": [ - { - "bearer": [] - }, - { - "cookie": [] - }, - { - "api_key": [] - } - ], - "tags": [ - "User" - ] - } - }, - "/user/{id}": { + "/users/{id}": { "delete": { "operationId": "deleteUser", "parameters": [ @@ -6459,12 +6006,89 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] + }, + "get": { + "operationId": "getUserById", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserResponseDto" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": ["User"] } }, - "/user/{id}/restore": { + "/users/{id}/profile-image": { + "get": { + "operationId": "getProfileImage", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "format": "uuid", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/octet-stream": { + "schema": { + "format": "binary", + "type": "string" + } + } + }, + "description": "" + } + }, + "security": [ + { + "bearer": [] + }, + { + "cookie": [] + }, + { + "api_key": [] + } + ], + "tags": ["User"] + } + }, + "/users/{id}/restore": { "post": { "operationId": "restoreUser", "parameters": [ @@ -6501,16 +6125,14 @@ "api_key": [] } ], - "tags": [ - "User" - ] + "tags": ["User"] } } }, "info": { "title": "Immich", "description": "Immich API", - "version": "1.103.1", + "version": "1.105.1", "contact": {} }, "tags": [], @@ -6556,10 +6178,7 @@ "type": "string" } }, - "required": [ - "apiKey", - "secret" - ], + "required": ["apiKey", "secret"], "type": "object" }, "APIKeyResponseDto": { @@ -6579,12 +6198,7 @@ "type": "string" } }, - "required": [ - "createdAt", - "id", - "name", - "updatedAt" - ], + "required": ["createdAt", "id", "name", "updatedAt"], "type": "object" }, "APIKeyUpdateDto": { @@ -6593,9 +6207,7 @@ "type": "string" } }, - "required": [ - "name" - ], + "required": ["name"], "type": "object" }, "ActivityCreateDto": { @@ -6615,10 +6227,7 @@ "$ref": "#/components/schemas/ReactionType" } }, - "required": [ - "albumId", - "type" - ], + "required": ["albumId", "type"], "type": "object" }, "ActivityResponseDto": { @@ -6639,23 +6248,14 @@ "type": "string" }, "type": { - "enum": [ - "comment", - "like" - ], + "enum": ["comment", "like"], "type": "string" }, "user": { "$ref": "#/components/schemas/UserDto" } }, - "required": [ - "assetId", - "createdAt", - "id", - "type", - "user" - ], + "required": ["assetId", "createdAt", "id", "type", "user"], "type": "object" }, "ActivityStatisticsResponseDto": { @@ -6664,9 +6264,7 @@ "type": "integer" } }, - "required": [ - "comments" - ], + "required": ["comments"], "type": "object" }, "AddUsersDto": { @@ -6676,20 +6274,9 @@ "$ref": "#/components/schemas/AlbumUserAddDto" }, "type": "array" - }, - "sharedUserIds": { - "deprecated": true, - "description": "This property was deprecated in v1.102.0", - "items": { - "format": "uuid", - "type": "string" - }, - "type": "array" } }, - "required": [ - "albumUsers" - ], + "required": ["albumUsers"], "type": "object" }, "AdminOnboardingUpdateDto": { @@ -6698,9 +6285,7 @@ "type": "boolean" } }, - "required": [ - "isOnboarded" - ], + "required": ["isOnboarded"], "type": "object" }, "AlbumCountResponseDto": { @@ -6715,11 +6300,7 @@ "type": "integer" } }, - "required": [ - "notShared", - "owned", - "shared" - ], + "required": ["notShared", "owned", "shared"], "type": "object" }, "AlbumResponseDto": { @@ -6782,14 +6363,6 @@ "shared": { "type": "boolean" }, - "sharedUsers": { - "deprecated": true, - "description": "This property was deprecated in v1.102.0", - "items": { - "$ref": "#/components/schemas/UserResponseDto" - }, - "type": "array" - }, "startDate": { "format": "date-time", "type": "string" @@ -6813,7 +6386,6 @@ "owner", "ownerId", "shared", - "sharedUsers", "updatedAt" ], "type": "object" @@ -6828,9 +6400,7 @@ "type": "string" } }, - "required": [ - "userId" - ], + "required": ["userId"], "type": "object" }, "AlbumUserCreateDto": { @@ -6843,10 +6413,7 @@ "type": "string" } }, - "required": [ - "role", - "userId" - ], + "required": ["role", "userId"], "type": "object" }, "AlbumUserResponseDto": { @@ -6858,17 +6425,11 @@ "$ref": "#/components/schemas/UserResponseDto" } }, - "required": [ - "role", - "user" - ], + "required": ["role", "user"], "type": "object" }, "AlbumUserRole": { - "enum": [ - "editor", - "viewer" - ], + "enum": ["editor", "viewer"], "type": "string" }, "AllJobStatusResponseDto": { @@ -6876,6 +6437,9 @@ "backgroundTask": { "$ref": "#/components/schemas/JobStatusDto" }, + "duplicateDetection": { + "$ref": "#/components/schemas/JobStatusDto" + }, "faceDetection": { "$ref": "#/components/schemas/JobStatusDto" }, @@ -6915,6 +6479,7 @@ }, "required": [ "backgroundTask", + "duplicateDetection", "faceDetection", "facialRecognition", "library", @@ -6943,9 +6508,7 @@ "type": "array" } }, - "required": [ - "ids" - ], + "required": ["ids"], "type": "object" }, "AssetBulkUpdateDto": { @@ -6953,6 +6516,10 @@ "dateTimeOriginal": { "type": "string" }, + "duplicateId": { + "nullable": true, + "type": "string" + }, "ids": { "items": { "format": "uuid", @@ -6980,9 +6547,7 @@ "type": "string" } }, - "required": [ - "ids" - ], + "required": ["ids"], "type": "object" }, "AssetBulkUploadCheckDto": { @@ -6994,9 +6559,7 @@ "type": "array" } }, - "required": [ - "assets" - ], + "required": ["assets"], "type": "object" }, "AssetBulkUploadCheckItem": { @@ -7009,10 +6572,7 @@ "type": "string" } }, - "required": [ - "checksum", - "id" - ], + "required": ["checksum", "id"], "type": "object" }, "AssetBulkUploadCheckResponseDto": { @@ -7024,18 +6584,13 @@ "type": "array" } }, - "required": [ - "results" - ], + "required": ["results"], "type": "object" }, "AssetBulkUploadCheckResult": { "properties": { "action": { - "enum": [ - "accept", - "reject" - ], + "enum": ["accept", "reject"], "type": "string" }, "assetId": { @@ -7045,17 +6600,11 @@ "type": "string" }, "reason": { - "enum": [ - "duplicate", - "unsupported-format" - ], + "enum": ["duplicate", "unsupported-format"], "type": "string" } }, - "required": [ - "action", - "id" - ], + "required": ["action", "id"], "type": "object" }, "AssetDeltaSyncDto": { @@ -7072,10 +6621,7 @@ "type": "array" } }, - "required": [ - "updatedAfter", - "userIds" - ], + "required": ["updatedAfter", "userIds"], "type": "object" }, "AssetDeltaSyncResponseDto": { @@ -7096,11 +6642,7 @@ "type": "array" } }, - "required": [ - "deleted", - "needsFullSync", - "upserted" - ], + "required": ["deleted", "needsFullSync", "upserted"], "type": "object" }, "AssetFaceResponseDto": { @@ -7157,9 +6699,7 @@ "type": "array" } }, - "required": [ - "data" - ], + "required": ["data"], "type": "object" }, "AssetFaceUpdateItem": { @@ -7173,10 +6713,7 @@ "type": "string" } }, - "required": [ - "assetId", - "personId" - ], + "required": ["assetId", "personId"], "type": "object" }, "AssetFaceWithoutPersonResponseDto": { @@ -7224,10 +6761,7 @@ "type": "string" } }, - "required": [ - "duplicate", - "id" - ], + "required": ["duplicate", "id"], "type": "object" }, "AssetFullSyncDto": { @@ -7253,10 +6787,7 @@ "type": "string" } }, - "required": [ - "limit", - "updatedUntil" - ], + "required": ["limit", "updatedUntil"], "type": "object" }, "AssetIdsDto": { @@ -7269,9 +6800,7 @@ "type": "array" } }, - "required": [ - "assetIds" - ], + "required": ["assetIds"], "type": "object" }, "AssetIdsResponseDto": { @@ -7280,29 +6809,18 @@ "type": "string" }, "error": { - "enum": [ - "duplicate", - "no_permission", - "not_found" - ], + "enum": ["duplicate", "no_permission", "not_found"], "type": "string" }, "success": { "type": "boolean" } }, - "required": [ - "assetId", - "success" - ], + "required": ["assetId", "success"], "type": "object" }, "AssetJobName": { - "enum": [ - "regenerate-thumbnail", - "refresh-metadata", - "transcode-video" - ], + "enum": ["regenerate-thumbnail", "refresh-metadata", "transcode-video"], "type": "string" }, "AssetJobsDto": { @@ -7318,17 +6836,60 @@ "$ref": "#/components/schemas/AssetJobName" } }, + "required": ["assetIds", "name"], + "type": "object" + }, + "AssetMediaReplaceDto": { + "properties": { + "assetData": { + "format": "binary", + "type": "string" + }, + "deviceAssetId": { + "type": "string" + }, + "deviceId": { + "type": "string" + }, + "duration": { + "type": "string" + }, + "fileCreatedAt": { + "format": "date-time", + "type": "string" + }, + "fileModifiedAt": { + "format": "date-time", + "type": "string" + } + }, "required": [ - "assetIds", - "name" + "assetData", + "deviceAssetId", + "deviceId", + "fileCreatedAt", + "fileModifiedAt" ], "type": "object" }, + "AssetMediaResponseDto": { + "properties": { + "id": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/AssetMediaStatus" + } + }, + "required": ["id", "status"], + "type": "object" + }, + "AssetMediaStatus": { + "enum": ["replaced", "duplicate"], + "type": "string" + }, "AssetOrder": { - "enum": [ - "asc", - "desc" - ], + "enum": ["asc", "desc"], "type": "string" }, "AssetResponseDto": { @@ -7343,6 +6904,10 @@ "deviceId": { "type": "string" }, + "duplicateId": { + "nullable": true, + "type": "string" + }, "duration": { "type": "string" }, @@ -7366,26 +6931,19 @@ "isArchived": { "type": "boolean" }, - "isExternal": { - "deprecated": true, - "description": "This property was deprecated in v1.104.0", - "type": "boolean" - }, "isFavorite": { "type": "boolean" }, "isOffline": { "type": "boolean" }, - "isReadOnly": { - "deprecated": true, - "description": "This property was deprecated in v1.104.0", - "type": "boolean" - }, "isTrashed": { "type": "boolean" }, "libraryId": { + "deprecated": true, + "description": "This property was deprecated in v1.106.0", + "nullable": true, "type": "string" }, "livePhotoVideoId": { @@ -7462,7 +7020,6 @@ "isFavorite", "isOffline", "isTrashed", - "libraryId", "localDateTime", "originalFileName", "originalPath", @@ -7487,28 +7044,15 @@ "type": "integer" } }, - "required": [ - "images", - "total", - "videos" - ], + "required": ["images", "total", "videos"], "type": "object" }, "AssetTypeEnum": { - "enum": [ - "IMAGE", - "VIDEO", - "AUDIO", - "OTHER" - ], + "enum": ["IMAGE", "VIDEO", "AUDIO", "OTHER"], "type": "string" }, "AudioCodec": { - "enum": [ - "mp3", - "aac", - "libopus" - ], + "enum": ["mp3", "aac", "libopus"], "type": "string" }, "AuditDeletesResponseDto": { @@ -7523,21 +7067,13 @@ "type": "boolean" } }, - "required": [ - "ids", - "needsFullSync" - ], + "required": ["ids", "needsFullSync"], "type": "object" }, "BulkIdResponseDto": { "properties": { "error": { - "enum": [ - "duplicate", - "no_permission", - "not_found", - "unknown" - ], + "enum": ["duplicate", "no_permission", "not_found", "unknown"], "type": "string" }, "id": { @@ -7547,10 +7083,7 @@ "type": "boolean" } }, - "required": [ - "id", - "success" - ], + "required": ["id", "success"], "type": "object" }, "BulkIdsDto": { @@ -7563,9 +7096,7 @@ "type": "array" } }, - "required": [ - "ids" - ], + "required": ["ids"], "type": "object" }, "CLIPConfig": { @@ -7583,25 +7114,15 @@ "$ref": "#/components/schemas/ModelType" } }, - "required": [ - "enabled", - "modelName" - ], + "required": ["enabled", "modelName"], "type": "object" }, "CLIPMode": { - "enum": [ - "vision", - "text" - ], + "enum": ["vision", "text"], "type": "string" }, "CQMode": { - "enum": [ - "auto", - "cqp", - "icq" - ], + "enum": ["auto", "cqp", "icq"], "type": "string" }, "ChangePasswordDto": { @@ -7616,10 +7137,7 @@ "type": "string" } }, - "required": [ - "newPassword", - "password" - ], + "required": ["newPassword", "password"], "type": "object" }, "CheckExistingAssetsDto": { @@ -7634,10 +7152,7 @@ "type": "string" } }, - "required": [ - "deviceAssetIds", - "deviceId" - ], + "required": ["deviceAssetIds", "deviceId"], "type": "object" }, "CheckExistingAssetsResponseDto": { @@ -7649,16 +7164,11 @@ "type": "array" } }, - "required": [ - "existingIds" - ], + "required": ["existingIds"], "type": "object" }, "Colorspace": { - "enum": [ - "srgb", - "p3" - ], + "enum": ["srgb", "p3"], "type": "string" }, "CreateAlbumDto": { @@ -7667,7 +7177,6 @@ "type": "string" }, "albumUsers": { - "description": "This property was added in v1.104.0", "items": { "$ref": "#/components/schemas/AlbumUserCreateDto" }, @@ -7682,20 +7191,9 @@ }, "description": { "type": "string" - }, - "sharedWithUserIds": { - "deprecated": true, - "description": "This property was deprecated in v1.104.0", - "items": { - "format": "uuid", - "type": "string" - }, - "type": "array" } }, - "required": [ - "albumName" - ], + "required": ["albumName"], "type": "object" }, "CreateAssetDto": { @@ -7733,10 +7231,6 @@ "isVisible": { "type": "boolean" }, - "libraryId": { - "format": "uuid", - "type": "string" - }, "livePhotoData": { "format": "binary", "type": "string" @@ -7769,24 +7263,15 @@ }, "type": "array" }, - "isVisible": { - "type": "boolean" - }, "name": { "type": "string" }, "ownerId": { "format": "uuid", "type": "string" - }, - "type": { - "$ref": "#/components/schemas/LibraryType" } }, - "required": [ - "ownerId", - "type" - ], + "required": ["ownerId"], "type": "object" }, "CreateProfileImageDto": { @@ -7796,9 +7281,7 @@ "type": "string" } }, - "required": [ - "file" - ], + "required": ["file"], "type": "object" }, "CreateProfileImageResponseDto": { @@ -7810,10 +7293,7 @@ "type": "string" } }, - "required": [ - "profileImagePath", - "userId" - ], + "required": ["profileImagePath", "userId"], "type": "object" }, "CreateTagDto": { @@ -7825,10 +7305,7 @@ "$ref": "#/components/schemas/TagTypeEnum" } }, - "required": [ - "name", - "type" - ], + "required": ["name", "type"], "type": "object" }, "CreateUserDto": { @@ -7862,11 +7339,7 @@ "type": "string" } }, - "required": [ - "email", - "name", - "password" - ], + "required": ["email", "name", "password"], "type": "object" }, "DeleteUserDto": { @@ -7889,10 +7362,7 @@ "type": "integer" } }, - "required": [ - "assetIds", - "size" - ], + "required": ["assetIds", "size"], "type": "object" }, "DownloadInfoDto": { @@ -7931,17 +7401,41 @@ "type": "integer" } }, - "required": [ - "archives", - "totalSize" - ], + "required": ["archives", "totalSize"], + "type": "object" + }, + "DuplicateDetectionConfig": { + "properties": { + "enabled": { + "type": "boolean" + }, + "maxDistance": { + "format": "float", + "maximum": 0.1, + "minimum": 0.001, + "type": "number" + } + }, + "required": ["enabled", "maxDistance"], + "type": "object" + }, + "DuplicateResponseDto": { + "properties": { + "assets": { + "items": { + "$ref": "#/components/schemas/AssetResponseDto" + }, + "type": "array" + }, + "duplicateId": { + "type": "string" + } + }, + "required": ["assets", "duplicateId"], "type": "object" }, "EntityType": { - "enum": [ - "ASSET", - "ALBUM" - ], + "enum": ["ASSET", "ALBUM"], "type": "string" }, "ExifResponseDto": { @@ -8064,9 +7558,7 @@ "type": "string" } }, - "required": [ - "id" - ], + "required": ["id"], "type": "object" }, "FileChecksumDto": { @@ -8078,9 +7570,7 @@ "type": "array" } }, - "required": [ - "filenames" - ], + "required": ["filenames"], "type": "object" }, "FileChecksumResponseDto": { @@ -8092,10 +7582,7 @@ "type": "string" } }, - "required": [ - "checksum", - "filename" - ], + "required": ["checksum", "filename"], "type": "object" }, "FileReportDto": { @@ -8113,10 +7600,7 @@ "type": "array" } }, - "required": [ - "extras", - "orphans" - ], + "required": ["extras", "orphans"], "type": "object" }, "FileReportFixDto": { @@ -8128,9 +7612,7 @@ "type": "array" } }, - "required": [ - "items" - ], + "required": ["items"], "type": "object" }, "FileReportItemDto": { @@ -8152,29 +7634,15 @@ "type": "string" } }, - "required": [ - "entityId", - "entityType", - "pathType", - "pathValue" - ], + "required": ["entityId", "entityType", "pathType", "pathValue"], "type": "object" }, "ImageFormat": { - "enum": [ - "jpeg", - "webp" - ], + "enum": ["jpeg", "webp"], "type": "string" }, "JobCommand": { - "enum": [ - "start", - "pause", - "resume", - "empty", - "clear-failed" - ], + "enum": ["start", "pause", "resume", "empty", "clear-failed"], "type": "string" }, "JobCommandDto": { @@ -8186,10 +7654,7 @@ "type": "boolean" } }, - "required": [ - "command", - "force" - ], + "required": ["command", "force"], "type": "object" }, "JobCountsDto": { @@ -8231,6 +7696,7 @@ "faceDetection", "facialRecognition", "smartSearch", + "duplicateDetection", "backgroundTask", "storageTemplateMigration", "migration", @@ -8248,9 +7714,7 @@ "type": "integer" } }, - "required": [ - "concurrency" - ], + "required": ["concurrency"], "type": "object" }, "JobStatusDto": { @@ -8262,10 +7726,7 @@ "$ref": "#/components/schemas/QueueStatusDto" } }, - "required": [ - "jobCounts", - "queueStatus" - ], + "required": ["jobCounts", "queueStatus"], "type": "object" }, "LibraryResponseDto": { @@ -8303,9 +7764,6 @@ "nullable": true, "type": "string" }, - "type": { - "$ref": "#/components/schemas/LibraryType" - }, "updatedAt": { "format": "date-time", "type": "string" @@ -8320,7 +7778,6 @@ "name", "ownerId", "refreshedAt", - "type", "updatedAt" ], "type": "object" @@ -8345,30 +7802,11 @@ "type": "integer" } }, - "required": [ - "photos", - "total", - "usage", - "videos" - ], + "required": ["photos", "total", "usage", "videos"], "type": "object" }, - "LibraryType": { - "enum": [ - "UPLOAD", - "EXTERNAL" - ], - "type": "string" - }, "LogLevel": { - "enum": [ - "verbose", - "debug", - "log", - "warn", - "error", - "fatal" - ], + "enum": ["verbose", "debug", "log", "warn", "error", "fatal"], "type": "string" }, "LoginCredentialDto": { @@ -8382,10 +7820,7 @@ "type": "string" } }, - "required": [ - "email", - "password" - ], + "required": ["email", "password"], "type": "object" }, "LoginResponseDto": { @@ -8432,10 +7867,7 @@ "type": "boolean" } }, - "required": [ - "redirectUri", - "successful" - ], + "required": ["redirectUri", "successful"], "type": "object" }, "MapMarkerResponseDto": { @@ -8464,21 +7896,11 @@ "type": "string" } }, - "required": [ - "city", - "country", - "id", - "lat", - "lon", - "state" - ], + "required": ["city", "country", "id", "lat", "lon", "state"], "type": "object" }, "MapTheme": { - "enum": [ - "light", - "dark" - ], + "enum": ["light", "dark"], "type": "string" }, "MemoryCreateDto": { @@ -8508,11 +7930,7 @@ "$ref": "#/components/schemas/MemoryType" } }, - "required": [ - "data", - "memoryAt", - "type" - ], + "required": ["data", "memoryAt", "type"], "type": "object" }, "MemoryLaneResponseDto": { @@ -8523,20 +7941,11 @@ }, "type": "array" }, - "title": { - "deprecated": true, - "description": "This property was deprecated in v1.100.0", - "type": "string" - }, "yearsAgo": { "type": "integer" } }, - "required": [ - "assets", - "title", - "yearsAgo" - ], + "required": ["assets", "yearsAgo"], "type": "object" }, "MemoryResponseDto": { @@ -8576,9 +7985,7 @@ "type": "string" }, "type": { - "enum": [ - "on_this_day" - ], + "enum": ["on_this_day"], "type": "string" }, "updatedAt": { @@ -8600,9 +8007,7 @@ "type": "object" }, "MemoryType": { - "enum": [ - "on_this_day" - ], + "enum": ["on_this_day"], "type": "string" }, "MemoryUpdateDto": { @@ -8631,9 +8036,7 @@ "type": "array" } }, - "required": [ - "ids" - ], + "required": ["ids"], "type": "object" }, "MetadataSearchDto": { @@ -8725,11 +8128,6 @@ "previewPath": { "type": "string" }, - "resizePath": { - "deprecated": true, - "description": "This property was deprecated in v1.100.0", - "type": "string" - }, "size": { "maximum": 1000, "minimum": 1, @@ -8768,11 +8166,6 @@ "format": "date-time", "type": "string" }, - "webpPath": { - "deprecated": true, - "description": "This property was deprecated in v1.100.0", - "type": "string" - }, "withArchived": { "default": false, "type": "boolean" @@ -8793,10 +8186,7 @@ "type": "object" }, "ModelType": { - "enum": [ - "facial-recognition", - "clip" - ], + "enum": ["facial-recognition", "clip"], "type": "string" }, "OAuthAuthorizeResponseDto": { @@ -8805,9 +8195,7 @@ "type": "string" } }, - "required": [ - "url" - ], + "required": ["url"], "type": "object" }, "OAuthCallbackDto": { @@ -8816,9 +8204,7 @@ "type": "string" } }, - "required": [ - "url" - ], + "required": ["url"], "type": "object" }, "OAuthConfigDto": { @@ -8827,9 +8213,7 @@ "type": "string" } }, - "required": [ - "redirectUri" - ], + "required": ["redirectUri"], "type": "object" }, "OnThisDayDto": { @@ -8839,9 +8223,7 @@ "type": "number" } }, - "required": [ - "year" - ], + "required": ["year"], "type": "object" }, "PartnerResponseDto": { @@ -8927,11 +8309,7 @@ "type": "object" }, "PathEntityType": { - "enum": [ - "asset", - "person", - "user" - ], + "enum": ["asset", "person", "user"], "type": "string" }, "PathType": { @@ -8961,11 +8339,7 @@ "type": "integer" } }, - "required": [ - "hidden", - "people", - "total" - ], + "required": ["hidden", "people", "total"], "type": "object" }, "PeopleUpdateDto": { @@ -8977,9 +8351,7 @@ "type": "array" } }, - "required": [ - "people" - ], + "required": ["people"], "type": "object" }, "PeopleUpdateItem": { @@ -9007,9 +8379,7 @@ "type": "string" } }, - "required": [ - "id" - ], + "required": ["id"], "type": "object" }, "PeopleWithFacesResponseDto": { @@ -9024,10 +8394,7 @@ "type": "array" } }, - "required": [ - "numberOfFaces", - "visiblePeople" - ], + "required": ["numberOfFaces", "visiblePeople"], "type": "object" }, "PersonCreateDto": { @@ -9069,13 +8436,7 @@ "type": "string" } }, - "required": [ - "birthDate", - "id", - "isHidden", - "name", - "thumbnailPath" - ], + "required": ["birthDate", "id", "isHidden", "name", "thumbnailPath"], "type": "object" }, "PersonStatisticsResponseDto": { @@ -9084,9 +8445,7 @@ "type": "integer" } }, - "required": [ - "assets" - ], + "required": ["assets"], "type": "object" }, "PersonUpdateDto": { @@ -9166,11 +8525,7 @@ "type": "string" } }, - "required": [ - "latitude", - "longitude", - "name" - ], + "required": ["latitude", "longitude", "name"], "type": "object" }, "QueueStatusDto": { @@ -9182,24 +8537,15 @@ "type": "boolean" } }, - "required": [ - "isActive", - "isPaused" - ], + "required": ["isActive", "isPaused"], "type": "object" }, "ReactionLevel": { - "enum": [ - "album", - "asset" - ], + "enum": ["album", "asset"], "type": "string" }, "ReactionType": { - "enum": [ - "comment", - "like" - ], + "enum": ["comment", "like"], "type": "string" }, "RecognitionConfig": { @@ -9250,10 +8596,7 @@ "type": "string" } }, - "required": [ - "lastImportFileName", - "lastUpdate" - ], + "required": ["lastImportFileName", "lastUpdate"], "type": "object" }, "ScanLibraryDto": { @@ -9288,12 +8631,7 @@ "type": "integer" } }, - "required": [ - "count", - "facets", - "items", - "total" - ], + "required": ["count", "facets", "items", "total"], "type": "object" }, "SearchAssetResponseDto": { @@ -9321,13 +8659,7 @@ "type": "integer" } }, - "required": [ - "count", - "facets", - "items", - "nextPage", - "total" - ], + "required": ["count", "facets", "items", "nextPage", "total"], "type": "object" }, "SearchExploreItem": { @@ -9339,10 +8671,7 @@ "type": "string" } }, - "required": [ - "data", - "value" - ], + "required": ["data", "value"], "type": "object" }, "SearchExploreResponseDto": { @@ -9357,10 +8686,7 @@ "type": "array" } }, - "required": [ - "fieldName", - "items" - ], + "required": ["fieldName", "items"], "type": "object" }, "SearchFacetCountResponseDto": { @@ -9372,10 +8698,7 @@ "type": "string" } }, - "required": [ - "count", - "value" - ], + "required": ["count", "value"], "type": "object" }, "SearchFacetResponseDto": { @@ -9390,10 +8713,7 @@ "type": "string" } }, - "required": [ - "counts", - "fieldName" - ], + "required": ["counts", "fieldName"], "type": "object" }, "SearchResponseDto": { @@ -9405,20 +8725,11 @@ "$ref": "#/components/schemas/SearchAssetResponseDto" } }, - "required": [ - "albums", - "assets" - ], + "required": ["albums", "assets"], "type": "object" }, "SearchSuggestionType": { - "enum": [ - "country", - "state", - "city", - "camera-make", - "camera-model" - ], + "enum": ["country", "state", "city", "camera-make", "camera-model"], "type": "string" }, "ServerConfigDto": { @@ -9461,6 +8772,9 @@ "configFile": { "type": "boolean" }, + "duplicateDetection": { + "type": "boolean" + }, "email": { "type": "boolean" }, @@ -9497,6 +8811,7 @@ }, "required": [ "configFile", + "duplicateDetection", "email", "facialRecognition", "map", @@ -9511,7 +8826,76 @@ ], "type": "object" }, - "ServerInfoResponseDto": { + "ServerMediaTypesResponseDto": { + "properties": { + "image": { + "items": { + "type": "string" + }, + "type": "array" + }, + "sidecar": { + "items": { + "type": "string" + }, + "type": "array" + }, + "video": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["image", "sidecar", "video"], + "type": "object" + }, + "ServerPingResponse": { + "properties": { + "res": { + "example": "pong", + "readOnly": true, + "type": "string" + } + }, + "required": ["res"], + "type": "object" + }, + "ServerStatsResponseDto": { + "properties": { + "photos": { + "default": 0, + "type": "integer" + }, + "usage": { + "default": 0, + "format": "int64", + "type": "integer" + }, + "usageByUser": { + "default": [], + "example": [ + { + "photos": 1, + "videos": 1, + "diskUsageRaw": 1 + } + ], + "items": { + "$ref": "#/components/schemas/UsageByUserDto" + }, + "title": "Array of usage for each user", + "type": "array" + }, + "videos": { + "default": 0, + "type": "integer" + } + }, + "required": ["photos", "usage", "usageByUser", "videos"], + "type": "object" + }, + "ServerStorageResponseDto": { "properties": { "diskAvailable": { "type": "string" @@ -9550,95 +8934,13 @@ ], "type": "object" }, - "ServerMediaTypesResponseDto": { - "properties": { - "image": { - "items": { - "type": "string" - }, - "type": "array" - }, - "sidecar": { - "items": { - "type": "string" - }, - "type": "array" - }, - "video": { - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "image", - "sidecar", - "video" - ], - "type": "object" - }, - "ServerPingResponse": { - "properties": { - "res": { - "example": "pong", - "readOnly": true, - "type": "string" - } - }, - "required": [ - "res" - ], - "type": "object" - }, - "ServerStatsResponseDto": { - "properties": { - "photos": { - "default": 0, - "type": "integer" - }, - "usage": { - "default": 0, - "format": "int64", - "type": "integer" - }, - "usageByUser": { - "default": [], - "example": [ - { - "photos": 1, - "videos": 1, - "diskUsageRaw": 1 - } - ], - "items": { - "$ref": "#/components/schemas/UsageByUserDto" - }, - "title": "Array of usage for each user", - "type": "array" - }, - "videos": { - "default": 0, - "type": "integer" - } - }, - "required": [ - "photos", - "usage", - "usageByUser", - "videos" - ], - "type": "object" - }, "ServerThemeDto": { "properties": { "customCss": { "type": "string" } }, - "required": [ - "customCss" - ], + "required": ["customCss"], "type": "object" }, "ServerVersionResponseDto": { @@ -9653,11 +8955,7 @@ "type": "integer" } }, - "required": [ - "major", - "minor", - "patch" - ], + "required": ["major", "minor", "patch"], "type": "object" }, "SessionResponseDto": { @@ -9731,9 +9029,7 @@ "$ref": "#/components/schemas/SharedLinkType" } }, - "required": [ - "type" - ], + "required": ["type"], "type": "object" }, "SharedLinkEditDto": { @@ -9836,10 +9132,7 @@ "type": "object" }, "SharedLinkType": { - "enum": [ - "ALBUM", - "INDIVIDUAL" - ], + "enum": ["ALBUM", "INDIVIDUAL"], "type": "string" }, "SignUpDto": { @@ -9857,11 +9150,7 @@ "type": "string" } }, - "required": [ - "email", - "name", - "password" - ], + "required": ["email", "name", "password"], "type": "object" }, "SmartInfoResponseDto": { @@ -9996,9 +9285,7 @@ "type": "boolean" } }, - "required": [ - "query" - ], + "required": ["query"], "type": "object" }, "SystemConfigDto": { @@ -10081,6 +9368,9 @@ "accel": { "$ref": "#/components/schemas/TranscodeHWAccel" }, + "accelDecode": { + "type": "boolean" + }, "acceptedAudioCodecs": { "items": { "$ref": "#/components/schemas/AudioCodec" @@ -10156,6 +9446,7 @@ }, "required": [ "accel", + "accelDecode", "acceptedAudioCodecs", "acceptedVideoCodecs", "bframes", @@ -10277,10 +9568,7 @@ "$ref": "#/components/schemas/SystemConfigLibraryWatchDto" } }, - "required": [ - "scan", - "watch" - ], + "required": ["scan", "watch"], "type": "object" }, "SystemConfigLibraryScanDto": { @@ -10292,10 +9580,7 @@ "type": "boolean" } }, - "required": [ - "cronExpression", - "enabled" - ], + "required": ["cronExpression", "enabled"], "type": "object" }, "SystemConfigLibraryWatchDto": { @@ -10304,9 +9589,7 @@ "type": "boolean" } }, - "required": [ - "enabled" - ], + "required": ["enabled"], "type": "object" }, "SystemConfigLoggingDto": { @@ -10318,10 +9601,7 @@ "$ref": "#/components/schemas/LogLevel" } }, - "required": [ - "enabled", - "level" - ], + "required": ["enabled", "level"], "type": "object" }, "SystemConfigMachineLearningDto": { @@ -10329,6 +9609,9 @@ "clip": { "$ref": "#/components/schemas/CLIPConfig" }, + "duplicateDetection": { + "$ref": "#/components/schemas/DuplicateDetectionConfig" + }, "enabled": { "type": "boolean" }, @@ -10341,6 +9624,7 @@ }, "required": [ "clip", + "duplicateDetection", "enabled", "facialRecognition", "url" @@ -10359,11 +9643,7 @@ "type": "string" } }, - "required": [ - "darkStyle", - "enabled", - "lightStyle" - ], + "required": ["darkStyle", "enabled", "lightStyle"], "type": "object" }, "SystemConfigNewVersionCheckDto": { @@ -10372,9 +9652,7 @@ "type": "boolean" } }, - "required": [ - "enabled" - ], + "required": ["enabled"], "type": "object" }, "SystemConfigNotificationsDto": { @@ -10383,9 +9661,7 @@ "$ref": "#/components/schemas/SystemConfigSmtpDto" } }, - "required": [ - "smtp" - ], + "required": ["smtp"], "type": "object" }, "SystemConfigOAuthDto": { @@ -10458,9 +9734,7 @@ "type": "boolean" } }, - "required": [ - "enabled" - ], + "required": ["enabled"], "type": "object" }, "SystemConfigReverseGeocodingDto": { @@ -10469,9 +9743,7 @@ "type": "boolean" } }, - "required": [ - "enabled" - ], + "required": ["enabled"], "type": "object" }, "SystemConfigServerDto": { @@ -10483,10 +9755,7 @@ "type": "string" } }, - "required": [ - "externalDomain", - "loginPageMessage" - ], + "required": ["externalDomain", "loginPageMessage"], "type": "object" }, "SystemConfigSmtpDto": { @@ -10504,12 +9773,7 @@ "$ref": "#/components/schemas/SystemConfigSmtpTransportDto" } }, - "required": [ - "enabled", - "from", - "replyTo", - "transport" - ], + "required": ["enabled", "from", "replyTo", "transport"], "type": "object" }, "SystemConfigSmtpTransportDto": { @@ -10532,13 +9796,7 @@ "type": "string" } }, - "required": [ - "host", - "ignoreCert", - "password", - "port", - "username" - ], + "required": ["host", "ignoreCert", "password", "port", "username"], "type": "object" }, "SystemConfigStorageTemplateDto": { @@ -10553,11 +9811,7 @@ "type": "string" } }, - "required": [ - "enabled", - "hashVerificationEnabled", - "template" - ], + "required": ["enabled", "hashVerificationEnabled", "template"], "type": "object" }, "SystemConfigTemplateStorageOptionDto": { @@ -10629,9 +9883,7 @@ "type": "string" } }, - "required": [ - "customCss" - ], + "required": ["customCss"], "type": "object" }, "SystemConfigTrashDto": { @@ -10644,10 +9896,7 @@ "type": "boolean" } }, - "required": [ - "days", - "enabled" - ], + "required": ["days", "enabled"], "type": "object" }, "SystemConfigUserDto": { @@ -10657,9 +9906,7 @@ "type": "integer" } }, - "required": [ - "deleteDelay" - ], + "required": ["deleteDelay"], "type": "object" }, "TagResponseDto": { @@ -10677,27 +9924,15 @@ "type": "string" } }, - "required": [ - "id", - "name", - "type", - "userId" - ], + "required": ["id", "name", "type", "userId"], "type": "object" }, "TagTypeEnum": { - "enum": [ - "OBJECT", - "FACE", - "CUSTOM" - ], + "enum": ["OBJECT", "FACE", "CUSTOM"], "type": "string" }, "ThumbnailFormat": { - "enum": [ - "JPEG", - "WEBP" - ], + "enum": ["JPEG", "WEBP"], "type": "string" }, "TimeBucketResponseDto": { @@ -10709,46 +9944,23 @@ "type": "string" } }, - "required": [ - "count", - "timeBucket" - ], + "required": ["count", "timeBucket"], "type": "object" }, "TimeBucketSize": { - "enum": [ - "DAY", - "MONTH" - ], + "enum": ["DAY", "MONTH"], "type": "string" }, "ToneMapping": { - "enum": [ - "hable", - "mobius", - "reinhard", - "disabled" - ], + "enum": ["hable", "mobius", "reinhard", "disabled"], "type": "string" }, "TranscodeHWAccel": { - "enum": [ - "nvenc", - "qsv", - "vaapi", - "rkmpp", - "disabled" - ], + "enum": ["nvenc", "qsv", "vaapi", "rkmpp", "disabled"], "type": "string" }, "TranscodePolicy": { - "enum": [ - "all", - "optimal", - "bitrate", - "required", - "disabled" - ], + "enum": ["all", "optimal", "bitrate", "required", "disabled"], "type": "string" }, "UpdateAlbumDto": { @@ -10778,9 +9990,7 @@ "$ref": "#/components/schemas/AlbumUserRole" } }, - "required": [ - "role" - ], + "required": ["role"], "type": "object" }, "UpdateAssetDto": { @@ -10820,9 +10030,6 @@ }, "type": "array" }, - "isVisible": { - "type": "boolean" - }, "name": { "type": "string" } @@ -10835,9 +10042,7 @@ "type": "boolean" } }, - "required": [ - "inTimeline" - ], + "required": ["inTimeline"], "type": "object" }, "UpdateStackParentDto": { @@ -10851,10 +10056,7 @@ "type": "string" } }, - "required": [ - "newParentId", - "oldParentId" - ], + "required": ["newParentId", "oldParentId"], "type": "object" }, "UpdateTagDto": { @@ -10902,9 +10104,7 @@ "type": "string" } }, - "required": [ - "id" - ], + "required": ["id"], "type": "object" }, "UsageByUserDto": { @@ -10974,13 +10174,7 @@ "type": "string" } }, - "required": [ - "avatarColor", - "email", - "id", - "name", - "profileImagePath" - ], + "required": ["avatarColor", "email", "id", "name", "profileImagePath"], "type": "object" }, "UserResponseDto": { @@ -11063,11 +10257,7 @@ "type": "object" }, "UserStatus": { - "enum": [ - "active", - "removing", - "deleted" - ], + "enum": ["active", "removing", "deleted"], "type": "string" }, "ValidateAccessTokenResponseDto": { @@ -11076,9 +10266,7 @@ "type": "boolean" } }, - "required": [ - "authStatus" - ], + "required": ["authStatus"], "type": "object" }, "ValidateLibraryDto": { @@ -11111,10 +10299,7 @@ "type": "string" } }, - "required": [ - "importPath", - "isValid" - ], + "required": ["importPath", "isValid"], "type": "object" }, "ValidateLibraryResponseDto": { @@ -11129,14 +10314,9 @@ "type": "object" }, "VideoCodec": { - "enum": [ - "h264", - "hevc", - "vp9", - "av1" - ], + "enum": ["h264", "hevc", "vp9", "av1"], "type": "string" } } } -} \ No newline at end of file +} diff --git a/open-api/openapitools.json b/open-api/openapitools.json index e73b975830..cfe74d51f8 100644 --- a/open-api/openapitools.json +++ b/open-api/openapitools.json @@ -2,6 +2,6 @@ "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", "spaces": 2, "generator-cli": { - "version": "7.2.0" + "version": "7.5.0" } } diff --git a/open-api/typescript-sdk/README.md b/open-api/typescript-sdk/README.md index 53a10eefc5..91b702d43e 100644 --- a/open-api/typescript-sdk/README.md +++ b/open-api/typescript-sdk/README.md @@ -13,16 +13,14 @@ npm i --save @immich/sdk For a more detailed example, check out the [`@immich/cli`](https://github.com/immich-app/immich/tree/main/cli). ```typescript -import { defaults, getAllAlbums, getAllAssets, getMyUserInfo } from "@immich/sdk"; +import { getAllAlbums, getMyUserInfo, init } from "@immich/sdk"; const API_KEY = ""; // process.env.IMMICH_API_KEY -defaults.baseUrl = "https://demo.immich.app/api"; -defaults.headers = { "x-api-key": API_KEY }; +init({ baseUrl: "https://demo.immich.app/api", apiKey: API_KEY }); const user = await getMyUserInfo(); -const assets = await getAllAssets({ take: 1000 }); const albums = await getAllAlbums({}); -console.log({ user, assets, albums }); +console.log({ user, albums }); ``` diff --git a/open-api/typescript-sdk/package-lock.json b/open-api/typescript-sdk/package-lock.json index ebc087ec0e..264a89a1cd 100644 --- a/open-api/typescript-sdk/package-lock.json +++ b/open-api/typescript-sdk/package-lock.json @@ -1,12 +1,12 @@ { "name": "@immich/sdk", - "version": "1.103.1", + "version": "1.105.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@immich/sdk", - "version": "1.103.1", + "version": "1.105.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" @@ -22,10 +22,11 @@ "integrity": "sha512-8tKiYffhwTGHSHYGnZ3oneLGCjX0po/XAXQ5Ng9fqKkvIdl/xz8+Vh8i+6xjzZqvZ2pLVpUcuSfnvNI/x67L0g==" }, "node_modules/@types/node": { - "version": "20.12.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz", - "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } diff --git a/open-api/typescript-sdk/package.json b/open-api/typescript-sdk/package.json index 5f11a18da5..81c52c8b3e 100644 --- a/open-api/typescript-sdk/package.json +++ b/open-api/typescript-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@immich/sdk", - "version": "1.103.1", + "version": "1.105.1", "description": "Auto-generated TypeScript SDK for the Immich API", "type": "module", "main": "./build/index.js", diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index fa53473f98..a82bd78148 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1,6 +1,6 @@ /** * Immich - * 1.103.1 + * 1.105.1 * DO NOT MODIFY - This file has been generated using oazapfts. * See https://www.npmjs.com/package/oazapfts */ @@ -119,6 +119,7 @@ export type AssetResponseDto = { checksum: string; deviceAssetId: string; deviceId: string; + duplicateId?: string | null; duration: string; exifInfo?: ExifResponseDto; fileCreatedAt: string; @@ -126,14 +127,11 @@ export type AssetResponseDto = { hasMetadata: boolean; id: string; isArchived: boolean; - /** This property was deprecated in v1.104.0 */ - isExternal?: boolean; isFavorite: boolean; isOffline: boolean; - /** This property was deprecated in v1.104.0 */ - isReadOnly?: boolean; isTrashed: boolean; - libraryId: string; + /** This property was deprecated in v1.106.0 */ + libraryId?: string | null; livePhotoVideoId?: string | null; localDateTime: string; originalFileName: string; @@ -168,8 +166,6 @@ export type AlbumResponseDto = { owner: UserResponseDto; ownerId: string; shared: boolean; - /** This property was deprecated in v1.102.0 */ - sharedUsers: UserResponseDto[]; startDate?: string; updatedAt: string; }; @@ -179,12 +175,9 @@ export type AlbumUserCreateDto = { }; export type CreateAlbumDto = { albumName: string; - /** This property was added in v1.104.0 */ albumUsers?: AlbumUserCreateDto[]; assetIds?: string[]; description?: string; - /** This property was deprecated in v1.104.0 */ - sharedWithUserIds?: string[]; }; export type AlbumCountResponseDto = { notShared: number; @@ -215,8 +208,6 @@ export type AlbumUserAddDto = { }; export type AddUsersDto = { albumUsers: AlbumUserAddDto[]; - /** This property was deprecated in v1.102.0 */ - sharedUserIds?: string[]; }; export type ApiKeyResponseDto = { createdAt: string; @@ -240,6 +231,7 @@ export type AssetBulkDeleteDto = { }; export type AssetBulkUpdateDto = { dateTimeOriginal?: string; + duplicateId?: string | null; ids: string[]; isArchived?: boolean; isFavorite?: boolean; @@ -286,8 +278,6 @@ export type MapMarkerResponseDto = { }; export type MemoryLaneResponseDto = { assets: AssetResponseDto[]; - /** This property was deprecated in v1.100.0 */ - title: string; yearsAgo: number; }; export type UpdateStackParentDto = { @@ -310,7 +300,6 @@ export type CreateAssetDto = { isFavorite?: boolean; isOffline?: boolean; isVisible?: boolean; - libraryId?: string; livePhotoData?: Blob; sidecarData?: Blob; }; @@ -326,6 +315,18 @@ export type UpdateAssetDto = { latitude?: number; longitude?: number; }; +export type AssetMediaReplaceDto = { + assetData: Blob; + deviceAssetId: string; + deviceId: string; + duration?: string; + fileCreatedAt: string; + fileModifiedAt: string; +}; +export type AssetMediaResponseDto = { + id: string; + status: AssetMediaStatus; +}; export type AuditDeletesResponseDto = { ids: string[]; needsFullSync: boolean; @@ -376,6 +377,10 @@ export type DownloadResponseDto = { archives: DownloadArchiveInfo[]; totalSize: number; }; +export type DuplicateResponseDto = { + assets: AssetResponseDto[]; + duplicateId: string; +}; export type PersonResponseDto = { birthDate: string | null; id: string; @@ -414,6 +419,7 @@ export type JobStatusDto = { }; export type AllJobStatusResponseDto = { backgroundTask: JobStatusDto; + duplicateDetection: JobStatusDto; faceDetection: JobStatusDto; facialRecognition: JobStatusDto; library: JobStatusDto; @@ -440,21 +446,17 @@ export type LibraryResponseDto = { name: string; ownerId: string; refreshedAt: string | null; - "type": LibraryType; updatedAt: string; }; export type CreateLibraryDto = { exclusionPatterns?: string[]; importPaths?: string[]; - isVisible?: boolean; name?: string; ownerId: string; - "type": LibraryType; }; export type UpdateLibraryDto = { exclusionPatterns?: string[]; importPaths?: string[]; - isVisible?: boolean; name?: string; }; export type ScanLibraryDto = { @@ -649,8 +651,6 @@ export type MetadataSearchDto = { page?: number; personIds?: string[]; previewPath?: string; - /** This property was deprecated in v1.100.0 */ - resizePath?: string; size?: number; state?: string; takenAfter?: string; @@ -661,8 +661,6 @@ export type MetadataSearchDto = { "type"?: AssetTypeEnum; updatedAfter?: string; updatedBefore?: string; - /** This property was deprecated in v1.100.0 */ - webpPath?: string; withArchived?: boolean; withDeleted?: boolean; withExif?: boolean; @@ -734,15 +732,6 @@ export type SmartSearchDto = { withDeleted?: boolean; withExif?: boolean; }; -export type ServerInfoResponseDto = { - diskAvailable: string; - diskAvailableRaw: number; - diskSize: string; - diskSizeRaw: number; - diskUsagePercentage: number; - diskUse: string; - diskUseRaw: number; -}; export type ServerConfigDto = { externalDomain: string; isInitialized: boolean; @@ -754,6 +743,7 @@ export type ServerConfigDto = { }; export type ServerFeaturesDto = { configFile: boolean; + duplicateDetection: boolean; email: boolean; facialRecognition: boolean; map: boolean; @@ -789,6 +779,15 @@ export type ServerStatsResponseDto = { usageByUser: UsageByUserDto[]; videos: number; }; +export type ServerStorageResponseDto = { + diskAvailable: string; + diskAvailableRaw: number; + diskSize: string; + diskSizeRaw: number; + diskUsagePercentage: number; + diskUse: string; + diskUseRaw: number; +}; export type ServerThemeDto = { customCss: string; }; @@ -867,6 +866,7 @@ export type AssetFullSyncDto = { }; export type SystemConfigFFmpegDto = { accel: TranscodeHWAccel; + accelDecode: boolean; acceptedAudioCodecs: AudioCodec[]; acceptedVideoCodecs: VideoCodec[]; bframes: number; @@ -933,6 +933,10 @@ export type ClipConfig = { modelName: string; modelType?: ModelType; }; +export type DuplicateDetectionConfig = { + enabled: boolean; + maxDistance: number; +}; export type RecognitionConfig = { enabled: boolean; maxDistance: number; @@ -943,6 +947,7 @@ export type RecognitionConfig = { }; export type SystemConfigMachineLearningDto = { clip: ClipConfig; + duplicateDetection: DuplicateDetectionConfig; enabled: boolean; facialRecognition: RecognitionConfig; url: string; @@ -1101,7 +1106,7 @@ export function getActivities({ albumId, assetId, level, $type, userId }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ActivityResponseDto[]; - }>(`/activity${QS.query(QS.explode({ + }>(`/activities${QS.query(QS.explode({ albumId, assetId, level, @@ -1117,7 +1122,7 @@ export function createActivity({ activityCreateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: ActivityResponseDto; - }>("/activity", oazapfts.json({ + }>("/activities", oazapfts.json({ ...opts, method: "POST", body: activityCreateDto @@ -1130,7 +1135,7 @@ export function getActivityStatistics({ albumId, assetId }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ActivityStatisticsResponseDto; - }>(`/activity/statistics${QS.query(QS.explode({ + }>(`/activities/statistics${QS.query(QS.explode({ albumId, assetId }))}`, { @@ -1140,7 +1145,7 @@ export function getActivityStatistics({ albumId, assetId }: { export function deleteActivity({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/activity/${encodeURIComponent(id)}`, { + return oazapfts.ok(oazapfts.fetchText(`/activities/${encodeURIComponent(id)}`, { ...opts, method: "DELETE" })); @@ -1152,7 +1157,7 @@ export function getAllAlbums({ assetId, shared }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AlbumResponseDto[]; - }>(`/album${QS.query(QS.explode({ + }>(`/albums${QS.query(QS.explode({ assetId, shared }))}`, { @@ -1165,7 +1170,7 @@ export function createAlbum({ createAlbumDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: AlbumResponseDto; - }>("/album", oazapfts.json({ + }>("/albums", oazapfts.json({ ...opts, method: "POST", body: createAlbumDto @@ -1175,14 +1180,14 @@ export function getAlbumCount(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AlbumCountResponseDto; - }>("/album/count", { + }>("/albums/count", { ...opts })); } export function deleteAlbum({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/album/${encodeURIComponent(id)}`, { + return oazapfts.ok(oazapfts.fetchText(`/albums/${encodeURIComponent(id)}`, { ...opts, method: "DELETE" })); @@ -1195,7 +1200,7 @@ export function getAlbumInfo({ id, key, withoutAssets }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AlbumResponseDto; - }>(`/album/${encodeURIComponent(id)}${QS.query(QS.explode({ + }>(`/albums/${encodeURIComponent(id)}${QS.query(QS.explode({ key, withoutAssets }))}`, { @@ -1209,7 +1214,7 @@ export function updateAlbumInfo({ id, updateAlbumDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AlbumResponseDto; - }>(`/album/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/albums/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PATCH", body: updateAlbumDto @@ -1222,7 +1227,7 @@ export function removeAssetFromAlbum({ id, bulkIdsDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: BulkIdResponseDto[]; - }>(`/album/${encodeURIComponent(id)}/assets`, oazapfts.json({ + }>(`/albums/${encodeURIComponent(id)}/assets`, oazapfts.json({ ...opts, method: "DELETE", body: bulkIdsDto @@ -1236,7 +1241,7 @@ export function addAssetsToAlbum({ id, key, bulkIdsDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: BulkIdResponseDto[]; - }>(`/album/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ + }>(`/albums/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ key }))}`, oazapfts.json({ ...opts, @@ -1248,7 +1253,7 @@ export function removeUserFromAlbum({ id, userId }: { id: string; userId: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/album/${encodeURIComponent(id)}/user/${encodeURIComponent(userId)}`, { + return oazapfts.ok(oazapfts.fetchText(`/albums/${encodeURIComponent(id)}/user/${encodeURIComponent(userId)}`, { ...opts, method: "DELETE" })); @@ -1258,7 +1263,7 @@ export function updateAlbumUser({ id, userId, updateAlbumUserDto }: { userId: string; updateAlbumUserDto: UpdateAlbumUserDto; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/album/${encodeURIComponent(id)}/user/${encodeURIComponent(userId)}`, oazapfts.json({ + return oazapfts.ok(oazapfts.fetchText(`/albums/${encodeURIComponent(id)}/user/${encodeURIComponent(userId)}`, oazapfts.json({ ...opts, method: "PUT", body: updateAlbumUserDto @@ -1271,7 +1276,7 @@ export function addUsersToAlbum({ id, addUsersDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AlbumResponseDto; - }>(`/album/${encodeURIComponent(id)}/users`, oazapfts.json({ + }>(`/albums/${encodeURIComponent(id)}/users`, oazapfts.json({ ...opts, method: "PUT", body: addUsersDto @@ -1281,7 +1286,7 @@ export function getApiKeys(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ApiKeyResponseDto[]; - }>("/api-key", { + }>("/api-keys", { ...opts })); } @@ -1291,7 +1296,7 @@ export function createApiKey({ apiKeyCreateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: ApiKeyCreateResponseDto; - }>("/api-key", oazapfts.json({ + }>("/api-keys", oazapfts.json({ ...opts, method: "POST", body: apiKeyCreateDto @@ -1300,7 +1305,7 @@ export function createApiKey({ apiKeyCreateDto }: { export function deleteApiKey({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/api-key/${encodeURIComponent(id)}`, { + return oazapfts.ok(oazapfts.fetchText(`/api-keys/${encodeURIComponent(id)}`, { ...opts, method: "DELETE" })); @@ -1311,7 +1316,7 @@ export function getApiKey({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ApiKeyResponseDto; - }>(`/api-key/${encodeURIComponent(id)}`, { + }>(`/api-keys/${encodeURIComponent(id)}`, { ...opts })); } @@ -1322,7 +1327,7 @@ export function updateApiKey({ id, apiKeyUpdateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ApiKeyResponseDto; - }>(`/api-key/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/api-keys/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PUT", body: apiKeyUpdateDto @@ -1337,37 +1342,6 @@ export function deleteAssets({ assetBulkDeleteDto }: { body: assetBulkDeleteDto }))); } -/** - * Get all AssetEntity belong to the user - */ -export function getAllAssets({ ifNoneMatch, isArchived, isFavorite, skip, take, updatedAfter, updatedBefore, userId }: { - ifNoneMatch?: string; - isArchived?: boolean; - isFavorite?: boolean; - skip?: number; - take?: number; - updatedAfter?: string; - updatedBefore?: string; - userId?: string; -}, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: AssetResponseDto[]; - }>(`/asset${QS.query(QS.explode({ - isArchived, - isFavorite, - skip, - take, - updatedAfter, - updatedBefore, - userId - }))}`, { - ...opts, - headers: oazapfts.mergeHeaders(opts?.headers, { - "if-none-match": ifNoneMatch - }) - })); -} export function updateAssets({ assetBulkUpdateDto }: { assetBulkUpdateDto: AssetBulkUpdateDto; }, opts?: Oazapfts.RequestOpts) { @@ -1446,12 +1420,13 @@ export function runAssetJobs({ assetJobsDto }: { body: assetJobsDto }))); } -export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners }: { +export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners, withSharedAlbums }: { fileCreatedAfter?: string; fileCreatedBefore?: string; isArchived?: boolean; isFavorite?: boolean; withPartners?: boolean; + withSharedAlbums?: boolean; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -1461,7 +1436,8 @@ export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, fileCreatedBefore, isArchived, isFavorite, - withPartners + withPartners, + withSharedAlbums }))}`, { ...opts })); @@ -1577,6 +1553,25 @@ export function updateAsset({ id, updateAssetDto }: { body: updateAssetDto }))); } +/** + * Replace the asset with new file, without changing its id + */ +export function replaceAsset({ id, key, assetMediaReplaceDto }: { + id: string; + key?: string; + assetMediaReplaceDto: AssetMediaReplaceDto; +}, opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: AssetMediaResponseDto; + }>(`/asset/${encodeURIComponent(id)}/file${QS.query(QS.explode({ + key + }))}`, oazapfts.multipart({ + ...opts, + method: "PUT", + body: assetMediaReplaceDto + }))); +} export function getAuditDeletes({ after, entityType, userId }: { after: string; entityType: EntityType; @@ -1691,13 +1686,21 @@ export function getDownloadInfo({ key, downloadInfoDto }: { body: downloadInfoDto }))); } +export function getAssetDuplicates(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: DuplicateResponseDto[]; + }>("/duplicates", { + ...opts + })); +} export function getFaces({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetFaceResponseDto[]; - }>(`/face${QS.query(QS.explode({ + }>(`/faces${QS.query(QS.explode({ id }))}`, { ...opts @@ -1721,7 +1724,7 @@ export function reassignFacesById({ id, faceDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PersonResponseDto; - }>(`/face/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/faces/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PUT", body: faceDto @@ -1748,15 +1751,11 @@ export function sendJobCommand({ id, jobCommandDto }: { body: jobCommandDto }))); } -export function getAllLibraries({ $type }: { - $type?: LibraryType; -}, opts?: Oazapfts.RequestOpts) { +export function getAllLibraries(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: LibraryResponseDto[]; - }>(`/library${QS.query(QS.explode({ - "type": $type - }))}`, { + }>("/libraries", { ...opts })); } @@ -1766,7 +1765,7 @@ export function createLibrary({ createLibraryDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: LibraryResponseDto; - }>("/library", oazapfts.json({ + }>("/libraries", oazapfts.json({ ...opts, method: "POST", body: createLibraryDto @@ -1775,7 +1774,7 @@ export function createLibrary({ createLibraryDto }: { export function deleteLibrary({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/library/${encodeURIComponent(id)}`, { + return oazapfts.ok(oazapfts.fetchText(`/libraries/${encodeURIComponent(id)}`, { ...opts, method: "DELETE" })); @@ -1786,7 +1785,7 @@ export function getLibrary({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: LibraryResponseDto; - }>(`/library/${encodeURIComponent(id)}`, { + }>(`/libraries/${encodeURIComponent(id)}`, { ...opts })); } @@ -1797,7 +1796,7 @@ export function updateLibrary({ id, updateLibraryDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: LibraryResponseDto; - }>(`/library/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/libraries/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PUT", body: updateLibraryDto @@ -1806,7 +1805,7 @@ export function updateLibrary({ id, updateLibraryDto }: { export function removeOfflineFiles({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/library/${encodeURIComponent(id)}/removeOffline`, { + return oazapfts.ok(oazapfts.fetchText(`/libraries/${encodeURIComponent(id)}/removeOffline`, { ...opts, method: "POST" })); @@ -1815,7 +1814,7 @@ export function scanLibrary({ id, scanLibraryDto }: { id: string; scanLibraryDto: ScanLibraryDto; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/library/${encodeURIComponent(id)}/scan`, oazapfts.json({ + return oazapfts.ok(oazapfts.fetchText(`/libraries/${encodeURIComponent(id)}/scan`, oazapfts.json({ ...opts, method: "POST", body: scanLibraryDto @@ -1827,7 +1826,7 @@ export function getLibraryStatistics({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: LibraryStatsResponseDto; - }>(`/library/${encodeURIComponent(id)}/statistics`, { + }>(`/libraries/${encodeURIComponent(id)}/statistics`, { ...opts })); } @@ -1838,7 +1837,7 @@ export function validate({ id, validateLibraryDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: ValidateLibraryResponseDto; - }>(`/library/${encodeURIComponent(id)}/validate`, oazapfts.json({ + }>(`/libraries/${encodeURIComponent(id)}/validate`, oazapfts.json({ ...opts, method: "POST", body: validateLibraryDto @@ -1977,7 +1976,7 @@ export function getPartners({ direction }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PartnerResponseDto[]; - }>(`/partner${QS.query(QS.explode({ + }>(`/partners${QS.query(QS.explode({ direction }))}`, { ...opts @@ -1986,7 +1985,7 @@ export function getPartners({ direction }: { export function removePartner({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/partner/${encodeURIComponent(id)}`, { + return oazapfts.ok(oazapfts.fetchText(`/partners/${encodeURIComponent(id)}`, { ...opts, method: "DELETE" })); @@ -1997,7 +1996,7 @@ export function createPartner({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: PartnerResponseDto; - }>(`/partner/${encodeURIComponent(id)}`, { + }>(`/partners/${encodeURIComponent(id)}`, { ...opts, method: "POST" })); @@ -2009,7 +2008,7 @@ export function updatePartner({ id, updatePartnerDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PartnerResponseDto; - }>(`/partner/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/partners/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PUT", body: updatePartnerDto @@ -2033,7 +2032,7 @@ export function getAllPeople({ withHidden }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PeopleResponseDto; - }>(`/person${QS.query(QS.explode({ + }>(`/people${QS.query(QS.explode({ withHidden }))}`, { ...opts @@ -2045,7 +2044,7 @@ export function createPerson({ personCreateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: PersonResponseDto; - }>("/person", oazapfts.json({ + }>("/people", oazapfts.json({ ...opts, method: "POST", body: personCreateDto @@ -2057,7 +2056,7 @@ export function updatePeople({ peopleUpdateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: BulkIdResponseDto[]; - }>("/person", oazapfts.json({ + }>("/people", oazapfts.json({ ...opts, method: "PUT", body: peopleUpdateDto @@ -2069,7 +2068,7 @@ export function getPerson({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PersonResponseDto; - }>(`/person/${encodeURIComponent(id)}`, { + }>(`/people/${encodeURIComponent(id)}`, { ...opts })); } @@ -2080,7 +2079,7 @@ export function updatePerson({ id, personUpdateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PersonResponseDto; - }>(`/person/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/people/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PUT", body: personUpdateDto @@ -2092,7 +2091,7 @@ export function getPersonAssets({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetResponseDto[]; - }>(`/person/${encodeURIComponent(id)}/assets`, { + }>(`/people/${encodeURIComponent(id)}/assets`, { ...opts })); } @@ -2103,7 +2102,7 @@ export function mergePerson({ id, mergePersonDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: BulkIdResponseDto[]; - }>(`/person/${encodeURIComponent(id)}/merge`, oazapfts.json({ + }>(`/people/${encodeURIComponent(id)}/merge`, oazapfts.json({ ...opts, method: "POST", body: mergePersonDto @@ -2116,7 +2115,7 @@ export function reassignFaces({ id, assetFaceUpdateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PersonResponseDto[]; - }>(`/person/${encodeURIComponent(id)}/reassign`, oazapfts.json({ + }>(`/people/${encodeURIComponent(id)}/reassign`, oazapfts.json({ ...opts, method: "PUT", body: assetFaceUpdateDto @@ -2128,7 +2127,7 @@ export function getPersonStatistics({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: PersonStatisticsResponseDto; - }>(`/person/${encodeURIComponent(id)}/statistics`, { + }>(`/people/${encodeURIComponent(id)}/statistics`, { ...opts })); } @@ -2138,7 +2137,7 @@ export function getPersonThumbnail({ id }: { return oazapfts.ok(oazapfts.fetchBlob<{ status: 200; data: Blob; - }>(`/person/${encodeURIComponent(id)}/thumbnail`, { + }>(`/people/${encodeURIComponent(id)}/thumbnail`, { ...opts })); } @@ -2146,7 +2145,7 @@ export function getAuditFiles(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: FileReportDto; - }>("/report", { + }>("/reports", { ...opts })); } @@ -2156,7 +2155,7 @@ export function getFileChecksums({ fileChecksumDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: FileChecksumResponseDto[]; - }>("/report/checksum", oazapfts.json({ + }>("/reports/checksum", oazapfts.json({ ...opts, method: "POST", body: fileChecksumDto @@ -2165,7 +2164,7 @@ export function getFileChecksums({ fileChecksumDto }: { export function fixAuditFiles({ fileReportFixDto }: { fileReportFixDto: FileReportFixDto; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText("/report/fix", oazapfts.json({ + return oazapfts.ok(oazapfts.fetchText("/reports/fix", oazapfts.json({ ...opts, method: "POST", body: fileReportFixDto @@ -2257,14 +2256,6 @@ export function getSearchSuggestions({ country, make, model, state, $type }: { ...opts })); } -export function getServerInfo(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: ServerInfoResponseDto; - }>("/server-info", { - ...opts - })); -} export function getServerConfig(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2305,6 +2296,14 @@ export function getServerStatistics(opts?: Oazapfts.RequestOpts) { ...opts })); } +export function getStorage(opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: ServerStorageResponseDto; + }>("/server-info/storage", { + ...opts + })); +} export function getTheme(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -2347,7 +2346,7 @@ export function getAllSharedLinks(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: SharedLinkResponseDto[]; - }>("/shared-link", { + }>("/shared-links", { ...opts })); } @@ -2357,7 +2356,7 @@ export function createSharedLink({ sharedLinkCreateDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: SharedLinkResponseDto; - }>("/shared-link", oazapfts.json({ + }>("/shared-links", oazapfts.json({ ...opts, method: "POST", body: sharedLinkCreateDto @@ -2371,7 +2370,7 @@ export function getMySharedLink({ key, password, token }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: SharedLinkResponseDto; - }>(`/shared-link/me${QS.query(QS.explode({ + }>(`/shared-links/me${QS.query(QS.explode({ key, password, token @@ -2382,7 +2381,7 @@ export function getMySharedLink({ key, password, token }: { export function removeSharedLink({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/shared-link/${encodeURIComponent(id)}`, { + return oazapfts.ok(oazapfts.fetchText(`/shared-links/${encodeURIComponent(id)}`, { ...opts, method: "DELETE" })); @@ -2393,7 +2392,7 @@ export function getSharedLinkById({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: SharedLinkResponseDto; - }>(`/shared-link/${encodeURIComponent(id)}`, { + }>(`/shared-links/${encodeURIComponent(id)}`, { ...opts })); } @@ -2404,7 +2403,7 @@ export function updateSharedLink({ id, sharedLinkEditDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: SharedLinkResponseDto; - }>(`/shared-link/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/shared-links/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PATCH", body: sharedLinkEditDto @@ -2418,7 +2417,7 @@ export function removeSharedLinkAssets({ id, key, assetIdsDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetIdsResponseDto[]; - }>(`/shared-link/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ + }>(`/shared-links/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ key }))}`, oazapfts.json({ ...opts, @@ -2434,7 +2433,7 @@ export function addSharedLinkAssets({ id, key, assetIdsDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetIdsResponseDto[]; - }>(`/shared-link/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ + }>(`/shared-links/${encodeURIComponent(id)}/assets${QS.query(QS.explode({ key }))}`, oazapfts.json({ ...opts, @@ -2545,7 +2544,7 @@ export function getAllTags(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: TagResponseDto[]; - }>("/tag", { + }>("/tags", { ...opts })); } @@ -2555,7 +2554,7 @@ export function createTag({ createTagDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: TagResponseDto; - }>("/tag", oazapfts.json({ + }>("/tags", oazapfts.json({ ...opts, method: "POST", body: createTagDto @@ -2564,7 +2563,7 @@ export function createTag({ createTagDto }: { export function deleteTag({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText(`/tag/${encodeURIComponent(id)}`, { + return oazapfts.ok(oazapfts.fetchText(`/tags/${encodeURIComponent(id)}`, { ...opts, method: "DELETE" })); @@ -2575,7 +2574,7 @@ export function getTagById({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: TagResponseDto; - }>(`/tag/${encodeURIComponent(id)}`, { + }>(`/tags/${encodeURIComponent(id)}`, { ...opts })); } @@ -2586,7 +2585,7 @@ export function updateTag({ id, updateTagDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: TagResponseDto; - }>(`/tag/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/tags/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "PATCH", body: updateTagDto @@ -2599,7 +2598,7 @@ export function untagAssets({ id, assetIdsDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetIdsResponseDto[]; - }>(`/tag/${encodeURIComponent(id)}/assets`, oazapfts.json({ + }>(`/tags/${encodeURIComponent(id)}/assets`, oazapfts.json({ ...opts, method: "DELETE", body: assetIdsDto @@ -2611,7 +2610,7 @@ export function getTagAssets({ id }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetResponseDto[]; - }>(`/tag/${encodeURIComponent(id)}/assets`, { + }>(`/tags/${encodeURIComponent(id)}/assets`, { ...opts })); } @@ -2622,7 +2621,7 @@ export function tagAssets({ id, assetIdsDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: AssetIdsResponseDto[]; - }>(`/tag/${encodeURIComponent(id)}/assets`, oazapfts.json({ + }>(`/tags/${encodeURIComponent(id)}/assets`, oazapfts.json({ ...opts, method: "PUT", body: assetIdsDto @@ -2721,7 +2720,7 @@ export function getAllUsers({ isAll }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: UserResponseDto[]; - }>(`/user${QS.query(QS.explode({ + }>(`/users${QS.query(QS.explode({ isAll }))}`, { ...opts @@ -2733,7 +2732,7 @@ export function createUser({ createUserDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: UserResponseDto; - }>("/user", oazapfts.json({ + }>("/users", oazapfts.json({ ...opts, method: "POST", body: createUserDto @@ -2745,32 +2744,22 @@ export function updateUser({ updateUserDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: UserResponseDto; - }>("/user", oazapfts.json({ + }>("/users", oazapfts.json({ ...opts, method: "PUT", body: updateUserDto }))); } -export function getUserById({ id }: { - id: string; -}, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchJson<{ - status: 200; - data: UserResponseDto; - }>(`/user/info/${encodeURIComponent(id)}`, { - ...opts - })); -} export function getMyUserInfo(opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: UserResponseDto; - }>("/user/me", { + }>("/users/me", { ...opts })); } export function deleteProfileImage(opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchText("/user/profile-image", { + return oazapfts.ok(oazapfts.fetchText("/users/profile-image", { ...opts, method: "DELETE" })); @@ -2781,22 +2770,12 @@ export function createProfileImage({ createProfileImageDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: CreateProfileImageResponseDto; - }>("/user/profile-image", oazapfts.multipart({ + }>("/users/profile-image", oazapfts.multipart({ ...opts, method: "POST", body: createProfileImageDto }))); } -export function getProfileImage({ id }: { - id: string; -}, opts?: Oazapfts.RequestOpts) { - return oazapfts.ok(oazapfts.fetchBlob<{ - status: 200; - data: Blob; - }>(`/user/profile-image/${encodeURIComponent(id)}`, { - ...opts - })); -} export function deleteUser({ id, deleteUserDto }: { id: string; deleteUserDto: DeleteUserDto; @@ -2804,19 +2783,39 @@ export function deleteUser({ id, deleteUserDto }: { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; data: UserResponseDto; - }>(`/user/${encodeURIComponent(id)}`, oazapfts.json({ + }>(`/users/${encodeURIComponent(id)}`, oazapfts.json({ ...opts, method: "DELETE", body: deleteUserDto }))); } +export function getUserById({ id }: { + id: string; +}, opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchJson<{ + status: 200; + data: UserResponseDto; + }>(`/users/${encodeURIComponent(id)}`, { + ...opts + })); +} +export function getProfileImage({ id }: { + id: string; +}, opts?: Oazapfts.RequestOpts) { + return oazapfts.ok(oazapfts.fetchBlob<{ + status: 200; + data: Blob; + }>(`/users/${encodeURIComponent(id)}/profile-image`, { + ...opts + })); +} export function restoreUser({ id }: { id: string; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 201; data: UserResponseDto; - }>(`/user/${encodeURIComponent(id)}/restore`, { + }>(`/users/${encodeURIComponent(id)}/restore`, { ...opts, method: "POST" })); @@ -2892,6 +2891,10 @@ export enum ThumbnailFormat { Jpeg = "JPEG", Webp = "WEBP" } +export enum AssetMediaStatus { + Replaced = "replaced", + Duplicate = "duplicate" +} export enum EntityType { Asset = "ASSET", Album = "ALBUM" @@ -2903,6 +2906,7 @@ export enum JobName { FaceDetection = "faceDetection", FacialRecognition = "facialRecognition", SmartSearch = "smartSearch", + DuplicateDetection = "duplicateDetection", BackgroundTask = "backgroundTask", StorageTemplateMigration = "storageTemplateMigration", Migration = "migration", @@ -2918,10 +2922,6 @@ export enum JobCommand { Empty = "empty", ClearFailed = "clear-failed" } -export enum LibraryType { - Upload = "UPLOAD", - External = "EXTERNAL" -} export enum Type2 { OnThisDay = "on_this_day" } diff --git a/open-api/typescript-sdk/src/index.ts b/open-api/typescript-sdk/src/index.ts index d81c7282ac..0a715c564b 100644 --- a/open-api/typescript-sdk/src/index.ts +++ b/open-api/typescript-sdk/src/index.ts @@ -1,2 +1,25 @@ +import { defaults } from './fetch-client.js'; + export * from './fetch-client.js'; export * from './fetch-errors.js'; + +export interface InitOptions { + baseUrl: string; + apiKey: string; +} + +export const init = ({ baseUrl, apiKey }: InitOptions) => { + setBaseUrl(baseUrl); + setApiKey(apiKey); +}; + +export const getBaseUrl = () => defaults.baseUrl; + +export const setBaseUrl = (baseUrl: string) => { + defaults.baseUrl = baseUrl; +}; + +export const setApiKey = (apiKey: string) => { + defaults.headers = defaults.headers || {}; + defaults.headers['x-api-key'] = apiKey; +}; diff --git a/readme_i18n/README_ar_JO.md b/readme_i18n/README_ar_JO.md index 33cc0014e9..4fcb75845a 100644 --- a/readme_i18n/README_ar_JO.md +++ b/readme_i18n/README_ar_JO.md @@ -18,6 +18,7 @@

+ English Català Español Français @@ -30,6 +31,7 @@ 中文 Русский Português Brasileiro + Svenska العربية

@@ -126,4 +128,4 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM Star History Chart - \ No newline at end of file + diff --git a/readme_i18n/README_ca_ES.md b/readme_i18n/README_ca_ES.md index 528be54219..02541ee19d 100644 --- a/readme_i18n/README_ca_ES.md +++ b/readme_i18n/README_ca_ES.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_de_DE.md b/readme_i18n/README_de_DE.md index e6a7ec78ec..da87e1a780 100644 --- a/readme_i18n/README_de_DE.md +++ b/readme_i18n/README_de_DE.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_es_ES.md b/readme_i18n/README_es_ES.md index cef5049b9f..a25264c9e8 100644 --- a/readme_i18n/README_es_ES.md +++ b/readme_i18n/README_es_ES.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_fr_FR.md b/readme_i18n/README_fr_FR.md index 36d8e49498..08be3cc02f 100644 --- a/readme_i18n/README_fr_FR.md +++ b/readme_i18n/README_fr_FR.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_it_IT.md b/readme_i18n/README_it_IT.md index 7d70068359..cbc44022b2 100644 --- a/readme_i18n/README_it_IT.md +++ b/readme_i18n/README_it_IT.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_ja_JP.md b/readme_i18n/README_ja_JP.md index a4042b9eb7..f6d087981f 100644 --- a/readme_i18n/README_ja_JP.md +++ b/readme_i18n/README_ja_JP.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_ko_KR.md b/readme_i18n/README_ko_KR.md index 5f28844e19..694a5e8655 100644 --- a/readme_i18n/README_ko_KR.md +++ b/readme_i18n/README_ko_KR.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_nl_NL.md b/readme_i18n/README_nl_NL.md index 1785660294..86d68a5644 100644 --- a/readme_i18n/README_nl_NL.md +++ b/readme_i18n/README_nl_NL.md @@ -29,6 +29,7 @@ Türkçe 中文 Português Brasileiro + Svenska العربية

@@ -42,7 +43,7 @@ ## Inhoud s - [Officiële documentatie](https://immich.app/docs) -- [Roadmap](https://github.com/orgs/immich-app/projects/1) +- [Toekomstplannen](https://github.com/orgs/immich-app/projects/1) - [Demo](#demo) - [Functies](#functies) - [Introductie](https://immich.app/docs/overview/introduction) @@ -59,7 +60,7 @@ De demo is te bekijken op https://demo.immich.app. Voor de mobiele app kunt u gebruik maken van `https://demo.immich.app/api` voor de `Server Endpoint URL` -```bash title="Demo Credential" +```bash title="Demo inloggegevens" De inloggegevens email: demo@immich.app wachtwoord: demo @@ -69,12 +70,18 @@ wachtwoord: demo Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM ``` +## Activiteit + +![Activiteit](https://repobeats.axiom.co/api/embed/9e86d9dc3ddd137161f2f6d2e758d7863b1789cb.svg "Repobeats analytics image" + + # Functies | Functies | Mobiel | Web | |-----------------------------------------------------|--------|-----| | Upload en bekijk video's en foto's | Ja | Ja | | Automatische back-up wanneer de app wordt geopend | Ja | NVT | +| Duplicatie van bestanden voorkomen | Ja | Ja | | Selectieve album(s) voor back-up | Ja | NVT | | Download foto's en video's naar een lokaal apparaat | Ja | Ja | | Ondersteuning voor meerdere gebruikers | Ja | Ja | @@ -89,6 +96,7 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM | OAuth-ondersteuning | Ja | Ja | | API-sleutels | NVT | Ja | | LivePhoto-back-up en weergave | iOS | Ja | +| Ondersteuning 360 Graden foto weergave | Nee | Ja | | Door de gebruiker gedefinieerde opslagstructuur | Ja | Ja | | Openbaar delen | Nee | Ja | | Archief en Favorieten | Ja | Ja | @@ -98,3 +106,19 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM | Herinneringen (x jaar geleden) | Ja | Ja | | Offline-ondersteuning | Ja | Nee | | Alleen-lezen galerij | Ja | Ja | + +## Contributie-leden + + + + + +## Ster geschiedenis + + + + + + Star History Chart + + diff --git a/readme_i18n/README_pt_BR.md b/readme_i18n/README_pt_BR.md index 1e05b91ada..e1a4061ec9 100644 --- a/readme_i18n/README_pt_BR.md +++ b/readme_i18n/README_pt_BR.md @@ -18,7 +18,7 @@

- English + English Català Español Français @@ -30,6 +30,8 @@ Türkçe 中文 Русский + Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_ru_RU.md b/readme_i18n/README_ru_RU.md index fcde51e355..d972c2f7e1 100644 --- a/readme_i18n/README_ru_RU.md +++ b/readme_i18n/README_ru_RU.md @@ -9,15 +9,16 @@

- +

-

Immich - Высокопроизводительное решение для автономоного создания фото и видео архивов

+

Высокопроизводительное автономное решение для хранения и группировки фото и видео


- +

+ English Català Español Français @@ -30,15 +31,16 @@ 中文 Русский Português Brasileiro + Svenska العربية

## Предупреждение - ⚠️ Этот проект находится **в очень активной** разработке. -- ⚠️ Ожидайте ошибок и критических изменение. -- ⚠️ **Не используйте это приложение для бекапа ваших фото и видео.** -- ⚠️ Всегда следуйте [3-2-1](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) плану резервного копирования ваших драгоценных фото и видео! +- ⚠️ Ожидайте множество ошибок и глобальных изменений. +- ⚠️ **Не используйте это приложение как единственное хранилище своих фото и видео.** +- ⚠️ Всегда следуйте [плану резервного копирования «3-2-1»](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/ "Стратегии резервного копирования: Почему стратегия резервного копирования «3-2-1» — лучшая") для ваших драгоценных фотографий и видео! ## Содержание @@ -47,18 +49,18 @@ - [Демо](#demo) - [Возможности](#features) - [Введение](https://immich.app/docs/overview/introduction) -- [Инсталяция](https://immich.app/docs/install/requirements) -- [Гайд по доработке проекта](https://immich.app/docs/overview/support-the-project) +- [Установка](https://immich.app/docs/install/requirements) +- [Гид по доработке проекта](https://immich.app/docs/overview/support-the-project) ## Документация -Вы можете найти основную документация, включая инструкции по установке по ссылке https://immich.app/. +Вы можете прочитать инструкции по установке и остальную документацию [здесь](https://immich.app/) ## Демо -Вы можете посмотреть веб демо по ссылке https://demo.immich.app +Вы можете опробовать [демонстрационную версию](https://demo.immich.app/). -Для мобильного приложения вы можете использовать адрес `https://demo.immich.app/api` в поле `Server Endpoint URL` +Для мобильного приложения вы можете использовать адрес `https://demo.immich.app/api` в поле `Server Endpoint URL`. ```bash title="Демо доступ" Реквизиты доступа @@ -70,38 +72,56 @@ Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM ``` +## Активность + +![Activities](https://repobeats.axiom.co/api/embed/9e86d9dc3ddd137161f2f6d2e758d7863b1789cb.svg "Repobeats analytics image") + ## Возможности + | Возможности | Приложение | Веб | | --------------------------------------------------- | ---------- | --- | -| Выгрузка на сервер и просмотр видео и фото | Да | Да | -| Авто бекап когда приложение открыто | Да | Н/Д | -| Выбор альбома(ов) для бекапа | Да | Н/Д | -| загрузка с сервера фото и видео на устройство | Да | Да | +| Загрузка на сервер и просмотр видео и фото | Да | Да | +| Автоматический бекап, когда приложение открыто | Да | Н/Д | +| Предотвращение дупликации данных | Да | Да | +| Выбор альбома (-ов) для бекапа | Да | Н/Д | +| Скачивание с сервера фото и видео на устройство | Да | Да | | Поддержка нескольких пользователей | Да | Да | | Альбомы и общие альбомы | Да | Да | | Прокручиваемая/перетаскиваемая полоса прокрутки | Да | Да | -| Поддержка формата RAW | Да | Да | +| Поддержка raw-форматов | Да | Да | | Просмотр метаданных (EXIF, map) | Да | Да | | Поиск до метаданным, объектам, лицам и CLIP | Да | Да | -| Административные функци (управление пользователями) | Нет | Да | -| Фоновый бекпа | Да | Н/Д | +| Административные функции (управление пользователями)| Нет | Да | +| Фоновое резервное копирование | Да | Н/Д | | Виртуальная прокрутка | Да | Да | | Поддержка OAuth | Да | Да | | Ключи API | Н/Д | Да | -| LivePhoto/MotionPhoto бекап и воспроизведение | Да | Да | +| LivePhoto/MotionPhoto воспроизведение и бекап | Да | Да | +| Поддержка отображения изображений 360° | Нет | Да | | Настраиваемая структура хранилища | Да | Да | -| Публичные альбомы | Нет | Да | -| Архив и Избранное | Да | Да | +| Общий доступ к контенту | Нет | Да | +| Архив и избранное | Да | Да | | Мировая карта | Да | Да | | Совместное использование | Да | Да | -| Распознавание лиц и группировка по лицам | Да | Да | -| В этот день (x лет назад) | Да | Да | +| Распознавание и группировка по лицам | Да | Да | +| Воспоминания (в этот день x лет назад) | Да | Да | | Работа без интернета | Да | Нет | -| Галлереи только для просмотра | Да | Да | -| Колллажи | Да | Да | +| Галереи только для просмотра | Да | Да | +| Коллажи | Да | Да | ## Авторы + + +## Star History + + + + + + Star History Chart + + diff --git a/readme_i18n/README_sv_SE.md b/readme_i18n/README_sv_SE.md new file mode 100644 index 0000000000..05bcdec11b --- /dev/null +++ b/readme_i18n/README_sv_SE.md @@ -0,0 +1,129 @@ +

+
+ License: AGPLv3 + + Discord + +
+
+

+ +

+ +

+

Högpresterande self-hostad lösning för hantering av foton och videor

+
+ + + +
+

+ + English + Català + Español + Deutsch + Français + Italiano + 日本語 + 한국어 + Deutsch + Nederlands + Türkçe + 中文 + Русский + Português Brasileiro + العربية +

+ +## Ansvarsfriskrivning + +- ⚠️ Projektet är under **mycket aktiv** utveckling. +- ⚠️ Förvänta dig buggar och brytande förändringar. +- ⚠️ **Använd inte appen som enda lagringssätt för dina foton och videor.** +- ⚠️ Tillämpa alltid [3-2-1](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/)-strategin för säkerhetskopiering av dina foton och videor! + +## Innehåll + +- [Officiell Dokumentation](https://immich.app/docs) +- [Roadmap](https://github.com/orgs/immich-app/projects/1) +- [Demo](#demo) +- [Funktioner](#features) +- [Introduktion](https://immich.app/docs/overview/introduction) +- [Installation](https://immich.app/docs/install/requirements) +- [Riktlinjer för Bidrag](https://immich.app/docs/overview/support-the-project) + +## Dokumentation + +Dokumentation och installationsguider hittas på https://imiich.app/. + +## Demo + +Ett webb-demo finns att testa på https://demo.immich.app + +Använd `https://demo.immich.app/api` i mobilappen som `Server Endpoint URL` + +```bash title="Inloggningsuppgifter För Demo" +Inloggsningsuppgifter +epost: demo@immich.app +lösenord: demo +``` + +``` +Spec: Free-tier Oracle VM - Amsterdam - 2.4Ghz quad-core ARM64 CPU, 24GB RAM +``` + +## Aktiviteter + +![Activities](https://repobeats.axiom.co/api/embed/9e86d9dc3ddd137161f2f6d2e758d7863b1789cb.svg "Repobeats analytics image") + +## Funktioner + + +| Funktioner | Mobil | Webb | +| :-----------------------------------------------------------| ----- | ---- | +| Ladda upp och visa videor och foton | Ja | Ja | +| Automatisk säkerhetskopiering när appen öppnas | Ja | N/A | +| Förhindra duplicering av resurser | Ja | Ja | +| Valbara album för säkerhetskopiering | Ja | N/A | +| Ladda ner foton och videor lokalt till en enhet | Ja | Ja | +| Stöd för flera användare | Ja | Ja | +| Album and Delade album | Ja | Ja | +| Rullningslist | Ja | Ja | +| Stöd för råformat | Ja | Ja | +| Visning av metadata (EXIF, karta) | Ja | Ja | +| Sök via metadata, objekt, ansikten och CLIP | Ja | Ja | +| Administrative functions (user management) | Nej | Ja | +| Administrativa funktioner (hantering av användare) | Nej | Ja | +| Säkerhetskopiering i bakgrunden | Ja | N/A | +| Virtuell skroll | Ja | Ja | +| Stöd för OAuth | Ja | Ja | +| API-nycklar | N/A | Ja | +| Säkerhetskopiering och uppspelning av LivePhoto/MotionPhoto | Ja | Ja | +| Stöd för visning av 360-graders bilder | Nej | Ja | +| Användardefinierad lagringsstruktur | Ja | Ja | +| Publik Delning | Nej | Ja | +| Arkiv och Favoriter | Ja | Ja | +| Världskarta | Ja | Ja | +| Dela med Partner | Ja | Ja | +| Ansiktsigenkänning och klustring | Ja | Ja | +| Minnen (x år sedan) | Ja | Ja | +| Offline-stöd | Ja | Nej | +| Skrivskyddat galleri | Ja | Ja | +| Bildstapling | Ja | Ja | + +## Medverkande + + + + + +## Stjärn-Historik + + + + + + Star History Chart + + diff --git a/readme_i18n/README_tr_TR.md b/readme_i18n/README_tr_TR.md index 60dc40eb1b..b1b4b946b7 100644 --- a/readme_i18n/README_tr_TR.md +++ b/readme_i18n/README_tr_TR.md @@ -27,8 +27,11 @@ 한국어 Deutsch Nederlands + Türkçe 中文 + Русский Português Brasileiro + Svenska العربية

diff --git a/readme_i18n/README_zh_CN.md b/readme_i18n/README_zh_CN.md index 7129e59791..dbef824ab6 100644 --- a/readme_i18n/README_zh_CN.md +++ b/readme_i18n/README_zh_CN.md @@ -34,6 +34,7 @@ Türkçe Русский Português Brasileiro + Svenska العربية

diff --git a/server/.eslintrc.js b/server/.eslintrc.js index 79c48c4015..243f1b11e0 100644 --- a/server/.eslintrc.js +++ b/server/.eslintrc.js @@ -25,6 +25,7 @@ module.exports = { 'unicorn/prefer-event-target': 'off', 'unicorn/no-thenable': 'off', 'unicorn/import-style': 'off', + 'unicorn/prefer-structured-clone': 'off', '@typescript-eslint/await-thenable': 'error', '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-misused-promises': 'error', diff --git a/server/.nvmrc b/server/.nvmrc index 95267e9aae..973f49d55c 100644 --- a/server/.nvmrc +++ b/server/.nvmrc @@ -1 +1 @@ -v20.12 +20.13 diff --git a/server/Dockerfile b/server/Dockerfile index 205eaeb208..ab5a730d37 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,5 +1,5 @@ # dev build -FROM ghcr.io/immich-app/base-server-dev:20240507@sha256:ca3b8f7ca4ef72cb191b97d2715bfa0e3decdf39e666c5020536e41cf14cee1e as dev +FROM ghcr.io/immich-app/base-server-dev:20240521@sha256:1558bd68efc2c3a4bb4968428abd66b992a41a76afc1dbb601d2a7ea2a1f7c9a as dev RUN apt-get install --no-install-recommends -yqq tini WORKDIR /usr/src/app @@ -11,7 +11,7 @@ RUN npm ci && \ rm -rf node_modules/@img/sharp-linuxmusl-x64 COPY server . ENV PATH="${PATH}:/usr/src/app/bin" \ - NODE_ENV=development \ + IMMICH_ENV=development \ NVIDIA_DRIVER_CAPABILITIES=all \ NVIDIA_VISIBLE_DEVICES=all ENTRYPOINT ["tini", "--", "/bin/sh"] @@ -25,7 +25,7 @@ COPY --from=dev /usr/src/app/node_modules/@img ./node_modules/@img COPY --from=dev /usr/src/app/node_modules/exiftool-vendored.pl ./node_modules/exiftool-vendored.pl # web build -FROM node:iron-alpine3.18@sha256:fe31b16ddfb4ba4ae1a42ea540e9e44b916d754e67c64642b090839a9b2ed0ee as web +FROM node:iron-alpine3.18@sha256:53108f67824964a573ea435fed258f6cee4d88343e9859a99d356883e71b490c as web WORKDIR /usr/src/open-api/typescript-sdk COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./ @@ -41,7 +41,7 @@ RUN npm run build # prod build -FROM ghcr.io/immich-app/base-server-prod:20240507@sha256:1394878615cc665fd6b04f07b78d6586bb5d888423cdf8987cea072d1d72fd1f +FROM ghcr.io/immich-app/base-server-prod:20240521@sha256:894e6dff5617062c03e65d44d946169a60df51e232b63b6f38bac1c0d168d989 WORKDIR /usr/src/app ENV NODE_ENV=production \ @@ -61,3 +61,6 @@ ENV PATH="${PATH}:/usr/src/app/bin" VOLUME /usr/src/app/upload EXPOSE 3001 ENTRYPOINT ["tini", "--", "/bin/bash"] +CMD ["start.sh"] + +HEALTHCHECK CMD npm run healthcheck diff --git a/server/package-lock.json b/server/package-lock.json index 3beec64001..2fac212086 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich", - "version": "1.103.1", + "version": "1.105.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "immich", - "version": "1.103.1", + "version": "1.105.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@nestjs/bullmq": "^10.0.1", @@ -48,7 +48,7 @@ "mnemonist": "^0.39.8", "nest-commander": "^3.11.1", "nestjs-cls": "^4.3.0", - "nestjs-otel": "^5.1.5", + "nestjs-otel": "^6.0.0", "nodemailer": "^6.9.13", "openid-client": "^5.4.3", "pg": "^8.11.3", @@ -57,6 +57,7 @@ "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "sanitize-filename": "^1.6.3", + "semver": "^7.6.2", "sharp": "^0.33.0", "sirv": "^2.0.4", "thumbhash": "^0.1.1", @@ -83,6 +84,7 @@ "@types/node": "^20.5.7", "@types/nodemailer": "^6.4.14", "@types/picomatch": "^2.3.3", + "@types/semver": "^7.5.8", "@types/supertest": "^6.0.0", "@types/ua-parser-js": "^0.7.36", "@typescript-eslint/eslint-plugin": "^7.0.0", @@ -91,7 +93,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "mock-fs": "^5.2.0", "prettier": "^3.0.2", "prettier-plugin-organize-imports": "^3.2.3", @@ -342,9 +344,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "engines": { "node": ">=6.9.0" } @@ -1138,9 +1140,9 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz", - "integrity": "sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", "cpu": [ "arm64" ], @@ -1163,9 +1165,9 @@ } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.3.tgz", - "integrity": "sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", "cpu": [ "x64" ], @@ -1356,9 +1358,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.3.tgz", - "integrity": "sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", "cpu": [ "arm" ], @@ -1381,9 +1383,9 @@ } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.3.tgz", - "integrity": "sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", "cpu": [ "arm64" ], @@ -1406,9 +1408,9 @@ } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.3.tgz", - "integrity": "sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", "cpu": [ "s390x" ], @@ -1417,7 +1419,7 @@ "linux" ], "engines": { - "glibc": ">=2.28", + "glibc": ">=2.31", "node": "^18.17.0 || ^20.3.0 || >=21.0.0", "npm": ">=9.6.5", "pnpm": ">=7.1.0", @@ -1431,9 +1433,9 @@ } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.3.tgz", - "integrity": "sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", "cpu": [ "x64" ], @@ -1456,9 +1458,9 @@ } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.3.tgz", - "integrity": "sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", "cpu": [ "arm64" ], @@ -1481,9 +1483,9 @@ } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.3.tgz", - "integrity": "sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", "cpu": [ "x64" ], @@ -1506,15 +1508,15 @@ } }, "node_modules/@img/sharp-wasm32": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.3.tgz", - "integrity": "sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", "cpu": [ "wasm32" ], "optional": true, "dependencies": { - "@emnapi/runtime": "^1.1.0" + "@emnapi/runtime": "^1.1.1" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0", @@ -1527,9 +1529,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.3.tgz", - "integrity": "sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", "cpu": [ "ia32" ], @@ -1548,9 +1550,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.3.tgz", - "integrity": "sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", "cpu": [ "x64" ], @@ -2518,29 +2520,40 @@ "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==" }, "node_modules/@opentelemetry/api": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", - "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==", "engines": { "node": ">=8.0.0" } }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.1.tgz", + "integrity": "sha512-E3skn949Pk1z2XtXu/lxf6QAZpawuTM/IUEXcAzpiUkTd73Hmvw26FiN3cJuTmkpM5hZzHwkomVdtrh/n/zzwA==", + "dependencies": { + "@opentelemetry/api": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@opentelemetry/auto-instrumentations-node": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.46.0.tgz", - "integrity": "sha512-F8d8usvvpuEngiNSyHaT0QU6CEwg9q5LFXscSeU4qhFQ+n8eoWcifk3jBcytRLansljtQu1XGdC+dV1oqbIomQ==", + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.46.1.tgz", + "integrity": "sha512-s0CwmY9KYtPawOhV5YO2Gf62uVOQRNvT6Or8IZ0S4gr/kPVNhoMehTsQvqBwSWQfoFrkmW3KKOHiKJEp4dVGXg==", "dependencies": { "@opentelemetry/instrumentation": "^0.51.0", "@opentelemetry/instrumentation-amqplib": "^0.37.0", - "@opentelemetry/instrumentation-aws-lambda": "^0.41.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.41.1", "@opentelemetry/instrumentation-aws-sdk": "^0.41.0", "@opentelemetry/instrumentation-bunyan": "^0.38.0", "@opentelemetry/instrumentation-cassandra-driver": "^0.38.0", - "@opentelemetry/instrumentation-connect": "^0.36.0", + "@opentelemetry/instrumentation-connect": "^0.36.1", "@opentelemetry/instrumentation-cucumber": "^0.6.0", "@opentelemetry/instrumentation-dataloader": "^0.9.0", "@opentelemetry/instrumentation-dns": "^0.36.1", - "@opentelemetry/instrumentation-express": "^0.38.0", + "@opentelemetry/instrumentation-express": "^0.39.0", "@opentelemetry/instrumentation-fastify": "^0.36.1", "@opentelemetry/instrumentation-fs": "^0.12.0", "@opentelemetry/instrumentation-generic-pool": "^0.36.0", @@ -2570,7 +2583,7 @@ "@opentelemetry/instrumentation-undici": "^0.2.0", "@opentelemetry/instrumentation-winston": "^0.37.0", "@opentelemetry/resource-detector-alibaba-cloud": "^0.28.9", - "@opentelemetry/resource-detector-aws": "^1.4.2", + "@opentelemetry/resource-detector-aws": "^1.5.0", "@opentelemetry/resource-detector-azure": "^0.2.6", "@opentelemetry/resource-detector-container": "^0.3.9", "@opentelemetry/resource-detector-gcp": "^0.29.9", @@ -2584,47 +2597,10 @@ "@opentelemetry/api": "^1.4.1" } }, - "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.0.tgz", - "integrity": "sha512-FP2oN7mVPqcdxJDTTnKExj4mi91EH+DNuArKfHTjPuJWe2K1JfMIVXNfahw1h3onJxQnxS8K0stKkogX05s+Aw==", - "dependencies": { - "@opentelemetry/semantic-conventions": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/resources": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.0.tgz", - "integrity": "sha512-mxC7E7ocUS1tLzepnA7O9/G8G6ZTdjCH2pXme1DDDuCuk6n2/53GADX+GWBuyX0dfIxeMInIbJAdjlfN9GNr6A==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/auto-instrumentations-node/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.0.tgz", - "integrity": "sha512-yL0jI6Ltuz8R+Opj7jClGrul6pOoYrdfVmzQS4SITXRPH7I5IRZbrwe/6/v8v4WYMa6MYZG480S1+uc/IGfqsA==", - "engines": { - "node": ">=14" - } - }, "node_modules/@opentelemetry/context-async-hooks": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.24.0.tgz", - "integrity": "sha512-s7xaQ9ifDpJvwbWRLkZD/J5hY35w+MECm4TQUkg6szRcny9lf6oVhWij4w3JJFQgvHQMXU7oXOpX8Z05HxV/8g==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.24.1.tgz", + "integrity": "sha512-R5r6DO4kgEOVBxFXhXjwospLQkv+sYxwCfjvoZBe7Zm6KKXAV9kDSJhi/D1BweowdZmO+sdbENLs374gER8hpQ==", "engines": { "node": ">=14" }, @@ -2633,11 +2609,11 @@ } }, "node_modules/@opentelemetry/core": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.23.0.tgz", - "integrity": "sha512-hdQ/a9TMzMQF/BO8Cz1juA43/L5YGtCSiKoOHmrTEf7VMDAZgy8ucpWx3eQTnQ3gBloRcWtzvcrMZABC3PTSKQ==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.1.tgz", + "integrity": "sha512-wMSGfsdmibI88K9wB498zXY04yThPexo8jvwNNlm542HZB7XrrMRBbAyKJqG8qDRJwIBdBrPMi4V9ZPW/sqrcg==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.23.0" + "@opentelemetry/semantic-conventions": "1.24.1" }, "engines": { "node": ">=14" @@ -2647,13 +2623,13 @@ } }, "node_modules/@opentelemetry/exporter-prometheus": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.51.0.tgz", - "integrity": "sha512-oT5l3Mff1U40U5Knr/XZFkYlvvLVVBGsM7u6cU99YZRlNX2uovGImZIeAhy60i178GVg2dpN1d5iQHYvN457aQ==", + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.51.1.tgz", + "integrity": "sha512-c8TrTlLm9JJRIHW6MtFv6ESoZRgXBXD/YrTRYylWiyYBOVbYHo1c5Qaw/j/thXDhkmYOYAn4LAhJZpLl5gBFEQ==", "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-metrics": "1.24.0" + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-metrics": "1.24.1" }, "engines": { "node": ">=14" @@ -2662,66 +2638,86 @@ "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.0.tgz", - "integrity": "sha512-FP2oN7mVPqcdxJDTTnKExj4mi91EH+DNuArKfHTjPuJWe2K1JfMIVXNfahw1h3onJxQnxS8K0stKkogX05s+Aw==", + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.51.1.tgz", + "integrity": "sha512-P9+Hkszih95ITvldGZ+kXvj9HpD1QfS+PwooyHK72GYA+Bgm+yUSAsDkUkDms8+s9HW6poxURv3LcjaMuBBpVQ==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.24.0" + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-grpc-exporter-base": "0.51.1", + "@opentelemetry/otlp-transformer": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/resources": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.0.tgz", - "integrity": "sha512-mxC7E7ocUS1tLzepnA7O9/G8G6ZTdjCH2pXme1DDDuCuk6n2/53GADX+GWBuyX0dfIxeMInIbJAdjlfN9GNr6A==", + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.51.1.tgz", + "integrity": "sha512-n+LhLPsX07URh+HhV2SHVSvz1t4G/l/CE5BjpmhAPqeTceFac1VpyQkavWEJbvnK5bUEXijWt4LxAxFpt2fXyw==", "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "@opentelemetry/otlp-transformer": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/sdk-metrics": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.0.tgz", - "integrity": "sha512-4tJ+E6N019OZVB/nUW/LoK9xHxfeh88TCoaTqHeLBE9wLYfi6irWW6J9cphMav7J8Qk0D5b7/RM4VEY4dArWOA==", + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.51.1.tgz", + "integrity": "sha512-SE9f0/6V6EeXC9i+WA4WFjS1EYgaBCpAnI5+lxWvZ7iO7EU1IvHvZhP6Kojr0nLldo83gqg6G7OWFqsID3uF+w==", "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "lodash.merge": "^4.6.2" + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "@opentelemetry/otlp-proto-exporter-base": "0.51.1", + "@opentelemetry/otlp-transformer": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.0.tgz", - "integrity": "sha512-yL0jI6Ltuz8R+Opj7jClGrul6pOoYrdfVmzQS4SITXRPH7I5IRZbrwe/6/v8v4WYMa6MYZG480S1+uc/IGfqsA==", + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.24.1.tgz", + "integrity": "sha512-+Rl/VFmu2n6eaRMnVbyfZx1DqR/1KNyWebYuHyQBZaEAVIn/ZLgmofRpXN1X2nhJ4BNaptQUNxAstCYYz6dKoQ==", + "dependencies": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" + }, "engines": { "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" } }, "node_modules/@opentelemetry/host-metrics": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/host-metrics/-/host-metrics-0.32.2.tgz", - "integrity": "sha512-zrnls0CWMAYEUHQbdplY0M6v3L/cgEoiwpjAnHAaG7M3ICs7K4/Hms1UlVMDydEvNDkQilx63scpDcE1/M5V4A==", + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/host-metrics/-/host-metrics-0.35.1.tgz", + "integrity": "sha512-d49/Un/pzqUSsGLeO8PvrX2bLxVAORcaoL3nxjJCzGikXA6gjWXxGOfT8D4qePlgnocozppWszefMHoRFS2MsA==", "dependencies": { "@opentelemetry/sdk-metrics": "^1.8.0", - "systeminformation": "^5.0.0" + "systeminformation": "^5.21.20" }, "engines": { "node": ">=14" @@ -2766,14 +2762,14 @@ } }, "node_modules/@opentelemetry/instrumentation-aws-lambda": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.41.0.tgz", - "integrity": "sha512-TeK7ZGtmEDqkfuwyAvlexnG11e7kEux0PncShqdyst2h1k1nVKmwnY/woPCUcTyU08PX6fa9YEyJ9E+G6wZacQ==", + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.41.1.tgz", + "integrity": "sha512-/BLG+0DQr2tCILFGJKJH2Fg6eyjhqOlVflYpNddUEXnzyQ/PAhTdgirkqbICFgeSW2XYcEY9zXpuRldrVNw9cA==", "dependencies": { "@opentelemetry/instrumentation": "^0.51.0", "@opentelemetry/propagator-aws-xray": "^1.3.1", "@opentelemetry/resources": "^1.8.0", - "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0", "@types/aws-lambda": "8.10.122" }, "engines": { @@ -2816,17 +2812,6 @@ "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-bunyan/node_modules/@opentelemetry/api-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.0.tgz", - "integrity": "sha512-m/jtfBPEIXS1asltl8fPQtO3Sb1qMpuL61unQajUmM8zIxeMF1AlqzWXM3QedcYgTTFiJCew5uJjyhpmqhc0+g==", - "dependencies": { - "@opentelemetry/api": "^1.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/@opentelemetry/instrumentation-cassandra-driver": { "version": "0.38.0", "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.38.0.tgz", @@ -2843,13 +2828,13 @@ } }, "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.36.0.tgz", - "integrity": "sha512-k9++bmJZ9zDEs3u3DnKTn2l7QTiNFg3gPx7G9rW0TPnP+xZoBSBTrEcGYBaqflQlrFG23Q58+X1sM2ayWPv5Fg==", + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.36.1.tgz", + "integrity": "sha512-xI5Q/CMmzBmHshPnzzjD19ptFaYO/rQWzokpNio4QixZYWhJsa35QgRvN9FhPkwgtuJIbt/CWWAufJ3egJNHEA==", "dependencies": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.51.0", - "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0", "@types/connect": "3.4.36" }, "engines": { @@ -2905,9 +2890,9 @@ } }, "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.38.0.tgz", - "integrity": "sha512-izId/qcgMgfWV292ZI9b9E7HdV9446vi0Z5zu5fSlt4MF+R6LZXbZLTQAaboJ4Y2+JbtH7apvko1DF93qTFtqw==", + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.39.0.tgz", + "integrity": "sha512-AG8U7z7D0JcBu/7dDcwb47UMEzj9/FMiJV2iQZqrsZnxR3FjB9J9oIH2iszJYci2eUdp2WbdvtpD9RV/zmME5A==", "dependencies": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.51.0", @@ -3397,7 +3382,7 @@ "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-winston/node_modules/@opentelemetry/api-logs": { + "node_modules/@opentelemetry/instrumentation/node_modules/@opentelemetry/api-logs": { "version": "0.51.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.0.tgz", "integrity": "sha512-m/jtfBPEIXS1asltl8fPQtO3Sb1qMpuL61unQajUmM8zIxeMF1AlqzWXM3QedcYgTTFiJCew5uJjyhpmqhc0+g==", @@ -3408,15 +3393,70 @@ "node": ">=14" } }, - "node_modules/@opentelemetry/instrumentation/node_modules/@opentelemetry/api-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.0.tgz", - "integrity": "sha512-m/jtfBPEIXS1asltl8fPQtO3Sb1qMpuL61unQajUmM8zIxeMF1AlqzWXM3QedcYgTTFiJCew5uJjyhpmqhc0+g==", + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.51.1.tgz", + "integrity": "sha512-UYlnOYyDdzo1Gw559EHCzru0RwhvuXCwoH8jGo9J4gO1TE58GjnEmIjomMsKBCym3qWNJfIQXw+9SZCV0DdQNg==", "dependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/core": "1.24.1" }, "engines": { "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.51.1.tgz", + "integrity": "sha512-ZAS+4pq8o7dsugGTwV9s6JMKSxi+guIHdn0acOv0bqj26e9pWDFx5Ky+bI0aY46uR9Y0JyXqY+KAEYM/SO3DFA==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "protobufjs": "^7.2.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-proto-exporter-base": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.51.1.tgz", + "integrity": "sha512-gxxxwfk0inDMb5DLeuxQ3L8TtptxSiTNHE4nnAJH34IQXAVRhXSXW1rK8PmDKDngRPIZ6J7ncUCjjIn8b+AgqQ==", + "dependencies": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "protobufjs": "^7.2.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.51.1.tgz", + "integrity": "sha512-OppYOXwV9LQqqtYUCywqoOqX/JT9LQ5/FMuPZ//eTkvuHdUC4ZMwz2c6uSoT2R90GWvvGnF1iEqTGyTT3xAt2Q==", + "dependencies": { + "@opentelemetry/api-logs": "0.51.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-logs": "0.51.1", + "@opentelemetry/sdk-metrics": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" } }, "node_modules/@opentelemetry/propagation-utils": { @@ -3444,6 +3484,34 @@ "@opentelemetry/api": "^1.0.0" } }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.24.1.tgz", + "integrity": "sha512-nda97ZwhpZKyUJTXqQuKzNhPMUgMLunbbGWn8kroBwegn+nh6OhtyGkrVQsQLNdVKJl0KeB5z0ZgeWszrYhwFw==", + "dependencies": { + "@opentelemetry/core": "1.24.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.24.1.tgz", + "integrity": "sha512-7bRBJn3FG1l195A1m+xXRHvgzAOBsfmRi9uZ5Da18oTh7BLmNDiA8+kpk51FpTsU1PCikPVpRDNPhKVB6lyzZg==", + "dependencies": { + "@opentelemetry/core": "1.24.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, "node_modules/@opentelemetry/redis-common": { "version": "0.36.2", "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", @@ -3468,9 +3536,9 @@ } }, "node_modules/@opentelemetry/resource-detector-aws": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.4.2.tgz", - "integrity": "sha512-Rt4cztIz8UZZ32wRbotKPVbkRfukiMM8xfzf2C1M+Puv91Cw6kDJHAfWCqkx7FdNe0e6aF4u2lkFweE1849RCg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.5.0.tgz", + "integrity": "sha512-JNk/kSzzNQaiMo/F0b/bm8S3Qtr/m89BckN9B4U/cPHSqKLdxX03vgRBOqkXJ5KlAD8kc6K1Etcr8QfvGw6+uA==", "dependencies": { "@opentelemetry/core": "^1.0.0", "@opentelemetry/resources": "^1.0.0", @@ -3531,12 +3599,12 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.23.0.tgz", - "integrity": "sha512-iPRLfVfcEQynYGo7e4Di+ti+YQTAY0h5mQEUJcHlU9JOqpb4x965O6PZ+wMcwYVY63G96KtdS86YCM1BF1vQZg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.1.tgz", + "integrity": "sha512-cyv0MwAaPF7O86x5hk3NNgenMObeejZFLJJDVuSeSMIsknlsj3oOZzRv3qSzlwYomXsICfBeFFlxwHQte5mGXQ==", "dependencies": { - "@opentelemetry/core": "1.23.0", - "@opentelemetry/semantic-conventions": "1.23.0" + "@opentelemetry/core": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" }, "engines": { "node": ">=14" @@ -3545,13 +3613,29 @@ "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.23.0.tgz", - "integrity": "sha512-4OkvW6+wST4h6LFG23rXSTf6nmTf201h9dzq7bE0z5R9ESEVLERZz6WXwE7PSgg1gdjlaznm1jLJf8GttypFDg==", + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.51.1.tgz", + "integrity": "sha512-ULQQtl82b673PpZc5/0EtH4V+BrwVOgKJZEB7tYZnGTG3I98tQVk89S9/JSixomDr++F4ih+LSJTCqIKBz+MQQ==", "dependencies": { - "@opentelemetry/core": "1.23.0", - "@opentelemetry/resources": "1.23.0", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.9.0", + "@opentelemetry/api-logs": ">=0.39.1" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.1.tgz", + "integrity": "sha512-FrAqCbbGao9iKI+Mgh+OsC9+U2YMoXnlDHe06yH7dvavCKzE3S892dGtX54+WhSFVxHR/TMRVJiK/CV93GR0TQ==", + "dependencies": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", "lodash.merge": "^4.6.2" }, "engines": { @@ -3562,23 +3646,23 @@ } }, "node_modules/@opentelemetry/sdk-node": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.51.0.tgz", - "integrity": "sha512-MrPXDQsTAj3lcY8YUCjb7dvSXVZ5jG6wmjD2LB68V1rsLBdP8j70jsI9GaKijY7QB6psbLq6apO1vYeim5U7aw==", + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.51.1.tgz", + "integrity": "sha512-GgmNF9C+6esr8PIJxCqHw84rEOkYm6XdFWZ2+Wyc3qaUt92ACoN7uSw5iKNvaUq62W0xii1wsGxwHzyENtPP8w==", "dependencies": { - "@opentelemetry/api-logs": "0.51.0", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/exporter-trace-otlp-grpc": "0.51.0", - "@opentelemetry/exporter-trace-otlp-http": "0.51.0", - "@opentelemetry/exporter-trace-otlp-proto": "0.51.0", - "@opentelemetry/exporter-zipkin": "1.24.0", - "@opentelemetry/instrumentation": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-logs": "0.51.0", - "@opentelemetry/sdk-metrics": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0", - "@opentelemetry/sdk-trace-node": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" + "@opentelemetry/api-logs": "0.51.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/exporter-trace-otlp-grpc": "0.51.1", + "@opentelemetry/exporter-trace-otlp-http": "0.51.1", + "@opentelemetry/exporter-trace-otlp-proto": "0.51.1", + "@opentelemetry/exporter-zipkin": "1.24.1", + "@opentelemetry/instrumentation": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-logs": "0.51.1", + "@opentelemetry/sdk-metrics": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1", + "@opentelemetry/sdk-trace-node": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" }, "engines": { "node": ">=14" @@ -3587,23 +3671,44 @@ "@opentelemetry/api": ">=1.3.0 <1.9.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/api-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.0.tgz", - "integrity": "sha512-m/jtfBPEIXS1asltl8fPQtO3Sb1qMpuL61unQajUmM8zIxeMF1AlqzWXM3QedcYgTTFiJCew5uJjyhpmqhc0+g==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/instrumentation": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.51.1.tgz", + "integrity": "sha512-JIrvhpgqY6437QIqToyozrUG1h5UhwHkaGK/WAX+fkrpyPtc+RO5FkRtUd9BH0MibabHHvqsnBGKfKVijbmp8w==", "dependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api-logs": "0.51.1", + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.7.4", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" }, "engines": { "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.0.tgz", - "integrity": "sha512-FP2oN7mVPqcdxJDTTnKExj4mi91EH+DNuArKfHTjPuJWe2K1JfMIVXNfahw1h3onJxQnxS8K0stKkogX05s+Aw==", + "node_modules/@opentelemetry/sdk-node/node_modules/import-in-the-middle": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.7.4.tgz", + "integrity": "sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.24.0" + "acorn": "^8.8.2", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.1.tgz", + "integrity": "sha512-zz+N423IcySgjihl2NfjBf0qw1RWe11XIAWVrTNOSSI6dtSPJiVom2zipFB2AEEtJWpv0Iz6DY6+TjnyTV5pWg==", + "dependencies": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" }, "engines": { "node": ">=14" @@ -3612,246 +3717,16 @@ "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-trace-otlp-grpc": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.51.0.tgz", - "integrity": "sha512-xQpxKzS8ZnxYCa1v+3EKWhwMrSK3+RezpJ+AEKaP2pf2QbLfHt7kKfSn7niR2u3A1Tbe2aC7Ptt9+MafhThOOQ==", + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.24.1.tgz", + "integrity": "sha512-/FZX8uWaGIAwsDhqI8VvQ+qWtfMNlXjaFYGc+vmxgdRFppCSSIRwrPyIhJO1qx61okyYhoyxVEZAfoiNxrfJCg==", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.51.0", - "@opentelemetry/otlp-transformer": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.51.0.tgz", - "integrity": "sha512-zODqnLZmPOxj9CarFv0TrVlx9mgj0TfCMCiUiTdNi9iA2rgdKVo+bjJjpYF6LCTJOQCR5TScAUCKyzwkgDI+iA==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "@opentelemetry/otlp-transformer": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-trace-otlp-proto": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.51.0.tgz", - "integrity": "sha512-Fi7r0iMqGoFCQQ+WY0pYOWp395vdinZJIkYKnNbnreHxAN/kVDBl2FxbV3DeOKuRxEY08Gyb9ggPf+Zrqp7l/w==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "@opentelemetry/otlp-proto-exporter-base": "0.51.0", - "@opentelemetry/otlp-transformer": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-zipkin": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.24.0.tgz", - "integrity": "sha512-QeGv0PHONswmu567pf9QliJ6s6DgCu5+ziF+soNS1LTcr1VRRVLViYLmGxmzDFUC48sjNTu7sumcKT0nJXsGBw==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.51.0.tgz", - "integrity": "sha512-hR4c9vWVz1QgzCBSyy9zSDkvfTgaK96E6/tfVP6O4dzdZW9HqWimA3lXV/KXadEGqShvM4GToz9EHp2A5RU5bQ==", - "dependencies": { - "@opentelemetry/core": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-grpc-exporter-base": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.51.0.tgz", - "integrity": "sha512-oTRtDvvB0bTRTBVrvKA/oM1gIAqQ6DVQS07pvqiL1cZS8wBrGgpw+2iTd0nV661Y/MhDn/kNWp8lRhMEIKN9bw==", - "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "protobufjs": "^7.2.3" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-proto-exporter-base": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.51.0.tgz", - "integrity": "sha512-WDANDLSUh11Gu5o6iCzmjZraIv5bK8z1L/t6lxQ2NeEKiKUPo5pVOBBQQC/yAQU2yeqkiO1GRCieH+XahZf60A==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "protobufjs": "^7.2.3" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.51.0.tgz", - "integrity": "sha512-ylLgx2xumVoSefDHP9GMAU/LG+TU3+8eacVDXV5o1RqWxsdVOaQmCTY0XyDgeRTn6hIOVAq/HHQbRq3iWOrt2A==", - "dependencies": { - "@opentelemetry/api-logs": "0.51.0", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-logs": "0.51.0", - "@opentelemetry/sdk-metrics": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/propagator-b3": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.24.0.tgz", - "integrity": "sha512-7TMIDE4+NO5vnkor+zned42wqca+hmhW5gWKhmYjUHC5B5uojo1PvtmBrd7kigFu96XvL4ZUWVzibWRWIQ/++Q==", - "dependencies": { - "@opentelemetry/core": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/propagator-jaeger": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.24.0.tgz", - "integrity": "sha512-r3MX3AmJiUeiWTXSDOdwBeaO+ahvWcFCpuKxmhhsH8Q8LqDnjhNd3krqBh4Qsq9wa0WhWtiQaDs/NOCWoMOlOw==", - "dependencies": { - "@opentelemetry/core": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/resources": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.0.tgz", - "integrity": "sha512-mxC7E7ocUS1tLzepnA7O9/G8G6ZTdjCH2pXme1DDDuCuk6n2/53GADX+GWBuyX0dfIxeMInIbJAdjlfN9GNr6A==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.51.0.tgz", - "integrity": "sha512-K4fMBRFD8hQ6khk0rvYFuo6L9ymeGgByir6BcuFIgQuQ00OhYwBi9AruZz5V733Ejq7P8ObR3YyubkOUIbeVAw==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.9.0", - "@opentelemetry/api-logs": ">=0.39.1" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-metrics": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.0.tgz", - "integrity": "sha512-4tJ+E6N019OZVB/nUW/LoK9xHxfeh88TCoaTqHeLBE9wLYfi6irWW6J9cphMav7J8Qk0D5b7/RM4VEY4dArWOA==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "lodash.merge": "^4.6.2" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.0.tgz", - "integrity": "sha512-H9sLETZ4jw9UJ3totV8oM5R0m4CW0ZIOLfp4NV3g0CM8HD5zGZcaW88xqzWDgiYRpctFxd+WmHtGX/Upoa2vRg==", - "dependencies": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-node": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.24.0.tgz", - "integrity": "sha512-QgByHmM9uloTpcYEEyW9YJEIMKHFSIM677RH9pJPWWwtM2NQFbEp/8HIJw80Ymtaz6cAxg1Kay1ByqIVzq3t5g==", - "dependencies": { - "@opentelemetry/context-async-hooks": "1.24.0", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/propagator-b3": "1.24.0", - "@opentelemetry/propagator-jaeger": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0", + "@opentelemetry/context-async-hooks": "1.24.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/propagator-b3": "1.24.1", + "@opentelemetry/propagator-jaeger": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1", "semver": "^7.5.2" }, "engines": { @@ -3861,18 +3736,10 @@ "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.0.tgz", - "integrity": "sha512-yL0jI6Ltuz8R+Opj7jClGrul6pOoYrdfVmzQS4SITXRPH7I5IRZbrwe/6/v8v4WYMa6MYZG480S1+uc/IGfqsA==", - "engines": { - "node": ">=14" - } - }, "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.23.0.tgz", - "integrity": "sha512-MiqFvfOzfR31t8cc74CTP1OZfz7MbqpAnLCra8NqQoaHJX6ncIRTdYOQYBDQ2uFISDq0WY8Y9dDTWvsgzzBYRg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.1.tgz", + "integrity": "sha512-VkliWlS4/+GHLLW7J/rVBA00uXus1SWvwFvcUDxDwmFxYfg/2VI6ekwdXS28cjI8Qz2ky2BzG8OUHo+WeYIWqw==", "engines": { "node": ">=14" } @@ -5275,14 +5142,14 @@ "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" }, "node_modules/@swc/core": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.17.tgz", - "integrity": "sha512-tq+mdWvodMBNBBZbwFIMTVGYHe9N7zvEaycVVjfvAx20k1XozHbHhRv+9pEVFJjwRxLdXmtvFZd3QZHRAOpoNQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", + "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", "devOptional": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.2", - "@swc/types": "^0.1.5" + "@swc/types": "0.1.7" }, "engines": { "node": ">=10" @@ -5292,16 +5159,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.4.17", - "@swc/core-darwin-x64": "1.4.17", - "@swc/core-linux-arm-gnueabihf": "1.4.17", - "@swc/core-linux-arm64-gnu": "1.4.17", - "@swc/core-linux-arm64-musl": "1.4.17", - "@swc/core-linux-x64-gnu": "1.4.17", - "@swc/core-linux-x64-musl": "1.4.17", - "@swc/core-win32-arm64-msvc": "1.4.17", - "@swc/core-win32-ia32-msvc": "1.4.17", - "@swc/core-win32-x64-msvc": "1.4.17" + "@swc/core-darwin-arm64": "1.5.7", + "@swc/core-darwin-x64": "1.5.7", + "@swc/core-linux-arm-gnueabihf": "1.5.7", + "@swc/core-linux-arm64-gnu": "1.5.7", + "@swc/core-linux-arm64-musl": "1.5.7", + "@swc/core-linux-x64-gnu": "1.5.7", + "@swc/core-linux-x64-musl": "1.5.7", + "@swc/core-win32-arm64-msvc": "1.5.7", + "@swc/core-win32-ia32-msvc": "1.5.7", + "@swc/core-win32-x64-msvc": "1.5.7" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -5313,9 +5180,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.17.tgz", - "integrity": "sha512-HVl+W4LezoqHBAYg2JCqR+s9ife9yPfgWSj37iIawLWzOmuuJ7jVdIB7Ee2B75bEisSEKyxRlTl6Y1Oq3owBgw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz", + "integrity": "sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==", "cpu": [ "arm64" ], @@ -5329,9 +5196,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.17.tgz", - "integrity": "sha512-WYRO9Fdzq4S/he8zjW5I95G1zcvyd9yyD3Tgi4/ic84P5XDlSMpBDpBLbr/dCPjmSg7aUXxNQqKqGkl6dQxYlA==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz", + "integrity": "sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==", "cpu": [ "x64" ], @@ -5345,9 +5212,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.17.tgz", - "integrity": "sha512-cgbvpWOvtMH0XFjvwppUCR+Y+nf6QPaGu6AQ5hqCP+5Lv2zO5PG0RfasC4zBIjF53xgwEaaWmGP5/361P30X8Q==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz", + "integrity": "sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==", "cpu": [ "arm" ], @@ -5361,9 +5228,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.17.tgz", - "integrity": "sha512-l7zHgaIY24cF9dyQ/FOWbmZDsEj2a9gRFbmgx2u19e3FzOPuOnaopFj0fRYXXKCmtdx+anD750iBIYnTR+pq/Q==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz", + "integrity": "sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==", "cpu": [ "arm64" ], @@ -5377,9 +5244,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.17.tgz", - "integrity": "sha512-qhH4gr9gAlVk8MBtzXbzTP3BJyqbAfUOATGkyUtohh85fPXQYuzVlbExix3FZXTwFHNidGHY8C+ocscI7uDaYw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz", + "integrity": "sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==", "cpu": [ "arm64" ], @@ -5393,9 +5260,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.17.tgz", - "integrity": "sha512-vRDFATL1oN5oZMImkwbgSHEkp8xG1ofEASBypze01W1Tqto8t+yo6gsp69wzCZBlxldsvPpvFZW55Jq0Rn+UnA==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz", + "integrity": "sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==", "cpu": [ "x64" ], @@ -5409,9 +5276,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.17.tgz", - "integrity": "sha512-zQNPXAXn3nmPqv54JVEN8k2JMEcMTQ6veVuU0p5O+A7KscJq+AGle/7ZQXzpXSfUCXlLMX4wvd+rwfGhh3J4cw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz", + "integrity": "sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==", "cpu": [ "x64" ], @@ -5425,9 +5292,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.17.tgz", - "integrity": "sha512-z86n7EhOwyzxwm+DLE5NoLkxCTme2lq7QZlDjbQyfCxOt6isWz8rkW5QowTX8w9Rdmk34ncrjSLvnHOeLY17+w==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz", + "integrity": "sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==", "cpu": [ "arm64" ], @@ -5441,9 +5308,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.17.tgz", - "integrity": "sha512-JBwuSTJIgiJJX6wtr4wmXbfvOswHFj223AumUrK544QV69k60FJ9q2adPW9Csk+a8wm1hLxq4HKa2K334UHJ/g==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz", + "integrity": "sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==", "cpu": [ "ia32" ], @@ -5457,9 +5324,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.17.tgz", - "integrity": "sha512-jFkOnGQamtVDBm3MF5Kq1lgW8vx4Rm1UvJWRUfg+0gx7Uc3Jp3QMFeMNw/rDNQYRDYPG3yunCC+2463ycd5+dg==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", + "integrity": "sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==", "cpu": [ "x64" ], @@ -5486,9 +5353,9 @@ } }, "node_modules/@swc/types": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.6.tgz", - "integrity": "sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", + "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", "dependencies": { "@swc/counter": "^0.1.3" } @@ -5818,9 +5685,9 @@ } }, "node_modules/@types/lodash": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", - "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.3.tgz", + "integrity": "sha512-zmNrEJaBvNskZXQWaUQq6bktF4IDGVfDS78M+YEk5aCn9M/b94/mB/6WCyfH2/MjwBdc6QuOor95CIlKWYRL3A==", "dev": true }, "node_modules/@types/luxon": { @@ -5874,9 +5741,9 @@ } }, "node_modules/@types/node": { - "version": "20.12.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz", - "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "dependencies": { "undici-types": "~5.26.4" } @@ -6127,21 +5994,19 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", - "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz", + "integrity": "sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/type-utils": "7.9.0", + "@typescript-eslint/utils": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -6162,15 +6027,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", - "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.9.0.tgz", + "integrity": "sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4" }, "engines": { @@ -6190,13 +6055,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz", + "integrity": "sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0" + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6207,13 +6072,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", - "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz", + "integrity": "sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/utils": "7.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6234,9 +6099,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.9.0.tgz", + "integrity": "sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6247,13 +6112,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz", + "integrity": "sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6299,18 +6164,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.9.0.tgz", + "integrity": "sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6324,12 +6186,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz", + "integrity": "sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/types": "7.9.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -6346,9 +6208,9 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vitest/coverage-v8": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.3.tgz", - "integrity": "sha512-DPyGSu/fPHOJuPxzFSQoT4N/Fu/2aJfZRtEpEp8GI7NHsXBGE94CQ+pbEGBUMFjatsHPDJw/+TAF9r4ens2CNw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", + "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -6369,17 +6231,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.5.3" + "vitest": "1.6.0" } }, "node_modules/@vitest/expect": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.3.tgz", - "integrity": "sha512-y+waPz31pOFr3rD7vWTbwiLe5+MgsMm40jTZbQE8p8/qXyBX3CQsIXRx9XK12IbY7q/t5a5aM/ckt33b4PxK2g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -6387,12 +6249,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz", - "integrity": "sha512-7PlfuReN8692IKQIdCxwir1AOaP5THfNkp0Uc4BKr2na+9lALNit7ub9l3/R7MP8aV61+mHKRGiqEKRIwu6iiQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.3", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -6428,9 +6290,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.3.tgz", - "integrity": "sha512-K3mvIsjyKYBhNIDujMD2gfQEzddLe51nNOAf45yKRt/QFJcUIeTQd2trRvv6M6oCBHNVnZwFWbQ4yj96ibiDsA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -6442,9 +6304,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.3.tgz", - "integrity": "sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -6454,9 +6316,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.3.tgz", - "integrity": "sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -6656,6 +6518,14 @@ "acorn": "^8" } }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -7260,9 +7130,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "funding": [ { "type": "opencollective", @@ -7278,8 +7148,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -7473,9 +7343,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001581", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz", - "integrity": "sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==", + "version": "1.0.30001618", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001618.tgz", + "integrity": "sha512-p407+D1tIkDvsEAPS22lJxLQQaG8OTBEqo0KhzfABGk0TU4juBNDSfH0hyAp/HRyx+M8L17z/ltyhxh27FTfQg==", "funding": [ { "type": "opencollective", @@ -7580,6 +7450,21 @@ "node": ">=6.0" } }, + "node_modules/ci-info": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", + "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, "node_modules/cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", @@ -7952,12 +7837,12 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/core-js-compat": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.1.tgz", - "integrity": "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==", + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", "dev": true, "dependencies": { - "browserslist": "^4.22.2" + "browserslist": "^4.23.0" }, "funding": { "type": "opencollective", @@ -8532,9 +8417,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.650", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.650.tgz", - "integrity": "sha512-sYSQhJCJa4aGA1wYol5cMQgekDBlbVfTRavlGZVr3WZpDdOPcp6a6xUnFfrt8TqZhsBYYbDxJZCjGfHuGupCRQ==" + "version": "1.4.769", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.769.tgz", + "integrity": "sha512-bZu7p623NEA2rHTc9K1vykl57ektSPQYFFqQir8BOYf6EKOB+yIsbFB9Kpm7Cgt6tsLr9sRkqfqSZUw7LP1XxQ==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -8831,17 +8716,17 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "52.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz", - "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==", + "version": "53.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz", + "integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "@eslint-community/eslint-utils": "^4.4.0", - "@eslint/eslintrc": "^2.1.4", + "@eslint/eslintrc": "^3.0.2", "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.34.0", + "core-js-compat": "^3.37.0", "esquery": "^1.5.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.1", @@ -8850,11 +8735,11 @@ "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.27", "regjsparser": "^0.10.0", - "semver": "^7.5.4", + "semver": "^7.6.1", "strip-indent": "^3.0.0" }, "engines": { - "node": ">=16" + "node": ">=18.18" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" @@ -8863,33 +8748,92 @@ "eslint": ">=8.56.0" } }, - "node_modules/eslint-plugin-unicorn/node_modules/ci-info": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", - "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-plugin-unicorn/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -10132,9 +10076,9 @@ } }, "node_modules/i18n-iso-countries": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.11.1.tgz", - "integrity": "sha512-4+Z011pr/7SgwY4VH9Zkblp2b6Gl/2YqJF4f/OjhrwB6RvkbwctoQL8XhmZjGq8oHg4yJAsDv0j7xf7fO63TkA==", + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.11.2.tgz", + "integrity": "sha512-aquYZvUqNW968dFDezDpnz8/b0qRosO3A1XBXlVAdZREABcMKU+zdu7+ckLeWrCdF6YYPVkwsdktPaZOIHdIAA==", "dependencies": { "diacritics": "1.3.0" }, @@ -10623,6 +10567,18 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -11448,12 +11404,12 @@ } }, "node_modules/nestjs-otel": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nestjs-otel/-/nestjs-otel-5.1.5.tgz", - "integrity": "sha512-4u87aSy/GpbwuYvb5OAm0Zk3CP/q9QATI2bb9DQNpLYC5uYsqNkLHL3AdLBMVueNIMqp8rZui67XW0WTM8rr6g==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/nestjs-otel/-/nestjs-otel-6.1.0.tgz", + "integrity": "sha512-X04WirM8OgaO7R1ThDaciKXD8YD/CdRV3MMqnf6+63nDo/qqQ14JU3lGqbL+sfdCZ2Rg7Cd0SiCOApPUbvlV+g==", "dependencies": { - "@opentelemetry/api": "^1.4.1", - "@opentelemetry/host-metrics": "^0.32.2", + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/host-metrics": "^0.35.1", "response-time": "^2.3.2" }, "peerDependencies": { @@ -13958,9 +13914,9 @@ } }, "node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -13969,7 +13925,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14" + "node": ">=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -14145,12 +14101,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -14158,22 +14111,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -14298,9 +14235,9 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "node_modules/sharp": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.3.tgz", - "integrity": "sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", "hasInstallScript": true, "dependencies": { "color": "^4.2.3", @@ -14315,8 +14252,8 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.3", - "@img/sharp-darwin-x64": "0.33.3", + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", "@img/sharp-libvips-darwin-arm64": "1.0.2", "@img/sharp-libvips-darwin-x64": "1.0.2", "@img/sharp-libvips-linux-arm": "1.0.2", @@ -14325,15 +14262,15 @@ "@img/sharp-libvips-linux-x64": "1.0.2", "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", "@img/sharp-libvips-linuxmusl-x64": "1.0.2", - "@img/sharp-linux-arm": "0.33.3", - "@img/sharp-linux-arm64": "0.33.3", - "@img/sharp-linux-s390x": "0.33.3", - "@img/sharp-linux-x64": "0.33.3", - "@img/sharp-linuxmusl-arm64": "0.33.3", - "@img/sharp-linuxmusl-x64": "0.33.3", - "@img/sharp-wasm32": "0.33.3", - "@img/sharp-win32-ia32": "0.33.3", - "@img/sharp-win32-x64": "0.33.3" + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4" } }, "node_modules/shebang-command": { @@ -16205,9 +16142,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.3.tgz", - "integrity": "sha512-axFo00qiCpU/JLd8N1gu9iEYL3xTbMbMrbe5nDp9GL0nb6gurIdZLkkFogZXWnE8Oyy5kfSLwNVIcVsnhE7lgQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -16227,16 +16164,16 @@ } }, "node_modules/vitest": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.3.tgz", - "integrity": "sha512-2oM7nLXylw3mQlW6GXnRriw+7YvZFk/YNV8AxIC3Z3MfFbuziLGWP9GPxxu/7nRlXhqyxBikpamr+lEEj1sUEw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.3", - "@vitest/runner": "1.5.3", - "@vitest/snapshot": "1.5.3", - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -16250,7 +16187,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.3", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -16265,8 +16202,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.3", - "@vitest/ui": "1.5.3", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, @@ -16806,9 +16743,9 @@ "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==" }, "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==" }, "@babel/highlight": { "version": "7.24.2", @@ -17303,18 +17240,18 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" }, "@img/sharp-darwin-arm64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz", - "integrity": "sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", + "integrity": "sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==", "optional": true, "requires": { "@img/sharp-libvips-darwin-arm64": "1.0.2" } }, "@img/sharp-darwin-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.3.tgz", - "integrity": "sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.4.tgz", + "integrity": "sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==", "optional": true, "requires": { "@img/sharp-libvips-darwin-x64": "1.0.2" @@ -17369,78 +17306,78 @@ "optional": true }, "@img/sharp-linux-arm": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.3.tgz", - "integrity": "sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.4.tgz", + "integrity": "sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==", "optional": true, "requires": { "@img/sharp-libvips-linux-arm": "1.0.2" } }, "@img/sharp-linux-arm64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.3.tgz", - "integrity": "sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.4.tgz", + "integrity": "sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==", "optional": true, "requires": { "@img/sharp-libvips-linux-arm64": "1.0.2" } }, "@img/sharp-linux-s390x": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.3.tgz", - "integrity": "sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.4.tgz", + "integrity": "sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==", "optional": true, "requires": { "@img/sharp-libvips-linux-s390x": "1.0.2" } }, "@img/sharp-linux-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.3.tgz", - "integrity": "sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.4.tgz", + "integrity": "sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==", "optional": true, "requires": { "@img/sharp-libvips-linux-x64": "1.0.2" } }, "@img/sharp-linuxmusl-arm64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.3.tgz", - "integrity": "sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.4.tgz", + "integrity": "sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==", "optional": true, "requires": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.2" } }, "@img/sharp-linuxmusl-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.3.tgz", - "integrity": "sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.4.tgz", + "integrity": "sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==", "optional": true, "requires": { "@img/sharp-libvips-linuxmusl-x64": "1.0.2" } }, "@img/sharp-wasm32": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.3.tgz", - "integrity": "sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.4.tgz", + "integrity": "sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==", "optional": true, "requires": { - "@emnapi/runtime": "^1.1.0" + "@emnapi/runtime": "^1.1.1" } }, "@img/sharp-win32-ia32": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.3.tgz", - "integrity": "sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.4.tgz", + "integrity": "sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==", "optional": true }, "@img/sharp-win32-x64": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.3.tgz", - "integrity": "sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.4.tgz", + "integrity": "sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==", "optional": true }, "@ioredis/commands": { @@ -18007,26 +17944,34 @@ "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==" }, "@opentelemetry/api": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", - "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.8.0.tgz", + "integrity": "sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==" + }, + "@opentelemetry/api-logs": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.1.tgz", + "integrity": "sha512-E3skn949Pk1z2XtXu/lxf6QAZpawuTM/IUEXcAzpiUkTd73Hmvw26FiN3cJuTmkpM5hZzHwkomVdtrh/n/zzwA==", + "requires": { + "@opentelemetry/api": "^1.0.0" + } }, "@opentelemetry/auto-instrumentations-node": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.46.0.tgz", - "integrity": "sha512-F8d8usvvpuEngiNSyHaT0QU6CEwg9q5LFXscSeU4qhFQ+n8eoWcifk3jBcytRLansljtQu1XGdC+dV1oqbIomQ==", + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.46.1.tgz", + "integrity": "sha512-s0CwmY9KYtPawOhV5YO2Gf62uVOQRNvT6Or8IZ0S4gr/kPVNhoMehTsQvqBwSWQfoFrkmW3KKOHiKJEp4dVGXg==", "requires": { "@opentelemetry/instrumentation": "^0.51.0", "@opentelemetry/instrumentation-amqplib": "^0.37.0", - "@opentelemetry/instrumentation-aws-lambda": "^0.41.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.41.1", "@opentelemetry/instrumentation-aws-sdk": "^0.41.0", "@opentelemetry/instrumentation-bunyan": "^0.38.0", "@opentelemetry/instrumentation-cassandra-driver": "^0.38.0", - "@opentelemetry/instrumentation-connect": "^0.36.0", + "@opentelemetry/instrumentation-connect": "^0.36.1", "@opentelemetry/instrumentation-cucumber": "^0.6.0", "@opentelemetry/instrumentation-dataloader": "^0.9.0", "@opentelemetry/instrumentation-dns": "^0.36.1", - "@opentelemetry/instrumentation-express": "^0.38.0", + "@opentelemetry/instrumentation-express": "^0.39.0", "@opentelemetry/instrumentation-fastify": "^0.36.1", "@opentelemetry/instrumentation-fs": "^0.12.0", "@opentelemetry/instrumentation-generic-pool": "^0.36.0", @@ -18056,103 +18001,94 @@ "@opentelemetry/instrumentation-undici": "^0.2.0", "@opentelemetry/instrumentation-winston": "^0.37.0", "@opentelemetry/resource-detector-alibaba-cloud": "^0.28.9", - "@opentelemetry/resource-detector-aws": "^1.4.2", + "@opentelemetry/resource-detector-aws": "^1.5.0", "@opentelemetry/resource-detector-azure": "^0.2.6", "@opentelemetry/resource-detector-container": "^0.3.9", "@opentelemetry/resource-detector-gcp": "^0.29.9", "@opentelemetry/resources": "^1.24.0", "@opentelemetry/sdk-node": "^0.51.0" - }, - "dependencies": { - "@opentelemetry/core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.0.tgz", - "integrity": "sha512-FP2oN7mVPqcdxJDTTnKExj4mi91EH+DNuArKfHTjPuJWe2K1JfMIVXNfahw1h3onJxQnxS8K0stKkogX05s+Aw==", - "requires": { - "@opentelemetry/semantic-conventions": "1.24.0" - } - }, - "@opentelemetry/resources": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.0.tgz", - "integrity": "sha512-mxC7E7ocUS1tLzepnA7O9/G8G6ZTdjCH2pXme1DDDuCuk6n2/53GADX+GWBuyX0dfIxeMInIbJAdjlfN9GNr6A==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - } - }, - "@opentelemetry/semantic-conventions": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.0.tgz", - "integrity": "sha512-yL0jI6Ltuz8R+Opj7jClGrul6pOoYrdfVmzQS4SITXRPH7I5IRZbrwe/6/v8v4WYMa6MYZG480S1+uc/IGfqsA==" - } } }, "@opentelemetry/context-async-hooks": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.24.0.tgz", - "integrity": "sha512-s7xaQ9ifDpJvwbWRLkZD/J5hY35w+MECm4TQUkg6szRcny9lf6oVhWij4w3JJFQgvHQMXU7oXOpX8Z05HxV/8g==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.24.1.tgz", + "integrity": "sha512-R5r6DO4kgEOVBxFXhXjwospLQkv+sYxwCfjvoZBe7Zm6KKXAV9kDSJhi/D1BweowdZmO+sdbENLs374gER8hpQ==", "requires": {} }, "@opentelemetry/core": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.23.0.tgz", - "integrity": "sha512-hdQ/a9TMzMQF/BO8Cz1juA43/L5YGtCSiKoOHmrTEf7VMDAZgy8ucpWx3eQTnQ3gBloRcWtzvcrMZABC3PTSKQ==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.1.tgz", + "integrity": "sha512-wMSGfsdmibI88K9wB498zXY04yThPexo8jvwNNlm542HZB7XrrMRBbAyKJqG8qDRJwIBdBrPMi4V9ZPW/sqrcg==", "requires": { - "@opentelemetry/semantic-conventions": "1.23.0" + "@opentelemetry/semantic-conventions": "1.24.1" } }, "@opentelemetry/exporter-prometheus": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.51.0.tgz", - "integrity": "sha512-oT5l3Mff1U40U5Knr/XZFkYlvvLVVBGsM7u6cU99YZRlNX2uovGImZIeAhy60i178GVg2dpN1d5iQHYvN457aQ==", + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.51.1.tgz", + "integrity": "sha512-c8TrTlLm9JJRIHW6MtFv6ESoZRgXBXD/YrTRYylWiyYBOVbYHo1c5Qaw/j/thXDhkmYOYAn4LAhJZpLl5gBFEQ==", "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-metrics": "1.24.0" - }, - "dependencies": { - "@opentelemetry/core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.0.tgz", - "integrity": "sha512-FP2oN7mVPqcdxJDTTnKExj4mi91EH+DNuArKfHTjPuJWe2K1JfMIVXNfahw1h3onJxQnxS8K0stKkogX05s+Aw==", - "requires": { - "@opentelemetry/semantic-conventions": "1.24.0" - } - }, - "@opentelemetry/resources": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.0.tgz", - "integrity": "sha512-mxC7E7ocUS1tLzepnA7O9/G8G6ZTdjCH2pXme1DDDuCuk6n2/53GADX+GWBuyX0dfIxeMInIbJAdjlfN9GNr6A==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - } - }, - "@opentelemetry/sdk-metrics": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.0.tgz", - "integrity": "sha512-4tJ+E6N019OZVB/nUW/LoK9xHxfeh88TCoaTqHeLBE9wLYfi6irWW6J9cphMav7J8Qk0D5b7/RM4VEY4dArWOA==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "lodash.merge": "^4.6.2" - } - }, - "@opentelemetry/semantic-conventions": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.0.tgz", - "integrity": "sha512-yL0jI6Ltuz8R+Opj7jClGrul6pOoYrdfVmzQS4SITXRPH7I5IRZbrwe/6/v8v4WYMa6MYZG480S1+uc/IGfqsA==" - } + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-metrics": "1.24.1" + } + }, + "@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.51.1.tgz", + "integrity": "sha512-P9+Hkszih95ITvldGZ+kXvj9HpD1QfS+PwooyHK72GYA+Bgm+yUSAsDkUkDms8+s9HW6poxURv3LcjaMuBBpVQ==", + "requires": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-grpc-exporter-base": "0.51.1", + "@opentelemetry/otlp-transformer": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" + } + }, + "@opentelemetry/exporter-trace-otlp-http": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.51.1.tgz", + "integrity": "sha512-n+LhLPsX07URh+HhV2SHVSvz1t4G/l/CE5BjpmhAPqeTceFac1VpyQkavWEJbvnK5bUEXijWt4LxAxFpt2fXyw==", + "requires": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "@opentelemetry/otlp-transformer": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" + } + }, + "@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.51.1.tgz", + "integrity": "sha512-SE9f0/6V6EeXC9i+WA4WFjS1EYgaBCpAnI5+lxWvZ7iO7EU1IvHvZhP6Kojr0nLldo83gqg6G7OWFqsID3uF+w==", + "requires": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "@opentelemetry/otlp-proto-exporter-base": "0.51.1", + "@opentelemetry/otlp-transformer": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" + } + }, + "@opentelemetry/exporter-zipkin": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.24.1.tgz", + "integrity": "sha512-+Rl/VFmu2n6eaRMnVbyfZx1DqR/1KNyWebYuHyQBZaEAVIn/ZLgmofRpXN1X2nhJ4BNaptQUNxAstCYYz6dKoQ==", + "requires": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" } }, "@opentelemetry/host-metrics": { - "version": "0.32.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/host-metrics/-/host-metrics-0.32.2.tgz", - "integrity": "sha512-zrnls0CWMAYEUHQbdplY0M6v3L/cgEoiwpjAnHAaG7M3ICs7K4/Hms1UlVMDydEvNDkQilx63scpDcE1/M5V4A==", + "version": "0.35.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/host-metrics/-/host-metrics-0.35.1.tgz", + "integrity": "sha512-d49/Un/pzqUSsGLeO8PvrX2bLxVAORcaoL3nxjJCzGikXA6gjWXxGOfT8D4qePlgnocozppWszefMHoRFS2MsA==", "requires": { "@opentelemetry/sdk-metrics": "^1.8.0", - "systeminformation": "^5.0.0" + "systeminformation": "^5.21.20" } }, "@opentelemetry/instrumentation": { @@ -18189,14 +18125,14 @@ } }, "@opentelemetry/instrumentation-aws-lambda": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.41.0.tgz", - "integrity": "sha512-TeK7ZGtmEDqkfuwyAvlexnG11e7kEux0PncShqdyst2h1k1nVKmwnY/woPCUcTyU08PX6fa9YEyJ9E+G6wZacQ==", + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.41.1.tgz", + "integrity": "sha512-/BLG+0DQr2tCILFGJKJH2Fg6eyjhqOlVflYpNddUEXnzyQ/PAhTdgirkqbICFgeSW2XYcEY9zXpuRldrVNw9cA==", "requires": { "@opentelemetry/instrumentation": "^0.51.0", "@opentelemetry/propagator-aws-xray": "^1.3.1", "@opentelemetry/resources": "^1.8.0", - "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0", "@types/aws-lambda": "8.10.122" } }, @@ -18219,16 +18155,6 @@ "@opentelemetry/api-logs": "^0.51.0", "@opentelemetry/instrumentation": "^0.51.0", "@types/bunyan": "1.8.9" - }, - "dependencies": { - "@opentelemetry/api-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.0.tgz", - "integrity": "sha512-m/jtfBPEIXS1asltl8fPQtO3Sb1qMpuL61unQajUmM8zIxeMF1AlqzWXM3QedcYgTTFiJCew5uJjyhpmqhc0+g==", - "requires": { - "@opentelemetry/api": "^1.0.0" - } - } } }, "@opentelemetry/instrumentation-cassandra-driver": { @@ -18241,13 +18167,13 @@ } }, "@opentelemetry/instrumentation-connect": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.36.0.tgz", - "integrity": "sha512-k9++bmJZ9zDEs3u3DnKTn2l7QTiNFg3gPx7G9rW0TPnP+xZoBSBTrEcGYBaqflQlrFG23Q58+X1sM2ayWPv5Fg==", + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.36.1.tgz", + "integrity": "sha512-xI5Q/CMmzBmHshPnzzjD19ptFaYO/rQWzokpNio4QixZYWhJsa35QgRvN9FhPkwgtuJIbt/CWWAufJ3egJNHEA==", "requires": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.51.0", - "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0", "@types/connect": "3.4.36" } }, @@ -18279,9 +18205,9 @@ } }, "@opentelemetry/instrumentation-express": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.38.0.tgz", - "integrity": "sha512-izId/qcgMgfWV292ZI9b9E7HdV9446vi0Z5zu5fSlt4MF+R6LZXbZLTQAaboJ4Y2+JbtH7apvko1DF93qTFtqw==", + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.39.0.tgz", + "integrity": "sha512-AG8U7z7D0JcBu/7dDcwb47UMEzj9/FMiJV2iQZqrsZnxR3FjB9J9oIH2iszJYci2eUdp2WbdvtpD9RV/zmME5A==", "requires": { "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.51.0", @@ -18589,16 +18515,48 @@ "requires": { "@opentelemetry/api-logs": "^0.51.0", "@opentelemetry/instrumentation": "^0.51.0" - }, - "dependencies": { - "@opentelemetry/api-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.0.tgz", - "integrity": "sha512-m/jtfBPEIXS1asltl8fPQtO3Sb1qMpuL61unQajUmM8zIxeMF1AlqzWXM3QedcYgTTFiJCew5uJjyhpmqhc0+g==", - "requires": { - "@opentelemetry/api": "^1.0.0" - } - } + } + }, + "@opentelemetry/otlp-exporter-base": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.51.1.tgz", + "integrity": "sha512-UYlnOYyDdzo1Gw559EHCzru0RwhvuXCwoH8jGo9J4gO1TE58GjnEmIjomMsKBCym3qWNJfIQXw+9SZCV0DdQNg==", + "requires": { + "@opentelemetry/core": "1.24.1" + } + }, + "@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.51.1.tgz", + "integrity": "sha512-ZAS+4pq8o7dsugGTwV9s6JMKSxi+guIHdn0acOv0bqj26e9pWDFx5Ky+bI0aY46uR9Y0JyXqY+KAEYM/SO3DFA==", + "requires": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "protobufjs": "^7.2.3" + } + }, + "@opentelemetry/otlp-proto-exporter-base": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.51.1.tgz", + "integrity": "sha512-gxxxwfk0inDMb5DLeuxQ3L8TtptxSiTNHE4nnAJH34IQXAVRhXSXW1rK8PmDKDngRPIZ6J7ncUCjjIn8b+AgqQ==", + "requires": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/otlp-exporter-base": "0.51.1", + "protobufjs": "^7.2.3" + } + }, + "@opentelemetry/otlp-transformer": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.51.1.tgz", + "integrity": "sha512-OppYOXwV9LQqqtYUCywqoOqX/JT9LQ5/FMuPZ//eTkvuHdUC4ZMwz2c6uSoT2R90GWvvGnF1iEqTGyTT3xAt2Q==", + "requires": { + "@opentelemetry/api-logs": "0.51.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-logs": "0.51.1", + "@opentelemetry/sdk-metrics": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1" } }, "@opentelemetry/propagation-utils": { @@ -18615,6 +18573,22 @@ "@opentelemetry/core": "^1.0.0" } }, + "@opentelemetry/propagator-b3": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.24.1.tgz", + "integrity": "sha512-nda97ZwhpZKyUJTXqQuKzNhPMUgMLunbbGWn8kroBwegn+nh6OhtyGkrVQsQLNdVKJl0KeB5z0ZgeWszrYhwFw==", + "requires": { + "@opentelemetry/core": "1.24.1" + } + }, + "@opentelemetry/propagator-jaeger": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.24.1.tgz", + "integrity": "sha512-7bRBJn3FG1l195A1m+xXRHvgzAOBsfmRi9uZ5Da18oTh7BLmNDiA8+kpk51FpTsU1PCikPVpRDNPhKVB6lyzZg==", + "requires": { + "@opentelemetry/core": "1.24.1" + } + }, "@opentelemetry/redis-common": { "version": "0.36.2", "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", @@ -18630,9 +18604,9 @@ } }, "@opentelemetry/resource-detector-aws": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.4.2.tgz", - "integrity": "sha512-Rt4cztIz8UZZ32wRbotKPVbkRfukiMM8xfzf2C1M+Puv91Cw6kDJHAfWCqkx7FdNe0e6aF4u2lkFweE1849RCg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.5.0.tgz", + "integrity": "sha512-JNk/kSzzNQaiMo/F0b/bm8S3Qtr/m89BckN9B4U/cPHSqKLdxX03vgRBOqkXJ5KlAD8kc6K1Etcr8QfvGw6+uA==", "requires": { "@opentelemetry/core": "^1.0.0", "@opentelemetry/resources": "^1.0.0", @@ -18669,229 +18643,106 @@ } }, "@opentelemetry/resources": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.23.0.tgz", - "integrity": "sha512-iPRLfVfcEQynYGo7e4Di+ti+YQTAY0h5mQEUJcHlU9JOqpb4x965O6PZ+wMcwYVY63G96KtdS86YCM1BF1vQZg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.1.tgz", + "integrity": "sha512-cyv0MwAaPF7O86x5hk3NNgenMObeejZFLJJDVuSeSMIsknlsj3oOZzRv3qSzlwYomXsICfBeFFlxwHQte5mGXQ==", "requires": { - "@opentelemetry/core": "1.23.0", - "@opentelemetry/semantic-conventions": "1.23.0" + "@opentelemetry/core": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" + } + }, + "@opentelemetry/sdk-logs": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.51.1.tgz", + "integrity": "sha512-ULQQtl82b673PpZc5/0EtH4V+BrwVOgKJZEB7tYZnGTG3I98tQVk89S9/JSixomDr++F4ih+LSJTCqIKBz+MQQ==", + "requires": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1" } }, "@opentelemetry/sdk-metrics": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.23.0.tgz", - "integrity": "sha512-4OkvW6+wST4h6LFG23rXSTf6nmTf201h9dzq7bE0z5R9ESEVLERZz6WXwE7PSgg1gdjlaznm1jLJf8GttypFDg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.1.tgz", + "integrity": "sha512-FrAqCbbGao9iKI+Mgh+OsC9+U2YMoXnlDHe06yH7dvavCKzE3S892dGtX54+WhSFVxHR/TMRVJiK/CV93GR0TQ==", "requires": { - "@opentelemetry/core": "1.23.0", - "@opentelemetry/resources": "1.23.0", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", "lodash.merge": "^4.6.2" } }, "@opentelemetry/sdk-node": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.51.0.tgz", - "integrity": "sha512-MrPXDQsTAj3lcY8YUCjb7dvSXVZ5jG6wmjD2LB68V1rsLBdP8j70jsI9GaKijY7QB6psbLq6apO1vYeim5U7aw==", + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.51.1.tgz", + "integrity": "sha512-GgmNF9C+6esr8PIJxCqHw84rEOkYm6XdFWZ2+Wyc3qaUt92ACoN7uSw5iKNvaUq62W0xii1wsGxwHzyENtPP8w==", "requires": { - "@opentelemetry/api-logs": "0.51.0", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/exporter-trace-otlp-grpc": "0.51.0", - "@opentelemetry/exporter-trace-otlp-http": "0.51.0", - "@opentelemetry/exporter-trace-otlp-proto": "0.51.0", - "@opentelemetry/exporter-zipkin": "1.24.0", - "@opentelemetry/instrumentation": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-logs": "0.51.0", - "@opentelemetry/sdk-metrics": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0", - "@opentelemetry/sdk-trace-node": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" + "@opentelemetry/api-logs": "0.51.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/exporter-trace-otlp-grpc": "0.51.1", + "@opentelemetry/exporter-trace-otlp-http": "0.51.1", + "@opentelemetry/exporter-trace-otlp-proto": "0.51.1", + "@opentelemetry/exporter-zipkin": "1.24.1", + "@opentelemetry/instrumentation": "0.51.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/sdk-logs": "0.51.1", + "@opentelemetry/sdk-metrics": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1", + "@opentelemetry/sdk-trace-node": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" }, "dependencies": { - "@opentelemetry/api-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.51.0.tgz", - "integrity": "sha512-m/jtfBPEIXS1asltl8fPQtO3Sb1qMpuL61unQajUmM8zIxeMF1AlqzWXM3QedcYgTTFiJCew5uJjyhpmqhc0+g==", + "@opentelemetry/instrumentation": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.51.1.tgz", + "integrity": "sha512-JIrvhpgqY6437QIqToyozrUG1h5UhwHkaGK/WAX+fkrpyPtc+RO5FkRtUd9BH0MibabHHvqsnBGKfKVijbmp8w==", "requires": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api-logs": "0.51.1", + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.7.4", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" } }, - "@opentelemetry/core": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.24.0.tgz", - "integrity": "sha512-FP2oN7mVPqcdxJDTTnKExj4mi91EH+DNuArKfHTjPuJWe2K1JfMIVXNfahw1h3onJxQnxS8K0stKkogX05s+Aw==", + "import-in-the-middle": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.7.4.tgz", + "integrity": "sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg==", "requires": { - "@opentelemetry/semantic-conventions": "1.24.0" + "acorn": "^8.8.2", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" } - }, - "@opentelemetry/exporter-trace-otlp-grpc": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.51.0.tgz", - "integrity": "sha512-xQpxKzS8ZnxYCa1v+3EKWhwMrSK3+RezpJ+AEKaP2pf2QbLfHt7kKfSn7niR2u3A1Tbe2aC7Ptt9+MafhThOOQ==", - "requires": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.51.0", - "@opentelemetry/otlp-transformer": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - } - }, - "@opentelemetry/exporter-trace-otlp-http": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.51.0.tgz", - "integrity": "sha512-zODqnLZmPOxj9CarFv0TrVlx9mgj0TfCMCiUiTdNi9iA2rgdKVo+bjJjpYF6LCTJOQCR5TScAUCKyzwkgDI+iA==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "@opentelemetry/otlp-transformer": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - } - }, - "@opentelemetry/exporter-trace-otlp-proto": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.51.0.tgz", - "integrity": "sha512-Fi7r0iMqGoFCQQ+WY0pYOWp395vdinZJIkYKnNbnreHxAN/kVDBl2FxbV3DeOKuRxEY08Gyb9ggPf+Zrqp7l/w==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "@opentelemetry/otlp-proto-exporter-base": "0.51.0", - "@opentelemetry/otlp-transformer": "0.51.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - } - }, - "@opentelemetry/exporter-zipkin": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.24.0.tgz", - "integrity": "sha512-QeGv0PHONswmu567pf9QliJ6s6DgCu5+ziF+soNS1LTcr1VRRVLViYLmGxmzDFUC48sjNTu7sumcKT0nJXsGBw==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - } - }, - "@opentelemetry/otlp-exporter-base": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.51.0.tgz", - "integrity": "sha512-hR4c9vWVz1QgzCBSyy9zSDkvfTgaK96E6/tfVP6O4dzdZW9HqWimA3lXV/KXadEGqShvM4GToz9EHp2A5RU5bQ==", - "requires": { - "@opentelemetry/core": "1.24.0" - } - }, - "@opentelemetry/otlp-grpc-exporter-base": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.51.0.tgz", - "integrity": "sha512-oTRtDvvB0bTRTBVrvKA/oM1gIAqQ6DVQS07pvqiL1cZS8wBrGgpw+2iTd0nV661Y/MhDn/kNWp8lRhMEIKN9bw==", - "requires": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "protobufjs": "^7.2.3" - } - }, - "@opentelemetry/otlp-proto-exporter-base": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.51.0.tgz", - "integrity": "sha512-WDANDLSUh11Gu5o6iCzmjZraIv5bK8z1L/t6lxQ2NeEKiKUPo5pVOBBQQC/yAQU2yeqkiO1GRCieH+XahZf60A==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/otlp-exporter-base": "0.51.0", - "protobufjs": "^7.2.3" - } - }, - "@opentelemetry/otlp-transformer": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.51.0.tgz", - "integrity": "sha512-ylLgx2xumVoSefDHP9GMAU/LG+TU3+8eacVDXV5o1RqWxsdVOaQmCTY0XyDgeRTn6hIOVAq/HHQbRq3iWOrt2A==", - "requires": { - "@opentelemetry/api-logs": "0.51.0", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/sdk-logs": "0.51.0", - "@opentelemetry/sdk-metrics": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0" - } - }, - "@opentelemetry/propagator-b3": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.24.0.tgz", - "integrity": "sha512-7TMIDE4+NO5vnkor+zned42wqca+hmhW5gWKhmYjUHC5B5uojo1PvtmBrd7kigFu96XvL4ZUWVzibWRWIQ/++Q==", - "requires": { - "@opentelemetry/core": "1.24.0" - } - }, - "@opentelemetry/propagator-jaeger": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.24.0.tgz", - "integrity": "sha512-r3MX3AmJiUeiWTXSDOdwBeaO+ahvWcFCpuKxmhhsH8Q8LqDnjhNd3krqBh4Qsq9wa0WhWtiQaDs/NOCWoMOlOw==", - "requires": { - "@opentelemetry/core": "1.24.0" - } - }, - "@opentelemetry/resources": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.24.0.tgz", - "integrity": "sha512-mxC7E7ocUS1tLzepnA7O9/G8G6ZTdjCH2pXme1DDDuCuk6n2/53GADX+GWBuyX0dfIxeMInIbJAdjlfN9GNr6A==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - } - }, - "@opentelemetry/sdk-logs": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.51.0.tgz", - "integrity": "sha512-K4fMBRFD8hQ6khk0rvYFuo6L9ymeGgByir6BcuFIgQuQ00OhYwBi9AruZz5V733Ejq7P8ObR3YyubkOUIbeVAw==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0" - } - }, - "@opentelemetry/sdk-metrics": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.24.0.tgz", - "integrity": "sha512-4tJ+E6N019OZVB/nUW/LoK9xHxfeh88TCoaTqHeLBE9wLYfi6irWW6J9cphMav7J8Qk0D5b7/RM4VEY4dArWOA==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "lodash.merge": "^4.6.2" - } - }, - "@opentelemetry/sdk-trace-base": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.0.tgz", - "integrity": "sha512-H9sLETZ4jw9UJ3totV8oM5R0m4CW0ZIOLfp4NV3g0CM8HD5zGZcaW88xqzWDgiYRpctFxd+WmHtGX/Upoa2vRg==", - "requires": { - "@opentelemetry/core": "1.24.0", - "@opentelemetry/resources": "1.24.0", - "@opentelemetry/semantic-conventions": "1.24.0" - } - }, - "@opentelemetry/sdk-trace-node": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.24.0.tgz", - "integrity": "sha512-QgByHmM9uloTpcYEEyW9YJEIMKHFSIM677RH9pJPWWwtM2NQFbEp/8HIJw80Ymtaz6cAxg1Kay1ByqIVzq3t5g==", - "requires": { - "@opentelemetry/context-async-hooks": "1.24.0", - "@opentelemetry/core": "1.24.0", - "@opentelemetry/propagator-b3": "1.24.0", - "@opentelemetry/propagator-jaeger": "1.24.0", - "@opentelemetry/sdk-trace-base": "1.24.0", - "semver": "^7.5.2" - } - }, - "@opentelemetry/semantic-conventions": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.0.tgz", - "integrity": "sha512-yL0jI6Ltuz8R+Opj7jClGrul6pOoYrdfVmzQS4SITXRPH7I5IRZbrwe/6/v8v4WYMa6MYZG480S1+uc/IGfqsA==" } } }, + "@opentelemetry/sdk-trace-base": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.24.1.tgz", + "integrity": "sha512-zz+N423IcySgjihl2NfjBf0qw1RWe11XIAWVrTNOSSI6dtSPJiVom2zipFB2AEEtJWpv0Iz6DY6+TjnyTV5pWg==", + "requires": { + "@opentelemetry/core": "1.24.1", + "@opentelemetry/resources": "1.24.1", + "@opentelemetry/semantic-conventions": "1.24.1" + } + }, + "@opentelemetry/sdk-trace-node": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.24.1.tgz", + "integrity": "sha512-/FZX8uWaGIAwsDhqI8VvQ+qWtfMNlXjaFYGc+vmxgdRFppCSSIRwrPyIhJO1qx61okyYhoyxVEZAfoiNxrfJCg==", + "requires": { + "@opentelemetry/context-async-hooks": "1.24.1", + "@opentelemetry/core": "1.24.1", + "@opentelemetry/propagator-b3": "1.24.1", + "@opentelemetry/propagator-jaeger": "1.24.1", + "@opentelemetry/sdk-trace-base": "1.24.1", + "semver": "^7.5.2" + } + }, "@opentelemetry/semantic-conventions": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.23.0.tgz", - "integrity": "sha512-MiqFvfOzfR31t8cc74CTP1OZfz7MbqpAnLCra8NqQoaHJX6ncIRTdYOQYBDQ2uFISDq0WY8Y9dDTWvsgzzBYRg==" + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.24.1.tgz", + "integrity": "sha512-VkliWlS4/+GHLLW7J/rVBA00uXus1SWvwFvcUDxDwmFxYfg/2VI6ekwdXS28cjI8Qz2ky2BzG8OUHo+WeYIWqw==" }, "@opentelemetry/sql-common": { "version": "0.40.1", @@ -19696,92 +19547,92 @@ "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" }, "@swc/core": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.17.tgz", - "integrity": "sha512-tq+mdWvodMBNBBZbwFIMTVGYHe9N7zvEaycVVjfvAx20k1XozHbHhRv+9pEVFJjwRxLdXmtvFZd3QZHRAOpoNQ==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", + "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", "devOptional": true, "requires": { - "@swc/core-darwin-arm64": "1.4.17", - "@swc/core-darwin-x64": "1.4.17", - "@swc/core-linux-arm-gnueabihf": "1.4.17", - "@swc/core-linux-arm64-gnu": "1.4.17", - "@swc/core-linux-arm64-musl": "1.4.17", - "@swc/core-linux-x64-gnu": "1.4.17", - "@swc/core-linux-x64-musl": "1.4.17", - "@swc/core-win32-arm64-msvc": "1.4.17", - "@swc/core-win32-ia32-msvc": "1.4.17", - "@swc/core-win32-x64-msvc": "1.4.17", + "@swc/core-darwin-arm64": "1.5.7", + "@swc/core-darwin-x64": "1.5.7", + "@swc/core-linux-arm-gnueabihf": "1.5.7", + "@swc/core-linux-arm64-gnu": "1.5.7", + "@swc/core-linux-arm64-musl": "1.5.7", + "@swc/core-linux-x64-gnu": "1.5.7", + "@swc/core-linux-x64-musl": "1.5.7", + "@swc/core-win32-arm64-msvc": "1.5.7", + "@swc/core-win32-ia32-msvc": "1.5.7", + "@swc/core-win32-x64-msvc": "1.5.7", "@swc/counter": "^0.1.2", - "@swc/types": "^0.1.5" + "@swc/types": "0.1.7" } }, "@swc/core-darwin-arm64": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.17.tgz", - "integrity": "sha512-HVl+W4LezoqHBAYg2JCqR+s9ife9yPfgWSj37iIawLWzOmuuJ7jVdIB7Ee2B75bEisSEKyxRlTl6Y1Oq3owBgw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.7.tgz", + "integrity": "sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.17.tgz", - "integrity": "sha512-WYRO9Fdzq4S/he8zjW5I95G1zcvyd9yyD3Tgi4/ic84P5XDlSMpBDpBLbr/dCPjmSg7aUXxNQqKqGkl6dQxYlA==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.7.tgz", + "integrity": "sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.17.tgz", - "integrity": "sha512-cgbvpWOvtMH0XFjvwppUCR+Y+nf6QPaGu6AQ5hqCP+5Lv2zO5PG0RfasC4zBIjF53xgwEaaWmGP5/361P30X8Q==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.7.tgz", + "integrity": "sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.17.tgz", - "integrity": "sha512-l7zHgaIY24cF9dyQ/FOWbmZDsEj2a9gRFbmgx2u19e3FzOPuOnaopFj0fRYXXKCmtdx+anD750iBIYnTR+pq/Q==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.7.tgz", + "integrity": "sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.17.tgz", - "integrity": "sha512-qhH4gr9gAlVk8MBtzXbzTP3BJyqbAfUOATGkyUtohh85fPXQYuzVlbExix3FZXTwFHNidGHY8C+ocscI7uDaYw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.7.tgz", + "integrity": "sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.17.tgz", - "integrity": "sha512-vRDFATL1oN5oZMImkwbgSHEkp8xG1ofEASBypze01W1Tqto8t+yo6gsp69wzCZBlxldsvPpvFZW55Jq0Rn+UnA==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.7.tgz", + "integrity": "sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.17.tgz", - "integrity": "sha512-zQNPXAXn3nmPqv54JVEN8k2JMEcMTQ6veVuU0p5O+A7KscJq+AGle/7ZQXzpXSfUCXlLMX4wvd+rwfGhh3J4cw==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.7.tgz", + "integrity": "sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.17.tgz", - "integrity": "sha512-z86n7EhOwyzxwm+DLE5NoLkxCTme2lq7QZlDjbQyfCxOt6isWz8rkW5QowTX8w9Rdmk34ncrjSLvnHOeLY17+w==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.7.tgz", + "integrity": "sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.17.tgz", - "integrity": "sha512-JBwuSTJIgiJJX6wtr4wmXbfvOswHFj223AumUrK544QV69k60FJ9q2adPW9Csk+a8wm1hLxq4HKa2K334UHJ/g==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.7.tgz", + "integrity": "sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.4.17", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.17.tgz", - "integrity": "sha512-jFkOnGQamtVDBm3MF5Kq1lgW8vx4Rm1UvJWRUfg+0gx7Uc3Jp3QMFeMNw/rDNQYRDYPG3yunCC+2463ycd5+dg==", + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.7.tgz", + "integrity": "sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==", "dev": true, "optional": true }, @@ -19799,9 +19650,9 @@ } }, "@swc/types": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.6.tgz", - "integrity": "sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", + "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", "requires": { "@swc/counter": "^0.1.3" } @@ -20122,9 +19973,9 @@ } }, "@types/lodash": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", - "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.3.tgz", + "integrity": "sha512-zmNrEJaBvNskZXQWaUQq6bktF4IDGVfDS78M+YEk5aCn9M/b94/mB/6WCyfH2/MjwBdc6QuOor95CIlKWYRL3A==", "dev": true }, "@types/luxon": { @@ -20178,9 +20029,9 @@ } }, "@types/node": { - "version": "20.12.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz", - "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==", + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", "requires": { "undici-types": "~5.26.4" } @@ -20418,73 +20269,71 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", - "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz", + "integrity": "sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/type-utils": "7.9.0", + "@typescript-eslint/utils": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/parser": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", - "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.9.0.tgz", + "integrity": "sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz", + "integrity": "sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==", "dev": true, "requires": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0" + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0" } }, "@typescript-eslint/type-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", - "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz", + "integrity": "sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/utils": "7.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" } }, "@typescript-eslint/types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.9.0.tgz", + "integrity": "sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz", + "integrity": "sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==", "dev": true, "requires": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -20514,27 +20363,24 @@ } }, "@typescript-eslint/utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.9.0.tgz", + "integrity": "sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0" } }, "@typescript-eslint/visitor-keys": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz", + "integrity": "sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==", "dev": true, "requires": { - "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/types": "7.9.0", "eslint-visitor-keys": "^3.4.3" } }, @@ -20544,9 +20390,9 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "@vitest/coverage-v8": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.3.tgz", - "integrity": "sha512-DPyGSu/fPHOJuPxzFSQoT4N/Fu/2aJfZRtEpEp8GI7NHsXBGE94CQ+pbEGBUMFjatsHPDJw/+TAF9r4ens2CNw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", + "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.1", @@ -20565,23 +20411,23 @@ } }, "@vitest/expect": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.3.tgz", - "integrity": "sha512-y+waPz31pOFr3rD7vWTbwiLe5+MgsMm40jTZbQE8p8/qXyBX3CQsIXRx9XK12IbY7q/t5a5aM/ckt33b4PxK2g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "requires": { - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" } }, "@vitest/runner": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz", - "integrity": "sha512-7PlfuReN8692IKQIdCxwir1AOaP5THfNkp0Uc4BKr2na+9lALNit7ub9l3/R7MP8aV61+mHKRGiqEKRIwu6iiQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "requires": { - "@vitest/utils": "1.5.3", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -20604,9 +20450,9 @@ } }, "@vitest/snapshot": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.3.tgz", - "integrity": "sha512-K3mvIsjyKYBhNIDujMD2gfQEzddLe51nNOAf45yKRt/QFJcUIeTQd2trRvv6M6oCBHNVnZwFWbQ4yj96ibiDsA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "requires": { "magic-string": "^0.30.5", @@ -20615,18 +20461,18 @@ } }, "@vitest/spy": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.3.tgz", - "integrity": "sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "requires": { "tinyspy": "^2.2.0" } }, "@vitest/utils": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.3.tgz", - "integrity": "sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "requires": { "diff-sequences": "^29.6.3", @@ -20809,6 +20655,12 @@ "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "requires": {} }, + "acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "requires": {} + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -21255,12 +21107,12 @@ } }, "browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "requires": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" } @@ -21391,9 +21243,9 @@ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, "caniuse-lite": { - "version": "1.0.30001581", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001581.tgz", - "integrity": "sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==" + "version": "1.0.30001618", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001618.tgz", + "integrity": "sha512-p407+D1tIkDvsEAPS22lJxLQQaG8OTBEqo0KhzfABGk0TU4juBNDSfH0hyAp/HRyx+M8L17z/ltyhxh27FTfQg==" }, "chai": { "version": "4.4.1", @@ -21458,6 +21310,12 @@ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, + "ci-info": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", + "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "dev": true + }, "cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", @@ -21741,12 +21599,12 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "core-js-compat": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.1.tgz", - "integrity": "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==", + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", "dev": true, "requires": { - "browserslist": "^4.22.2" + "browserslist": "^4.23.0" } }, "core-util-is": { @@ -22156,9 +22014,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.650", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.650.tgz", - "integrity": "sha512-sYSQhJCJa4aGA1wYol5cMQgekDBlbVfTRavlGZVr3WZpDdOPcp6a6xUnFfrt8TqZhsBYYbDxJZCjGfHuGupCRQ==" + "version": "1.4.769", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.769.tgz", + "integrity": "sha512-bZu7p623NEA2rHTc9K1vykl57ektSPQYFFqQir8BOYf6EKOB+yIsbFB9Kpm7Cgt6tsLr9sRkqfqSZUw7LP1XxQ==" }, "emoji-regex": { "version": "8.0.0", @@ -22403,17 +22261,17 @@ } }, "eslint-plugin-unicorn": { - "version": "52.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz", - "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==", + "version": "53.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz", + "integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "@eslint-community/eslint-utils": "^4.4.0", - "@eslint/eslintrc": "^2.1.4", + "@eslint/eslintrc": "^3.0.2", "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.34.0", + "core-js-compat": "^3.37.0", "esquery": "^1.5.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.1", @@ -22422,20 +22280,66 @@ "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.27", "regjsparser": "^0.10.0", - "semver": "^7.5.4", + "semver": "^7.6.1", "strip-indent": "^3.0.0" }, "dependencies": { - "ci-info": { + "@eslint/eslintrc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "eslint-visitor-keys": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", - "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true }, - "jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "requires": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + } + }, + "globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true } } @@ -23323,9 +23227,9 @@ "dev": true }, "i18n-iso-countries": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.11.1.tgz", - "integrity": "sha512-4+Z011pr/7SgwY4VH9Zkblp2b6Gl/2YqJF4f/OjhrwB6RvkbwctoQL8XhmZjGq8oHg4yJAsDv0j7xf7fO63TkA==", + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.11.2.tgz", + "integrity": "sha512-aquYZvUqNW968dFDezDpnz8/b0qRosO3A1XBXlVAdZREABcMKU+zdu7+ckLeWrCdF6YYPVkwsdktPaZOIHdIAA==", "requires": { "diacritics": "1.3.0" } @@ -23667,6 +23571,12 @@ "argparse": "^2.0.1" } }, + "jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true + }, "json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -24316,12 +24226,12 @@ "requires": {} }, "nestjs-otel": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/nestjs-otel/-/nestjs-otel-5.1.5.tgz", - "integrity": "sha512-4u87aSy/GpbwuYvb5OAm0Zk3CP/q9QATI2bb9DQNpLYC5uYsqNkLHL3AdLBMVueNIMqp8rZui67XW0WTM8rr6g==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/nestjs-otel/-/nestjs-otel-6.1.0.tgz", + "integrity": "sha512-X04WirM8OgaO7R1ThDaciKXD8YD/CdRV3MMqnf6+63nDo/qqQ14JU3lGqbL+sfdCZ2Rg7Cd0SiCOApPUbvlV+g==", "requires": { - "@opentelemetry/api": "^1.4.1", - "@opentelemetry/host-metrics": "^0.32.2", + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/host-metrics": "^0.35.1", "response-time": "^2.3.2" } }, @@ -25898,9 +25808,9 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", "dev": true, "requires": { "glob": "^10.3.7" @@ -26022,27 +25932,9 @@ } }, "semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" }, "send": { "version": "0.18.0", @@ -26158,12 +26050,12 @@ } }, "sharp": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.3.tgz", - "integrity": "sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==", + "version": "0.33.4", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.4.tgz", + "integrity": "sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==", "requires": { - "@img/sharp-darwin-arm64": "0.33.3", - "@img/sharp-darwin-x64": "0.33.3", + "@img/sharp-darwin-arm64": "0.33.4", + "@img/sharp-darwin-x64": "0.33.4", "@img/sharp-libvips-darwin-arm64": "1.0.2", "@img/sharp-libvips-darwin-x64": "1.0.2", "@img/sharp-libvips-linux-arm": "1.0.2", @@ -26172,15 +26064,15 @@ "@img/sharp-libvips-linux-x64": "1.0.2", "@img/sharp-libvips-linuxmusl-arm64": "1.0.2", "@img/sharp-libvips-linuxmusl-x64": "1.0.2", - "@img/sharp-linux-arm": "0.33.3", - "@img/sharp-linux-arm64": "0.33.3", - "@img/sharp-linux-s390x": "0.33.3", - "@img/sharp-linux-x64": "0.33.3", - "@img/sharp-linuxmusl-arm64": "0.33.3", - "@img/sharp-linuxmusl-x64": "0.33.3", - "@img/sharp-wasm32": "0.33.3", - "@img/sharp-win32-ia32": "0.33.3", - "@img/sharp-win32-x64": "0.33.3", + "@img/sharp-linux-arm": "0.33.4", + "@img/sharp-linux-arm64": "0.33.4", + "@img/sharp-linux-s390x": "0.33.4", + "@img/sharp-linux-x64": "0.33.4", + "@img/sharp-linuxmusl-arm64": "0.33.4", + "@img/sharp-linuxmusl-x64": "0.33.4", + "@img/sharp-wasm32": "0.33.4", + "@img/sharp-win32-ia32": "0.33.4", + "@img/sharp-win32-x64": "0.33.4", "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.0" @@ -27463,9 +27355,9 @@ } }, "vite-node": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.3.tgz", - "integrity": "sha512-axFo00qiCpU/JLd8N1gu9iEYL3xTbMbMrbe5nDp9GL0nb6gurIdZLkkFogZXWnE8Oyy5kfSLwNVIcVsnhE7lgQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "requires": { "cac": "^6.7.14", @@ -27476,16 +27368,16 @@ } }, "vitest": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.3.tgz", - "integrity": "sha512-2oM7nLXylw3mQlW6GXnRriw+7YvZFk/YNV8AxIC3Z3MfFbuziLGWP9GPxxu/7nRlXhqyxBikpamr+lEEj1sUEw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "requires": { - "@vitest/expect": "1.5.3", - "@vitest/runner": "1.5.3", - "@vitest/snapshot": "1.5.3", - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -27499,7 +27391,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.3", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" } }, diff --git a/server/package.json b/server/package.json index 328b58fdd7..e657ca0757 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "immich", - "version": "1.103.1", + "version": "1.105.1", "description": "", "author": "", "private": true, @@ -18,6 +18,7 @@ "check": "tsc --noEmit", "check:code": "npm run format && npm run lint && npm run check", "check:all": "npm run check:code && npm run test:cov", + "healthcheck": "node ./dist/utils/healthcheck.js", "test": "vitest", "test:watch": "vitest --watch", "test:cov": "vitest --coverage", @@ -29,7 +30,8 @@ "typeorm:migrations:revert": "typeorm migration:revert -d ./dist/database.config.js", "typeorm:schema:drop": "typeorm query -d ./dist/database.config.js 'DROP schema public cascade; CREATE schema public;'", "typeorm:schema:reset": "npm run typeorm:schema:drop && npm run typeorm:migrations:run", - "sql:generate": "node ./dist/utils/sql.js", + "sync:open-api": "node ./dist/bin/sync-open-api.js", + "sync:sql": "node ./dist/bin/sync-sql.js", "email:dev": "email dev -p 3050 --dir src/emails" }, "dependencies": { @@ -72,7 +74,7 @@ "mnemonist": "^0.39.8", "nest-commander": "^3.11.1", "nestjs-cls": "^4.3.0", - "nestjs-otel": "^5.1.5", + "nestjs-otel": "^6.0.0", "nodemailer": "^6.9.13", "openid-client": "^5.4.3", "pg": "^8.11.3", @@ -81,6 +83,7 @@ "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "sanitize-filename": "^1.6.3", + "semver": "^7.6.2", "sharp": "^0.33.0", "sirv": "^2.0.4", "thumbhash": "^0.1.1", @@ -107,6 +110,7 @@ "@types/node": "^20.5.7", "@types/nodemailer": "^6.4.14", "@types/picomatch": "^2.3.3", + "@types/semver": "^7.5.8", "@types/supertest": "^6.0.0", "@types/ua-parser-js": "^0.7.36", "@typescript-eslint/eslint-plugin": "^7.0.0", @@ -115,7 +119,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "mock-fs": "^5.2.0", "prettier": "^3.0.2", "prettier-plugin-organize-imports": "^3.2.3", @@ -129,6 +133,6 @@ "vitest": "^1.5.0" }, "volta": { - "node": "20.12.2" + "node": "20.13.1" } } diff --git a/server/src/bin/sync-open-api.ts b/server/src/bin/sync-open-api.ts new file mode 100644 index 0000000000..70e2bb8c35 --- /dev/null +++ b/server/src/bin/sync-open-api.ts @@ -0,0 +1,23 @@ +#!/usr/bin/env node +process.env.DB_URL = 'postgres://postgres:postgres@localhost:5432/immich'; +import { NestFactory } from '@nestjs/core'; +import { NestExpressApplication } from '@nestjs/platform-express'; +import { ApiModule } from 'src/app.module'; +import { useSwagger } from 'src/utils/misc'; + +const sync = async () => { + const app = await NestFactory.create(ApiModule, { preview: true }); + useSwagger(app, true); + await app.close(); +}; + +sync() + .then(() => { + console.log('Done'); + process.exit(0); + }) + .catch((error) => { + console.error(error); + console.log('Something went wrong'); + process.exit(1); + }); diff --git a/server/src/utils/sql.ts b/server/src/bin/sync-sql.ts similarity index 100% rename from server/src/utils/sql.ts rename to server/src/bin/sync-sql.ts diff --git a/server/src/commands/list-users.command.ts b/server/src/commands/list-users.command.ts index ea3e745463..299ea82283 100644 --- a/server/src/commands/list-users.command.ts +++ b/server/src/commands/list-users.command.ts @@ -1,18 +1,18 @@ import { Command, CommandRunner } from 'nest-commander'; -import { UserService } from 'src/services/user.service'; +import { CliService } from 'src/services/cli.service'; @Command({ name: 'list-users', description: 'List Immich users', }) export class ListUsersCommand extends CommandRunner { - constructor(private userService: UserService) { + constructor(private service: CliService) { super(); } async run(): Promise { try { - const users = await this.userService.listUsers(); + const users = await this.service.listUsers(); console.dir(users); } catch (error) { console.error(error); diff --git a/server/src/commands/oauth-login.ts b/server/src/commands/oauth-login.ts index c9bb4d5ef4..9ec7013fa5 100644 --- a/server/src/commands/oauth-login.ts +++ b/server/src/commands/oauth-login.ts @@ -1,19 +1,17 @@ import { Command, CommandRunner } from 'nest-commander'; -import { SystemConfigService } from 'src/services/system-config.service'; +import { CliService } from 'src/services/cli.service'; @Command({ name: 'enable-oauth-login', description: 'Enable OAuth login', }) export class EnableOAuthLogin extends CommandRunner { - constructor(private configService: SystemConfigService) { + constructor(private service: CliService) { super(); } async run(): Promise { - const config = await this.configService.getConfig(); - config.oauth.enabled = true; - await this.configService.updateConfig(config); + await this.service.enableOAuthLogin(); console.log('OAuth login has been enabled.'); } } @@ -23,14 +21,12 @@ export class EnableOAuthLogin extends CommandRunner { description: 'Disable OAuth login', }) export class DisableOAuthLogin extends CommandRunner { - constructor(private configService: SystemConfigService) { + constructor(private service: CliService) { super(); } async run(): Promise { - const config = await this.configService.getConfig(); - config.oauth.enabled = false; - await this.configService.updateConfig(config); + await this.service.disableOAuthLogin(); console.log('OAuth login has been disabled.'); } } diff --git a/server/src/commands/password-login.ts b/server/src/commands/password-login.ts index 3d992f8583..057abd1649 100644 --- a/server/src/commands/password-login.ts +++ b/server/src/commands/password-login.ts @@ -1,19 +1,17 @@ import { Command, CommandRunner } from 'nest-commander'; -import { SystemConfigService } from 'src/services/system-config.service'; +import { CliService } from 'src/services/cli.service'; @Command({ name: 'enable-password-login', description: 'Enable password login', }) export class EnablePasswordLoginCommand extends CommandRunner { - constructor(private configService: SystemConfigService) { + constructor(private service: CliService) { super(); } async run(): Promise { - const config = await this.configService.getConfig(); - config.passwordLogin.enabled = true; - await this.configService.updateConfig(config); + await this.service.enablePasswordLogin(); console.log('Password login has been enabled.'); } } @@ -23,14 +21,12 @@ export class EnablePasswordLoginCommand extends CommandRunner { description: 'Disable password login', }) export class DisablePasswordLoginCommand extends CommandRunner { - constructor(private configService: SystemConfigService) { + constructor(private service: CliService) { super(); } async run(): Promise { - const config = await this.configService.getConfig(); - config.passwordLogin.enabled = false; - await this.configService.updateConfig(config); + await this.service.disablePasswordLogin(); console.log('Password login has been disabled.'); } } diff --git a/server/src/commands/reset-admin-password.command.ts b/server/src/commands/reset-admin-password.command.ts index f7c0775c8b..32f77109b0 100644 --- a/server/src/commands/reset-admin-password.command.ts +++ b/server/src/commands/reset-admin-password.command.ts @@ -1,20 +1,9 @@ import { Command, CommandRunner, InquirerService, Question, QuestionSet } from 'nest-commander'; import { UserResponseDto } from 'src/dtos/user.dto'; -import { UserService } from 'src/services/user.service'; +import { CliService } from 'src/services/cli.service'; -@Command({ - name: 'reset-admin-password', - description: 'Reset the admin password', -}) -export class ResetAdminPasswordCommand extends CommandRunner { - constructor( - private userService: UserService, - private inquirer: InquirerService, - ) { - super(); - } - - ask = (admin: UserResponseDto) => { +const prompt = (inquirer: InquirerService) => { + return function ask(admin: UserResponseDto) { const { id, oauthId, email, name } = admin; console.log(`Found Admin: - ID=${id} @@ -22,12 +11,25 @@ export class ResetAdminPasswordCommand extends CommandRunner { - Email=${email} - Name=${name}`); - return this.inquirer.ask<{ password: string }>('prompt-password', {}).then(({ password }) => password); + return inquirer.ask<{ password: string }>('prompt-password', {}).then(({ password }) => password); }; +}; + +@Command({ + name: 'reset-admin-password', + description: 'Reset the admin password', +}) +export class ResetAdminPasswordCommand extends CommandRunner { + constructor( + private service: CliService, + private inquirer: InquirerService, + ) { + super(); + } async run(): Promise { try { - const { password, provided } = await this.userService.resetAdminPassword(this.ask); + const { password, provided } = await this.service.resetAdminPassword(prompt(this.inquirer)); if (provided) { console.log(`The admin password has been updated.`); diff --git a/server/src/config.ts b/server/src/config.ts index f6af82a94d..0f8a645005 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -1,12 +1,354 @@ import { RegisterQueueOptions } from '@nestjs/bullmq'; import { ConfigModuleOptions } from '@nestjs/config'; +import { CronExpression } from '@nestjs/schedule'; import { QueueOptions } from 'bullmq'; import { Request, Response } from 'express'; import { RedisOptions } from 'ioredis'; import Joi from 'joi'; import { CLS_ID, ClsModuleOptions } from 'nestjs-cls'; -import { LogLevel } from 'src/entities/system-config.entity'; -import { QueueName } from 'src/interfaces/job.interface'; +import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface'; + +export enum TranscodePolicy { + ALL = 'all', + OPTIMAL = 'optimal', + BITRATE = 'bitrate', + REQUIRED = 'required', + DISABLED = 'disabled', +} + +export enum TranscodeTarget { + NONE, + AUDIO, + VIDEO, + ALL, +} + +export enum VideoCodec { + H264 = 'h264', + HEVC = 'hevc', + VP9 = 'vp9', + AV1 = 'av1', +} + +export enum AudioCodec { + MP3 = 'mp3', + AAC = 'aac', + LIBOPUS = 'libopus', +} + +export enum TranscodeHWAccel { + NVENC = 'nvenc', + QSV = 'qsv', + VAAPI = 'vaapi', + RKMPP = 'rkmpp', + DISABLED = 'disabled', +} + +export enum ToneMapping { + HABLE = 'hable', + MOBIUS = 'mobius', + REINHARD = 'reinhard', + DISABLED = 'disabled', +} + +export enum CQMode { + AUTO = 'auto', + CQP = 'cqp', + ICQ = 'icq', +} + +export enum Colorspace { + SRGB = 'srgb', + P3 = 'p3', +} + +export enum ImageFormat { + JPEG = 'jpeg', + WEBP = 'webp', +} + +export enum LogLevel { + VERBOSE = 'verbose', + DEBUG = 'debug', + LOG = 'log', + WARN = 'warn', + ERROR = 'error', + FATAL = 'fatal', +} + +export interface SystemConfig { + ffmpeg: { + crf: number; + threads: number; + preset: string; + targetVideoCodec: VideoCodec; + acceptedVideoCodecs: VideoCodec[]; + targetAudioCodec: AudioCodec; + acceptedAudioCodecs: AudioCodec[]; + targetResolution: string; + maxBitrate: string; + bframes: number; + refs: number; + gopSize: number; + npl: number; + temporalAQ: boolean; + cqMode: CQMode; + twoPass: boolean; + preferredHwDevice: string; + transcode: TranscodePolicy; + accel: TranscodeHWAccel; + accelDecode: boolean; + tonemap: ToneMapping; + }; + job: Record; + logging: { + enabled: boolean; + level: LogLevel; + }; + machineLearning: { + enabled: boolean; + url: string; + clip: { + enabled: boolean; + modelName: string; + }; + duplicateDetection: { + enabled: boolean; + maxDistance: number; + }; + facialRecognition: { + enabled: boolean; + modelName: string; + minScore: number; + minFaces: number; + maxDistance: number; + }; + }; + map: { + enabled: boolean; + lightStyle: string; + darkStyle: string; + }; + reverseGeocoding: { + enabled: boolean; + }; + oauth: { + autoLaunch: boolean; + autoRegister: boolean; + buttonText: string; + clientId: string; + clientSecret: string; + defaultStorageQuota: number; + enabled: boolean; + issuerUrl: string; + mobileOverrideEnabled: boolean; + mobileRedirectUri: string; + scope: string; + signingAlgorithm: string; + storageLabelClaim: string; + storageQuotaClaim: string; + }; + passwordLogin: { + enabled: boolean; + }; + storageTemplate: { + enabled: boolean; + hashVerificationEnabled: boolean; + template: string; + }; + image: { + thumbnailFormat: ImageFormat; + thumbnailSize: number; + previewFormat: ImageFormat; + previewSize: number; + quality: number; + colorspace: Colorspace; + extractEmbedded: boolean; + }; + newVersionCheck: { + enabled: boolean; + }; + trash: { + enabled: boolean; + days: number; + }; + theme: { + customCss: string; + }; + library: { + scan: { + enabled: boolean; + cronExpression: string; + }; + watch: { + enabled: boolean; + }; + }; + notifications: { + smtp: { + enabled: boolean; + from: string; + replyTo: string; + transport: { + ignoreCert: boolean; + host: string; + port: number; + username: string; + password: string; + }; + }; + }; + server: { + externalDomain: string; + loginPageMessage: string; + }; + user: { + deleteDelay: number; + }; +} + +export const defaults = Object.freeze({ + ffmpeg: { + crf: 23, + threads: 0, + preset: 'ultrafast', + targetVideoCodec: VideoCodec.H264, + acceptedVideoCodecs: [VideoCodec.H264], + targetAudioCodec: AudioCodec.AAC, + acceptedAudioCodecs: [AudioCodec.AAC, AudioCodec.MP3, AudioCodec.LIBOPUS], + targetResolution: '720', + maxBitrate: '0', + bframes: -1, + refs: 0, + gopSize: 0, + npl: 0, + temporalAQ: false, + cqMode: CQMode.AUTO, + twoPass: false, + preferredHwDevice: 'auto', + transcode: TranscodePolicy.REQUIRED, + tonemap: ToneMapping.HABLE, + accel: TranscodeHWAccel.DISABLED, + accelDecode: false, + }, + job: { + [QueueName.BACKGROUND_TASK]: { concurrency: 5 }, + [QueueName.SMART_SEARCH]: { concurrency: 2 }, + [QueueName.METADATA_EXTRACTION]: { concurrency: 5 }, + [QueueName.FACE_DETECTION]: { concurrency: 2 }, + [QueueName.SEARCH]: { concurrency: 5 }, + [QueueName.SIDECAR]: { concurrency: 5 }, + [QueueName.LIBRARY]: { concurrency: 5 }, + [QueueName.MIGRATION]: { concurrency: 5 }, + [QueueName.THUMBNAIL_GENERATION]: { concurrency: 5 }, + [QueueName.VIDEO_CONVERSION]: { concurrency: 1 }, + [QueueName.NOTIFICATION]: { concurrency: 5 }, + }, + logging: { + enabled: true, + level: LogLevel.LOG, + }, + machineLearning: { + enabled: process.env.IMMICH_MACHINE_LEARNING_ENABLED !== 'false', + url: process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003', + clip: { + enabled: true, + modelName: 'ViT-B-32__openai', + }, + duplicateDetection: { + enabled: false, + maxDistance: 0.03, + }, + facialRecognition: { + enabled: true, + modelName: 'buffalo_l', + minScore: 0.7, + maxDistance: 0.5, + minFaces: 3, + }, + }, + map: { + enabled: true, + lightStyle: '', + darkStyle: '', + }, + reverseGeocoding: { + enabled: true, + }, + oauth: { + autoLaunch: false, + autoRegister: true, + buttonText: 'Login with OAuth', + clientId: '', + clientSecret: '', + defaultStorageQuota: 0, + enabled: false, + issuerUrl: '', + mobileOverrideEnabled: false, + mobileRedirectUri: '', + scope: 'openid email profile', + signingAlgorithm: 'RS256', + storageLabelClaim: 'preferred_username', + storageQuotaClaim: 'immich_quota', + }, + passwordLogin: { + enabled: true, + }, + storageTemplate: { + enabled: false, + hashVerificationEnabled: true, + template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}', + }, + image: { + thumbnailFormat: ImageFormat.WEBP, + thumbnailSize: 250, + previewFormat: ImageFormat.JPEG, + previewSize: 1440, + quality: 80, + colorspace: Colorspace.P3, + extractEmbedded: false, + }, + newVersionCheck: { + enabled: true, + }, + trash: { + enabled: true, + days: 30, + }, + theme: { + customCss: '', + }, + library: { + scan: { + enabled: true, + cronExpression: CronExpression.EVERY_DAY_AT_MIDNIGHT, + }, + watch: { + enabled: false, + }, + }, + server: { + externalDomain: '', + loginPageMessage: '', + }, + notifications: { + smtp: { + enabled: false, + from: '', + replyTo: '', + transport: { + ignoreCert: false, + host: '', + port: 587, + username: '', + password: '', + }, + }, + }, + user: { + deleteDelay: 7, + }, +}); const WHEN_DB_URL_SET = Joi.when('DB_URL', { is: Joi.exist(), @@ -18,8 +360,8 @@ export const immichAppConfig: ConfigModuleOptions = { envFilePath: '.env', isGlobal: true, validationSchema: Joi.object({ - NODE_ENV: Joi.string().optional().valid('development', 'production', 'staging').default('development'), - LOG_LEVEL: Joi.string() + IMMICH_ENV: Joi.string().optional().valid('development', 'production').default('production'), + IMMICH_LOG_LEVEL: Joi.string() .optional() .valid(...Object.values(LogLevel)), @@ -30,8 +372,7 @@ export const immichAppConfig: ConfigModuleOptions = { DB_VECTOR_EXTENSION: Joi.string().optional().valid('pgvector', 'pgvecto.rs').default('pgvecto.rs'), DB_SKIP_MIGRATIONS: Joi.boolean().optional().default(false), - MACHINE_LEARNING_PORT: Joi.number().optional(), - MICROSERVICES_PORT: Joi.number().optional(), + IMMICH_PORT: Joi.number().optional(), IMMICH_METRICS_PORT: Joi.number().optional(), IMMICH_METRICS: Joi.boolean().optional().default(false), diff --git a/server/src/constants.ts b/server/src/constants.ts index b6d6de815e..e5ab35a11e 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -1,7 +1,11 @@ import { Duration } from 'luxon'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; -import { Version } from 'src/utils/version'; +import { SemVer } from 'semver'; + +export const POSTGRES_VERSION_RANGE = '>=14.0.0'; +export const VECTORS_VERSION_RANGE = '0.2.x'; +export const VECTOR_VERSION_RANGE = '>=0.5 <1'; export const NEXT_RELEASE = 'NEXT_RELEASE'; export const LIFECYCLE_EXTENSION = 'x-immich-lifecycle'; @@ -11,13 +15,13 @@ export const ADDED_IN_PREFIX = 'This property was added in '; export const SALT_ROUNDS = 10; const { version } = JSON.parse(readFileSync('./package.json', 'utf8')); -export const serverVersion = Version.fromString(version); +export const serverVersion = new SemVer(version); export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 }); export const ONE_HOUR = Duration.fromObject({ hours: 1 }); -export const envName = (process.env.NODE_ENV || 'development').toUpperCase(); -export const isDev = process.env.NODE_ENV === 'development'; +export const envName = (process.env.IMMICH_ENV || 'production').toUpperCase(); +export const isDev = () => process.env.IMMICH_ENV === 'development'; export const APP_MEDIA_LOCATION = process.env.IMMICH_MEDIA_LOCATION || './upload'; export const WEB_ROOT = process.env.IMMICH_WEB_ROOT || '/usr/src/app/www'; diff --git a/server/src/controllers/activity.controller.ts b/server/src/controllers/activity.controller.ts index 9a5fc41885..de59437a89 100644 --- a/server/src/controllers/activity.controller.ts +++ b/server/src/controllers/activity.controller.ts @@ -14,7 +14,7 @@ import { ActivityService } from 'src/services/activity.service'; import { UUIDParamDto } from 'src/validation'; @ApiTags('Activity') -@Controller('activity') +@Controller('activities') export class ActivityController { constructor(private service: ActivityService) {} diff --git a/server/src/controllers/album.controller.ts b/server/src/controllers/album.controller.ts index c38f733b42..ea42ed4d79 100644 --- a/server/src/controllers/album.controller.ts +++ b/server/src/controllers/album.controller.ts @@ -17,7 +17,7 @@ import { AlbumService } from 'src/services/album.service'; import { ParseMeUUIDPipe, UUIDParamDto } from 'src/validation'; @ApiTags('Album') -@Controller('album') +@Controller('albums') export class AlbumController { constructor(private service: AlbumService) {} diff --git a/server/src/controllers/api-key.controller.ts b/server/src/controllers/api-key.controller.ts index e0b07ede50..4225bdc1bc 100644 --- a/server/src/controllers/api-key.controller.ts +++ b/server/src/controllers/api-key.controller.ts @@ -7,7 +7,7 @@ import { APIKeyService } from 'src/services/api-key.service'; import { UUIDParamDto } from 'src/validation'; @ApiTags('API Key') -@Controller('api-key') +@Controller('api-keys') export class APIKeyController { constructor(private service: APIKeyService) {} diff --git a/server/src/controllers/asset-media.controller.ts b/server/src/controllers/asset-media.controller.ts new file mode 100644 index 0000000000..064a6d22ab --- /dev/null +++ b/server/src/controllers/asset-media.controller.ts @@ -0,0 +1,94 @@ +import { + Body, + Controller, + HttpCode, + HttpStatus, + Inject, + Param, + ParseFilePipe, + Post, + Put, + Res, + UploadedFiles, + UseInterceptors, +} from '@nestjs/common'; +import { ApiConsumes, ApiTags } from '@nestjs/swagger'; +import { Response } from 'express'; +import { EndpointLifecycle } from 'src/decorators'; +import { + AssetBulkUploadCheckResponseDto, + AssetMediaResponseDto, + AssetMediaStatusEnum, + CheckExistingAssetsResponseDto, +} from 'src/dtos/asset-media-response.dto'; +import { + AssetBulkUploadCheckDto, + AssetMediaReplaceDto, + CheckExistingAssetsDto, + UploadFieldName, +} from 'src/dtos/asset-media.dto'; +import { AuthDto } from 'src/dtos/auth.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { Auth, Authenticated } from 'src/middleware/auth.guard'; +import { FileUploadInterceptor, Route, UploadFiles, getFiles } from 'src/middleware/file-upload.interceptor'; +import { AssetMediaService } from 'src/services/asset-media.service'; +import { FileNotEmptyValidator, UUIDParamDto } from 'src/validation'; + +@ApiTags('Asset') +@Controller(Route.ASSET) +export class AssetMediaController { + constructor( + @Inject(ILoggerRepository) private logger: ILoggerRepository, + private service: AssetMediaService, + ) {} + + /** + * Replace the asset with new file, without changing its id + */ + @Put(':id/file') + @UseInterceptors(FileUploadInterceptor) + @ApiConsumes('multipart/form-data') + @Authenticated({ sharedLink: true }) + @EndpointLifecycle({ addedAt: 'v1.106.0' }) + async replaceAsset( + @Auth() auth: AuthDto, + @Param() { id }: UUIDParamDto, + @UploadedFiles(new ParseFilePipe({ validators: [new FileNotEmptyValidator([UploadFieldName.ASSET_DATA])] })) + files: UploadFiles, + @Body() dto: AssetMediaReplaceDto, + @Res({ passthrough: true }) res: Response, + ): Promise { + const { file } = getFiles(files); + const responseDto = await this.service.replaceAsset(auth, id, dto, file); + if (responseDto.status === AssetMediaStatusEnum.DUPLICATE) { + res.status(HttpStatus.OK); + } + return responseDto; + } + + /** + * Checks if multiple assets exist on the server and returns all existing - used by background backup + */ + @Post('exist') + @HttpCode(HttpStatus.OK) + @Authenticated() + checkExistingAssets( + @Auth() auth: AuthDto, + @Body() dto: CheckExistingAssetsDto, + ): Promise { + return this.service.checkExistingAssets(auth, dto); + } + + /** + * Checks if assets exist by checksums + */ + @Post('bulk-upload-check') + @HttpCode(HttpStatus.OK) + @Authenticated() + checkBulkUpload( + @Auth() auth: AuthDto, + @Body() dto: AssetBulkUploadCheckDto, + ): Promise { + return this.service.bulkUploadCheck(auth, dto); + } +} diff --git a/server/src/controllers/asset-v1.controller.ts b/server/src/controllers/asset-v1.controller.ts index 2f093e1d1f..380aaca390 100644 --- a/server/src/controllers/asset-v1.controller.ts +++ b/server/src/controllers/asset-v1.controller.ts @@ -2,8 +2,8 @@ import { Body, Controller, Get, - HttpCode, HttpStatus, + Inject, Next, Param, ParseFilePipe, @@ -15,38 +15,24 @@ import { } from '@nestjs/common'; import { ApiBody, ApiConsumes, ApiHeader, ApiTags } from '@nestjs/swagger'; import { NextFunction, Response } from 'express'; -import { AssetResponseDto } from 'src/dtos/asset-response.dto'; -import { - AssetBulkUploadCheckResponseDto, - AssetFileUploadResponseDto, - CheckExistingAssetsResponseDto, -} from 'src/dtos/asset-v1-response.dto'; -import { - AssetBulkUploadCheckDto, - AssetSearchDto, - CheckExistingAssetsDto, - CreateAssetDto, - GetAssetThumbnailDto, - ServeFileDto, -} from 'src/dtos/asset-v1.dto'; +import { AssetFileUploadResponseDto } from 'src/dtos/asset-v1-response.dto'; +import { CreateAssetDto, GetAssetThumbnailDto, ServeFileDto } from 'src/dtos/asset-v1.dto'; import { AuthDto, ImmichHeader } from 'src/dtos/auth.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; -import { FileUploadInterceptor, ImmichFile, Route, mapToUploadFile } from 'src/middleware/file-upload.interceptor'; +import { FileUploadInterceptor, Route, UploadFiles, mapToUploadFile } from 'src/middleware/file-upload.interceptor'; import { AssetServiceV1 } from 'src/services/asset-v1.service'; import { sendFile } from 'src/utils/file'; import { FileNotEmptyValidator, UUIDParamDto } from 'src/validation'; -interface UploadFiles { - assetData: ImmichFile[]; - livePhotoData?: ImmichFile[]; - sidecarData: ImmichFile[]; -} - @ApiTags('Asset') @Controller(Route.ASSET) export class AssetControllerV1 { - constructor(private service: AssetServiceV1) {} + constructor( + private service: AssetServiceV1, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) {} @Post('upload') @UseInterceptors(AssetUploadInterceptor, FileUploadInterceptor) @@ -95,7 +81,7 @@ export class AssetControllerV1 { @Param() { id }: UUIDParamDto, @Query() dto: ServeFileDto, ) { - await sendFile(res, next, () => this.service.serveFile(auth, id, dto)); + await sendFile(res, next, () => this.service.serveFile(auth, id, dto), this.logger); } @Get('/thumbnail/:id') @@ -108,47 +94,6 @@ export class AssetControllerV1 { @Param() { id }: UUIDParamDto, @Query() dto: GetAssetThumbnailDto, ) { - await sendFile(res, next, () => this.service.serveThumbnail(auth, id, dto)); - } - - /** - * Get all AssetEntity belong to the user - */ - @Get('/') - @ApiHeader({ - name: 'if-none-match', - description: 'ETag of data already cached on the client', - required: false, - schema: { type: 'string' }, - }) - @Authenticated() - getAllAssets(@Auth() auth: AuthDto, @Query() dto: AssetSearchDto): Promise { - return this.service.getAllAssets(auth, dto); - } - - /** - * Checks if multiple assets exist on the server and returns all existing - used by background backup - */ - @Post('/exist') - @HttpCode(HttpStatus.OK) - @Authenticated() - checkExistingAssets( - @Auth() auth: AuthDto, - @Body() dto: CheckExistingAssetsDto, - ): Promise { - return this.service.checkExistingAssets(auth, dto); - } - - /** - * Checks if assets exist by checksums - */ - @Post('/bulk-upload-check') - @HttpCode(HttpStatus.OK) - @Authenticated() - checkBulkUpload( - @Auth() auth: AuthDto, - @Body() dto: AssetBulkUploadCheckDto, - ): Promise { - return this.service.bulkUploadCheck(auth, dto); + await sendFile(res, next, () => this.service.serveThumbnail(auth, id, dto), this.logger); } } diff --git a/server/src/controllers/download.controller.ts b/server/src/controllers/download.controller.ts index c9f26864af..bc1d01c4be 100644 --- a/server/src/controllers/download.controller.ts +++ b/server/src/controllers/download.controller.ts @@ -1,9 +1,10 @@ -import { Body, Controller, HttpCode, HttpStatus, Next, Param, Post, Res, StreamableFile } from '@nestjs/common'; +import { Body, Controller, HttpCode, HttpStatus, Inject, Next, Param, Post, Res, StreamableFile } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { NextFunction, Response } from 'express'; import { AssetIdsDto } from 'src/dtos/asset.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { DownloadInfoDto, DownloadResponseDto } from 'src/dtos/download.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { DownloadService } from 'src/services/download.service'; import { asStreamableFile, sendFile } from 'src/utils/file'; @@ -12,7 +13,10 @@ import { UUIDParamDto } from 'src/validation'; @ApiTags('Download') @Controller('download') export class DownloadController { - constructor(private service: DownloadService) {} + constructor( + private service: DownloadService, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) {} @Post('info') @Authenticated({ sharedLink: true }) @@ -38,6 +42,6 @@ export class DownloadController { @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, ) { - await sendFile(res, next, () => this.service.downloadFile(auth, id)); + await sendFile(res, next, () => this.service.downloadFile(auth, id), this.logger); } } diff --git a/server/src/controllers/duplicate.controller.ts b/server/src/controllers/duplicate.controller.ts new file mode 100644 index 0000000000..57a200ac39 --- /dev/null +++ b/server/src/controllers/duplicate.controller.ts @@ -0,0 +1,18 @@ +import { Controller, Get } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { AuthDto } from 'src/dtos/auth.dto'; +import { DuplicateResponseDto } from 'src/dtos/duplicate.dto'; +import { Auth, Authenticated } from 'src/middleware/auth.guard'; +import { DuplicateService } from 'src/services/duplicate.service'; + +@ApiTags('Duplicate') +@Controller('duplicates') +export class DuplicateController { + constructor(private service: DuplicateService) {} + + @Get() + @Authenticated() + getAssetDuplicates(@Auth() auth: AuthDto): Promise { + return this.service.getDuplicates(auth); + } +} diff --git a/server/src/controllers/face.controller.ts b/server/src/controllers/face.controller.ts index ec15bf3c59..38d65b0961 100644 --- a/server/src/controllers/face.controller.ts +++ b/server/src/controllers/face.controller.ts @@ -7,7 +7,7 @@ import { PersonService } from 'src/services/person.service'; import { UUIDParamDto } from 'src/validation'; @ApiTags('Face') -@Controller('face') +@Controller('faces') export class FaceController { constructor(private service: PersonService) {} diff --git a/server/src/controllers/file-report.controller.ts b/server/src/controllers/file-report.controller.ts index 1f9ebe52dd..523debfb4c 100644 --- a/server/src/controllers/file-report.controller.ts +++ b/server/src/controllers/file-report.controller.ts @@ -5,7 +5,7 @@ import { Authenticated } from 'src/middleware/auth.guard'; import { AuditService } from 'src/services/audit.service'; @ApiTags('File Report') -@Controller('report') +@Controller('reports') export class ReportController { constructor(private service: AuditService) {} diff --git a/server/src/controllers/index.ts b/server/src/controllers/index.ts index df1a44a157..187ba4b4db 100644 --- a/server/src/controllers/index.ts +++ b/server/src/controllers/index.ts @@ -2,11 +2,13 @@ import { ActivityController } from 'src/controllers/activity.controller'; import { AlbumController } from 'src/controllers/album.controller'; import { APIKeyController } from 'src/controllers/api-key.controller'; import { AppController } from 'src/controllers/app.controller'; +import { AssetMediaController } from 'src/controllers/asset-media.controller'; import { AssetControllerV1 } from 'src/controllers/asset-v1.controller'; import { AssetController } from 'src/controllers/asset.controller'; import { AuditController } from 'src/controllers/audit.controller'; import { AuthController } from 'src/controllers/auth.controller'; import { DownloadController } from 'src/controllers/download.controller'; +import { DuplicateController } from 'src/controllers/duplicate.controller'; import { FaceController } from 'src/controllers/face.controller'; import { ReportController } from 'src/controllers/file-report.controller'; import { JobController } from 'src/controllers/job.controller'; @@ -34,9 +36,11 @@ export const controllers = [ AppController, AssetController, AssetControllerV1, + AssetMediaController, AuditController, AuthController, DownloadController, + DuplicateController, FaceController, JobController, LibraryController, diff --git a/server/src/controllers/library.controller.ts b/server/src/controllers/library.controller.ts index 74a4f73d2a..b6d65874ca 100644 --- a/server/src/controllers/library.controller.ts +++ b/server/src/controllers/library.controller.ts @@ -1,11 +1,10 @@ -import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common'; +import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { CreateLibraryDto, LibraryResponseDto, LibraryStatsResponseDto, ScanLibraryDto, - SearchLibraryDto, UpdateLibraryDto, ValidateLibraryDto, ValidateLibraryResponseDto, @@ -15,14 +14,14 @@ import { LibraryService } from 'src/services/library.service'; import { UUIDParamDto } from 'src/validation'; @ApiTags('Library') -@Controller('library') +@Controller('libraries') export class LibraryController { constructor(private service: LibraryService) {} @Get() @Authenticated({ admin: true }) - getAllLibraries(@Query() dto: SearchLibraryDto): Promise { - return this.service.getAll(dto); + getAllLibraries(): Promise { + return this.service.getAll(); } @Post() diff --git a/server/src/controllers/partner.controller.ts b/server/src/controllers/partner.controller.ts index 1faf82898c..102f6f10ce 100644 --- a/server/src/controllers/partner.controller.ts +++ b/server/src/controllers/partner.controller.ts @@ -8,7 +8,7 @@ import { PartnerService } from 'src/services/partner.service'; import { UUIDParamDto } from 'src/validation'; @ApiTags('Partner') -@Controller('partner') +@Controller('partners') export class PartnerController { constructor(private service: PartnerService) {} diff --git a/server/src/controllers/person.controller.ts b/server/src/controllers/person.controller.ts index 6b9b658aeb..95de777f84 100644 --- a/server/src/controllers/person.controller.ts +++ b/server/src/controllers/person.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Delete, Get, Next, Param, Post, Put, Query, Res } from '@nestjs/common'; +import { Body, Controller, Delete, Get, Inject, Next, Param, Post, Put, Query, Res } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { NextFunction, Response } from 'express'; import { BulkIdResponseDto } from 'src/dtos/asset-ids.response.dto'; @@ -15,15 +15,19 @@ import { PersonStatisticsResponseDto, PersonUpdateDto, } from 'src/dtos/person.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { PersonService } from 'src/services/person.service'; import { sendFile } from 'src/utils/file'; import { UUIDParamDto } from 'src/validation'; @ApiTags('Person') -@Controller('person') +@Controller('people') export class PersonController { - constructor(private service: PersonService) {} + constructor( + private service: PersonService, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) {} @Get() @Authenticated() @@ -74,7 +78,7 @@ export class PersonController { @Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, ) { - await sendFile(res, next, () => this.service.getThumbnail(auth, id)); + await sendFile(res, next, () => this.service.getThumbnail(auth, id), this.logger); } @Get(':id/assets') diff --git a/server/src/controllers/server-info.controller.ts b/server/src/controllers/server-info.controller.ts index 758c50299a..03968c1f5e 100644 --- a/server/src/controllers/server-info.controller.ts +++ b/server/src/controllers/server-info.controller.ts @@ -3,25 +3,29 @@ import { ApiTags } from '@nestjs/swagger'; import { ServerConfigDto, ServerFeaturesDto, - ServerInfoResponseDto, ServerMediaTypesResponseDto, ServerPingResponse, ServerStatsResponseDto, + ServerStorageResponseDto, ServerThemeDto, ServerVersionResponseDto, } from 'src/dtos/server-info.dto'; import { Authenticated } from 'src/middleware/auth.guard'; import { ServerInfoService } from 'src/services/server-info.service'; +import { VersionService } from 'src/services/version.service'; @ApiTags('Server Info') @Controller('server-info') export class ServerInfoController { - constructor(private service: ServerInfoService) {} + constructor( + private service: ServerInfoService, + private versionService: VersionService, + ) {} - @Get() + @Get('storage') @Authenticated() - getServerInfo(): Promise { - return this.service.getInfo(); + getStorage(): Promise { + return this.service.getStorage(); } @Get('ping') @@ -31,7 +35,7 @@ export class ServerInfoController { @Get('version') getServerVersion(): ServerVersionResponseDto { - return this.service.getVersion(); + return this.versionService.getVersion(); } @Get('features') diff --git a/server/src/controllers/shared-link.controller.ts b/server/src/controllers/shared-link.controller.ts index 64d3e38e7e..a7be1911d9 100644 --- a/server/src/controllers/shared-link.controller.ts +++ b/server/src/controllers/shared-link.controller.ts @@ -17,7 +17,7 @@ import { respondWithCookie } from 'src/utils/response'; import { UUIDParamDto } from 'src/validation'; @ApiTags('Shared Link') -@Controller('shared-link') +@Controller('shared-links') export class SharedLinkController { constructor(private service: SharedLinkService) {} diff --git a/server/src/controllers/tag.controller.ts b/server/src/controllers/tag.controller.ts index 2a46fdec71..1f8a44dd5b 100644 --- a/server/src/controllers/tag.controller.ts +++ b/server/src/controllers/tag.controller.ts @@ -10,7 +10,7 @@ import { TagService } from 'src/services/tag.service'; import { UUIDParamDto } from 'src/validation'; @ApiTags('Tag') -@Controller('tag') +@Controller('tags') export class TagController { constructor(private service: TagService) {} diff --git a/server/src/controllers/user.controller.ts b/server/src/controllers/user.controller.ts index 8b1abbb26d..1b995c5944 100644 --- a/server/src/controllers/user.controller.ts +++ b/server/src/controllers/user.controller.ts @@ -5,6 +5,7 @@ import { Get, HttpCode, HttpStatus, + Inject, Next, Param, Post, @@ -19,6 +20,7 @@ import { NextFunction, Response } from 'express'; import { AuthDto } from 'src/dtos/auth.dto'; import { CreateProfileImageDto, CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto'; import { CreateUserDto, DeleteUserDto, UpdateUserDto, UserResponseDto } from 'src/dtos/user.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { FileUploadInterceptor, Route } from 'src/middleware/file-upload.interceptor'; import { UserService } from 'src/services/user.service'; @@ -28,7 +30,10 @@ import { UUIDParamDto } from 'src/validation'; @ApiTags('User') @Controller(Route.USER) export class UserController { - constructor(private service: UserService) {} + constructor( + private service: UserService, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) {} @Get() @Authenticated() @@ -36,10 +41,10 @@ export class UserController { return this.service.getAll(auth, isAll); } - @Get('info/:id') - @Authenticated() - getUserById(@Param() { id }: UUIDParamDto): Promise { - return this.service.get(id); + @Post() + @Authenticated({ admin: true }) + createUser(@Body() createUserDto: CreateUserDto): Promise { + return this.service.create(createUserDto); } @Get('me') @@ -48,10 +53,10 @@ export class UserController { return this.service.getMe(auth); } - @Post() - @Authenticated({ admin: true }) - createUser(@Body() createUserDto: CreateUserDto): Promise { - return this.service.create(createUserDto); + @Get(':id') + @Authenticated() + getUserById(@Param() { id }: UUIDParamDto): Promise { + return this.service.get(id); } @Delete('profile-image') @@ -96,10 +101,10 @@ export class UserController { return this.service.createProfileImage(auth, fileInfo); } - @Get('profile-image/:id') + @Get(':id/profile-image') @FileResponse() @Authenticated() async getProfileImage(@Res() res: Response, @Next() next: NextFunction, @Param() { id }: UUIDParamDto) { - await sendFile(res, next, () => this.service.getProfileImage(id)); + await sendFile(res, next, () => this.service.getProfileImage(id), this.logger); } } diff --git a/server/src/cores/access.core.ts b/server/src/cores/access.core.ts index 6f8930d05a..ae666562cf 100644 --- a/server/src/cores/access.core.ts +++ b/server/src/cores/access.core.ts @@ -274,7 +274,7 @@ export class AccessCore { } case Permission.ASSET_UPLOAD: { - return await this.repository.library.checkOwnerAccess(auth.user.id, ids); + return ids.has(auth.user.id) ? new Set([auth.user.id]) : new Set(); } case Permission.ARCHIVE_READ: { diff --git a/server/src/cores/storage.core.ts b/server/src/cores/storage.core.ts index 4e5f4742a4..5861c31ff8 100644 --- a/server/src/cores/storage.core.ts +++ b/server/src/cores/storage.core.ts @@ -1,18 +1,18 @@ import { randomUUID } from 'node:crypto'; import { dirname, join, resolve } from 'node:path'; +import { ImageFormat } from 'src/config'; import { APP_MEDIA_LOCATION } from 'src/constants'; import { SystemConfigCore } from 'src/cores/system-config.core'; import { AssetEntity } from 'src/entities/asset.entity'; import { AssetPathType, PathType, PersonPathType } from 'src/entities/move.entity'; import { PersonEntity } from 'src/entities/person.entity'; -import { ImageFormat } from 'src/entities/system-config.entity'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; export enum StorageFolder { ENCODED_VIDEO = 'encoded-video', @@ -49,10 +49,10 @@ export class StorageCore { private moveRepository: IMoveRepository, private personRepository: IPersonRepository, private storageRepository: IStorageRepository, - systemConfigRepository: ISystemConfigRepository, + systemMetadataRepository: ISystemMetadataRepository, private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(systemConfigRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); } static create( @@ -61,7 +61,7 @@ export class StorageCore { moveRepository: IMoveRepository, personRepository: IPersonRepository, storageRepository: IStorageRepository, - systemConfigRepository: ISystemConfigRepository, + systemMetadataRepository: ISystemMetadataRepository, logger: ILoggerRepository, ) { if (!instance) { @@ -71,7 +71,7 @@ export class StorageCore { moveRepository, personRepository, storageRepository, - systemConfigRepository, + systemMetadataRepository, logger, ); } diff --git a/server/src/cores/system-config.core.ts b/server/src/cores/system-config.core.ts index 17d9ed2270..b03fe482c3 100644 --- a/server/src/cores/system-config.core.ts +++ b/server/src/cores/system-config.core.ts @@ -1,201 +1,37 @@ -import { BadRequestException, ForbiddenException, Injectable } from '@nestjs/common'; -import { CronExpression } from '@nestjs/schedule'; +import { Injectable } from '@nestjs/common'; +import AsyncLock from 'async-lock'; import { plainToInstance } from 'class-transformer'; import { validate } from 'class-validator'; import { load as loadYaml } from 'js-yaml'; import * as _ from 'lodash'; import { Subject } from 'rxjs'; +import { SystemConfig, defaults } from 'src/config'; import { SystemConfigDto } from 'src/dtos/system-config.dto'; -import { - AudioCodec, - CQMode, - Colorspace, - ImageFormat, - LogLevel, - SystemConfig, - SystemConfigEntity, - SystemConfigKey, - SystemConfigValue, - ToneMapping, - TranscodeHWAccel, - TranscodePolicy, - VideoCodec, -} from 'src/entities/system-config.entity'; -import { QueueName } from 'src/interfaces/job.interface'; +import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; +import { DatabaseLock } from 'src/interfaces/database.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { getKeysDeep, unsetDeep } from 'src/utils/misc'; +import { DeepPartial } from 'typeorm'; export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise; -export const defaults = Object.freeze({ - ffmpeg: { - crf: 23, - threads: 0, - preset: 'ultrafast', - targetVideoCodec: VideoCodec.H264, - acceptedVideoCodecs: [VideoCodec.H264], - targetAudioCodec: AudioCodec.AAC, - acceptedAudioCodecs: [AudioCodec.AAC, AudioCodec.MP3, AudioCodec.LIBOPUS], - targetResolution: '720', - maxBitrate: '0', - bframes: -1, - refs: 0, - gopSize: 0, - npl: 0, - temporalAQ: false, - cqMode: CQMode.AUTO, - twoPass: false, - preferredHwDevice: 'auto', - transcode: TranscodePolicy.REQUIRED, - tonemap: ToneMapping.HABLE, - accel: TranscodeHWAccel.DISABLED, - }, - job: { - [QueueName.BACKGROUND_TASK]: { concurrency: 5 }, - [QueueName.SMART_SEARCH]: { concurrency: 2 }, - [QueueName.METADATA_EXTRACTION]: { concurrency: 5 }, - [QueueName.FACE_DETECTION]: { concurrency: 2 }, - [QueueName.SEARCH]: { concurrency: 5 }, - [QueueName.SIDECAR]: { concurrency: 5 }, - [QueueName.LIBRARY]: { concurrency: 5 }, - [QueueName.MIGRATION]: { concurrency: 5 }, - [QueueName.THUMBNAIL_GENERATION]: { concurrency: 5 }, - [QueueName.VIDEO_CONVERSION]: { concurrency: 1 }, - [QueueName.NOTIFICATION]: { concurrency: 5 }, - }, - logging: { - enabled: true, - level: LogLevel.LOG, - }, - machineLearning: { - enabled: process.env.IMMICH_MACHINE_LEARNING_ENABLED !== 'false', - url: process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003', - clip: { - enabled: true, - modelName: 'ViT-B-32__openai', - }, - facialRecognition: { - enabled: true, - modelName: 'buffalo_l', - minScore: 0.7, - maxDistance: 0.5, - minFaces: 3, - }, - }, - map: { - enabled: true, - lightStyle: '', - darkStyle: '', - }, - reverseGeocoding: { - enabled: true, - }, - oauth: { - autoLaunch: false, - autoRegister: true, - buttonText: 'Login with OAuth', - clientId: '', - clientSecret: '', - defaultStorageQuota: 0, - enabled: false, - issuerUrl: '', - mobileOverrideEnabled: false, - mobileRedirectUri: '', - scope: 'openid email profile', - signingAlgorithm: 'RS256', - storageLabelClaim: 'preferred_username', - storageQuotaClaim: 'immich_quota', - }, - passwordLogin: { - enabled: true, - }, - storageTemplate: { - enabled: false, - hashVerificationEnabled: true, - template: '{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}', - }, - image: { - thumbnailFormat: ImageFormat.WEBP, - thumbnailSize: 250, - previewFormat: ImageFormat.JPEG, - previewSize: 1440, - quality: 80, - colorspace: Colorspace.P3, - extractEmbedded: false, - }, - newVersionCheck: { - enabled: true, - }, - trash: { - enabled: true, - days: 30, - }, - theme: { - customCss: '', - }, - library: { - scan: { - enabled: true, - cronExpression: CronExpression.EVERY_DAY_AT_MIDNIGHT, - }, - watch: { - enabled: false, - }, - }, - server: { - externalDomain: '', - loginPageMessage: '', - }, - notifications: { - smtp: { - enabled: false, - from: '', - replyTo: '', - transport: { - ignoreCert: false, - host: '', - port: 587, - username: '', - password: '', - }, - }, - }, - user: { - deleteDelay: 7, - }, -}); - -export enum FeatureFlag { - SMART_SEARCH = 'smartSearch', - FACIAL_RECOGNITION = 'facialRecognition', - MAP = 'map', - REVERSE_GEOCODING = 'reverseGeocoding', - SIDECAR = 'sidecar', - SEARCH = 'search', - OAUTH = 'oauth', - OAUTH_AUTO_LAUNCH = 'oauthAutoLaunch', - PASSWORD_LOGIN = 'passwordLogin', - CONFIG_FILE = 'configFile', - TRASH = 'trash', - EMAIL = 'email', -} - -export type FeatureFlags = Record; - let instance: SystemConfigCore | null; @Injectable() export class SystemConfigCore { - private configCache: SystemConfigEntity[] | null = null; + private readonly asyncLock = new AsyncLock(); + private config: SystemConfig | null = null; + private lastUpdated: number | null = null; - public config$ = new Subject(); + config$ = new Subject(); private constructor( - private repository: ISystemConfigRepository, + private repository: ISystemMetadataRepository, private logger: ILoggerRepository, ) {} - static create(repository: ISystemConfigRepository, logger: ILoggerRepository) { + static create(repository: ISystemMetadataRepository, logger: ILoggerRepository) { if (!instance) { instance = new SystemConfigCore(repository, logger); } @@ -206,182 +42,103 @@ export class SystemConfigCore { instance = null; } - async requireFeature(feature: FeatureFlag) { - const hasFeature = await this.hasFeature(feature); - if (!hasFeature) { - switch (feature) { - case FeatureFlag.SMART_SEARCH: { - throw new BadRequestException('Smart search is not enabled'); - } - case FeatureFlag.FACIAL_RECOGNITION: { - throw new BadRequestException('Facial recognition is not enabled'); - } - case FeatureFlag.SIDECAR: { - throw new BadRequestException('Sidecar is not enabled'); - } - case FeatureFlag.SEARCH: { - throw new BadRequestException('Search is not enabled'); - } - case FeatureFlag.OAUTH: { - throw new BadRequestException('OAuth is not enabled'); - } - case FeatureFlag.PASSWORD_LOGIN: { - throw new BadRequestException('Password login is not enabled'); - } - case FeatureFlag.CONFIG_FILE: { - throw new BadRequestException('Config file is not set'); - } - default: { - throw new ForbiddenException(`Missing required feature: ${feature}`); + async getConfig(force = false): Promise { + if (force || !this.config) { + const lastUpdated = this.lastUpdated; + await this.asyncLock.acquire(DatabaseLock[DatabaseLock.GetSystemConfig], async () => { + if (lastUpdated === this.lastUpdated) { + this.config = await this.buildConfig(); + this.lastUpdated = Date.now(); } + }); + } + + return this.config!; + } + + async updateConfig(newConfig: SystemConfig): Promise { + // get the difference between the new config and the default config + const partialConfig: DeepPartial = {}; + for (const property of getKeysDeep(defaults)) { + const newValue = _.get(newConfig, property); + const isEmpty = newValue === undefined || newValue === null || newValue === ''; + const defaultValue = _.get(defaults, property); + const isEqual = newValue === defaultValue || _.isEqual(newValue, defaultValue); + + if (isEmpty || isEqual) { + continue; } + + _.set(partialConfig, property, newValue); } + + await this.repository.set(SystemMetadataKey.SYSTEM_CONFIG, partialConfig); + + const config = await this.getConfig(true); + this.config$.next(config); + return config; } - async hasFeature(feature: FeatureFlag) { - const features = await this.getFeatures(); - return features[feature] ?? false; + async refreshConfig() { + const newConfig = await this.getConfig(true); + this.config$.next(newConfig); } - async getFeatures(): Promise { - const config = await this.getConfig(); - const mlEnabled = config.machineLearning.enabled; - - return { - [FeatureFlag.SMART_SEARCH]: mlEnabled && config.machineLearning.clip.enabled, - [FeatureFlag.FACIAL_RECOGNITION]: mlEnabled && config.machineLearning.facialRecognition.enabled, - [FeatureFlag.MAP]: config.map.enabled, - [FeatureFlag.REVERSE_GEOCODING]: config.reverseGeocoding.enabled, - [FeatureFlag.SIDECAR]: true, - [FeatureFlag.SEARCH]: true, - [FeatureFlag.TRASH]: config.trash.enabled, - [FeatureFlag.OAUTH]: config.oauth.enabled, - [FeatureFlag.OAUTH_AUTO_LAUNCH]: config.oauth.autoLaunch, - [FeatureFlag.PASSWORD_LOGIN]: config.passwordLogin.enabled, - [FeatureFlag.CONFIG_FILE]: !!process.env.IMMICH_CONFIG_FILE, - [FeatureFlag.EMAIL]: config.notifications.smtp.enabled, - }; + isUsingConfigFile() { + return !!process.env.IMMICH_CONFIG_FILE; } - public getDefaults(): SystemConfig { - return defaults; - } + private async buildConfig() { + // load partial + const partial = this.isUsingConfigFile() + ? await this.loadFromFile(process.env.IMMICH_CONFIG_FILE as string) + : await this.repository.get(SystemMetadataKey.SYSTEM_CONFIG); - public async getConfig(force = false): Promise { - const configFilePath = process.env.IMMICH_CONFIG_FILE; + // merge with defaults const config = _.cloneDeep(defaults); - const overrides = configFilePath ? await this.loadFromFile(configFilePath, force) : await this.repository.load(); - - for (const { key, value } of overrides) { - // set via dot notation - _.set(config, key, value); + for (const property of getKeysDeep(partial)) { + _.set(config, property, _.get(partial, property)); } + // check for extra properties + const unknownKeys = _.cloneDeep(config); + for (const property of getKeysDeep(defaults)) { + unsetDeep(unknownKeys, property); + } + + if (!_.isEmpty(unknownKeys)) { + this.logger.warn(`Unknown keys found: ${JSON.stringify(unknownKeys, null, 2)}`); + } + + // validate full config const errors = await validate(plainToInstance(SystemConfigDto, config)); if (errors.length > 0) { - this.logger.error('Validation error', errors); - if (configFilePath) { + if (this.isUsingConfigFile()) { throw new Error(`Invalid value(s) in file: ${errors}`); + } else { + this.logger.error('Validation error', errors); } } if (!config.ffmpeg.acceptedVideoCodecs.includes(config.ffmpeg.targetVideoCodec)) { - config.ffmpeg.acceptedVideoCodecs.unshift(config.ffmpeg.targetVideoCodec); + config.ffmpeg.acceptedVideoCodecs.push(config.ffmpeg.targetVideoCodec); } if (!config.ffmpeg.acceptedAudioCodecs.includes(config.ffmpeg.targetAudioCodec)) { - config.ffmpeg.acceptedAudioCodecs.unshift(config.ffmpeg.targetAudioCodec); + config.ffmpeg.acceptedAudioCodecs.push(config.ffmpeg.targetAudioCodec); } return config; } - public async updateConfig(newConfig: SystemConfig): Promise { - if (await this.hasFeature(FeatureFlag.CONFIG_FILE)) { - throw new BadRequestException('Cannot update configuration while IMMICH_CONFIG_FILE is in use'); - } - - const updates: SystemConfigEntity[] = []; - const deletes: SystemConfigEntity[] = []; - - for (const key of Object.values(SystemConfigKey)) { - // get via dot notation - const item = { key, value: _.get(newConfig, key) as SystemConfigValue }; - const defaultValue = _.get(defaults, key); - const isMissing = !_.has(newConfig, key); - - if ( - isMissing || - item.value === null || - item.value === '' || - item.value === defaultValue || - _.isEqual(item.value, defaultValue) - ) { - deletes.push(item); - continue; - } - - updates.push(item); - } - - if (updates.length > 0) { - await this.repository.saveAll(updates); - } - - if (deletes.length > 0) { - await this.repository.deleteKeys(deletes.map((item) => item.key)); - } - - const config = await this.getConfig(); - - this.config$.next(config); - - return config; - } - - public async refreshConfig() { - const newConfig = await this.getConfig(true); - - this.config$.next(newConfig); - } - - private async loadFromFile(filepath: string, force = false) { - if (force || !this.configCache) { - try { - const file = await this.repository.readFile(filepath); - const config = loadYaml(file.toString()) as any; - const overrides: SystemConfigEntity[] = []; - - for (const key of Object.values(SystemConfigKey)) { - const value = _.get(config, key); - this.unsetDeep(config, key); - if (value !== undefined) { - overrides.push({ key, value }); - } - } - - if (!_.isEmpty(config)) { - this.logger.warn(`Unknown keys found: ${JSON.stringify(config, null, 2)}`); - } - - this.configCache = overrides; - } catch (error: Error | any) { - this.logger.error(`Unable to load configuration file: ${filepath}`); - throw error; - } - } - - return this.configCache; - } - - private unsetDeep(object: object, key: string) { - _.unset(object, key); - const path = key.split('.'); - while (path.pop()) { - if (!_.isEmpty(_.get(object, path))) { - return; - } - _.unset(object, path); + private async loadFromFile(filepath: string) { + try { + const file = await this.repository.readFile(filepath); + return loadYaml(file.toString()) as unknown; + } catch (error: Error | any) { + this.logger.error(`Unable to load configuration file: ${filepath}`); + this.logger.error(error); + throw error; } } } diff --git a/server/src/cores/user.core.ts b/server/src/cores/user.core.ts index e8596db3e7..504687fb18 100644 --- a/server/src/cores/user.core.ts +++ b/server/src/cores/user.core.ts @@ -2,10 +2,8 @@ import { BadRequestException, ForbiddenException } from '@nestjs/common'; import sanitize from 'sanitize-filename'; import { SALT_ROUNDS } from 'src/constants'; import { UserResponseDto } from 'src/dtos/user.dto'; -import { LibraryType } from 'src/entities/library.entity'; import { UserEntity } from 'src/entities/user.entity'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; -import { ILibraryRepository } from 'src/interfaces/library.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; let instance: UserCore | null; @@ -13,17 +11,12 @@ let instance: UserCore | null; export class UserCore { private constructor( private cryptoRepository: ICryptoRepository, - private libraryRepository: ILibraryRepository, private userRepository: IUserRepository, ) {} - static create( - cryptoRepository: ICryptoRepository, - libraryRepository: ILibraryRepository, - userRepository: IUserRepository, - ) { + static create(cryptoRepository: ICryptoRepository, userRepository: IUserRepository) { if (!instance) { - instance = new UserCore(cryptoRepository, libraryRepository, userRepository); + instance = new UserCore(cryptoRepository, userRepository); } return instance; @@ -70,7 +63,7 @@ export class UserCore { dto.storageLabel = null; } - return this.userRepository.update(id, dto); + return this.userRepository.update(id, { ...dto, updatedAt: new Date() }); } async createUser(dto: Partial & { email: string }): Promise { @@ -93,17 +86,7 @@ export class UserCore { if (payload.storageLabel) { payload.storageLabel = sanitize(payload.storageLabel.replaceAll('.', '')); } - const userEntity = await this.userRepository.create(payload); - await this.libraryRepository.create({ - owner: { id: userEntity.id } as UserEntity, - name: 'Default Library', - assets: [], - type: LibraryType.UPLOAD, - importPaths: [], - exclusionPatterns: [], - isVisible: true, - }); - return userEntity; + return this.userRepository.create(payload); } } diff --git a/server/src/database.config.ts b/server/src/database.config.ts index 9b7e16ae58..9cc317a734 100644 --- a/server/src/database.config.ts +++ b/server/src/database.config.ts @@ -33,5 +33,5 @@ export const databaseConfig: PostgresConnectionOptions = { */ export const dataSource = new DataSource({ ...databaseConfig, host: 'localhost' }); -export const vectorExt = +export const getVectorExtension = () => process.env.DB_VECTOR_EXTENSION === 'pgvector' ? DatabaseExtension.VECTOR : DatabaseExtension.VECTORS; diff --git a/server/src/dtos/album.dto.ts b/server/src/dtos/album.dto.ts index 19d03a4d8e..21eb649e11 100644 --- a/server/src/dtos/album.dto.ts +++ b/server/src/dtos/album.dto.ts @@ -2,7 +2,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { ArrayNotEmpty, IsArray, IsEnum, IsString, ValidateNested } from 'class-validator'; import _ from 'lodash'; -import { PropertyLifecycle } from 'src/decorators'; import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { UserResponseDto, mapUser } from 'src/dtos/user.dto'; @@ -25,10 +24,6 @@ export class AlbumUserAddDto { } export class AddUsersDto { - @ValidateUUID({ each: true, optional: true }) - @PropertyLifecycle({ deprecatedAt: 'v1.102.0' }) - sharedUserIds?: string[]; - @ArrayNotEmpty() albumUsers!: AlbumUserAddDto[]; } @@ -55,13 +50,8 @@ export class CreateAlbumDto { @IsArray() @ValidateNested({ each: true }) @Type(() => AlbumUserCreateDto) - @PropertyLifecycle({ addedAt: 'v1.104.0' }) albumUsers?: AlbumUserCreateDto[]; - @ValidateUUID({ optional: true, each: true }) - @PropertyLifecycle({ deprecatedAt: 'v1.104.0' }) - sharedWithUserIds?: string[]; - @ValidateUUID({ optional: true, each: true }) assetIds?: string[]; } @@ -137,8 +127,6 @@ export class AlbumResponseDto { updatedAt!: Date; albumThumbnailAssetId!: string | null; shared!: boolean; - @PropertyLifecycle({ deprecatedAt: 'v1.102.0' }) - sharedUsers!: UserResponseDto[]; albumUsers!: AlbumUserResponseDto[]; hasSharedLink!: boolean; assets!: AssetResponseDto[]; @@ -192,7 +180,6 @@ export const mapAlbum = (entity: AlbumEntity, withAssets: boolean, auth?: AuthDt id: entity.id, ownerId: entity.ownerId, owner: mapUser(entity.owner), - sharedUsers, albumUsers: albumUsersSorted, shared: hasSharedUser || hasSharedLink, hasSharedLink, diff --git a/server/src/dtos/asset-media-response.dto.ts b/server/src/dtos/asset-media-response.dto.ts new file mode 100644 index 0000000000..66e2e3160a --- /dev/null +++ b/server/src/dtos/asset-media-response.dto.ts @@ -0,0 +1,36 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export enum AssetMediaStatusEnum { + REPLACED = 'replaced', + DUPLICATE = 'duplicate', +} +export class AssetMediaResponseDto { + @ApiProperty({ enum: AssetMediaStatusEnum, enumName: 'AssetMediaStatus' }) + status!: AssetMediaStatusEnum; + id!: string; +} + +export enum AssetUploadAction { + ACCEPT = 'accept', + REJECT = 'reject', +} + +export enum AssetRejectReason { + DUPLICATE = 'duplicate', + UNSUPPORTED_FORMAT = 'unsupported-format', +} + +export class AssetBulkUploadCheckResult { + id!: string; + action!: AssetUploadAction; + reason?: AssetRejectReason; + assetId?: string; +} + +export class AssetBulkUploadCheckResponseDto { + results!: AssetBulkUploadCheckResult[]; +} + +export class CheckExistingAssetsResponseDto { + existingIds!: string[]; +} diff --git a/server/src/dtos/asset-media.dto.ts b/server/src/dtos/asset-media.dto.ts new file mode 100644 index 0000000000..2f8fa105cb --- /dev/null +++ b/server/src/dtos/asset-media.dto.ts @@ -0,0 +1,64 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { ArrayNotEmpty, IsArray, IsNotEmpty, IsString, ValidateNested } from 'class-validator'; +import { Optional, ValidateDate } from 'src/validation'; + +export enum UploadFieldName { + ASSET_DATA = 'assetData', + LIVE_PHOTO_DATA = 'livePhotoData', + SIDECAR_DATA = 'sidecarData', + PROFILE_DATA = 'file', +} + +export class AssetMediaReplaceDto { + @IsNotEmpty() + @IsString() + deviceAssetId!: string; + + @IsNotEmpty() + @IsString() + deviceId!: string; + + @ValidateDate() + fileCreatedAt!: Date; + + @ValidateDate() + fileModifiedAt!: Date; + + @Optional() + @IsString() + duration?: string; + + // The properties below are added to correctly generate the API docs + // and client SDKs. Validation should be handled in the controller. + @ApiProperty({ type: 'string', format: 'binary' }) + [UploadFieldName.ASSET_DATA]!: any; +} + +export class AssetBulkUploadCheckItem { + @IsString() + @IsNotEmpty() + id!: string; + + /** base64 or hex encoded sha1 hash */ + @IsString() + @IsNotEmpty() + checksum!: string; +} + +export class AssetBulkUploadCheckDto { + @IsArray() + @ValidateNested({ each: true }) + @Type(() => AssetBulkUploadCheckItem) + assets!: AssetBulkUploadCheckItem[]; +} + +export class CheckExistingAssetsDto { + @ArrayNotEmpty() + @IsString({ each: true }) + @IsNotEmpty({ each: true }) + deviceAssetIds!: string[]; + + @IsNotEmpty() + deviceId!: string; +} diff --git a/server/src/dtos/asset-response.dto.ts b/server/src/dtos/asset-response.dto.ts index 317a672ada..36a4ce88c0 100644 --- a/server/src/dtos/asset-response.dto.ts +++ b/server/src/dtos/asset-response.dto.ts @@ -31,7 +31,8 @@ export class AssetResponseDto extends SanitizedAssetResponseDto { deviceId!: string; ownerId!: string; owner?: UserResponseDto; - libraryId!: string; + @PropertyLifecycle({ deprecatedAt: 'v1.106.0' }) + libraryId?: string | null; originalPath!: string; originalFileName!: string; fileCreatedAt!: Date; @@ -41,10 +42,6 @@ export class AssetResponseDto extends SanitizedAssetResponseDto { isArchived!: boolean; isTrashed!: boolean; isOffline!: boolean; - @PropertyLifecycle({ deprecatedAt: 'v1.104.0' }) - isExternal?: boolean; - @PropertyLifecycle({ deprecatedAt: 'v1.104.0' }) - isReadOnly?: boolean; exifInfo?: ExifResponseDto; smartInfo?: SmartInfoResponseDto; tags?: TagResponseDto[]; @@ -55,6 +52,7 @@ export class AssetResponseDto extends SanitizedAssetResponseDto { stack?: AssetResponseDto[]; @ApiProperty({ type: 'integer' }) stackCount!: number | null; + duplicateId?: string | null; } export type AssetMapOptions = { @@ -132,16 +130,12 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As : undefined, stackCount: entity.stack?.assets?.length ?? null, isOffline: entity.isOffline, - isExternal: false, - isReadOnly: false, hasMetadata: true, + duplicateId: entity.duplicateId, }; } export class MemoryLaneResponseDto { - @PropertyLifecycle({ deprecatedAt: 'v1.100.0' }) - title!: string; - @ApiProperty({ type: 'integer' }) yearsAgo!: number; diff --git a/server/src/dtos/asset-v1-response.dto.ts b/server/src/dtos/asset-v1-response.dto.ts index 687b336428..f628b708dc 100644 --- a/server/src/dtos/asset-v1-response.dto.ts +++ b/server/src/dtos/asset-v1-response.dto.ts @@ -1,29 +1,4 @@ -export class AssetBulkUploadCheckResult { - id!: string; - action!: AssetUploadAction; - reason?: AssetRejectReason; - assetId?: string; -} - -export class AssetBulkUploadCheckResponseDto { - results!: AssetBulkUploadCheckResult[]; -} - -export enum AssetUploadAction { - ACCEPT = 'accept', - REJECT = 'reject', -} - -export enum AssetRejectReason { - DUPLICATE = 'duplicate', - UNSUPPORTED_FORMAT = 'unsupported-format', -} - export class AssetFileUploadResponseDto { id!: string; duplicate!: boolean; } - -export class CheckExistingAssetsResponseDto { - existingIds!: string[]; -} diff --git a/server/src/dtos/asset-v1.dto.ts b/server/src/dtos/asset-v1.dto.ts index 131d28ca4a..0ec68e677a 100644 --- a/server/src/dtos/asset-v1.dto.ts +++ b/server/src/dtos/asset-v1.dto.ts @@ -1,72 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; -import { Type } from 'class-transformer'; -import { ArrayNotEmpty, IsArray, IsEnum, IsInt, IsNotEmpty, IsString, IsUUID, ValidateNested } from 'class-validator'; +import { IsEnum, IsNotEmpty, IsString } from 'class-validator'; import { UploadFieldName } from 'src/dtos/asset.dto'; -import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation'; - -export class AssetBulkUploadCheckItem { - @IsString() - @IsNotEmpty() - id!: string; - - /** base64 or hex encoded sha1 hash */ - @IsString() - @IsNotEmpty() - checksum!: string; -} - -export class AssetBulkUploadCheckDto { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => AssetBulkUploadCheckItem) - assets!: AssetBulkUploadCheckItem[]; -} - -export class AssetSearchDto { - @ValidateBoolean({ optional: true }) - isFavorite?: boolean; - - @ValidateBoolean({ optional: true }) - isArchived?: boolean; - - @Optional() - @IsInt() - @Type(() => Number) - @ApiProperty({ type: 'integer' }) - skip?: number; - - @Optional() - @IsInt() - @Type(() => Number) - @ApiProperty({ type: 'integer' }) - take?: number; - - @Optional() - @IsUUID('4') - @ApiProperty({ format: 'uuid' }) - userId?: string; - - @ValidateDate({ optional: true }) - updatedAfter?: Date; - - @ValidateDate({ optional: true }) - updatedBefore?: Date; -} - -export class CheckExistingAssetsDto { - @ArrayNotEmpty() - @IsString({ each: true }) - @IsNotEmpty({ each: true }) - deviceAssetIds!: string[]; - - @IsNotEmpty() - deviceId!: string; -} +import { Optional, ValidateBoolean, ValidateDate } from 'src/validation'; export class CreateAssetDto { - @ValidateUUID({ optional: true }) - libraryId?: string; - @IsNotEmpty() @IsString() deviceAssetId!: string; diff --git a/server/src/dtos/asset.dto.ts b/server/src/dtos/asset.dto.ts index 72f1b24c1b..e60c323a6e 100644 --- a/server/src/dtos/asset.dto.ts +++ b/server/src/dtos/asset.dto.ts @@ -57,6 +57,9 @@ export class AssetBulkUpdateDto extends UpdateAssetBase { @ValidateBoolean({ optional: true }) removeParent?: boolean; + + @Optional() + duplicateId?: string | null; } export class UpdateAssetDto extends UpdateAssetBase { diff --git a/server/src/dtos/duplicate.dto.ts b/server/src/dtos/duplicate.dto.ts new file mode 100644 index 0000000000..73863fa95d --- /dev/null +++ b/server/src/dtos/duplicate.dto.ts @@ -0,0 +1,27 @@ +import { IsNotEmpty } from 'class-validator'; +import { groupBy } from 'lodash'; +import { AssetResponseDto } from 'src/dtos/asset-response.dto'; +import { ValidateUUID } from 'src/validation'; + +export class DuplicateResponseDto { + duplicateId!: string; + assets!: AssetResponseDto[]; +} + +export class ResolveDuplicatesDto { + @IsNotEmpty() + @ValidateUUID({ each: true }) + assetIds!: string[]; +} + +export function mapDuplicateResponse(assets: AssetResponseDto[]): DuplicateResponseDto[] { + const result = []; + + const grouped = groupBy(assets, (a) => a.duplicateId); + + for (const [duplicateId, assets] of Object.entries(grouped)) { + result.push({ duplicateId, assets }); + } + + return result; +} diff --git a/server/src/dtos/job.dto.ts b/server/src/dtos/job.dto.ts index 6234d055b9..b7d8cf59bf 100644 --- a/server/src/dtos/job.dto.ts +++ b/server/src/dtos/job.dto.ts @@ -73,6 +73,9 @@ export class AllJobStatusResponseDto implements Record @ApiProperty({ type: JobStatusDto }) [QueueName.SEARCH]!: JobStatusDto; + @ApiProperty({ type: JobStatusDto }) + [QueueName.DUPLICATE_DETECTION]!: JobStatusDto; + @ApiProperty({ type: JobStatusDto }) [QueueName.FACE_DETECTION]!: JobStatusDto; diff --git a/server/src/dtos/library.dto.ts b/server/src/dtos/library.dto.ts index b693d35adf..b9578a2c37 100644 --- a/server/src/dtos/library.dto.ts +++ b/server/src/dtos/library.dto.ts @@ -1,13 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; -import { ArrayMaxSize, ArrayUnique, IsEnum, IsNotEmpty, IsString } from 'class-validator'; -import { LibraryEntity, LibraryType } from 'src/entities/library.entity'; +import { ArrayMaxSize, ArrayUnique, IsNotEmpty, IsString } from 'class-validator'; +import { LibraryEntity } from 'src/entities/library.entity'; import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation'; export class CreateLibraryDto { - @IsEnum(LibraryType) - @ApiProperty({ enumName: 'LibraryType', enum: LibraryType }) - type!: LibraryType; - @ValidateUUID() ownerId!: string; @@ -16,9 +12,6 @@ export class CreateLibraryDto { @IsNotEmpty() name?: string; - @ValidateBoolean({ optional: true }) - isVisible?: boolean; - @Optional() @IsString({ each: true }) @IsNotEmpty({ each: true }) @@ -40,9 +33,6 @@ export class UpdateLibraryDto { @IsNotEmpty() name?: string; - @ValidateBoolean({ optional: true }) - isVisible?: boolean; - @Optional() @IsString({ each: true }) @IsNotEmpty({ each: true }) @@ -103,21 +93,11 @@ export class ScanLibraryDto { refreshAllFiles?: boolean; } -export class SearchLibraryDto { - @IsEnum(LibraryType) - @ApiProperty({ enumName: 'LibraryType', enum: LibraryType }) - @Optional() - type?: LibraryType; -} - export class LibraryResponseDto { id!: string; ownerId!: string; name!: string; - @ApiProperty({ enumName: 'LibraryType', enum: LibraryType }) - type!: LibraryType; - @ApiProperty({ type: 'integer' }) assetCount!: number; @@ -152,7 +132,6 @@ export function mapLibrary(entity: LibraryEntity): LibraryResponseDto { return { id: entity.id, ownerId: entity.ownerId, - type: entity.type, name: entity.name, createdAt: entity.createdAt, updatedAt: entity.updatedAt, diff --git a/server/src/dtos/model-config.dto.ts b/server/src/dtos/model-config.dto.ts index d1e8bf3391..a3efd19f82 100644 --- a/server/src/dtos/model-config.dto.ts +++ b/server/src/dtos/model-config.dto.ts @@ -4,10 +4,12 @@ import { IsEnum, IsNotEmpty, IsNumber, IsString, Max, Min } from 'class-validato import { CLIPMode, ModelType } from 'src/interfaces/machine-learning.interface'; import { Optional, ValidateBoolean } from 'src/validation'; -export class ModelConfig { +export class TaskConfig { @ValidateBoolean() enabled!: boolean; +} +export class ModelConfig extends TaskConfig { @IsString() @IsNotEmpty() modelName!: string; @@ -25,6 +27,15 @@ export class CLIPConfig extends ModelConfig { mode?: CLIPMode; } +export class DuplicateDetectionConfig extends TaskConfig { + @IsNumber() + @Min(0.001) + @Max(0.1) + @Type(() => Number) + @ApiProperty({ type: 'number', format: 'float' }) + maxDistance!: number; +} + export class RecognitionConfig extends ModelConfig { @IsNumber() @Min(0) diff --git a/server/src/dtos/search.dto.ts b/server/src/dtos/search.dto.ts index 31d4195e7a..5927aa86fc 100644 --- a/server/src/dtos/search.dto.ts +++ b/server/src/dtos/search.dto.ts @@ -1,7 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsEnum, IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator'; -import { PropertyLifecycle } from 'src/decorators'; import { AlbumResponseDto } from 'src/dtos/album.dto'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AssetOrder } from 'src/entities/album.entity'; @@ -155,18 +154,6 @@ export class MetadataSearchDto extends BaseSearchDto { @Optional() originalPath?: string; - @IsString() - @IsNotEmpty() - @Optional() - @PropertyLifecycle({ deprecatedAt: 'v1.100.0' }) - resizePath?: string; - - @IsString() - @IsNotEmpty() - @Optional() - @PropertyLifecycle({ deprecatedAt: 'v1.100.0' }) - webpPath?: string; - @IsString() @IsNotEmpty() @Optional() @@ -317,6 +304,9 @@ export class MapMarkerDto { @ValidateBoolean({ optional: true }) withPartners?: boolean; + + @ValidateBoolean({ optional: true }) + withSharedAlbums?: boolean; } export class MemoryLaneDto { diff --git a/server/src/dtos/server-info.dto.ts b/server/src/dtos/server-info.dto.ts index fae016b718..6afe8534c7 100644 --- a/server/src/dtos/server-info.dto.ts +++ b/server/src/dtos/server-info.dto.ts @@ -1,15 +1,13 @@ import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; -import type { DateTime } from 'luxon'; -import { FeatureFlags } from 'src/cores/system-config.core'; +import { SemVer } from 'semver'; import { SystemConfigThemeDto } from 'src/dtos/system-config.dto'; -import { IVersion, VersionType } from 'src/utils/version'; export class ServerPingResponse { @ApiResponseProperty({ type: String, example: 'pong' }) res!: string; } -export class ServerInfoResponseDto { +export class ServerStorageResponseDto { diskSize!: string; diskUse!: string; diskAvailable!: string; @@ -27,13 +25,17 @@ export class ServerInfoResponseDto { diskUsagePercentage!: number; } -export class ServerVersionResponseDto implements IVersion { +export class ServerVersionResponseDto { @ApiProperty({ type: 'integer' }) major!: number; @ApiProperty({ type: 'integer' }) minor!: number; @ApiProperty({ type: 'integer' }) patch!: number; + + static fromSemVer(value: SemVer) { + return { major: value.major, minor: value.minor, patch: value.patch }; + } } export class UsageByUserDto { @@ -96,8 +98,9 @@ export class ServerConfigDto { externalDomain!: string; } -export class ServerFeaturesDto implements FeatureFlags { +export class ServerFeaturesDto { smartSearch!: boolean; + duplicateDetection!: boolean; configFile!: boolean; facialRecognition!: boolean; map!: boolean; @@ -112,8 +115,9 @@ export class ServerFeaturesDto implements FeatureFlags { } export interface ReleaseNotification { - isAvailable: VersionType; - checkedAt: DateTime | null; + isAvailable: boolean; + /** ISO8601 */ + checkedAt: string; serverVersion: ServerVersionResponseDto; releaseVersion: ServerVersionResponseDto; } diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index 1d02e3bf92..4dcea6ec3d 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -18,7 +18,6 @@ import { ValidatorConstraint, ValidatorConstraintInterface, } from 'class-validator'; -import { CLIPConfig, RecognitionConfig } from 'src/dtos/model-config.dto'; import { AudioCodec, CQMode, @@ -30,7 +29,8 @@ import { TranscodeHWAccel, TranscodePolicy, VideoCodec, -} from 'src/entities/system-config.entity'; +} from 'src/config'; +import { CLIPConfig, DuplicateDetectionConfig, RecognitionConfig } from 'src/dtos/model-config.dto'; import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface'; import { ValidateBoolean, validateCronExpression } from 'src/validation'; @@ -132,6 +132,9 @@ export class SystemConfigFFmpegDto { @ApiProperty({ enumName: 'TranscodeHWAccel', enum: TranscodeHWAccel }) accel!: TranscodeHWAccel; + @ValidateBoolean() + accelDecode!: boolean; + @IsEnum(ToneMapping) @ApiProperty({ enumName: 'ToneMapping', enum: ToneMapping }) tonemap!: ToneMapping; @@ -262,6 +265,11 @@ class SystemConfigMachineLearningDto { @IsObject() clip!: CLIPConfig; + @Type(() => DuplicateDetectionConfig) + @ValidateNested() + @IsObject() + duplicateDetection!: DuplicateDetectionConfig; + @Type(() => RecognitionConfig) @ValidateNested() @IsObject() diff --git a/server/src/dtos/user-profile.dto.ts b/server/src/dtos/user-profile.dto.ts index 2f3d8cf224..bc879380c4 100644 --- a/server/src/dtos/user-profile.dto.ts +++ b/server/src/dtos/user-profile.dto.ts @@ -1,6 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; import { UploadFieldName } from 'src/dtos/asset.dto'; -import { UserAvatarColor, UserEntity } from 'src/entities/user.entity'; export class CreateProfileImageDto { @ApiProperty({ type: 'string', format: 'binary' }) @@ -18,11 +17,3 @@ export function mapCreateProfileImageResponse(userId: string, profileImagePath: profileImagePath: profileImagePath, }; } - -export const getRandomAvatarColor = (user: UserEntity): UserAvatarColor => { - const values = Object.values(UserAvatarColor); - const randomIndex = Math.floor( - [...user.email].map((letter) => letter.codePointAt(0) ?? 0).reduce((a, b) => a + b, 0) % values.length, - ); - return values[randomIndex] as UserAvatarColor; -}; diff --git a/server/src/dtos/user.dto.spec.ts b/server/src/dtos/user.dto.spec.ts index d07399f0ef..95e625a1a8 100644 --- a/server/src/dtos/user.dto.spec.ts +++ b/server/src/dtos/user.dto.spec.ts @@ -1,6 +1,6 @@ import { plainToInstance } from 'class-transformer'; import { validate } from 'class-validator'; -import { CreateAdminDto, CreateUserDto, CreateUserOAuthDto, UpdateUserDto } from 'src/dtos/user.dto'; +import { CreateUserDto, CreateUserOAuthDto, UpdateUserDto } from 'src/dtos/user.dto'; describe('update user DTO', () => { it('should allow emails without a tld', async () => { @@ -52,22 +52,6 @@ describe('create user DTO', () => { }); }); -describe('create admin DTO', () => { - it('should allow emails without a tld', async () => { - const someEmail = 'test@test'; - - const dto = plainToInstance(CreateAdminDto, { - isAdmin: true, - email: someEmail, - password: 'some password', - name: 'some name', - }); - const errors = await validate(dto); - expect(errors).toHaveLength(0); - expect(dto.email).toEqual(someEmail); - }); -}); - describe('create user oauth DTO', () => { it('should allow emails without a tld', async () => { const someEmail = 'test@test'; diff --git a/server/src/dtos/user.dto.ts b/server/src/dtos/user.dto.ts index d0d19e2713..18b9d07b08 100644 --- a/server/src/dtos/user.dto.ts +++ b/server/src/dtos/user.dto.ts @@ -1,8 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { Transform } from 'class-transformer'; import { IsBoolean, IsEmail, IsEnum, IsNotEmpty, IsNumber, IsPositive, IsString, IsUUID } from 'class-validator'; -import { getRandomAvatarColor } from 'src/dtos/user-profile.dto'; -import { UserAvatarColor, UserEntity, UserStatus } from 'src/entities/user.entity'; +import { UserAvatarColor } from 'src/entities/user-metadata.entity'; +import { UserEntity, UserStatus } from 'src/entities/user.entity'; +import { getPreferences } from 'src/utils/preferences'; import { Optional, ValidateBoolean, toEmail, toSanitized } from 'src/validation'; export class CreateUserDto { @@ -40,21 +41,6 @@ export class CreateUserDto { notify?: boolean; } -export class CreateAdminDto { - @IsNotEmpty() - isAdmin!: true; - - @IsEmail({ require_tld: false }) - @Transform(({ value }) => value?.toLowerCase()) - email!: string; - - @IsNotEmpty() - password!: string; - - @IsNotEmpty() - name!: string; -} - export class CreateUserOAuthDto { @IsEmail({ require_tld: false }) @Transform(({ value }) => value?.toLowerCase()) @@ -151,7 +137,7 @@ export const mapSimpleUser = (entity: UserEntity): UserDto => { email: entity.email, name: entity.name, profileImagePath: entity.profileImagePath, - avatarColor: entity.avatarColor ?? getRandomAvatarColor(entity), + avatarColor: getPreferences(entity).avatar.color, }; }; @@ -165,7 +151,7 @@ export function mapUser(entity: UserEntity): UserResponseDto { deletedAt: entity.deletedAt, updatedAt: entity.updatedAt, oauthId: entity.oauthId, - memoriesEnabled: entity.memoriesEnabled, + memoriesEnabled: getPreferences(entity).memories.enabled, quotaSizeInBytes: entity.quotaSizeInBytes, quotaUsageInBytes: entity.quotaUsageInBytes, status: entity.status, diff --git a/server/src/emails/welcome.email.tsx b/server/src/emails/welcome.email.tsx index ea6ca52d66..1e4bdd1496 100644 --- a/server/src/emails/welcome.email.tsx +++ b/server/src/emails/welcome.email.tsx @@ -105,8 +105,7 @@ export const WelcomeEmail = ({ baseUrl, displayName, username, password }: Welco Immich @@ -133,7 +132,7 @@ export const WelcomeEmail = ({ baseUrl, displayName, username, password }: Welco WelcomeEmail.PreviewProps = { baseUrl: 'https://demo.immich.app/auth/login', displayName: 'Alan Turing', - username: 'alanturing', + username: 'alanturing@immich.app', password: 'mysuperpassword', } as WelcomeEmailProps; diff --git a/server/src/entities/asset-job-status.entity.ts b/server/src/entities/asset-job-status.entity.ts index b500752037..44c0a04696 100644 --- a/server/src/entities/asset-job-status.entity.ts +++ b/server/src/entities/asset-job-status.entity.ts @@ -15,4 +15,7 @@ export class AssetJobStatusEntity { @Column({ type: 'timestamptz', nullable: true }) metadataExtractedAt!: Date | null; + + @Column({ type: 'timestamptz', nullable: true }) + duplicatesDetectedAt!: Date | null; } diff --git a/server/src/entities/asset.entity.ts b/server/src/entities/asset.entity.ts index 1181b42da9..2189d5389a 100644 --- a/server/src/entities/asset.entity.ts +++ b/server/src/entities/asset.entity.ts @@ -25,12 +25,17 @@ import { UpdateDateColumn, } from 'typeorm'; -export const ASSET_CHECKSUM_CONSTRAINT = 'UQ_assets_owner_library_checksum'; +export const ASSET_CHECKSUM_CONSTRAINT = 'UQ_assets_owner_checksum'; @Entity('assets') // Checksums must be unique per user and library -@Index(ASSET_CHECKSUM_CONSTRAINT, ['owner', 'library', 'checksum'], { +@Index(ASSET_CHECKSUM_CONSTRAINT, ['owner', 'checksum'], { unique: true, + where: '"libraryId" IS NULL', +}) +@Index('UQ_assets_owner_library_checksum' + '', ['owner', 'library', 'checksum'], { + unique: true, + where: '"libraryId" IS NOT NULL', }) @Index('IDX_day_of_month', { synchronize: false }) @Index('IDX_month', { synchronize: false }) @@ -51,11 +56,11 @@ export class AssetEntity { @Column() ownerId!: string; - @ManyToOne(() => LibraryEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: false }) - library!: LibraryEntity; + @ManyToOne(() => LibraryEntity, { onDelete: 'CASCADE', onUpdate: 'CASCADE' }) + library?: LibraryEntity | null; - @Column() - libraryId!: string; + @Column({ nullable: true }) + libraryId?: string | null; @Column() deviceId!: string; @@ -165,6 +170,10 @@ export class AssetEntity { @OneToOne(() => AssetJobStatusEntity, (jobStatus) => jobStatus.asset, { nullable: true }) jobStatus?: AssetJobStatusEntity; + + @Index('IDX_assets_duplicateId') + @Column({ type: 'uuid', nullable: true }) + duplicateId!: string | null; } export enum AssetType { diff --git a/server/src/entities/exif.entity.ts b/server/src/entities/exif.entity.ts index 6f7aafadf4..3461faa685 100644 --- a/server/src/entities/exif.entity.ts +++ b/server/src/entities/exif.entity.ts @@ -98,20 +98,4 @@ export class ExifEntity { /* Video info */ @Column({ type: 'float8', nullable: true }) fps?: number | null; - - @Index('exif_text_searchable', { synchronize: false }) - @Column({ - type: 'tsvector', - generatedType: 'STORED', - select: false, - asExpression: `TO_TSVECTOR('english', - COALESCE(make, '') || ' ' || - COALESCE(model, '') || ' ' || - COALESCE(orientation, '') || ' ' || - COALESCE("lensModel", '') || ' ' || - COALESCE("city", '') || ' ' || - COALESCE("state", '') || ' ' || - COALESCE("country", ''))`, - }) - exifTextSearchableColumn!: string; } diff --git a/server/src/entities/index.ts b/server/src/entities/index.ts index 0862dd48a2..313f2dc269 100644 --- a/server/src/entities/index.ts +++ b/server/src/entities/index.ts @@ -18,9 +18,9 @@ import { SessionEntity } from 'src/entities/session.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { SmartSearchEntity } from 'src/entities/smart-search.entity'; -import { SystemConfigEntity } from 'src/entities/system-config.entity'; import { SystemMetadataEntity } from 'src/entities/system-metadata.entity'; import { TagEntity } from 'src/entities/tag.entity'; +import { UserMetadataEntity } from 'src/entities/user-metadata.entity'; import { UserEntity } from 'src/entities/user.entity'; export const entities = [ @@ -42,10 +42,10 @@ export const entities = [ SharedLinkEntity, SmartInfoEntity, SmartSearchEntity, - SystemConfigEntity, SystemMetadataEntity, TagEntity, UserEntity, + UserMetadataEntity, SessionEntity, LibraryEntity, ]; diff --git a/server/src/entities/library.entity.ts b/server/src/entities/library.entity.ts index 8be560a889..a6053e4213 100644 --- a/server/src/entities/library.entity.ts +++ b/server/src/entities/library.entity.ts @@ -30,9 +30,6 @@ export class LibraryEntity { @Column() ownerId!: string; - @Column() - type!: LibraryType; - @Column('text', { array: true }) importPaths!: string[]; @@ -50,12 +47,4 @@ export class LibraryEntity { @Column({ type: 'timestamptz', nullable: true }) refreshedAt!: Date | null; - - @Column({ type: 'boolean', default: true }) - isVisible!: boolean; -} - -export enum LibraryType { - UPLOAD = 'UPLOAD', - EXTERNAL = 'EXTERNAL', } diff --git a/server/src/entities/smart-search.entity.ts b/server/src/entities/smart-search.entity.ts index 4595ad2403..da1e0e52f1 100644 --- a/server/src/entities/smart-search.entity.ts +++ b/server/src/entities/smart-search.entity.ts @@ -11,10 +11,6 @@ export class SmartSearchEntity { assetId!: string; @Index('clip_index', { synchronize: false }) - @Column({ - type: 'float4', - array: true, - select: false, - }) + @Column({ type: 'float4', array: true, transformer: { from: (v) => JSON.parse(v), to: (v) => v } }) embedding!: number[]; } diff --git a/server/src/entities/system-config.entity.ts b/server/src/entities/system-config.entity.ts deleted file mode 100644 index 3675a7846a..0000000000 --- a/server/src/entities/system-config.entity.ts +++ /dev/null @@ -1,339 +0,0 @@ -import { ConcurrentQueueName } from 'src/interfaces/job.interface'; -import { Column, Entity, PrimaryColumn } from 'typeorm'; - -export type SystemConfigValue = string | string[] | number | boolean; - -// https://stackoverflow.com/a/47058976 -// https://stackoverflow.com/a/70692231 -type PathsToStringProps = T extends SystemConfigValue - ? [] - : { - [K in keyof T]: [K, ...PathsToStringProps]; - }[keyof T]; - -type Join = T extends [] - ? never - : T extends [infer F] - ? F - : T extends [infer F, ...infer R] - ? F extends string - ? `${F}${D}${Join, D>}` - : never - : string; - -// dot notation matches path in `SystemConfig` -// TODO: migrate to key value per section -export const SystemConfigKey = { - FFMPEG_CRF: 'ffmpeg.crf', - FFMPEG_THREADS: 'ffmpeg.threads', - FFMPEG_PRESET: 'ffmpeg.preset', - FFMPEG_TARGET_VIDEO_CODEC: 'ffmpeg.targetVideoCodec', - FFMPEG_ACCEPTED_VIDEO_CODECS: 'ffmpeg.acceptedVideoCodecs', - FFMPEG_TARGET_AUDIO_CODEC: 'ffmpeg.targetAudioCodec', - FFMPEG_ACCEPTED_AUDIO_CODECS: 'ffmpeg.acceptedAudioCodecs', - FFMPEG_TARGET_RESOLUTION: 'ffmpeg.targetResolution', - FFMPEG_MAX_BITRATE: 'ffmpeg.maxBitrate', - FFMPEG_BFRAMES: 'ffmpeg.bframes', - FFMPEG_REFS: 'ffmpeg.refs', - FFMPEG_GOP_SIZE: 'ffmpeg.gopSize', - FFMPEG_NPL: 'ffmpeg.npl', - FFMPEG_TEMPORAL_AQ: 'ffmpeg.temporalAQ', - FFMPEG_CQ_MODE: 'ffmpeg.cqMode', - FFMPEG_TWO_PASS: 'ffmpeg.twoPass', - FFMPEG_PREFERRED_HW_DEVICE: 'ffmpeg.preferredHwDevice', - FFMPEG_TRANSCODE: 'ffmpeg.transcode', - FFMPEG_ACCEL: 'ffmpeg.accel', - FFMPEG_TONEMAP: 'ffmpeg.tonemap', - - JOB_THUMBNAIL_GENERATION_CONCURRENCY: 'job.thumbnailGeneration.concurrency', - JOB_METADATA_EXTRACTION_CONCURRENCY: 'job.metadataExtraction.concurrency', - JOB_VIDEO_CONVERSION_CONCURRENCY: 'job.videoConversion.concurrency', - JOB_FACE_DETECTION_CONCURRENCY: 'job.faceDetection.concurrency', - JOB_CLIP_ENCODING_CONCURRENCY: 'job.smartSearch.concurrency', - JOB_BACKGROUND_TASK_CONCURRENCY: 'job.backgroundTask.concurrency', - JOB_SEARCH_CONCURRENCY: 'job.search.concurrency', - JOB_SIDECAR_CONCURRENCY: 'job.sidecar.concurrency', - JOB_LIBRARY_CONCURRENCY: 'job.library.concurrency', - JOB_MIGRATION_CONCURRENCY: 'job.migration.concurrency', - - LIBRARY_SCAN_ENABLED: 'library.scan.enabled', - LIBRARY_SCAN_CRON_EXPRESSION: 'library.scan.cronExpression', - - LIBRARY_WATCH_ENABLED: 'library.watch.enabled', - - LOGGING_ENABLED: 'logging.enabled', - LOGGING_LEVEL: 'logging.level', - - MACHINE_LEARNING_ENABLED: 'machineLearning.enabled', - MACHINE_LEARNING_URL: 'machineLearning.url', - - MACHINE_LEARNING_CLIP_ENABLED: 'machineLearning.clip.enabled', - MACHINE_LEARNING_CLIP_MODEL_NAME: 'machineLearning.clip.modelName', - - MACHINE_LEARNING_FACIAL_RECOGNITION_ENABLED: 'machineLearning.facialRecognition.enabled', - MACHINE_LEARNING_FACIAL_RECOGNITION_MODEL_NAME: 'machineLearning.facialRecognition.modelName', - MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_SCORE: 'machineLearning.facialRecognition.minScore', - MACHINE_LEARNING_FACIAL_RECOGNITION_MAX_DISTANCE: 'machineLearning.facialRecognition.maxDistance', - MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES: 'machineLearning.facialRecognition.minFaces', - - MAP_ENABLED: 'map.enabled', - MAP_LIGHT_STYLE: 'map.lightStyle', - MAP_DARK_STYLE: 'map.darkStyle', - - NOTIFICATIONS_SMTP_ENABLED: 'notifications.smtp.enabled', - NOTIFICATIONS_SMTP_FROM: 'notifications.smtp.from', - NOTIFICATIONS_SMTP_REPLY_TO: 'notifications.smtp.replyTo', - NOTIFICATIONS_SMTP_TRANSPORT_IGNORE_CERT: 'notifications.smtp.transport.ignoreCert', - NOTIFICATIONS_SMTP_TRANSPORT_HOST: 'notifications.smtp.transport.host', - NOTIFICATIONS_SMTP_TRANSPORT_PORT: 'notifications.smtp.transport.port', - NOTIFICATIONS_SMTP_TRANSPORT_USERNAME: 'notifications.smtp.transport.username', - NOTIFICATIONS_SMTP_TRANSPORT_PASSWORD: 'notifications.smtp.transport.password', - - REVERSE_GEOCODING_ENABLED: 'reverseGeocoding.enabled', - - NEW_VERSION_CHECK_ENABLED: 'newVersionCheck.enabled', - - OAUTH_AUTO_LAUNCH: 'oauth.autoLaunch', - OAUTH_AUTO_REGISTER: 'oauth.autoRegister', - OAUTH_BUTTON_TEXT: 'oauth.buttonText', - OAUTH_CLIENT_ID: 'oauth.clientId', - OAUTH_CLIENT_SECRET: 'oauth.clientSecret', - OAUTH_DEFAULT_STORAGE_QUOTA: 'oauth.defaultStorageQuota', - OAUTH_ENABLED: 'oauth.enabled', - OAUTH_ISSUER_URL: 'oauth.issuerUrl', - OAUTH_MOBILE_OVERRIDE_ENABLED: 'oauth.mobileOverrideEnabled', - OAUTH_MOBILE_REDIRECT_URI: 'oauth.mobileRedirectUri', - OAUTH_SCOPE: 'oauth.scope', - OAUTH_SIGNING_ALGORITHM: 'oauth.signingAlgorithm', - OAUTH_STORAGE_LABEL_CLAIM: 'oauth.storageLabelClaim', - OAUTH_STORAGE_QUOTA_CLAIM: 'oauth.storageQuotaClaim', - - PASSWORD_LOGIN_ENABLED: 'passwordLogin.enabled', - - SERVER_EXTERNAL_DOMAIN: 'server.externalDomain', - SERVER_LOGIN_PAGE_MESSAGE: 'server.loginPageMessage', - - STORAGE_TEMPLATE_ENABLED: 'storageTemplate.enabled', - STORAGE_TEMPLATE_HASH_VERIFICATION_ENABLED: 'storageTemplate.hashVerificationEnabled', - STORAGE_TEMPLATE: 'storageTemplate.template', - - IMAGE_THUMBNAIL_FORMAT: 'image.thumbnailFormat', - IMAGE_THUMBNAIL_SIZE: 'image.thumbnailSize', - IMAGE_PREVIEW_FORMAT: 'image.previewFormat', - IMAGE_PREVIEW_SIZE: 'image.previewSize', - IMAGE_QUALITY: 'image.quality', - IMAGE_COLORSPACE: 'image.colorspace', - IMAGE_EXTRACT_EMBEDDED: 'image.extractEmbedded', - - TRASH_ENABLED: 'trash.enabled', - TRASH_DAYS: 'trash.days', - - THEME_CUSTOM_CSS: 'theme.customCss', - - USER_DELETE_DELAY: 'user.deleteDelay', -} as const satisfies Record, '.'>>; - -export type SystemConfigKeyPaths = (typeof SystemConfigKey)[keyof typeof SystemConfigKey]; - -@Entity('system_config') -export class SystemConfigEntity { - @PrimaryColumn({ type: 'varchar' }) - key!: SystemConfigKeyPaths; - - @Column({ type: 'varchar', nullable: true, transformer: { to: JSON.stringify, from: JSON.parse } }) - value!: T; -} - -export enum TranscodePolicy { - ALL = 'all', - OPTIMAL = 'optimal', - BITRATE = 'bitrate', - REQUIRED = 'required', - DISABLED = 'disabled', -} - -export enum TranscodeTarget { - NONE, - AUDIO, - VIDEO, - ALL, -} - -export enum VideoCodec { - H264 = 'h264', - HEVC = 'hevc', - VP9 = 'vp9', - AV1 = 'av1', -} - -export enum AudioCodec { - MP3 = 'mp3', - AAC = 'aac', - LIBOPUS = 'libopus', -} - -export enum TranscodeHWAccel { - NVENC = 'nvenc', - QSV = 'qsv', - VAAPI = 'vaapi', - RKMPP = 'rkmpp', - DISABLED = 'disabled', -} - -export enum ToneMapping { - HABLE = 'hable', - MOBIUS = 'mobius', - REINHARD = 'reinhard', - DISABLED = 'disabled', -} - -export enum CQMode { - AUTO = 'auto', - CQP = 'cqp', - ICQ = 'icq', -} - -export enum Colorspace { - SRGB = 'srgb', - P3 = 'p3', -} - -export enum ImageFormat { - JPEG = 'jpeg', - WEBP = 'webp', -} - -export enum LogLevel { - VERBOSE = 'verbose', - DEBUG = 'debug', - LOG = 'log', - WARN = 'warn', - ERROR = 'error', - FATAL = 'fatal', -} - -export interface SystemConfig { - ffmpeg: { - crf: number; - threads: number; - preset: string; - targetVideoCodec: VideoCodec; - acceptedVideoCodecs: VideoCodec[]; - targetAudioCodec: AudioCodec; - acceptedAudioCodecs: AudioCodec[]; - targetResolution: string; - maxBitrate: string; - bframes: number; - refs: number; - gopSize: number; - npl: number; - temporalAQ: boolean; - cqMode: CQMode; - twoPass: boolean; - preferredHwDevice: string; - transcode: TranscodePolicy; - accel: TranscodeHWAccel; - tonemap: ToneMapping; - }; - job: Record; - logging: { - enabled: boolean; - level: LogLevel; - }; - machineLearning: { - enabled: boolean; - url: string; - clip: { - enabled: boolean; - modelName: string; - }; - facialRecognition: { - enabled: boolean; - modelName: string; - minScore: number; - minFaces: number; - maxDistance: number; - }; - }; - map: { - enabled: boolean; - lightStyle: string; - darkStyle: string; - }; - reverseGeocoding: { - enabled: boolean; - }; - oauth: { - autoLaunch: boolean; - autoRegister: boolean; - buttonText: string; - clientId: string; - clientSecret: string; - defaultStorageQuota: number; - enabled: boolean; - issuerUrl: string; - mobileOverrideEnabled: boolean; - mobileRedirectUri: string; - scope: string; - signingAlgorithm: string; - storageLabelClaim: string; - storageQuotaClaim: string; - }; - passwordLogin: { - enabled: boolean; - }; - storageTemplate: { - enabled: boolean; - hashVerificationEnabled: boolean; - template: string; - }; - image: { - thumbnailFormat: ImageFormat; - thumbnailSize: number; - previewFormat: ImageFormat; - previewSize: number; - quality: number; - colorspace: Colorspace; - extractEmbedded: boolean; - }; - newVersionCheck: { - enabled: boolean; - }; - trash: { - enabled: boolean; - days: number; - }; - theme: { - customCss: string; - }; - library: { - scan: { - enabled: boolean; - cronExpression: string; - }; - watch: { - enabled: boolean; - }; - }; - notifications: { - smtp: { - enabled: boolean; - from: string; - replyTo: string; - transport: { - ignoreCert: boolean; - host: string; - port: number; - username: string; - password: string; - }; - }; - }; - server: { - externalDomain: string; - loginPageMessage: string; - }; - user: { - deleteDelay: number; - }; -} diff --git a/server/src/entities/system-metadata.entity.ts b/server/src/entities/system-metadata.entity.ts index 24e9f83c74..b097c21200 100644 --- a/server/src/entities/system-metadata.entity.ts +++ b/server/src/entities/system-metadata.entity.ts @@ -1,20 +1,27 @@ -import { Column, Entity, PrimaryColumn } from 'typeorm'; +import { SystemConfig } from 'src/config'; +import { Column, DeepPartial, Entity, PrimaryColumn } from 'typeorm'; @Entity('system_metadata') -export class SystemMetadataEntity { - @PrimaryColumn() - key!: string; +export class SystemMetadataEntity { + @PrimaryColumn({ type: 'varchar' }) + key!: T; - @Column({ type: 'jsonb', default: '{}', transformer: { to: JSON.stringify, from: JSON.parse } }) - value!: { [key: string]: unknown }; + @Column({ type: 'jsonb' }) + value!: SystemMetadata[T]; } export enum SystemMetadataKey { REVERSE_GEOCODING_STATE = 'reverse-geocoding-state', ADMIN_ONBOARDING = 'admin-onboarding', + SYSTEM_CONFIG = 'system-config', + VERSION_CHECK_STATE = 'version-check-state', } -export interface SystemMetadata extends Record { +export type VersionCheckMetadata = { checkedAt: string; releaseVersion: string }; + +export interface SystemMetadata extends Record> { [SystemMetadataKey.REVERSE_GEOCODING_STATE]: { lastUpdate?: string; lastImportFileName?: string }; [SystemMetadataKey.ADMIN_ONBOARDING]: { isOnboarded: boolean }; + [SystemMetadataKey.SYSTEM_CONFIG]: DeepPartial; + [SystemMetadataKey.VERSION_CHECK_STATE]: VersionCheckMetadata; } diff --git a/server/src/entities/user-metadata.entity.ts b/server/src/entities/user-metadata.entity.ts new file mode 100644 index 0000000000..26715e05e3 --- /dev/null +++ b/server/src/entities/user-metadata.entity.ts @@ -0,0 +1,63 @@ +import { UserEntity } from 'src/entities/user.entity'; +import { Column, DeepPartial, Entity, ManyToOne, PrimaryColumn } from 'typeorm'; + +@Entity('user_metadata') +export class UserMetadataEntity { + @PrimaryColumn({ type: 'uuid' }) + userId!: string; + + @ManyToOne(() => UserEntity, (user) => user.metadata, { onUpdate: 'CASCADE', onDelete: 'CASCADE' }) + user!: UserEntity; + + @PrimaryColumn({ type: 'varchar' }) + key!: T; + + @Column({ type: 'jsonb' }) + value!: UserMetadata[T]; +} + +export enum UserAvatarColor { + PRIMARY = 'primary', + PINK = 'pink', + RED = 'red', + YELLOW = 'yellow', + BLUE = 'blue', + GREEN = 'green', + PURPLE = 'purple', + ORANGE = 'orange', + GRAY = 'gray', + AMBER = 'amber', +} + +export interface UserPreferences { + memories: { + enabled: boolean; + }; + avatar: { + color: UserAvatarColor; + }; +} + +export const getDefaultPreferences = (user: { email: string }): UserPreferences => { + const values = Object.values(UserAvatarColor); + const randomIndex = Math.floor( + [...user.email].map((letter) => letter.codePointAt(0) ?? 0).reduce((a, b) => a + b, 0) % values.length, + ); + + return { + memories: { + enabled: true, + }, + avatar: { + color: values[randomIndex], + }, + }; +}; + +export enum UserMetadataKey { + PREFERENCES = 'preferences', +} + +export interface UserMetadata extends Record> { + [UserMetadataKey.PREFERENCES]: DeepPartial; +} diff --git a/server/src/entities/user.entity.ts b/server/src/entities/user.entity.ts index 4d6361abad..6878292ab0 100644 --- a/server/src/entities/user.entity.ts +++ b/server/src/entities/user.entity.ts @@ -1,5 +1,6 @@ import { AssetEntity } from 'src/entities/asset.entity'; import { TagEntity } from 'src/entities/tag.entity'; +import { UserMetadataEntity } from 'src/entities/user-metadata.entity'; import { Column, CreateDateColumn, @@ -10,19 +11,6 @@ import { UpdateDateColumn, } from 'typeorm'; -export enum UserAvatarColor { - PRIMARY = 'primary', - PINK = 'pink', - RED = 'red', - YELLOW = 'yellow', - BLUE = 'blue', - GREEN = 'green', - PURPLE = 'purple', - ORANGE = 'orange', - GRAY = 'gray', - AMBER = 'amber', -} - export enum UserStatus { ACTIVE = 'active', REMOVING = 'removing', @@ -37,9 +25,6 @@ export class UserEntity { @Column({ default: '' }) name!: string; - @Column({ type: 'varchar', nullable: true }) - avatarColor!: UserAvatarColor | null; - @Column({ default: false }) isAdmin!: boolean; @@ -73,9 +58,6 @@ export class UserEntity { @UpdateDateColumn({ type: 'timestamptz' }) updatedAt!: Date; - @Column({ default: true }) - memoriesEnabled!: boolean; - @OneToMany(() => TagEntity, (tag) => tag.user) tags!: TagEntity[]; @@ -87,4 +69,7 @@ export class UserEntity { @Column({ type: 'bigint', default: 0 }) quotaUsageInBytes!: number; + + @OneToMany(() => UserMetadataEntity, (metadata) => metadata.user) + metadata!: UserMetadataEntity[]; } diff --git a/server/src/interfaces/access.interface.ts b/server/src/interfaces/access.interface.ts index e07b877b66..6b408c263e 100644 --- a/server/src/interfaces/access.interface.ts +++ b/server/src/interfaces/access.interface.ts @@ -26,10 +26,6 @@ export interface IAccessRepository { checkSharedLinkAccess(sharedLinkId: string, albumIds: Set): Promise>; }; - library: { - checkOwnerAccess(userId: string, libraryIds: Set): Promise>; - }; - timeline: { checkPartnerAccess(userId: string, partnerIds: Set): Promise>; }; diff --git a/server/src/interfaces/asset-v1.interface.ts b/server/src/interfaces/asset-v1.interface.ts index 799a303ba6..73d90019e2 100644 --- a/server/src/interfaces/asset-v1.interface.ts +++ b/server/src/interfaces/asset-v1.interface.ts @@ -1,4 +1,3 @@ -import { AssetSearchDto, CheckExistingAssetsDto } from 'src/dtos/asset-v1.dto'; import { AssetEntity } from 'src/entities/asset.entity'; export interface AssetCheck { @@ -12,10 +11,7 @@ export interface AssetOwnerCheck extends AssetCheck { export interface IAssetRepositoryV1 { get(id: string): Promise; - getAllByUserId(userId: string, dto: AssetSearchDto): Promise; getAssetsByChecksums(userId: string, checksums: Buffer[]): Promise; - getExistingAssets(userId: string, checkDuplicateAssetDto: CheckExistingAssetsDto): Promise; - getByOriginalPath(originalPath: string): Promise; } export const IAssetRepositoryV1 = 'IAssetRepositoryV1'; diff --git a/server/src/interfaces/asset.interface.ts b/server/src/interfaces/asset.interface.ts index 2c8f077cfb..63a2c5a770 100644 --- a/server/src/interfaces/asset.interface.ts +++ b/server/src/interfaces/asset.interface.ts @@ -40,6 +40,7 @@ export enum WithoutProperty { ENCODED_VIDEO = 'encoded-video', EXIF = 'exif', SMART_SEARCH = 'smart-search', + DUPLICATE = 'duplicate', OBJECT_TAGS = 'object-tags', FACES = 'faces', PERSON = 'person', @@ -60,6 +61,7 @@ export interface AssetBuilderOptions { isArchived?: boolean; isFavorite?: boolean; isTrashed?: boolean; + isDuplicate?: boolean; albumId?: string; personId?: string; userIds?: string[]; @@ -109,7 +111,10 @@ export type AssetWithoutRelations = Omit< | 'tags' >; -export type AssetUpdateOptions = Pick & Partial; +type AssetUpdateWithoutRelations = Pick & Partial; +type AssetUpdateWithLivePhotoRelation = Pick & Pick; + +export type AssetUpdateOptions = AssetUpdateWithoutRelations | AssetUpdateWithLivePhotoRelation; export type AssetUpdateAllOptions = Omit, 'id'>; @@ -134,8 +139,6 @@ export interface AssetFullSyncOptions { lastCreationDate?: Date; lastId?: string; updatedUntil: Date; - isArchived?: false; - withStacked?: true; limit: number; } @@ -145,6 +148,12 @@ export interface AssetDeltaSyncOptions { limit: number; } +export interface AssetUpdateDuplicateOptions { + targetDuplicateId: string | null; + assetIds: string[]; + duplicateIds: string[]; +} + export type AssetPathEntity = Pick; export const IAssetRepository = 'IAssetRepository'; @@ -158,9 +167,11 @@ export interface IAssetRepository { ): Promise; getByIdsWithAllRelations(ids: string[]): Promise; getByDayOfYear(ownerIds: string[], monthDay: MonthDay): Promise; - getByChecksum(libraryId: string, checksum: Buffer): Promise; + getByChecksum(libraryId: string | null, checksum: Buffer): Promise; + getByChecksums(userId: string, checksums: Buffer[]): Promise; getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise; getByAlbumId(pagination: PaginationOptions, albumId: string): Paginated; + getByDeviceIds(ownerId: string, deviceId: string, deviceAssetIds: string[]): Promise; getByUserId(pagination: PaginationOptions, userId: string, options?: AssetSearchOptions): Paginated; getById( id: string, @@ -178,19 +189,21 @@ export interface IAssetRepository { getAll(pagination: PaginationOptions, options?: AssetSearchOptions): Paginated; getAllByDeviceId(userId: string, deviceId: string): Promise; updateAll(ids: string[], options: Partial): Promise; + updateDuplicates(options: AssetUpdateDuplicateOptions): Promise; update(asset: AssetUpdateOptions): Promise; remove(asset: AssetEntity): Promise; softDeleteAll(ids: string[]): Promise; restoreAll(ids: string[]): Promise; findLivePhotoMatch(options: LivePhotoSearchOptions): Promise; - getMapMarkers(ownerIds: string[], options?: MapMarkerSearchOptions): Promise; + getMapMarkers(ownerIds: string[], albumIds: string[], options?: MapMarkerSearchOptions): Promise; getStatistics(ownerId: string, options: AssetStatsOptions): Promise; getTimeBuckets(options: TimeBucketOptions): Promise; getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise; upsertExif(exif: Partial): Promise; - upsertJobStatus(jobStatus: Partial): Promise; + upsertJobStatus(...jobStatus: Partial[]): Promise; getAssetIdByCity(userId: string, options: AssetExploreFieldOptions): Promise>; getAssetIdByTag(userId: string, options: AssetExploreFieldOptions): Promise>; + getDuplicates(options: AssetBuilderOptions): Promise; getAllForUserFullSync(options: AssetFullSyncOptions): Promise; getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise; } diff --git a/server/src/interfaces/database.interface.ts b/server/src/interfaces/database.interface.ts index 42342eccc3..f78f6388fb 100644 --- a/server/src/interfaces/database.interface.ts +++ b/server/src/interfaces/database.interface.ts @@ -1,5 +1,3 @@ -import { Version } from 'src/utils/version'; - export enum DatabaseExtension { CUBE = 'cube', EARTH_DISTANCE = 'earthdistance', @@ -20,9 +18,10 @@ export enum DatabaseLock { StorageTemplateMigration = 420, CLIPDimSize = 512, LibraryWatch = 1337, + GetSystemConfig = 69, } -export const extName: Record = { +export const EXTENSION_NAMES: Record = { cube: 'cube', earthdistance: 'earthdistance', vector: 'pgvector', @@ -36,13 +35,12 @@ export interface VectorUpdateResult { export const IDatabaseRepository = 'IDatabaseRepository'; export interface IDatabaseRepository { - getExtensionVersion(extensionName: string): Promise; - getAvailableExtensionVersion(extension: DatabaseExtension): Promise; - getPreferredVectorExtension(): VectorExtension; - getPostgresVersion(): Promise; + getExtensionVersion(extensionName: string): Promise; + getAvailableExtensionVersion(extension: DatabaseExtension): Promise; + getPostgresVersion(): Promise; createExtension(extension: DatabaseExtension): Promise; - updateExtension(extension: DatabaseExtension, version?: Version): Promise; - updateVectorExtension(extension: VectorExtension, version?: Version): Promise; + updateExtension(extension: DatabaseExtension, version?: string): Promise; + updateVectorExtension(extension: VectorExtension, version?: string): Promise; reindex(index: VectorIndex): Promise; shouldReindex(name: VectorIndex): Promise; runMigrations(options?: { transaction?: 'all' | 'none' | 'each' }): Promise; diff --git a/server/src/interfaces/event.interface.ts b/server/src/interfaces/event.interface.ts index 49b5177f3d..e3539a823d 100644 --- a/server/src/interfaces/event.interface.ts +++ b/server/src/interfaces/event.interface.ts @@ -1,6 +1,6 @@ +import { SystemConfig } from 'src/config'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { ReleaseNotification, ServerVersionResponseDto } from 'src/dtos/server-info.dto'; -import { SystemConfig } from 'src/entities/system-config.entity'; export const IEventRepository = 'IEventRepository'; diff --git a/server/src/interfaces/job.interface.ts b/server/src/interfaces/job.interface.ts index 0deb6d7266..6393e3167a 100644 --- a/server/src/interfaces/job.interface.ts +++ b/server/src/interfaces/job.interface.ts @@ -5,6 +5,7 @@ export enum QueueName { FACE_DETECTION = 'faceDetection', FACIAL_RECOGNITION = 'facialRecognition', SMART_SEARCH = 'smartSearch', + DUPLICATE_DETECTION = 'duplicateDetection', BACKGROUND_TASK = 'backgroundTask', STORAGE_TEMPLATE_MIGRATION = 'storageTemplateMigration', MIGRATION = 'migration', @@ -16,7 +17,7 @@ export enum QueueName { export type ConcurrentQueueName = Exclude< QueueName, - QueueName.STORAGE_TEMPLATE_MIGRATION | QueueName.FACIAL_RECOGNITION + QueueName.STORAGE_TEMPLATE_MIGRATION | QueueName.FACIAL_RECOGNITION | QueueName.DUPLICATE_DETECTION >; export enum JobCommand { @@ -86,6 +87,10 @@ export enum JobName { QUEUE_SMART_SEARCH = 'queue-smart-search', SMART_SEARCH = 'smart-search', + // duplicate detection + QUEUE_DUPLICATE_DETECTION = 'queue-duplicate-detection', + DUPLICATE_DETECTION = 'duplicate-detection', + // XMP sidecars QUEUE_SIDECAR = 'queue-sidecar', SIDECAR_DISCOVERY = 'sidecar-discovery', @@ -95,6 +100,9 @@ export enum JobName { // Notification NOTIFY_SIGNUP = 'notify-signup', SEND_EMAIL = 'notification-send-email', + + // Version check + VERSION_CHECK = 'version-check', } export const JOBS_ASSET_PAGINATION_SIZE = 1000; @@ -105,7 +113,7 @@ export interface IBaseJob { export interface IEntityJob extends IBaseJob { id: string; - source?: 'upload' | 'sidecar-write'; + source?: 'upload' | 'sidecar-write' | 'copy'; } export interface ILibraryFileJob extends IEntityJob { @@ -212,6 +220,10 @@ export type JobItem = | { name: JobName.QUEUE_SMART_SEARCH; data: IBaseJob } | { name: JobName.SMART_SEARCH; data: IEntityJob } + // Duplicate Detection + | { name: JobName.QUEUE_DUPLICATE_DETECTION; data: IBaseJob } + | { name: JobName.DUPLICATE_DETECTION; data: IEntityJob } + // Filesystem | { name: JobName.DELETE_FILES; data: IDeleteFilesJob } @@ -234,7 +246,10 @@ export type JobItem = // Notification | { name: JobName.SEND_EMAIL; data: IEmailJob } - | { name: JobName.NOTIFY_SIGNUP; data: INotifySignupJob }; + | { name: JobName.NOTIFY_SIGNUP; data: INotifySignupJob } + + // Version check + | { name: JobName.VERSION_CHECK; data: IBaseJob }; export enum JobStatus { SUCCESS = 'success', diff --git a/server/src/interfaces/library.interface.ts b/server/src/interfaces/library.interface.ts index dbc7fab812..6468977df4 100644 --- a/server/src/interfaces/library.interface.ts +++ b/server/src/interfaces/library.interface.ts @@ -1,19 +1,16 @@ import { LibraryStatsResponseDto } from 'src/dtos/library.dto'; -import { LibraryEntity, LibraryType } from 'src/entities/library.entity'; +import { LibraryEntity } from 'src/entities/library.entity'; export const ILibraryRepository = 'ILibraryRepository'; export interface ILibraryRepository { - getCountForUser(ownerId: string): Promise; - getAll(withDeleted?: boolean, type?: LibraryType): Promise; + getAll(withDeleted?: boolean): Promise; getAllDeleted(): Promise; get(id: string, withDeleted?: boolean): Promise; create(library: Partial): Promise; delete(id: string): Promise; softDelete(id: string): Promise; - getDefaultUploadLibrary(ownerId: string): Promise; - getUploadLibraryCount(ownerId: string): Promise; update(library: Partial): Promise; - getStatistics(id: string): Promise; + getStatistics(id: string): Promise; getAssetIds(id: string, withDeleted?: boolean): Promise; } diff --git a/server/src/interfaces/logger.interface.ts b/server/src/interfaces/logger.interface.ts index d8e9a7d2ab..f0afdce2a5 100644 --- a/server/src/interfaces/logger.interface.ts +++ b/server/src/interfaces/logger.interface.ts @@ -1,8 +1,9 @@ -import { LogLevel } from 'src/entities/system-config.entity'; +import { LogLevel } from 'src/config'; export const ILoggerRepository = 'ILoggerRepository'; export interface ILoggerRepository { + setAppName(name: string): void; setContext(message: string): void; setLogLevel(level: LogLevel): void; diff --git a/server/src/interfaces/media.interface.ts b/server/src/interfaces/media.interface.ts index 092536b026..80beb8c436 100644 --- a/server/src/interfaces/media.interface.ts +++ b/server/src/interfaces/media.interface.ts @@ -1,5 +1,5 @@ import { Writable } from 'node:stream'; -import { ImageFormat, TranscodeTarget, VideoCodec } from 'src/entities/system-config.entity'; +import { ImageFormat, TranscodeTarget, VideoCodec } from 'src/config'; export const IMediaRepository = 'IMediaRepository'; diff --git a/server/src/interfaces/search.interface.ts b/server/src/interfaces/search.interface.ts index 56dbe1da4b..57523aa940 100644 --- a/server/src/interfaces/search.interface.ts +++ b/server/src/interfaces/search.interface.ts @@ -152,15 +152,29 @@ export interface FaceEmbeddingSearch extends SearchEmbeddingOptions { maxDistance?: number; } +export interface AssetDuplicateSearch { + assetId: string; + embedding: Embedding; + userIds: string[]; + maxDistance?: number; +} + export interface FaceSearchResult { distance: number; face: AssetFaceEntity; } +export interface AssetDuplicateResult { + assetId: string; + duplicateId: string | null; + distance: number; +} + export interface ISearchRepository { init(modelName: string): Promise; searchMetadata(pagination: SearchPaginationOptions, options: AssetSearchOptions): Paginated; searchSmart(pagination: SearchPaginationOptions, options: SmartSearchOptions): Paginated; + searchDuplicates(options: AssetDuplicateSearch): Promise; searchFaces(search: FaceEmbeddingSearch): Promise; upsert(assetId: string, embedding: number[]): Promise; searchPlaces(placeName: string): Promise; diff --git a/server/src/interfaces/system-config.interface.ts b/server/src/interfaces/system-config.interface.ts deleted file mode 100644 index f591a6671d..0000000000 --- a/server/src/interfaces/system-config.interface.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { SystemConfigEntity } from 'src/entities/system-config.entity'; - -export const ISystemConfigRepository = 'ISystemConfigRepository'; - -export interface ISystemConfigRepository { - fetchStyle(url: string): Promise; - load(): Promise; - readFile(filename: string): Promise; - saveAll(items: SystemConfigEntity[]): Promise; - deleteKeys(keys: string[]): Promise; -} diff --git a/server/src/interfaces/system-metadata.interface.ts b/server/src/interfaces/system-metadata.interface.ts index cbbce44e26..9bb9fd5077 100644 --- a/server/src/interfaces/system-metadata.interface.ts +++ b/server/src/interfaces/system-metadata.interface.ts @@ -5,4 +5,6 @@ export const ISystemMetadataRepository = 'ISystemMetadataRepository'; export interface ISystemMetadataRepository { get(key: T): Promise; set(key: T, value: SystemMetadata[T]): Promise; + fetchStyle(url: string): Promise; + readFile(filename: string): Promise; } diff --git a/server/src/interfaces/user.interface.ts b/server/src/interfaces/user.interface.ts index ebc70688ea..87ed2ccb08 100644 --- a/server/src/interfaces/user.interface.ts +++ b/server/src/interfaces/user.interface.ts @@ -1,3 +1,4 @@ +import { UserMetadata } from 'src/entities/user-metadata.entity'; import { UserEntity } from 'src/entities/user.entity'; export interface UserListFilter { @@ -31,6 +32,7 @@ export interface IUserRepository { getUserStats(): Promise; create(user: Partial): Promise; update(id: string, user: Partial): Promise; + upsertMetadata(id: string, item: { key: T; value: UserMetadata[T] }): Promise; delete(user: UserEntity, hard?: boolean): Promise; updateUsage(id: string, delta: number): Promise; syncUsage(id?: string): Promise; diff --git a/server/src/main.ts b/server/src/main.ts index 4638df4aee..167c772690 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -1,80 +1,8 @@ -import { NestFactory } from '@nestjs/core'; -import { NestExpressApplication } from '@nestjs/platform-express'; -import { json } from 'body-parser'; -import cookieParser from 'cookie-parser'; import { CommandFactory } from 'nest-commander'; -import { existsSync } from 'node:fs'; -import sirv from 'sirv'; -import { ApiModule, ImmichAdminModule, MicroservicesModule } from 'src/app.module'; -import { WEB_ROOT, envName, excludePaths, isDev, serverVersion } from 'src/constants'; -import { LogLevel } from 'src/entities/system-config.entity'; -import { ILoggerRepository } from 'src/interfaces/logger.interface'; -import { WebSocketAdapter } from 'src/middleware/websocket.adapter'; -import { ApiService } from 'src/services/api.service'; -import { otelSDK } from 'src/utils/instrumentation'; -import { useSwagger } from 'src/utils/misc'; - -const host = process.env.HOST; - -async function bootstrapMicroservices() { - otelSDK.start(); - - const port = Number(process.env.MICROSERVICES_PORT) || 3002; - const app = await NestFactory.create(MicroservicesModule, { bufferLogs: true }); - const logger = await app.resolve(ILoggerRepository); - logger.setContext('ImmichMicroservice'); - app.useLogger(logger); - app.useWebSocketAdapter(new WebSocketAdapter(app)); - - await (host ? app.listen(port, host) : app.listen(port)); - - logger.log(`Immich Microservices is listening on ${await app.getUrl()} [v${serverVersion}] [${envName}] `); -} - -async function bootstrapApi() { - otelSDK.start(); - - const port = Number(process.env.SERVER_PORT) || 3001; - const app = await NestFactory.create(ApiModule, { bufferLogs: true }); - const logger = await app.resolve(ILoggerRepository); - - logger.setContext('ImmichServer'); - app.useLogger(logger); - app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); - app.set('etag', 'strong'); - app.use(cookieParser()); - app.use(json({ limit: '10mb' })); - if (isDev) { - app.enableCors(); - } - app.useWebSocketAdapter(new WebSocketAdapter(app)); - useSwagger(app, isDev); - - app.setGlobalPrefix('api', { exclude: excludePaths }); - if (existsSync(WEB_ROOT)) { - // copied from https://github.com/sveltejs/kit/blob/679b5989fe62e3964b9a73b712d7b41831aa1f07/packages/adapter-node/src/handler.js#L46 - // provides serving of precompressed assets and caching of immutable assets - app.use( - sirv(WEB_ROOT, { - etag: true, - gzip: true, - brotli: true, - setHeaders: (res, pathname) => { - if (pathname.startsWith(`/_app/immutable`) && res.statusCode === 200) { - res.setHeader('cache-control', 'public,max-age=31536000,immutable'); - } - }, - }), - ); - } - app.use(app.get(ApiService).ssr(excludePaths)); - - const server = await (host ? app.listen(port, host) : app.listen(port)); - server.requestTimeout = 30 * 60 * 1000; - - logger.log(`Immich Server is listening on ${await app.getUrl()} [v${serverVersion}] [${envName}] `); -} - +import { Worker } from 'node:worker_threads'; +import { ImmichAdminModule } from 'src/app.module'; +import { LogLevel } from 'src/config'; +import { getWorkers } from 'src/utils/workers'; const immichApp = process.argv[2] || process.env.IMMICH_APP; if (process.argv[2] === immichApp) { @@ -82,27 +10,43 @@ if (process.argv[2] === immichApp) { } async function bootstrapImmichAdmin() { - process.env.LOG_LEVEL = LogLevel.WARN; + process.env.IMMICH_LOG_LEVEL = LogLevel.WARN; await CommandFactory.run(ImmichAdminModule); } +function bootstrapWorker(name: string) { + console.log(`Starting ${name} worker`); + const worker = new Worker(`./dist/workers/${name}.js`); + worker.on('exit', (exitCode) => { + if (exitCode !== 0) { + console.error(`${name} worker exited with code ${exitCode}`); + process.exit(exitCode); + } + }); +} + function bootstrap() { switch (immichApp) { - case 'immich': { - process.title = 'immich_server'; - return bootstrapApi(); - } - case 'microservices': { - process.title = 'immich_microservices'; - return bootstrapMicroservices(); - } case 'immich-admin': { process.title = 'immich_admin_cli'; return bootstrapImmichAdmin(); } - default: { - throw new Error(`Invalid app name: ${immichApp}. Expected one of immich|microservices|immich-admin`); + case 'immich': { + if (!process.env.IMMICH_WORKERS_INCLUDE) { + process.env.IMMICH_WORKERS_INCLUDE = 'api'; + } + break; } + case 'microservices': { + if (!process.env.IMMICH_WORKERS_INCLUDE) { + process.env.IMMICH_WORKERS_INCLUDE = 'microservices'; + } + break; + } + } + process.title = 'immich'; + for (const worker of getWorkers()) { + bootstrapWorker(worker); } } diff --git a/server/src/middleware/file-upload.interceptor.ts b/server/src/middleware/file-upload.interceptor.ts index 1b8405fe6e..f4fc755100 100644 --- a/server/src/middleware/file-upload.interceptor.ts +++ b/server/src/middleware/file-upload.interceptor.ts @@ -6,14 +6,34 @@ import { NextFunction, RequestHandler } from 'express'; import multer, { StorageEngine, diskStorage } from 'multer'; import { createHash, randomUUID } from 'node:crypto'; import { Observable } from 'rxjs'; -import { UploadFieldName } from 'src/dtos/asset.dto'; +import { UploadFieldName } from 'src/dtos/asset-media.dto'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AuthRequest } from 'src/middleware/auth.guard'; -import { AssetService, UploadFile } from 'src/services/asset.service'; +import { UploadFile } from 'src/services/asset-media.service'; +import { AssetService } from 'src/services/asset.service'; + +export interface UploadFiles { + assetData: ImmichFile[]; + livePhotoData?: ImmichFile[]; + sidecarData: ImmichFile[]; +} + +export function getFile(files: UploadFiles, property: 'assetData' | 'livePhotoData' | 'sidecarData') { + const file = files[property]?.[0]; + return file ? mapToUploadFile(file) : file; +} + +export function getFiles(files: UploadFiles) { + return { + file: getFile(files, 'assetData') as UploadFile, + livePhotoFile: getFile(files, 'livePhotoData'), + sidecarFile: getFile(files, 'sidecarData'), + }; +} export enum Route { ASSET = 'asset', - USER = 'user', + USER = 'users', } export interface ImmichFile extends Express.Multer.File { diff --git a/server/src/migrations/1656889061566-MatchMigrationsWithTypeORMEntities.ts b/server/src/migrations/1656889061566-MatchMigrationsWithTypeORMEntities.ts index 6bc1e56250..00a66d78e9 100644 --- a/server/src/migrations/1656889061566-MatchMigrationsWithTypeORMEntities.ts +++ b/server/src/migrations/1656889061566-MatchMigrationsWithTypeORMEntities.ts @@ -11,21 +11,6 @@ export class MatchMigrationsWithTypeORMEntities1656889061566 implements Migratio COALESCE("state", '') || ' ' || COALESCE("country", ''))) STORED`); await queryRunner.query(`ALTER TABLE "exif" ALTER COLUMN "exifTextSearchableColumn" SET NOT NULL`); - await queryRunner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, - ['GENERATED_COLUMN', 'exifTextSearchableColumn', 'postgres', 'public', 'exif'], - ); - await queryRunner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES ($1, $2, $3, $4, $5, $6)`, - [ - 'postgres', - 'public', - 'exif', - 'GENERATED_COLUMN', - 'exifTextSearchableColumn', - "TO_TSVECTOR('english',\n COALESCE(make, '') || ' ' ||\n COALESCE(model, '') || ' ' ||\n COALESCE(orientation, '') || ' ' ||\n COALESCE(\"lensModel\", '') || ' ' ||\n COALESCE(\"city\", '') || ' ' ||\n COALESCE(\"state\", '') || ' ' ||\n COALESCE(\"country\", ''))", - ], - ); await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "firstName" SET NOT NULL`); await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "lastName" SET NOT NULL`); await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "isAdmin" SET NOT NULL`); @@ -51,10 +36,6 @@ export class MatchMigrationsWithTypeORMEntities1656889061566 implements Migratio await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "isAdmin" DROP NOT NULL`); await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "lastName" DROP NOT NULL`); await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "firstName" DROP NOT NULL`); - await queryRunner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, - ['GENERATED_COLUMN', 'exifTextSearchableColumn', 'immich', 'public', 'exif'], - ); await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_7ae4e03729895bf87e056d7b598"`); await queryRunner.query(`ALTER TABLE "asset_album" DROP CONSTRAINT "FK_256a30a03a4a0aff0394051397d"`); diff --git a/server/src/migrations/1658860470248-AddExifImageNameAsSearchableText.ts b/server/src/migrations/1658860470248-AddExifImageNameAsSearchableText.ts index 3dfc655fc6..3b175be3e5 100644 --- a/server/src/migrations/1658860470248-AddExifImageNameAsSearchableText.ts +++ b/server/src/migrations/1658860470248-AddExifImageNameAsSearchableText.ts @@ -5,10 +5,6 @@ export class AddExifImageNameAsSearchableText1658860470248 implements MigrationI public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); - await queryRunner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, - ['GENERATED_COLUMN', 'exifTextSearchableColumn', 'immich', 'public', 'exif'], - ); await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', COALESCE(make, '') || ' ' || COALESCE(model, '') || ' ' || @@ -18,33 +14,9 @@ export class AddExifImageNameAsSearchableText1658860470248 implements MigrationI COALESCE("city", '') || ' ' || COALESCE("state", '') || ' ' || COALESCE("country", ''))) STORED`); - await queryRunner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, - ['GENERATED_COLUMN', 'exifTextSearchableColumn', 'immich', 'public', 'exif'], - ); - await queryRunner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES ($1, $2, $3, $4, $5, $6)`, - [ - 'immich', - 'public', - 'exif', - 'GENERATED_COLUMN', - 'exifTextSearchableColumn', - "TO_TSVECTOR('english',\n COALESCE(make, '') || ' ' ||\n COALESCE(model, '') || ' ' ||\n COALESCE(orientation, '') || ' ' ||\n COALESCE(\"lensModel\", '') || ' ' ||\n COALESCE(\"imageName\", '') || ' ' ||\n COALESCE(\"city\", '') || ' ' ||\n COALESCE(\"state\", '') || ' ' ||\n COALESCE(\"country\", ''))", - ], - ); } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, - ['GENERATED_COLUMN', 'exifTextSearchableColumn', 'immich', 'public', 'exif'], - ); - await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); - await queryRunner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES ($1, $2, $3, $4, $5, $6)`, - ['immich', 'public', 'exif', 'GENERATED_COLUMN', 'exifTextSearchableColumn', ''], - ); await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector NOT NULL`); } } diff --git a/server/src/migrations/1681159594469-RemoveImageNameFromEXIFTable.ts b/server/src/migrations/1681159594469-RemoveImageNameFromEXIFTable.ts index 87bf2a62e6..e188ea3506 100644 --- a/server/src/migrations/1681159594469-RemoveImageNameFromEXIFTable.ts +++ b/server/src/migrations/1681159594469-RemoveImageNameFromEXIFTable.ts @@ -5,10 +5,6 @@ export class RemoveImageNameFromEXIFTable1681159594469 implements MigrationInter public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN IF EXISTS "exifTextSearchableColumn"`); - await queryRunner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, - ['GENERATED_COLUMN', 'exifTextSearchableColumn', 'immich', 'public', 'exif'], - ); await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', COALESCE(make, '') || ' ' || COALESCE(model, '') || ' ' || @@ -17,37 +13,11 @@ export class RemoveImageNameFromEXIFTable1681159594469 implements MigrationInter COALESCE("city", '') || ' ' || COALESCE("state", '') || ' ' || COALESCE("country", ''))) STORED NOT NULL`); - await queryRunner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES ($1, $2, $3, $4, $5, $6)`, - [ - 'immich', - 'public', - 'exif', - 'GENERATED_COLUMN', - 'exifTextSearchableColumn', - "TO_TSVECTOR('english',\n COALESCE(make, '') || ' ' ||\n COALESCE(model, '') || ' ' ||\n COALESCE(orientation, '') || ' ' ||\n COALESCE(\"lensModel\", '') || ' ' ||\n COALESCE(\"city\", '') || ' ' ||\n COALESCE(\"state\", '') || ' ' ||\n COALESCE(\"country\", ''))", - ], - ); await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "imageName"`); } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, - ['GENERATED_COLUMN', 'exifTextSearchableColumn', 'immich', 'public', 'exif'], - ); await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); - await queryRunner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES ($1, $2, $3, $4, $5, $6)`, - [ - 'immich', - 'public', - 'exif', - 'GENERATED_COLUMN', - 'exifTextSearchableColumn', - "TO_TSVECTOR('english',\n COALESCE(make, '') || ' ' ||\n COALESCE(model, '') || ' ' ||\n COALESCE(orientation, '') || ' ' ||\n COALESCE(\"lensModel\", '') || ' ' ||\n COALESCE(\"imageName\", '') || ' ' ||\n COALESCE(\"city\", '') || ' ' ||\n COALESCE(\"state\", '') || ' ' ||\n COALESCE(\"country\", ''))", - ], - ); await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', COALESCE(make, '') || ' ' || COALESCE(model, '') || ' ' || diff --git a/server/src/migrations/1700362016675-Geodata.ts b/server/src/migrations/1700362016675-Geodata.ts index 1ef562ff7e..fa948e0896 100644 --- a/server/src/migrations/1700362016675-Geodata.ts +++ b/server/src/migrations/1700362016675-Geodata.ts @@ -8,8 +8,6 @@ export class Geodata1700362016675 implements MigrationInterface { await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS earthdistance`) await queryRunner.query(`CREATE TABLE "geodata_admin2" ("key" character varying NOT NULL, "name" character varying NOT NULL, CONSTRAINT "PK_1e3886455dbb684d6f6b4756726" PRIMARY KEY ("key"))`); await queryRunner.query(`CREATE TABLE "geodata_admin1" ("key" character varying NOT NULL, "name" character varying NOT NULL, CONSTRAINT "PK_3fe3a89c5aac789d365871cb172" PRIMARY KEY ("key"))`); - await queryRunner.query(`INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES ($1, $2, $3, $4, $5, $6)`, ["immich","public","geodata_places","GENERATED_COLUMN","admin1Key","\"countryCode\" || '.' || \"admin1Code\""]); - await queryRunner.query(`INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") VALUES ($1, $2, $3, $4, $5, $6)`, ["immich","public","geodata_places","GENERATED_COLUMN","admin2Key","\"countryCode\" || '.' || \"admin1Code\" || '.' || \"admin2Code\""]); await queryRunner.query(`CREATE TABLE "geodata_places" ("id" integer NOT NULL, "name" character varying(200) NOT NULL, "longitude" double precision NOT NULL, "latitude" double precision NOT NULL, "countryCode" character(2) NOT NULL, "admin1Code" character varying(20), "admin2Code" character varying(80), "admin1Key" character varying GENERATED ALWAYS AS ("countryCode" || '.' || "admin1Code") STORED, "admin2Key" character varying GENERATED ALWAYS AS ("countryCode" || '.' || "admin1Code" || '.' || "admin2Code") STORED, "modificationDate" date NOT NULL, CONSTRAINT "PK_c29918988912ef4036f3d7fbff4" PRIMARY KEY ("id"))`); await queryRunner.query(`ALTER TABLE "geodata_places" ADD "earthCoord" earth GENERATED ALWAYS AS (ll_to_earth(latitude, longitude)) STORED`) await queryRunner.query(`CREATE INDEX "IDX_geodata_gist_earthcoord" ON "geodata_places" USING gist ("earthCoord");`) @@ -18,8 +16,6 @@ export class Geodata1700362016675 implements MigrationInterface { public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(`DROP INDEX "IDX_geodata_gist_earthcoord"`); await queryRunner.query(`DROP TABLE "geodata_places"`); - await queryRunner.query(`DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, ["GENERATED_COLUMN","admin2Key","immich","public","geodata_places"]); - await queryRunner.query(`DELETE FROM "typeorm_metadata" WHERE "type" = $1 AND "name" = $2 AND "database" = $3 AND "schema" = $4 AND "table" = $5`, ["GENERATED_COLUMN","admin1Key","immich","public","geodata_places"]); await queryRunner.query(`DROP TABLE "geodata_admin1"`); await queryRunner.query(`DROP TABLE "geodata_admin2"`); await queryRunner.query(`DROP EXTENSION cube`); diff --git a/server/src/migrations/1700713871511-UsePgVectors.ts b/server/src/migrations/1700713871511-UsePgVectors.ts index 75c85e3e0a..033e2ba9ad 100644 --- a/server/src/migrations/1700713871511-UsePgVectors.ts +++ b/server/src/migrations/1700713871511-UsePgVectors.ts @@ -1,4 +1,4 @@ -import { vectorExt } from 'src/database.config'; +import { getVectorExtension } from 'src/database.config'; import { getCLIPModelInfo } from 'src/utils/misc'; import { MigrationInterface, QueryRunner } from 'typeorm'; @@ -7,7 +7,7 @@ export class UsePgVectors1700713871511 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`SET search_path TO "$user", public, vectors`); - await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS ${vectorExt}`); + await queryRunner.query(`CREATE EXTENSION IF NOT EXISTS ${getVectorExtension()}`); const faceDimQuery = await queryRunner.query(` SELECT CARDINALITY(embedding::real[]) as dimsize FROM asset_faces diff --git a/server/src/migrations/1700713994428-AddCLIPEmbeddingIndex.ts b/server/src/migrations/1700713994428-AddCLIPEmbeddingIndex.ts index 908ebdb8fa..e325f270fd 100644 --- a/server/src/migrations/1700713994428-AddCLIPEmbeddingIndex.ts +++ b/server/src/migrations/1700713994428-AddCLIPEmbeddingIndex.ts @@ -1,4 +1,4 @@ -import { vectorExt } from 'src/database.config'; +import { getVectorExtension } from 'src/database.config'; import { DatabaseExtension } from 'src/interfaces/database.interface'; import { MigrationInterface, QueryRunner } from 'typeorm'; @@ -6,7 +6,7 @@ export class AddCLIPEmbeddingIndex1700713994428 implements MigrationInterface { name = 'AddCLIPEmbeddingIndex1700713994428'; public async up(queryRunner: QueryRunner): Promise { - if (vectorExt === DatabaseExtension.VECTORS) { + if (getVectorExtension() === DatabaseExtension.VECTORS) { await queryRunner.query(`SET vectors.pgvector_compatibility=on`); } await queryRunner.query(`SET search_path TO "$user", public, vectors`); diff --git a/server/src/migrations/1700714033632-AddFaceEmbeddingIndex.ts b/server/src/migrations/1700714033632-AddFaceEmbeddingIndex.ts index 75bebfa8e8..bc6bad6dbd 100644 --- a/server/src/migrations/1700714033632-AddFaceEmbeddingIndex.ts +++ b/server/src/migrations/1700714033632-AddFaceEmbeddingIndex.ts @@ -1,4 +1,4 @@ -import { vectorExt } from 'src/database.config'; +import { getVectorExtension } from 'src/database.config'; import { DatabaseExtension } from 'src/interfaces/database.interface'; import { MigrationInterface, QueryRunner } from 'typeorm'; @@ -6,7 +6,7 @@ export class AddFaceEmbeddingIndex1700714033632 implements MigrationInterface { name = 'AddFaceEmbeddingIndex1700714033632'; public async up(queryRunner: QueryRunner): Promise { - if (vectorExt === DatabaseExtension.VECTORS) { + if (getVectorExtension() === DatabaseExtension.VECTORS) { await queryRunner.query(`SET vectors.pgvector_compatibility=on`); } await queryRunner.query(`SET search_path TO "$user", public, vectors`); diff --git a/server/src/migrations/1704571051932-DefaultOnboardingForExistingInstallations.ts b/server/src/migrations/1704571051932-DefaultOnboardingForExistingInstallations.ts index cba248b5f7..cd737b2a62 100644 --- a/server/src/migrations/1704571051932-DefaultOnboardingForExistingInstallations.ts +++ b/server/src/migrations/1704571051932-DefaultOnboardingForExistingInstallations.ts @@ -6,7 +6,7 @@ export class DefaultOnboardingForExistingInstallations1704571051932 implements M if (adminCount[0].count > 0) { await queryRunner.query(`INSERT INTO system_metadata (key, value) VALUES ($1, $2)`, [ 'admin-onboarding', - '"{\\"isOnboarded\\":true}"', + String.raw`"{\"isOnboarded\":true}"`, ]); } } diff --git a/server/src/migrations/1708059341865-GeodataLocationSearch.ts b/server/src/migrations/1708059341865-GeodataLocationSearch.ts index 136ca2598d..af2d5dc5f3 100644 --- a/server/src/migrations/1708059341865-GeodataLocationSearch.ts +++ b/server/src/migrations/1708059341865-GeodataLocationSearch.ts @@ -49,30 +49,6 @@ export class GeodataLocationSearch1708059341865 implements MigrationInterface { CREATE INDEX idx_geodata_places_admin2_name ON geodata_places USING gin (f_unaccent("admin2Name") gin_trgm_ops)`); - - await queryRunner.query( - ` - DELETE FROM "typeorm_metadata" - WHERE - "type" = $1 AND - "name" = $2 AND - "database" = $3 AND - "schema" = $4 AND - "table" = $5`, - ['GENERATED_COLUMN', 'admin1Key', 'immich', 'public', 'geodata_places'], - ); - - await queryRunner.query( - ` - DELETE FROM "typeorm_metadata" - WHERE - "type" = $1 AND - "name" = $2 AND - "database" = $3 AND - "schema" = $4 AND - "table" = $5`, - ['GENERATED_COLUMN', 'admin2Key', 'immich', 'public', 'geodata_places'], - ); } public async down(queryRunner: QueryRunner): Promise { @@ -91,7 +67,7 @@ export class GeodataLocationSearch1708059341865 implements MigrationInterface { )`); await queryRunner.query(` - ALTER TABLE geodata_places + ALTER TABLE geodata_places ADD COLUMN "admin1Key" character varying GENERATED ALWAYS AS ("countryCode" || '.' || "admin1Code") STORED, ADD COLUMN "admin2Key" character varying @@ -128,25 +104,5 @@ export class GeodataLocationSearch1708059341865 implements MigrationInterface { SET "admin2Name" = admin2.name FROM geodata_admin2 admin2 WHERE admin2.key = "admin2Key";`); - - await queryRunner.query( - ` - INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") - VALUES ($1, $2, $3, $4, $5, $6)`, - ['immich', 'public', 'geodata_places', 'GENERATED_COLUMN', 'admin1Key', '"countryCode" || \'.\' || "admin1Code"'], - ); - - await queryRunner.query( - `INSERT INTO "typeorm_metadata"("database", "schema", "table", "type", "name", "value") - VALUES ($1, $2, $3, $4, $5, $6)`, - [ - 'immich', - 'public', - 'geodata_places', - 'GENERATED_COLUMN', - 'admin2Key', - '"countryCode" || \'.\' || "admin1Code" || \'.\' || "admin2Code"', - ], - ); } } diff --git a/server/src/migrations/1711989989911-AddAssetDuplicateColumns.ts b/server/src/migrations/1711989989911-AddAssetDuplicateColumns.ts new file mode 100644 index 0000000000..d295ec2d7c --- /dev/null +++ b/server/src/migrations/1711989989911-AddAssetDuplicateColumns.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class CreateAssetDuplicateColumns1711989989911 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE assets ADD COLUMN "duplicateId" uuid`); + await queryRunner.query(`ALTER TABLE asset_job_status ADD COLUMN "duplicatesDetectedAt" timestamptz`); + await queryRunner.query(`CREATE INDEX "IDX_assets_duplicateId" ON assets ("duplicateId")`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE assets DROP COLUMN "duplicateId"`); + await queryRunner.query(`ALTER TABLE asset_job_status DROP COLUMN "duplicatesDetectedAt"`); + } +} diff --git a/server/src/migrations/1715435221124-MotionAssetExtensionMP4.ts b/server/src/migrations/1715435221124-MotionAssetExtensionMP4.ts new file mode 100644 index 0000000000..f037ba1fb0 --- /dev/null +++ b/server/src/migrations/1715435221124-MotionAssetExtensionMP4.ts @@ -0,0 +1,11 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class MotionAssetExtensionMP41715435221124 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `UPDATE "assets" SET "originalFileName" = regexp_replace("originalFileName", '\\.[a-zA-Z0-9]+$', '.mp4') WHERE "originalPath" LIKE '%.mp4' AND "isVisible" = false`, + ); + } + + public async down(): Promise {} +} diff --git a/server/src/migrations/1715623169039-RemoveTextSearchColumn.ts b/server/src/migrations/1715623169039-RemoveTextSearchColumn.ts new file mode 100644 index 0000000000..50e99f0b2a --- /dev/null +++ b/server/src/migrations/1715623169039-RemoveTextSearchColumn.ts @@ -0,0 +1,21 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class RemoveTextSearchColumn1715623169039 implements MigrationInterface { + name = 'RemoveTextSearchColumn1715623169039' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "exif" DROP COLUMN "exifTextSearchableColumn"`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "exif" ADD "exifTextSearchableColumn" tsvector GENERATED ALWAYS AS (TO_TSVECTOR('english', + COALESCE(make, '') || ' ' || + COALESCE(model, '') || ' ' || + COALESCE(orientation, '') || ' ' || + COALESCE("lensModel", '') || ' ' || + COALESCE("city", '') || ' ' || + COALESCE("state", '') || ' ' || + COALESCE("country", ''))) STORED NOT NULL`); + } + +} diff --git a/server/src/migrations/1715787369686-RemoveSystemConfigTable.ts b/server/src/migrations/1715787369686-RemoveSystemConfigTable.ts new file mode 100644 index 0000000000..c16eec7160 --- /dev/null +++ b/server/src/migrations/1715787369686-RemoveSystemConfigTable.ts @@ -0,0 +1,31 @@ +import _ from 'lodash'; +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RemoveSystemConfigTable1715787369686 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const overrides = await queryRunner.query('SELECT "key", "value" FROM "system_config"'); + if (overrides.length === 0) { + return; + } + + const config = {}; + for (const { key, value } of overrides) { + _.set(config, key, JSON.parse(value)); + } + + await queryRunner.query(`INSERT INTO "system_metadata" ("key", "value") VALUES ($1, $2)`, [ + 'system-config', + // yup, we're double-stringifying it + JSON.stringify(JSON.stringify(config)), + ]); + + await queryRunner.query(`DROP TABLE "system_config"`); + } + + public async down(queryRunner: QueryRunner): Promise { + // no data restore, you just get the table back + await queryRunner.query( + `CREATE TABLE "system_config" ("key" character varying NOT NULL, "value" character varying, CONSTRAINT "PK_aab69295b445016f56731f4d535" PRIMARY KEY ("key"))`, + ); + } +} diff --git a/server/src/migrations/1715798702876-RemoveLibraryIsVisible.ts b/server/src/migrations/1715798702876-RemoveLibraryIsVisible.ts new file mode 100644 index 0000000000..45f5248c1a --- /dev/null +++ b/server/src/migrations/1715798702876-RemoveLibraryIsVisible.ts @@ -0,0 +1,14 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class RemoveLibraryIsVisible1715798702876 implements MigrationInterface { + name = 'RemoveLibraryIsVisible1715798702876' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "libraries" DROP COLUMN "isVisible"`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "libraries" ADD "isVisible" boolean NOT NULL DEFAULT true`); + } + +} diff --git a/server/src/migrations/1715804005643-RemoveLibraryType.ts b/server/src/migrations/1715804005643-RemoveLibraryType.ts new file mode 100644 index 0000000000..d42ba4ec73 --- /dev/null +++ b/server/src/migrations/1715804005643-RemoveLibraryType.ts @@ -0,0 +1,29 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class RemoveLibraryType1715804005643 implements MigrationInterface { + name = 'RemoveLibraryType1715804005643'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "assets" DROP CONSTRAINT "FK_9977c3c1de01c3d848039a6b90c"`); + await queryRunner.query(`DROP INDEX "public"."UQ_assets_owner_library_checksum"`); + await queryRunner.query(`DROP INDEX "public"."IDX_originalPath_libraryId"`); + await queryRunner.query(`ALTER TABLE "assets" ALTER COLUMN "libraryId" DROP NOT NULL`); + await queryRunner.query(` + UPDATE "assets" + SET "libraryId" = NULL + FROM "libraries" + WHERE "assets"."libraryId" = "libraries"."id" + AND "libraries"."type" = 'UPLOAD' +`); + await queryRunner.query(`DELETE FROM "libraries" WHERE "type" = 'UPLOAD'`); + await queryRunner.query(`ALTER TABLE "libraries" DROP COLUMN "type"`); + await queryRunner.query(`CREATE INDEX "IDX_originalPath_libraryId" ON "assets" ("originalPath", "libraryId")`); + await queryRunner.query(`CREATE UNIQUE INDEX "UQ_assets_owner_checksum" ON "assets" ("ownerId", "checksum") WHERE "libraryId" IS NULL`); + await queryRunner.query(`CREATE UNIQUE INDEX "UQ_assets_owner_library_checksum" ON "assets" ("ownerId", "libraryId", "checksum") WHERE "libraryId" IS NOT NULL`); + await queryRunner.query(`ALTER TABLE "assets" ADD CONSTRAINT "FK_9977c3c1de01c3d848039a6b90c" FOREIGN KEY ("libraryId") REFERENCES "libraries"("id") ON DELETE CASCADE ON UPDATE CASCADE`); + } + + public async down(): Promise { + // not implemented + } +} diff --git a/server/src/migrations/1715890481637-FixJsonB.ts b/server/src/migrations/1715890481637-FixJsonB.ts new file mode 100644 index 0000000000..afb39565a3 --- /dev/null +++ b/server/src/migrations/1715890481637-FixJsonB.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class FixJsonB1715890481637 implements MigrationInterface { + name = 'FixJsonB1715890481637'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "system_metadata" ALTER COLUMN "value" DROP DEFAULT`); + const records = await queryRunner.query('SELECT "key", "value" FROM "system_metadata"'); + for (const { key, value } of records) { + await queryRunner.query(`UPDATE "system_metadata" SET "value" = $1 WHERE "key" = $2`, [value, key]); + } + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "system_metadata" ALTER COLUMN "value" SET DEFAULT '{}'`); + const records = await queryRunner.query('SELECT "key", "value" FROM "system_metadata"'); + for (const { key, value } of records) { + await queryRunner.query(`UPDATE "system_metadata" SET "value" = $1 WHERE "key" = $2`, [ + JSON.stringify(JSON.stringify(value)), + key, + ]); + } + } +} diff --git a/server/src/migrations/1716312279245-UserMetadata.ts b/server/src/migrations/1716312279245-UserMetadata.ts new file mode 100644 index 0000000000..b118a8d42a --- /dev/null +++ b/server/src/migrations/1716312279245-UserMetadata.ts @@ -0,0 +1,60 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UserMetadata1716312279245 implements MigrationInterface { + name = 'UserMetadata1716312279245'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "user_metadata" ("userId" uuid NOT NULL, "key" character varying NOT NULL, "value" jsonb NOT NULL, CONSTRAINT "PK_5931462150b3438cbc83277fe5a" PRIMARY KEY ("userId", "key"))`, + ); + const users = await queryRunner.query('SELECT "id", "memoriesEnabled", "avatarColor" FROM "users"'); + for (const { id, memoriesEnabled, avatarColor } of users) { + const preferences: any = {}; + if (!memoriesEnabled) { + preferences.memories = { enabled: false }; + } + + if (avatarColor) { + preferences.avatar = { color: avatarColor }; + } + + if (Object.keys(preferences).length === 0) { + continue; + } + + await queryRunner.query('INSERT INTO "user_metadata" ("userId", "key", "value") VALUES ($1, $2, $3)', [ + id, + 'preferences', + preferences, + ]); + } + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "memoriesEnabled"`); + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "avatarColor"`); + await queryRunner.query( + `ALTER TABLE "user_metadata" ADD CONSTRAINT "FK_6afb43681a21cf7815932bc38ac" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_metadata" DROP CONSTRAINT "FK_6afb43681a21cf7815932bc38ac"`); + await queryRunner.query(`ALTER TABLE "users" ADD "avatarColor" character varying`); + await queryRunner.query(`ALTER TABLE "users" ADD "memoriesEnabled" boolean NOT NULL DEFAULT true`); + const items = await queryRunner.query( + `SELECT "userId" as "id", "value" FROM "user_metadata" WHERE "key"='preferences'`, + ); + for (const { id, value } of items) { + if (!value) { + continue; + } + + if (value.avatar?.color) { + await queryRunner.query(`UPDATE "users" SET "avatarColor" = $1 WHERE "id" = $2`, [value.avatar.color, id]); + } + + if (value.memories?.enabled === false) { + await queryRunner.query(`UPDATE "users" SET "memoriesEnabled" = false WHERE "id" = $1`, [id]); + } + } + await queryRunner.query(`DROP TABLE "user_metadata"`); + } +} diff --git a/server/src/queries/access.repository.sql b/server/src/queries/access.repository.sql index 52cf28c77c..ffe4b6413f 100644 --- a/server/src/queries/access.repository.sql +++ b/server/src/queries/access.repository.sql @@ -153,6 +153,7 @@ FROM AND ("asset"."deletedAt" IS NULL) WHERE "partner"."sharedWithId" = $1 + AND "asset"."isArchived" = false AND "asset"."id" IN ($2) -- AccessRepository.asset.checkSharedLinkAccess @@ -191,20 +192,6 @@ WHERE AND ("SessionEntity"."id" IN ($2)) ) --- AccessRepository.library.checkOwnerAccess -SELECT - "LibraryEntity"."id" AS "LibraryEntity_id" -FROM - "libraries" "LibraryEntity" -WHERE - ( - ( - ("LibraryEntity"."id" IN ($1)) - AND ("LibraryEntity"."ownerId" = $2) - ) - ) - AND ("LibraryEntity"."deletedAt" IS NULL) - -- AccessRepository.memory.checkOwnerAccess SELECT "MemoryEntity"."id" AS "MemoryEntity_id" diff --git a/server/src/queries/activity.repository.sql b/server/src/queries/activity.repository.sql index c271e4bef2..3f3e04140c 100644 --- a/server/src/queries/activity.repository.sql +++ b/server/src/queries/activity.repository.sql @@ -12,7 +12,6 @@ SELECT "ActivityEntity"."isLiked" AS "ActivityEntity_isLiked", "ActivityEntity__ActivityEntity_user"."id" AS "ActivityEntity__ActivityEntity_user_id", "ActivityEntity__ActivityEntity_user"."name" AS "ActivityEntity__ActivityEntity_user_name", - "ActivityEntity__ActivityEntity_user"."avatarColor" AS "ActivityEntity__ActivityEntity_user_avatarColor", "ActivityEntity__ActivityEntity_user"."isAdmin" AS "ActivityEntity__ActivityEntity_user_isAdmin", "ActivityEntity__ActivityEntity_user"."email" AS "ActivityEntity__ActivityEntity_user_email", "ActivityEntity__ActivityEntity_user"."storageLabel" AS "ActivityEntity__ActivityEntity_user_storageLabel", @@ -23,7 +22,6 @@ SELECT "ActivityEntity__ActivityEntity_user"."deletedAt" AS "ActivityEntity__ActivityEntity_user_deletedAt", "ActivityEntity__ActivityEntity_user"."status" AS "ActivityEntity__ActivityEntity_user_status", "ActivityEntity__ActivityEntity_user"."updatedAt" AS "ActivityEntity__ActivityEntity_user_updatedAt", - "ActivityEntity__ActivityEntity_user"."memoriesEnabled" AS "ActivityEntity__ActivityEntity_user_memoriesEnabled", "ActivityEntity__ActivityEntity_user"."quotaSizeInBytes" AS "ActivityEntity__ActivityEntity_user_quotaSizeInBytes", "ActivityEntity__ActivityEntity_user"."quotaUsageInBytes" AS "ActivityEntity__ActivityEntity_user_quotaUsageInBytes" FROM diff --git a/server/src/queries/album.repository.sql b/server/src/queries/album.repository.sql index 2037e320a1..8ac7ed6731 100644 --- a/server/src/queries/album.repository.sql +++ b/server/src/queries/album.repository.sql @@ -18,7 +18,6 @@ FROM "AlbumEntity"."order" AS "AlbumEntity_order", "AlbumEntity__AlbumEntity_owner"."id" AS "AlbumEntity__AlbumEntity_owner_id", "AlbumEntity__AlbumEntity_owner"."name" AS "AlbumEntity__AlbumEntity_owner_name", - "AlbumEntity__AlbumEntity_owner"."avatarColor" AS "AlbumEntity__AlbumEntity_owner_avatarColor", "AlbumEntity__AlbumEntity_owner"."isAdmin" AS "AlbumEntity__AlbumEntity_owner_isAdmin", "AlbumEntity__AlbumEntity_owner"."email" AS "AlbumEntity__AlbumEntity_owner_email", "AlbumEntity__AlbumEntity_owner"."storageLabel" AS "AlbumEntity__AlbumEntity_owner_storageLabel", @@ -29,7 +28,6 @@ FROM "AlbumEntity__AlbumEntity_owner"."deletedAt" AS "AlbumEntity__AlbumEntity_owner_deletedAt", "AlbumEntity__AlbumEntity_owner"."status" AS "AlbumEntity__AlbumEntity_owner_status", "AlbumEntity__AlbumEntity_owner"."updatedAt" AS "AlbumEntity__AlbumEntity_owner_updatedAt", - "AlbumEntity__AlbumEntity_owner"."memoriesEnabled" AS "AlbumEntity__AlbumEntity_owner_memoriesEnabled", "AlbumEntity__AlbumEntity_owner"."quotaSizeInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaSizeInBytes", "AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes", "AlbumEntity__AlbumEntity_albumUsers"."albumsId" AS "AlbumEntity__AlbumEntity_albumUsers_albumsId", @@ -37,7 +35,6 @@ FROM "AlbumEntity__AlbumEntity_albumUsers"."role" AS "AlbumEntity__AlbumEntity_albumUsers_role", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."id" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_id", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."name" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_name", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."avatarColor" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_avatarColor", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."isAdmin" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_isAdmin", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."email" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_email", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."storageLabel" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_storageLabel", @@ -48,7 +45,6 @@ FROM "a641d58cf46d4a391ba060ac4dc337665c69ffea"."deletedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_deletedAt", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."status" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_status", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."updatedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_updatedAt", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."memoriesEnabled" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_memoriesEnabled", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaSizeInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaSizeInBytes", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaUsageInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaUsageInBytes", "AlbumEntity__AlbumEntity_sharedLinks"."id" AS "AlbumEntity__AlbumEntity_sharedLinks_id", @@ -98,7 +94,6 @@ SELECT "AlbumEntity"."order" AS "AlbumEntity_order", "AlbumEntity__AlbumEntity_owner"."id" AS "AlbumEntity__AlbumEntity_owner_id", "AlbumEntity__AlbumEntity_owner"."name" AS "AlbumEntity__AlbumEntity_owner_name", - "AlbumEntity__AlbumEntity_owner"."avatarColor" AS "AlbumEntity__AlbumEntity_owner_avatarColor", "AlbumEntity__AlbumEntity_owner"."isAdmin" AS "AlbumEntity__AlbumEntity_owner_isAdmin", "AlbumEntity__AlbumEntity_owner"."email" AS "AlbumEntity__AlbumEntity_owner_email", "AlbumEntity__AlbumEntity_owner"."storageLabel" AS "AlbumEntity__AlbumEntity_owner_storageLabel", @@ -109,7 +104,6 @@ SELECT "AlbumEntity__AlbumEntity_owner"."deletedAt" AS "AlbumEntity__AlbumEntity_owner_deletedAt", "AlbumEntity__AlbumEntity_owner"."status" AS "AlbumEntity__AlbumEntity_owner_status", "AlbumEntity__AlbumEntity_owner"."updatedAt" AS "AlbumEntity__AlbumEntity_owner_updatedAt", - "AlbumEntity__AlbumEntity_owner"."memoriesEnabled" AS "AlbumEntity__AlbumEntity_owner_memoriesEnabled", "AlbumEntity__AlbumEntity_owner"."quotaSizeInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaSizeInBytes", "AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes", "AlbumEntity__AlbumEntity_albumUsers"."albumsId" AS "AlbumEntity__AlbumEntity_albumUsers_albumsId", @@ -117,7 +111,6 @@ SELECT "AlbumEntity__AlbumEntity_albumUsers"."role" AS "AlbumEntity__AlbumEntity_albumUsers_role", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."id" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_id", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."name" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_name", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."avatarColor" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_avatarColor", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."isAdmin" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_isAdmin", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."email" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_email", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."storageLabel" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_storageLabel", @@ -128,7 +121,6 @@ SELECT "a641d58cf46d4a391ba060ac4dc337665c69ffea"."deletedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_deletedAt", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."status" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_status", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."updatedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_updatedAt", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."memoriesEnabled" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_memoriesEnabled", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaSizeInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaSizeInBytes", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaUsageInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaUsageInBytes" FROM @@ -160,7 +152,6 @@ SELECT "AlbumEntity"."order" AS "AlbumEntity_order", "AlbumEntity__AlbumEntity_owner"."id" AS "AlbumEntity__AlbumEntity_owner_id", "AlbumEntity__AlbumEntity_owner"."name" AS "AlbumEntity__AlbumEntity_owner_name", - "AlbumEntity__AlbumEntity_owner"."avatarColor" AS "AlbumEntity__AlbumEntity_owner_avatarColor", "AlbumEntity__AlbumEntity_owner"."isAdmin" AS "AlbumEntity__AlbumEntity_owner_isAdmin", "AlbumEntity__AlbumEntity_owner"."email" AS "AlbumEntity__AlbumEntity_owner_email", "AlbumEntity__AlbumEntity_owner"."storageLabel" AS "AlbumEntity__AlbumEntity_owner_storageLabel", @@ -171,7 +162,6 @@ SELECT "AlbumEntity__AlbumEntity_owner"."deletedAt" AS "AlbumEntity__AlbumEntity_owner_deletedAt", "AlbumEntity__AlbumEntity_owner"."status" AS "AlbumEntity__AlbumEntity_owner_status", "AlbumEntity__AlbumEntity_owner"."updatedAt" AS "AlbumEntity__AlbumEntity_owner_updatedAt", - "AlbumEntity__AlbumEntity_owner"."memoriesEnabled" AS "AlbumEntity__AlbumEntity_owner_memoriesEnabled", "AlbumEntity__AlbumEntity_owner"."quotaSizeInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaSizeInBytes", "AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes", "AlbumEntity__AlbumEntity_albumUsers"."albumsId" AS "AlbumEntity__AlbumEntity_albumUsers_albumsId", @@ -179,7 +169,6 @@ SELECT "AlbumEntity__AlbumEntity_albumUsers"."role" AS "AlbumEntity__AlbumEntity_albumUsers_role", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."id" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_id", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."name" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_name", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."avatarColor" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_avatarColor", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."isAdmin" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_isAdmin", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."email" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_email", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."storageLabel" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_storageLabel", @@ -190,7 +179,6 @@ SELECT "a641d58cf46d4a391ba060ac4dc337665c69ffea"."deletedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_deletedAt", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."status" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_status", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."updatedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_updatedAt", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."memoriesEnabled" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_memoriesEnabled", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaSizeInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaSizeInBytes", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaUsageInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaUsageInBytes" FROM @@ -299,7 +287,6 @@ SELECT "AlbumEntity__AlbumEntity_albumUsers"."role" AS "AlbumEntity__AlbumEntity_albumUsers_role", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."id" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_id", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."name" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_name", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."avatarColor" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_avatarColor", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."isAdmin" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_isAdmin", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."email" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_email", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."storageLabel" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_storageLabel", @@ -310,7 +297,6 @@ SELECT "a641d58cf46d4a391ba060ac4dc337665c69ffea"."deletedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_deletedAt", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."status" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_status", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."updatedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_updatedAt", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."memoriesEnabled" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_memoriesEnabled", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaSizeInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaSizeInBytes", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaUsageInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaUsageInBytes", "AlbumEntity__AlbumEntity_sharedLinks"."id" AS "AlbumEntity__AlbumEntity_sharedLinks_id", @@ -327,7 +313,6 @@ SELECT "AlbumEntity__AlbumEntity_sharedLinks"."albumId" AS "AlbumEntity__AlbumEntity_sharedLinks_albumId", "AlbumEntity__AlbumEntity_owner"."id" AS "AlbumEntity__AlbumEntity_owner_id", "AlbumEntity__AlbumEntity_owner"."name" AS "AlbumEntity__AlbumEntity_owner_name", - "AlbumEntity__AlbumEntity_owner"."avatarColor" AS "AlbumEntity__AlbumEntity_owner_avatarColor", "AlbumEntity__AlbumEntity_owner"."isAdmin" AS "AlbumEntity__AlbumEntity_owner_isAdmin", "AlbumEntity__AlbumEntity_owner"."email" AS "AlbumEntity__AlbumEntity_owner_email", "AlbumEntity__AlbumEntity_owner"."storageLabel" AS "AlbumEntity__AlbumEntity_owner_storageLabel", @@ -338,7 +323,6 @@ SELECT "AlbumEntity__AlbumEntity_owner"."deletedAt" AS "AlbumEntity__AlbumEntity_owner_deletedAt", "AlbumEntity__AlbumEntity_owner"."status" AS "AlbumEntity__AlbumEntity_owner_status", "AlbumEntity__AlbumEntity_owner"."updatedAt" AS "AlbumEntity__AlbumEntity_owner_updatedAt", - "AlbumEntity__AlbumEntity_owner"."memoriesEnabled" AS "AlbumEntity__AlbumEntity_owner_memoriesEnabled", "AlbumEntity__AlbumEntity_owner"."quotaSizeInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaSizeInBytes", "AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes" FROM @@ -376,7 +360,6 @@ SELECT "AlbumEntity__AlbumEntity_albumUsers"."role" AS "AlbumEntity__AlbumEntity_albumUsers_role", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."id" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_id", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."name" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_name", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."avatarColor" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_avatarColor", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."isAdmin" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_isAdmin", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."email" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_email", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."storageLabel" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_storageLabel", @@ -387,7 +370,6 @@ SELECT "a641d58cf46d4a391ba060ac4dc337665c69ffea"."deletedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_deletedAt", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."status" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_status", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."updatedAt" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_updatedAt", - "a641d58cf46d4a391ba060ac4dc337665c69ffea"."memoriesEnabled" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_memoriesEnabled", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaSizeInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaSizeInBytes", "a641d58cf46d4a391ba060ac4dc337665c69ffea"."quotaUsageInBytes" AS "a641d58cf46d4a391ba060ac4dc337665c69ffea_quotaUsageInBytes", "AlbumEntity__AlbumEntity_sharedLinks"."id" AS "AlbumEntity__AlbumEntity_sharedLinks_id", @@ -404,7 +386,6 @@ SELECT "AlbumEntity__AlbumEntity_sharedLinks"."albumId" AS "AlbumEntity__AlbumEntity_sharedLinks_albumId", "AlbumEntity__AlbumEntity_owner"."id" AS "AlbumEntity__AlbumEntity_owner_id", "AlbumEntity__AlbumEntity_owner"."name" AS "AlbumEntity__AlbumEntity_owner_name", - "AlbumEntity__AlbumEntity_owner"."avatarColor" AS "AlbumEntity__AlbumEntity_owner_avatarColor", "AlbumEntity__AlbumEntity_owner"."isAdmin" AS "AlbumEntity__AlbumEntity_owner_isAdmin", "AlbumEntity__AlbumEntity_owner"."email" AS "AlbumEntity__AlbumEntity_owner_email", "AlbumEntity__AlbumEntity_owner"."storageLabel" AS "AlbumEntity__AlbumEntity_owner_storageLabel", @@ -415,7 +396,6 @@ SELECT "AlbumEntity__AlbumEntity_owner"."deletedAt" AS "AlbumEntity__AlbumEntity_owner_deletedAt", "AlbumEntity__AlbumEntity_owner"."status" AS "AlbumEntity__AlbumEntity_owner_status", "AlbumEntity__AlbumEntity_owner"."updatedAt" AS "AlbumEntity__AlbumEntity_owner_updatedAt", - "AlbumEntity__AlbumEntity_owner"."memoriesEnabled" AS "AlbumEntity__AlbumEntity_owner_memoriesEnabled", "AlbumEntity__AlbumEntity_owner"."quotaSizeInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaSizeInBytes", "AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes" FROM @@ -504,7 +484,6 @@ SELECT "AlbumEntity__AlbumEntity_sharedLinks"."albumId" AS "AlbumEntity__AlbumEntity_sharedLinks_albumId", "AlbumEntity__AlbumEntity_owner"."id" AS "AlbumEntity__AlbumEntity_owner_id", "AlbumEntity__AlbumEntity_owner"."name" AS "AlbumEntity__AlbumEntity_owner_name", - "AlbumEntity__AlbumEntity_owner"."avatarColor" AS "AlbumEntity__AlbumEntity_owner_avatarColor", "AlbumEntity__AlbumEntity_owner"."isAdmin" AS "AlbumEntity__AlbumEntity_owner_isAdmin", "AlbumEntity__AlbumEntity_owner"."email" AS "AlbumEntity__AlbumEntity_owner_email", "AlbumEntity__AlbumEntity_owner"."storageLabel" AS "AlbumEntity__AlbumEntity_owner_storageLabel", @@ -515,7 +494,6 @@ SELECT "AlbumEntity__AlbumEntity_owner"."deletedAt" AS "AlbumEntity__AlbumEntity_owner_deletedAt", "AlbumEntity__AlbumEntity_owner"."status" AS "AlbumEntity__AlbumEntity_owner_status", "AlbumEntity__AlbumEntity_owner"."updatedAt" AS "AlbumEntity__AlbumEntity_owner_updatedAt", - "AlbumEntity__AlbumEntity_owner"."memoriesEnabled" AS "AlbumEntity__AlbumEntity_owner_memoriesEnabled", "AlbumEntity__AlbumEntity_owner"."quotaSizeInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaSizeInBytes", "AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes" FROM @@ -564,7 +542,6 @@ SELECT "AlbumEntity"."order" AS "AlbumEntity_order", "AlbumEntity__AlbumEntity_owner"."id" AS "AlbumEntity__AlbumEntity_owner_id", "AlbumEntity__AlbumEntity_owner"."name" AS "AlbumEntity__AlbumEntity_owner_name", - "AlbumEntity__AlbumEntity_owner"."avatarColor" AS "AlbumEntity__AlbumEntity_owner_avatarColor", "AlbumEntity__AlbumEntity_owner"."isAdmin" AS "AlbumEntity__AlbumEntity_owner_isAdmin", "AlbumEntity__AlbumEntity_owner"."email" AS "AlbumEntity__AlbumEntity_owner_email", "AlbumEntity__AlbumEntity_owner"."storageLabel" AS "AlbumEntity__AlbumEntity_owner_storageLabel", @@ -575,7 +552,6 @@ SELECT "AlbumEntity__AlbumEntity_owner"."deletedAt" AS "AlbumEntity__AlbumEntity_owner_deletedAt", "AlbumEntity__AlbumEntity_owner"."status" AS "AlbumEntity__AlbumEntity_owner_status", "AlbumEntity__AlbumEntity_owner"."updatedAt" AS "AlbumEntity__AlbumEntity_owner_updatedAt", - "AlbumEntity__AlbumEntity_owner"."memoriesEnabled" AS "AlbumEntity__AlbumEntity_owner_memoriesEnabled", "AlbumEntity__AlbumEntity_owner"."quotaSizeInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaSizeInBytes", "AlbumEntity__AlbumEntity_owner"."quotaUsageInBytes" AS "AlbumEntity__AlbumEntity_owner_quotaUsageInBytes" FROM diff --git a/server/src/queries/api.key.repository.sql b/server/src/queries/api.key.repository.sql index 22b8fd6722..fa0431fb0f 100644 --- a/server/src/queries/api.key.repository.sql +++ b/server/src/queries/api.key.repository.sql @@ -11,7 +11,6 @@ FROM "APIKeyEntity"."userId" AS "APIKeyEntity_userId", "APIKeyEntity__APIKeyEntity_user"."id" AS "APIKeyEntity__APIKeyEntity_user_id", "APIKeyEntity__APIKeyEntity_user"."name" AS "APIKeyEntity__APIKeyEntity_user_name", - "APIKeyEntity__APIKeyEntity_user"."avatarColor" AS "APIKeyEntity__APIKeyEntity_user_avatarColor", "APIKeyEntity__APIKeyEntity_user"."isAdmin" AS "APIKeyEntity__APIKeyEntity_user_isAdmin", "APIKeyEntity__APIKeyEntity_user"."email" AS "APIKeyEntity__APIKeyEntity_user_email", "APIKeyEntity__APIKeyEntity_user"."storageLabel" AS "APIKeyEntity__APIKeyEntity_user_storageLabel", @@ -22,7 +21,6 @@ FROM "APIKeyEntity__APIKeyEntity_user"."deletedAt" AS "APIKeyEntity__APIKeyEntity_user_deletedAt", "APIKeyEntity__APIKeyEntity_user"."status" AS "APIKeyEntity__APIKeyEntity_user_status", "APIKeyEntity__APIKeyEntity_user"."updatedAt" AS "APIKeyEntity__APIKeyEntity_user_updatedAt", - "APIKeyEntity__APIKeyEntity_user"."memoriesEnabled" AS "APIKeyEntity__APIKeyEntity_user_memoriesEnabled", "APIKeyEntity__APIKeyEntity_user"."quotaSizeInBytes" AS "APIKeyEntity__APIKeyEntity_user_quotaSizeInBytes", "APIKeyEntity__APIKeyEntity_user"."quotaUsageInBytes" AS "APIKeyEntity__APIKeyEntity_user_quotaUsageInBytes" FROM diff --git a/server/src/queries/asset.repository.sql b/server/src/queries/asset.repository.sql index 5626f96a45..9ef4b3aaf0 100644 --- a/server/src/queries/asset.repository.sql +++ b/server/src/queries/asset.repository.sql @@ -30,6 +30,7 @@ SELECT "entity"."originalFileName" AS "entity_originalFileName", "entity"."sidecarPath" AS "entity_sidecarPath", "entity"."stackId" AS "entity_stackId", + "entity"."duplicateId" AS "entity_duplicateId", "exifInfo"."assetId" AS "exifInfo_assetId", "exifInfo"."description" AS "exifInfo_description", "exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth", @@ -111,7 +112,8 @@ SELECT "AssetEntity"."livePhotoVideoId" AS "AssetEntity_livePhotoVideoId", "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName", "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath", - "AssetEntity"."stackId" AS "AssetEntity_stackId" + "AssetEntity"."stackId" AS "AssetEntity_stackId", + "AssetEntity"."duplicateId" AS "AssetEntity_duplicateId" FROM "assets" "AssetEntity" WHERE @@ -147,6 +149,7 @@ SELECT "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName", "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath", "AssetEntity"."stackId" AS "AssetEntity_stackId", + "AssetEntity"."duplicateId" AS "AssetEntity_duplicateId", "AssetEntity__AssetEntity_exifInfo"."assetId" AS "AssetEntity__AssetEntity_exifInfo_assetId", "AssetEntity__AssetEntity_exifInfo"."description" AS "AssetEntity__AssetEntity_exifInfo_description", "AssetEntity__AssetEntity_exifInfo"."exifImageWidth" AS "AssetEntity__AssetEntity_exifInfo_exifImageWidth", @@ -231,7 +234,8 @@ SELECT "bd93d5747511a4dad4923546c51365bf1a803774"."livePhotoVideoId" AS "bd93d5747511a4dad4923546c51365bf1a803774_livePhotoVideoId", "bd93d5747511a4dad4923546c51365bf1a803774"."originalFileName" AS "bd93d5747511a4dad4923546c51365bf1a803774_originalFileName", "bd93d5747511a4dad4923546c51365bf1a803774"."sidecarPath" AS "bd93d5747511a4dad4923546c51365bf1a803774_sidecarPath", - "bd93d5747511a4dad4923546c51365bf1a803774"."stackId" AS "bd93d5747511a4dad4923546c51365bf1a803774_stackId" + "bd93d5747511a4dad4923546c51365bf1a803774"."stackId" AS "bd93d5747511a4dad4923546c51365bf1a803774_stackId", + "bd93d5747511a4dad4923546c51365bf1a803774"."duplicateId" AS "bd93d5747511a4dad4923546c51365bf1a803774_duplicateId" FROM "assets" "AssetEntity" LEFT JOIN "exif" "AssetEntity__AssetEntity_exifInfo" ON "AssetEntity__AssetEntity_exifInfo"."assetId" = "AssetEntity"."id" @@ -312,7 +316,8 @@ FROM "AssetEntity"."livePhotoVideoId" AS "AssetEntity_livePhotoVideoId", "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName", "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath", - "AssetEntity"."stackId" AS "AssetEntity_stackId" + "AssetEntity"."stackId" AS "AssetEntity_stackId", + "AssetEntity"."duplicateId" AS "AssetEntity_duplicateId" FROM "assets" "AssetEntity" LEFT JOIN "libraries" "AssetEntity__AssetEntity_library" ON "AssetEntity__AssetEntity_library"."id" = "AssetEntity"."libraryId" @@ -408,7 +413,8 @@ SELECT "AssetEntity"."livePhotoVideoId" AS "AssetEntity_livePhotoVideoId", "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName", "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath", - "AssetEntity"."stackId" AS "AssetEntity_stackId" + "AssetEntity"."stackId" AS "AssetEntity_stackId", + "AssetEntity"."duplicateId" AS "AssetEntity_duplicateId" FROM "assets" "AssetEntity" WHERE @@ -424,6 +430,15 @@ SET WHERE "id" IN ($2) +-- AssetRepository.updateDuplicates +UPDATE "assets" +SET + "duplicateId" = $1, + "updatedAt" = CURRENT_TIMESTAMP +WHERE + "duplicateId" IN ($2) + OR "id" IN ($3) + -- AssetRepository.getByChecksum SELECT "AssetEntity"."id" AS "AssetEntity_id", @@ -453,7 +468,8 @@ SELECT "AssetEntity"."livePhotoVideoId" AS "AssetEntity_livePhotoVideoId", "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName", "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath", - "AssetEntity"."stackId" AS "AssetEntity_stackId" + "AssetEntity"."stackId" AS "AssetEntity_stackId", + "AssetEntity"."duplicateId" AS "AssetEntity_duplicateId" FROM "assets" "AssetEntity" WHERE @@ -467,27 +483,31 @@ WHERE LIMIT 1 --- AssetRepository.getUploadAssetIdByChecksum -SELECT DISTINCT - "distinctAlias"."AssetEntity_id" AS "ids_AssetEntity_id" +-- AssetRepository.getByChecksums +SELECT + "AssetEntity"."id" AS "AssetEntity_id", + "AssetEntity"."checksum" AS "AssetEntity_checksum" FROM + "assets" "AssetEntity" +WHERE ( - SELECT - "AssetEntity"."id" AS "AssetEntity_id" - FROM - "assets" "AssetEntity" - LEFT JOIN "libraries" "AssetEntity__AssetEntity_library" ON "AssetEntity__AssetEntity_library"."id" = "AssetEntity"."libraryId" - WHERE - ( - ("AssetEntity"."ownerId" = $1) - AND ("AssetEntity"."checksum" = $2) - AND ( - (("AssetEntity__AssetEntity_library"."type" = $3)) - ) - ) - ) "distinctAlias" -ORDER BY - "AssetEntity_id" ASC + ("AssetEntity"."ownerId" = $1) + AND ( + "AssetEntity"."checksum" IN ($2, $3, $4, $5, $6, $7, $8, $9, $10) + ) + ) + +-- AssetRepository.getUploadAssetIdByChecksum +SELECT + "AssetEntity"."id" AS "AssetEntity_id" +FROM + "assets" "AssetEntity" +WHERE + ( + ("AssetEntity"."ownerId" = $1) + AND ("AssetEntity"."checksum" = $2) + AND ("AssetEntity"."libraryId" IS NULL) + ) LIMIT 1 @@ -520,7 +540,8 @@ SELECT "AssetEntity"."livePhotoVideoId" AS "AssetEntity_livePhotoVideoId", "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName", "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath", - "AssetEntity"."stackId" AS "AssetEntity_stackId" + "AssetEntity"."stackId" AS "AssetEntity_stackId", + "AssetEntity"."duplicateId" AS "AssetEntity_duplicateId" FROM "assets" "AssetEntity" WHERE @@ -576,6 +597,7 @@ SELECT "asset"."originalFileName" AS "asset_originalFileName", "asset"."sidecarPath" AS "asset_sidecarPath", "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", "exifInfo"."assetId" AS "exifInfo_assetId", "exifInfo"."description" AS "exifInfo_description", "exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth", @@ -633,7 +655,8 @@ SELECT "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId", "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName", "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath", - "stackedAssets"."stackId" AS "stackedAssets_stackId" + "stackedAssets"."stackId" AS "stackedAssets_stackId", + "stackedAssets"."duplicateId" AS "stackedAssets_duplicateId" FROM "assets" "asset" LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id" @@ -714,6 +737,7 @@ SELECT "asset"."originalFileName" AS "asset_originalFileName", "asset"."sidecarPath" AS "asset_sidecarPath", "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", "exifInfo"."assetId" AS "exifInfo_assetId", "exifInfo"."description" AS "exifInfo_description", "exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth", @@ -771,7 +795,8 @@ SELECT "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId", "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName", "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath", - "stackedAssets"."stackId" AS "stackedAssets_stackId" + "stackedAssets"."stackId" AS "stackedAssets_stackId", + "stackedAssets"."duplicateId" AS "stackedAssets_duplicateId" FROM "assets" "asset" LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id" @@ -798,6 +823,112 @@ ORDER BY )::timestamptz DESC, "asset"."fileCreatedAt" DESC +-- AssetRepository.getDuplicates +SELECT + "asset"."id" AS "asset_id", + "asset"."deviceAssetId" AS "asset_deviceAssetId", + "asset"."ownerId" AS "asset_ownerId", + "asset"."libraryId" AS "asset_libraryId", + "asset"."deviceId" AS "asset_deviceId", + "asset"."type" AS "asset_type", + "asset"."originalPath" AS "asset_originalPath", + "asset"."previewPath" AS "asset_previewPath", + "asset"."thumbnailPath" AS "asset_thumbnailPath", + "asset"."thumbhash" AS "asset_thumbhash", + "asset"."encodedVideoPath" AS "asset_encodedVideoPath", + "asset"."createdAt" AS "asset_createdAt", + "asset"."updatedAt" AS "asset_updatedAt", + "asset"."deletedAt" AS "asset_deletedAt", + "asset"."fileCreatedAt" AS "asset_fileCreatedAt", + "asset"."localDateTime" AS "asset_localDateTime", + "asset"."fileModifiedAt" AS "asset_fileModifiedAt", + "asset"."isFavorite" AS "asset_isFavorite", + "asset"."isArchived" AS "asset_isArchived", + "asset"."isExternal" AS "asset_isExternal", + "asset"."isOffline" AS "asset_isOffline", + "asset"."checksum" AS "asset_checksum", + "asset"."duration" AS "asset_duration", + "asset"."isVisible" AS "asset_isVisible", + "asset"."livePhotoVideoId" AS "asset_livePhotoVideoId", + "asset"."originalFileName" AS "asset_originalFileName", + "asset"."sidecarPath" AS "asset_sidecarPath", + "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", + "exifInfo"."assetId" AS "exifInfo_assetId", + "exifInfo"."description" AS "exifInfo_description", + "exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth", + "exifInfo"."exifImageHeight" AS "exifInfo_exifImageHeight", + "exifInfo"."fileSizeInByte" AS "exifInfo_fileSizeInByte", + "exifInfo"."orientation" AS "exifInfo_orientation", + "exifInfo"."dateTimeOriginal" AS "exifInfo_dateTimeOriginal", + "exifInfo"."modifyDate" AS "exifInfo_modifyDate", + "exifInfo"."timeZone" AS "exifInfo_timeZone", + "exifInfo"."latitude" AS "exifInfo_latitude", + "exifInfo"."longitude" AS "exifInfo_longitude", + "exifInfo"."projectionType" AS "exifInfo_projectionType", + "exifInfo"."city" AS "exifInfo_city", + "exifInfo"."livePhotoCID" AS "exifInfo_livePhotoCID", + "exifInfo"."autoStackId" AS "exifInfo_autoStackId", + "exifInfo"."state" AS "exifInfo_state", + "exifInfo"."country" AS "exifInfo_country", + "exifInfo"."make" AS "exifInfo_make", + "exifInfo"."model" AS "exifInfo_model", + "exifInfo"."lensModel" AS "exifInfo_lensModel", + "exifInfo"."fNumber" AS "exifInfo_fNumber", + "exifInfo"."focalLength" AS "exifInfo_focalLength", + "exifInfo"."iso" AS "exifInfo_iso", + "exifInfo"."exposureTime" AS "exifInfo_exposureTime", + "exifInfo"."profileDescription" AS "exifInfo_profileDescription", + "exifInfo"."colorspace" AS "exifInfo_colorspace", + "exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample", + "exifInfo"."fps" AS "exifInfo_fps", + "stack"."id" AS "stack_id", + "stack"."primaryAssetId" AS "stack_primaryAssetId", + "stackedAssets"."id" AS "stackedAssets_id", + "stackedAssets"."deviceAssetId" AS "stackedAssets_deviceAssetId", + "stackedAssets"."ownerId" AS "stackedAssets_ownerId", + "stackedAssets"."libraryId" AS "stackedAssets_libraryId", + "stackedAssets"."deviceId" AS "stackedAssets_deviceId", + "stackedAssets"."type" AS "stackedAssets_type", + "stackedAssets"."originalPath" AS "stackedAssets_originalPath", + "stackedAssets"."previewPath" AS "stackedAssets_previewPath", + "stackedAssets"."thumbnailPath" AS "stackedAssets_thumbnailPath", + "stackedAssets"."thumbhash" AS "stackedAssets_thumbhash", + "stackedAssets"."encodedVideoPath" AS "stackedAssets_encodedVideoPath", + "stackedAssets"."createdAt" AS "stackedAssets_createdAt", + "stackedAssets"."updatedAt" AS "stackedAssets_updatedAt", + "stackedAssets"."deletedAt" AS "stackedAssets_deletedAt", + "stackedAssets"."fileCreatedAt" AS "stackedAssets_fileCreatedAt", + "stackedAssets"."localDateTime" AS "stackedAssets_localDateTime", + "stackedAssets"."fileModifiedAt" AS "stackedAssets_fileModifiedAt", + "stackedAssets"."isFavorite" AS "stackedAssets_isFavorite", + "stackedAssets"."isArchived" AS "stackedAssets_isArchived", + "stackedAssets"."isExternal" AS "stackedAssets_isExternal", + "stackedAssets"."isOffline" AS "stackedAssets_isOffline", + "stackedAssets"."checksum" AS "stackedAssets_checksum", + "stackedAssets"."duration" AS "stackedAssets_duration", + "stackedAssets"."isVisible" AS "stackedAssets_isVisible", + "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId", + "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName", + "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath", + "stackedAssets"."stackId" AS "stackedAssets_stackId", + "stackedAssets"."duplicateId" AS "stackedAssets_duplicateId" +FROM + "assets" "asset" + LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id" + LEFT JOIN "asset_stack" "stack" ON "stack"."id" = "asset"."stackId" + LEFT JOIN "assets" "stackedAssets" ON "stackedAssets"."stackId" = "stack"."id" + AND ("stackedAssets"."deletedAt" IS NULL) +WHERE + ( + "asset"."isVisible" = true + AND "asset"."ownerId" IN ($1, $2) + AND "asset"."duplicateId" IS NOT NULL + ) + AND ("asset"."deletedAt" IS NULL) +ORDER BY + "asset"."duplicateId" ASC + -- AssetRepository.getAssetIdByCity WITH "cities" AS ( @@ -888,6 +1019,7 @@ SELECT "asset"."originalFileName" AS "asset_originalFileName", "asset"."sidecarPath" AS "asset_sidecarPath", "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", "exifInfo"."assetId" AS "exifInfo_assetId", "exifInfo"."description" AS "exifInfo_description", "exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth", @@ -945,7 +1077,8 @@ SELECT "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId", "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName", "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath", - "stackedAssets"."stackId" AS "stackedAssets_stackId" + "stackedAssets"."stackId" AS "stackedAssets_stackId", + "stackedAssets"."duplicateId" AS "stackedAssets_duplicateId" FROM "assets" "asset" LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id" @@ -993,6 +1126,7 @@ SELECT "asset"."originalFileName" AS "asset_originalFileName", "asset"."sidecarPath" AS "asset_sidecarPath", "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", "exifInfo"."assetId" AS "exifInfo_assetId", "exifInfo"."description" AS "exifInfo_description", "exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth", @@ -1050,7 +1184,8 @@ SELECT "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId", "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName", "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath", - "stackedAssets"."stackId" AS "stackedAssets_stackId" + "stackedAssets"."stackId" AS "stackedAssets_stackId", + "stackedAssets"."duplicateId" AS "stackedAssets_duplicateId" FROM "assets" "asset" LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id" @@ -1060,8 +1195,4 @@ FROM WHERE "asset"."isVisible" = true AND "asset"."ownerId" IN ($1) - AND ( - "stack"."primaryAssetId" = "asset"."id" - OR "asset"."stackId" IS NULL - ) AND "asset"."updatedAt" > $2 diff --git a/server/src/queries/library.repository.sql b/server/src/queries/library.repository.sql index 93a6fc97fb..bc20bf4bd3 100644 --- a/server/src/queries/library.repository.sql +++ b/server/src/queries/library.repository.sql @@ -9,17 +9,14 @@ FROM "LibraryEntity"."id" AS "LibraryEntity_id", "LibraryEntity"."name" AS "LibraryEntity_name", "LibraryEntity"."ownerId" AS "LibraryEntity_ownerId", - "LibraryEntity"."type" AS "LibraryEntity_type", "LibraryEntity"."importPaths" AS "LibraryEntity_importPaths", "LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns", "LibraryEntity"."createdAt" AS "LibraryEntity_createdAt", "LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt", "LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt", "LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt", - "LibraryEntity"."isVisible" AS "LibraryEntity_isVisible", "LibraryEntity__LibraryEntity_owner"."id" AS "LibraryEntity__LibraryEntity_owner_id", "LibraryEntity__LibraryEntity_owner"."name" AS "LibraryEntity__LibraryEntity_owner_name", - "LibraryEntity__LibraryEntity_owner"."avatarColor" AS "LibraryEntity__LibraryEntity_owner_avatarColor", "LibraryEntity__LibraryEntity_owner"."isAdmin" AS "LibraryEntity__LibraryEntity_owner_isAdmin", "LibraryEntity__LibraryEntity_owner"."email" AS "LibraryEntity__LibraryEntity_owner_email", "LibraryEntity__LibraryEntity_owner"."storageLabel" AS "LibraryEntity__LibraryEntity_owner_storageLabel", @@ -30,7 +27,6 @@ FROM "LibraryEntity__LibraryEntity_owner"."deletedAt" AS "LibraryEntity__LibraryEntity_owner_deletedAt", "LibraryEntity__LibraryEntity_owner"."status" AS "LibraryEntity__LibraryEntity_owner_status", "LibraryEntity__LibraryEntity_owner"."updatedAt" AS "LibraryEntity__LibraryEntity_owner_updatedAt", - "LibraryEntity__LibraryEntity_owner"."memoriesEnabled" AS "LibraryEntity__LibraryEntity_owner_memoriesEnabled", "LibraryEntity__LibraryEntity_owner"."quotaSizeInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaSizeInBytes", "LibraryEntity__LibraryEntity_owner"."quotaUsageInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaUsageInBytes" FROM @@ -48,140 +44,19 @@ ORDER BY LIMIT 1 --- LibraryRepository.existsByName -SELECT - 1 AS "row_exists" -FROM - ( - SELECT - 1 AS dummy_column - ) "dummy_table" -WHERE - EXISTS ( - SELECT - 1 - FROM - "libraries" "LibraryEntity" - WHERE - ((("LibraryEntity"."name" = $1))) - AND ("LibraryEntity"."deletedAt" IS NULL) - ) -LIMIT - 1 - --- LibraryRepository.getCountForUser -SELECT - COUNT(1) AS "cnt" -FROM - "libraries" "LibraryEntity" -WHERE - ((("LibraryEntity"."ownerId" = $1))) - AND ("LibraryEntity"."deletedAt" IS NULL) - --- LibraryRepository.getDefaultUploadLibrary -SELECT - "LibraryEntity"."id" AS "LibraryEntity_id", - "LibraryEntity"."name" AS "LibraryEntity_name", - "LibraryEntity"."ownerId" AS "LibraryEntity_ownerId", - "LibraryEntity"."type" AS "LibraryEntity_type", - "LibraryEntity"."importPaths" AS "LibraryEntity_importPaths", - "LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns", - "LibraryEntity"."createdAt" AS "LibraryEntity_createdAt", - "LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt", - "LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt", - "LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt", - "LibraryEntity"."isVisible" AS "LibraryEntity_isVisible" -FROM - "libraries" "LibraryEntity" -WHERE - ( - ( - ("LibraryEntity"."ownerId" = $1) - AND ("LibraryEntity"."type" = $2) - ) - ) - AND ("LibraryEntity"."deletedAt" IS NULL) -ORDER BY - "LibraryEntity"."createdAt" ASC -LIMIT - 1 - --- LibraryRepository.getUploadLibraryCount -SELECT - COUNT(1) AS "cnt" -FROM - "libraries" "LibraryEntity" -WHERE - ( - ( - ("LibraryEntity"."ownerId" = $1) - AND ("LibraryEntity"."type" = $2) - ) - ) - AND ("LibraryEntity"."deletedAt" IS NULL) - --- LibraryRepository.getAllByUserId -SELECT - "LibraryEntity"."id" AS "LibraryEntity_id", - "LibraryEntity"."name" AS "LibraryEntity_name", - "LibraryEntity"."ownerId" AS "LibraryEntity_ownerId", - "LibraryEntity"."type" AS "LibraryEntity_type", - "LibraryEntity"."importPaths" AS "LibraryEntity_importPaths", - "LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns", - "LibraryEntity"."createdAt" AS "LibraryEntity_createdAt", - "LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt", - "LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt", - "LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt", - "LibraryEntity"."isVisible" AS "LibraryEntity_isVisible", - "LibraryEntity__LibraryEntity_owner"."id" AS "LibraryEntity__LibraryEntity_owner_id", - "LibraryEntity__LibraryEntity_owner"."name" AS "LibraryEntity__LibraryEntity_owner_name", - "LibraryEntity__LibraryEntity_owner"."avatarColor" AS "LibraryEntity__LibraryEntity_owner_avatarColor", - "LibraryEntity__LibraryEntity_owner"."isAdmin" AS "LibraryEntity__LibraryEntity_owner_isAdmin", - "LibraryEntity__LibraryEntity_owner"."email" AS "LibraryEntity__LibraryEntity_owner_email", - "LibraryEntity__LibraryEntity_owner"."storageLabel" AS "LibraryEntity__LibraryEntity_owner_storageLabel", - "LibraryEntity__LibraryEntity_owner"."oauthId" AS "LibraryEntity__LibraryEntity_owner_oauthId", - "LibraryEntity__LibraryEntity_owner"."profileImagePath" AS "LibraryEntity__LibraryEntity_owner_profileImagePath", - "LibraryEntity__LibraryEntity_owner"."shouldChangePassword" AS "LibraryEntity__LibraryEntity_owner_shouldChangePassword", - "LibraryEntity__LibraryEntity_owner"."createdAt" AS "LibraryEntity__LibraryEntity_owner_createdAt", - "LibraryEntity__LibraryEntity_owner"."deletedAt" AS "LibraryEntity__LibraryEntity_owner_deletedAt", - "LibraryEntity__LibraryEntity_owner"."status" AS "LibraryEntity__LibraryEntity_owner_status", - "LibraryEntity__LibraryEntity_owner"."updatedAt" AS "LibraryEntity__LibraryEntity_owner_updatedAt", - "LibraryEntity__LibraryEntity_owner"."memoriesEnabled" AS "LibraryEntity__LibraryEntity_owner_memoriesEnabled", - "LibraryEntity__LibraryEntity_owner"."quotaSizeInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaSizeInBytes", - "LibraryEntity__LibraryEntity_owner"."quotaUsageInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaUsageInBytes" -FROM - "libraries" "LibraryEntity" - LEFT JOIN "users" "LibraryEntity__LibraryEntity_owner" ON "LibraryEntity__LibraryEntity_owner"."id" = "LibraryEntity"."ownerId" - AND ( - "LibraryEntity__LibraryEntity_owner"."deletedAt" IS NULL - ) -WHERE - ( - ( - ("LibraryEntity"."ownerId" = $1) - AND ("LibraryEntity"."isVisible" = $2) - ) - ) - AND ("LibraryEntity"."deletedAt" IS NULL) -ORDER BY - "LibraryEntity"."createdAt" ASC - -- LibraryRepository.getAll SELECT "LibraryEntity"."id" AS "LibraryEntity_id", "LibraryEntity"."name" AS "LibraryEntity_name", "LibraryEntity"."ownerId" AS "LibraryEntity_ownerId", - "LibraryEntity"."type" AS "LibraryEntity_type", "LibraryEntity"."importPaths" AS "LibraryEntity_importPaths", "LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns", "LibraryEntity"."createdAt" AS "LibraryEntity_createdAt", "LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt", "LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt", "LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt", - "LibraryEntity"."isVisible" AS "LibraryEntity_isVisible", "LibraryEntity__LibraryEntity_owner"."id" AS "LibraryEntity__LibraryEntity_owner_id", "LibraryEntity__LibraryEntity_owner"."name" AS "LibraryEntity__LibraryEntity_owner_name", - "LibraryEntity__LibraryEntity_owner"."avatarColor" AS "LibraryEntity__LibraryEntity_owner_avatarColor", "LibraryEntity__LibraryEntity_owner"."isAdmin" AS "LibraryEntity__LibraryEntity_owner_isAdmin", "LibraryEntity__LibraryEntity_owner"."email" AS "LibraryEntity__LibraryEntity_owner_email", "LibraryEntity__LibraryEntity_owner"."storageLabel" AS "LibraryEntity__LibraryEntity_owner_storageLabel", @@ -192,7 +67,6 @@ SELECT "LibraryEntity__LibraryEntity_owner"."deletedAt" AS "LibraryEntity__LibraryEntity_owner_deletedAt", "LibraryEntity__LibraryEntity_owner"."status" AS "LibraryEntity__LibraryEntity_owner_status", "LibraryEntity__LibraryEntity_owner"."updatedAt" AS "LibraryEntity__LibraryEntity_owner_updatedAt", - "LibraryEntity__LibraryEntity_owner"."memoriesEnabled" AS "LibraryEntity__LibraryEntity_owner_memoriesEnabled", "LibraryEntity__LibraryEntity_owner"."quotaSizeInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaSizeInBytes", "LibraryEntity__LibraryEntity_owner"."quotaUsageInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaUsageInBytes" FROM @@ -211,17 +85,14 @@ SELECT "LibraryEntity"."id" AS "LibraryEntity_id", "LibraryEntity"."name" AS "LibraryEntity_name", "LibraryEntity"."ownerId" AS "LibraryEntity_ownerId", - "LibraryEntity"."type" AS "LibraryEntity_type", "LibraryEntity"."importPaths" AS "LibraryEntity_importPaths", "LibraryEntity"."exclusionPatterns" AS "LibraryEntity_exclusionPatterns", "LibraryEntity"."createdAt" AS "LibraryEntity_createdAt", "LibraryEntity"."updatedAt" AS "LibraryEntity_updatedAt", "LibraryEntity"."deletedAt" AS "LibraryEntity_deletedAt", "LibraryEntity"."refreshedAt" AS "LibraryEntity_refreshedAt", - "LibraryEntity"."isVisible" AS "LibraryEntity_isVisible", "LibraryEntity__LibraryEntity_owner"."id" AS "LibraryEntity__LibraryEntity_owner_id", "LibraryEntity__LibraryEntity_owner"."name" AS "LibraryEntity__LibraryEntity_owner_name", - "LibraryEntity__LibraryEntity_owner"."avatarColor" AS "LibraryEntity__LibraryEntity_owner_avatarColor", "LibraryEntity__LibraryEntity_owner"."isAdmin" AS "LibraryEntity__LibraryEntity_owner_isAdmin", "LibraryEntity__LibraryEntity_owner"."email" AS "LibraryEntity__LibraryEntity_owner_email", "LibraryEntity__LibraryEntity_owner"."storageLabel" AS "LibraryEntity__LibraryEntity_owner_storageLabel", @@ -232,17 +103,13 @@ SELECT "LibraryEntity__LibraryEntity_owner"."deletedAt" AS "LibraryEntity__LibraryEntity_owner_deletedAt", "LibraryEntity__LibraryEntity_owner"."status" AS "LibraryEntity__LibraryEntity_owner_status", "LibraryEntity__LibraryEntity_owner"."updatedAt" AS "LibraryEntity__LibraryEntity_owner_updatedAt", - "LibraryEntity__LibraryEntity_owner"."memoriesEnabled" AS "LibraryEntity__LibraryEntity_owner_memoriesEnabled", "LibraryEntity__LibraryEntity_owner"."quotaSizeInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaSizeInBytes", "LibraryEntity__LibraryEntity_owner"."quotaUsageInBytes" AS "LibraryEntity__LibraryEntity_owner_quotaUsageInBytes" FROM "libraries" "LibraryEntity" LEFT JOIN "users" "LibraryEntity__LibraryEntity_owner" ON "LibraryEntity__LibraryEntity_owner"."id" = "LibraryEntity"."ownerId" WHERE - ( - ("LibraryEntity"."isVisible" = $1) - AND (NOT ("LibraryEntity"."deletedAt" IS NULL)) - ) + ((NOT ("LibraryEntity"."deletedAt" IS NULL))) ORDER BY "LibraryEntity"."createdAt" ASC @@ -251,14 +118,12 @@ SELECT "libraries"."id" AS "libraries_id", "libraries"."name" AS "libraries_name", "libraries"."ownerId" AS "libraries_ownerId", - "libraries"."type" AS "libraries_type", "libraries"."importPaths" AS "libraries_importPaths", "libraries"."exclusionPatterns" AS "libraries_exclusionPatterns", "libraries"."createdAt" AS "libraries_createdAt", "libraries"."updatedAt" AS "libraries_updatedAt", "libraries"."deletedAt" AS "libraries_deletedAt", "libraries"."refreshedAt" AS "libraries_refreshedAt", - "libraries"."isVisible" AS "libraries_isVisible", COUNT("assets"."id") FILTER ( WHERE "assets"."type" = 'IMAGE' @@ -281,20 +146,6 @@ WHERE GROUP BY "libraries"."id" --- LibraryRepository.getOnlineAssetPaths -SELECT - "assets"."originalPath" AS "assets_originalPath" -FROM - "libraries" "library" - INNER JOIN "assets" "assets" ON "assets"."libraryId" = "library"."id" - AND ("assets"."deletedAt" IS NULL) -WHERE - ( - "library"."id" = $1 - AND "assets"."isOffline" = false - ) - AND ("library"."deletedAt" IS NULL) - -- LibraryRepository.getAssetIds SELECT "assets"."id" AS "assets_id" diff --git a/server/src/queries/memory.repository.sql b/server/src/queries/memory.repository.sql index aa3df240c1..691734e224 100644 --- a/server/src/queries/memory.repository.sql +++ b/server/src/queries/memory.repository.sql @@ -9,6 +9,12 @@ WHERE "memories_assets"."memoriesId" = $1 AND "memories_assets"."assetsId" IN ($2) +-- MemoryRepository.addAssetIds +INSERT INTO + "memories_assets_assets" ("memoriesId", "assetsId") +VALUES + ($1, $2) + -- MemoryRepository.removeAssetIds DELETE FROM "memories_assets_assets" WHERE diff --git a/server/src/queries/person.repository.sql b/server/src/queries/person.repository.sql index 894ff2e63f..9b82586431 100644 --- a/server/src/queries/person.repository.sql +++ b/server/src/queries/person.repository.sql @@ -177,7 +177,8 @@ FROM "AssetFaceEntity__AssetFaceEntity_asset"."livePhotoVideoId" AS "AssetFaceEntity__AssetFaceEntity_asset_livePhotoVideoId", "AssetFaceEntity__AssetFaceEntity_asset"."originalFileName" AS "AssetFaceEntity__AssetFaceEntity_asset_originalFileName", "AssetFaceEntity__AssetFaceEntity_asset"."sidecarPath" AS "AssetFaceEntity__AssetFaceEntity_asset_sidecarPath", - "AssetFaceEntity__AssetFaceEntity_asset"."stackId" AS "AssetFaceEntity__AssetFaceEntity_asset_stackId" + "AssetFaceEntity__AssetFaceEntity_asset"."stackId" AS "AssetFaceEntity__AssetFaceEntity_asset_stackId", + "AssetFaceEntity__AssetFaceEntity_asset"."duplicateId" AS "AssetFaceEntity__AssetFaceEntity_asset_duplicateId" FROM "asset_faces" "AssetFaceEntity" LEFT JOIN "person" "AssetFaceEntity__AssetFaceEntity_person" ON "AssetFaceEntity__AssetFaceEntity_person"."id" = "AssetFaceEntity"."personId" @@ -276,6 +277,7 @@ FROM "AssetEntity"."originalFileName" AS "AssetEntity_originalFileName", "AssetEntity"."sidecarPath" AS "AssetEntity_sidecarPath", "AssetEntity"."stackId" AS "AssetEntity_stackId", + "AssetEntity"."duplicateId" AS "AssetEntity_duplicateId", "AssetEntity__AssetEntity_faces"."id" AS "AssetEntity__AssetEntity_faces_id", "AssetEntity__AssetEntity_faces"."assetId" AS "AssetEntity__AssetEntity_faces_assetId", "AssetEntity__AssetEntity_faces"."personId" AS "AssetEntity__AssetEntity_faces_personId", @@ -406,7 +408,8 @@ SELECT "AssetFaceEntity__AssetFaceEntity_asset"."livePhotoVideoId" AS "AssetFaceEntity__AssetFaceEntity_asset_livePhotoVideoId", "AssetFaceEntity__AssetFaceEntity_asset"."originalFileName" AS "AssetFaceEntity__AssetFaceEntity_asset_originalFileName", "AssetFaceEntity__AssetFaceEntity_asset"."sidecarPath" AS "AssetFaceEntity__AssetFaceEntity_asset_sidecarPath", - "AssetFaceEntity__AssetFaceEntity_asset"."stackId" AS "AssetFaceEntity__AssetFaceEntity_asset_stackId" + "AssetFaceEntity__AssetFaceEntity_asset"."stackId" AS "AssetFaceEntity__AssetFaceEntity_asset_stackId", + "AssetFaceEntity__AssetFaceEntity_asset"."duplicateId" AS "AssetFaceEntity__AssetFaceEntity_asset_duplicateId" FROM "asset_faces" "AssetFaceEntity" LEFT JOIN "assets" "AssetFaceEntity__AssetFaceEntity_asset" ON "AssetFaceEntity__AssetFaceEntity_asset"."id" = "AssetFaceEntity"."assetId" diff --git a/server/src/queries/search.repository.sql b/server/src/queries/search.repository.sql index bfc52f488f..7ee74618fc 100644 --- a/server/src/queries/search.repository.sql +++ b/server/src/queries/search.repository.sql @@ -35,6 +35,7 @@ FROM "asset"."originalFileName" AS "asset_originalFileName", "asset"."sidecarPath" AS "asset_sidecarPath", "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", "stack"."id" AS "stack_id", "stack"."primaryAssetId" AS "stack_primaryAssetId", "stackedAssets"."id" AS "stackedAssets_id", @@ -64,7 +65,8 @@ FROM "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId", "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName", "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath", - "stackedAssets"."stackId" AS "stackedAssets_stackId" + "stackedAssets"."stackId" AS "stackedAssets_stackId", + "stackedAssets"."duplicateId" AS "stackedAssets_duplicateId" FROM "assets" "asset" LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id" @@ -129,6 +131,7 @@ SELECT "asset"."originalFileName" AS "asset_originalFileName", "asset"."sidecarPath" AS "asset_sidecarPath", "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", "stack"."id" AS "stack_id", "stack"."primaryAssetId" AS "stack_primaryAssetId", "stackedAssets"."id" AS "stackedAssets_id", @@ -158,7 +161,8 @@ SELECT "stackedAssets"."livePhotoVideoId" AS "stackedAssets_livePhotoVideoId", "stackedAssets"."originalFileName" AS "stackedAssets_originalFileName", "stackedAssets"."sidecarPath" AS "stackedAssets_sidecarPath", - "stackedAssets"."stackId" AS "stackedAssets_stackId" + "stackedAssets"."stackId" AS "stackedAssets_stackId", + "stackedAssets"."duplicateId" AS "stackedAssets_duplicateId" FROM "assets" "asset" LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "asset"."id" @@ -185,6 +189,35 @@ LIMIT 101 COMMIT +-- SearchRepository.searchDuplicates +WITH + "cte" AS ( + SELECT + "asset"."duplicateId" AS "duplicateId", + "search"."assetId" AS "assetId", + "search"."embedding" <= > $1 AS "distance" + FROM + "assets" "asset" + INNER JOIN "smart_search" "search" ON "search"."assetId" = "asset"."id" + WHERE + ( + "asset"."ownerId" IN ($2) + AND "asset"."id" != $3 + AND "asset"."isVisible" = $4 + ) + AND ("asset"."deletedAt" IS NULL) + ORDER BY + "search"."embedding" <= > $1 ASC + LIMIT + 64 + ) +SELECT + res.* +FROM + "cte" "res" +WHERE + res.distance <= $5 + -- SearchRepository.searchFaces START TRANSACTION SET @@ -338,6 +371,7 @@ SELECT "asset"."originalFileName" AS "asset_originalFileName", "asset"."sidecarPath" AS "asset_sidecarPath", "asset"."stackId" AS "asset_stackId", + "asset"."duplicateId" AS "asset_duplicateId", "exif"."assetId" AS "exif_assetId", "exif"."description" AS "exif_description", "exif"."exifImageWidth" AS "exif_exifImageWidth", diff --git a/server/src/queries/session.repository.sql b/server/src/queries/session.repository.sql index 87c1b55c9b..b26b291e8b 100644 --- a/server/src/queries/session.repository.sql +++ b/server/src/queries/session.repository.sql @@ -27,7 +27,6 @@ FROM "SessionEntity"."deviceOS" AS "SessionEntity_deviceOS", "SessionEntity__SessionEntity_user"."id" AS "SessionEntity__SessionEntity_user_id", "SessionEntity__SessionEntity_user"."name" AS "SessionEntity__SessionEntity_user_name", - "SessionEntity__SessionEntity_user"."avatarColor" AS "SessionEntity__SessionEntity_user_avatarColor", "SessionEntity__SessionEntity_user"."isAdmin" AS "SessionEntity__SessionEntity_user_isAdmin", "SessionEntity__SessionEntity_user"."email" AS "SessionEntity__SessionEntity_user_email", "SessionEntity__SessionEntity_user"."storageLabel" AS "SessionEntity__SessionEntity_user_storageLabel", @@ -38,7 +37,6 @@ FROM "SessionEntity__SessionEntity_user"."deletedAt" AS "SessionEntity__SessionEntity_user_deletedAt", "SessionEntity__SessionEntity_user"."status" AS "SessionEntity__SessionEntity_user_status", "SessionEntity__SessionEntity_user"."updatedAt" AS "SessionEntity__SessionEntity_user_updatedAt", - "SessionEntity__SessionEntity_user"."memoriesEnabled" AS "SessionEntity__SessionEntity_user_memoriesEnabled", "SessionEntity__SessionEntity_user"."quotaSizeInBytes" AS "SessionEntity__SessionEntity_user_quotaSizeInBytes", "SessionEntity__SessionEntity_user"."quotaUsageInBytes" AS "SessionEntity__SessionEntity_user_quotaUsageInBytes" FROM diff --git a/server/src/queries/shared.link.repository.sql b/server/src/queries/shared.link.repository.sql index ae416696ee..09f0cf7cb5 100644 --- a/server/src/queries/shared.link.repository.sql +++ b/server/src/queries/shared.link.repository.sql @@ -49,6 +49,7 @@ FROM "SharedLinkEntity__SharedLinkEntity_assets"."originalFileName" AS "SharedLinkEntity__SharedLinkEntity_assets_originalFileName", "SharedLinkEntity__SharedLinkEntity_assets"."sidecarPath" AS "SharedLinkEntity__SharedLinkEntity_assets_sidecarPath", "SharedLinkEntity__SharedLinkEntity_assets"."stackId" AS "SharedLinkEntity__SharedLinkEntity_assets_stackId", + "SharedLinkEntity__SharedLinkEntity_assets"."duplicateId" AS "SharedLinkEntity__SharedLinkEntity_assets_duplicateId", "9b1d35b344d838023994a3233afd6ffe098be6d8"."assetId" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_assetId", "9b1d35b344d838023994a3233afd6ffe098be6d8"."description" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_description", "9b1d35b344d838023994a3233afd6ffe098be6d8"."exifImageWidth" AS "9b1d35b344d838023994a3233afd6ffe098be6d8_exifImageWidth", @@ -115,6 +116,7 @@ FROM "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."originalFileName" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_originalFileName", "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."sidecarPath" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_sidecarPath", "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."stackId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_stackId", + "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6"."duplicateId" AS "4a35f463ae8c5544ede95c4b6d9ce8c686b6bfe6_duplicateId", "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."assetId" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_assetId", "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."description" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_description", "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."exifImageWidth" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_exifImageWidth", @@ -145,7 +147,6 @@ FROM "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f"."fps" AS "d9f2f4dd8920bad1d6907cdb1d699732daff3c2f_fps", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."id" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_id", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."name" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_name", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."avatarColor" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_avatarColor", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."isAdmin" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_isAdmin", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."email" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_email", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."storageLabel" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_storageLabel", @@ -156,7 +157,6 @@ FROM "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."deletedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_deletedAt", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."status" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_status", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."updatedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_updatedAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."memoriesEnabled" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_memoriesEnabled", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaSizeInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaSizeInBytes", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaUsageInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaUsageInBytes" FROM @@ -237,6 +237,7 @@ SELECT "SharedLinkEntity__SharedLinkEntity_assets"."originalFileName" AS "SharedLinkEntity__SharedLinkEntity_assets_originalFileName", "SharedLinkEntity__SharedLinkEntity_assets"."sidecarPath" AS "SharedLinkEntity__SharedLinkEntity_assets_sidecarPath", "SharedLinkEntity__SharedLinkEntity_assets"."stackId" AS "SharedLinkEntity__SharedLinkEntity_assets_stackId", + "SharedLinkEntity__SharedLinkEntity_assets"."duplicateId" AS "SharedLinkEntity__SharedLinkEntity_assets_duplicateId", "SharedLinkEntity__SharedLinkEntity_album"."id" AS "SharedLinkEntity__SharedLinkEntity_album_id", "SharedLinkEntity__SharedLinkEntity_album"."ownerId" AS "SharedLinkEntity__SharedLinkEntity_album_ownerId", "SharedLinkEntity__SharedLinkEntity_album"."albumName" AS "SharedLinkEntity__SharedLinkEntity_album_albumName", @@ -249,7 +250,6 @@ SELECT "SharedLinkEntity__SharedLinkEntity_album"."order" AS "SharedLinkEntity__SharedLinkEntity_album_order", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."id" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_id", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."name" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_name", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."avatarColor" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_avatarColor", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."isAdmin" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_isAdmin", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."email" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_email", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."storageLabel" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_storageLabel", @@ -260,7 +260,6 @@ SELECT "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."deletedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_deletedAt", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."status" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_status", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."updatedAt" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_updatedAt", - "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."memoriesEnabled" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_memoriesEnabled", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaSizeInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaSizeInBytes", "6d7fd45329a05fd86b3dbcacde87fe76e33a422d"."quotaUsageInBytes" AS "6d7fd45329a05fd86b3dbcacde87fe76e33a422d_quotaUsageInBytes" FROM @@ -303,7 +302,6 @@ FROM "SharedLinkEntity"."albumId" AS "SharedLinkEntity_albumId", "SharedLinkEntity__SharedLinkEntity_user"."id" AS "SharedLinkEntity__SharedLinkEntity_user_id", "SharedLinkEntity__SharedLinkEntity_user"."name" AS "SharedLinkEntity__SharedLinkEntity_user_name", - "SharedLinkEntity__SharedLinkEntity_user"."avatarColor" AS "SharedLinkEntity__SharedLinkEntity_user_avatarColor", "SharedLinkEntity__SharedLinkEntity_user"."isAdmin" AS "SharedLinkEntity__SharedLinkEntity_user_isAdmin", "SharedLinkEntity__SharedLinkEntity_user"."email" AS "SharedLinkEntity__SharedLinkEntity_user_email", "SharedLinkEntity__SharedLinkEntity_user"."storageLabel" AS "SharedLinkEntity__SharedLinkEntity_user_storageLabel", @@ -314,7 +312,6 @@ FROM "SharedLinkEntity__SharedLinkEntity_user"."deletedAt" AS "SharedLinkEntity__SharedLinkEntity_user_deletedAt", "SharedLinkEntity__SharedLinkEntity_user"."status" AS "SharedLinkEntity__SharedLinkEntity_user_status", "SharedLinkEntity__SharedLinkEntity_user"."updatedAt" AS "SharedLinkEntity__SharedLinkEntity_user_updatedAt", - "SharedLinkEntity__SharedLinkEntity_user"."memoriesEnabled" AS "SharedLinkEntity__SharedLinkEntity_user_memoriesEnabled", "SharedLinkEntity__SharedLinkEntity_user"."quotaSizeInBytes" AS "SharedLinkEntity__SharedLinkEntity_user_quotaSizeInBytes", "SharedLinkEntity__SharedLinkEntity_user"."quotaUsageInBytes" AS "SharedLinkEntity__SharedLinkEntity_user_quotaUsageInBytes" FROM diff --git a/server/src/queries/system.config.repository.sql b/server/src/queries/system.config.repository.sql deleted file mode 100644 index 276cab20fe..0000000000 --- a/server/src/queries/system.config.repository.sql +++ /dev/null @@ -1,13 +0,0 @@ --- NOTE: This file is auto generated by ./sql-generator - --- SystemConfigRepository.load -SELECT - "SystemConfigEntity"."key" AS "SystemConfigEntity_key", - "SystemConfigEntity"."value" AS "SystemConfigEntity_value" -FROM - "system_config" "SystemConfigEntity" - --- SystemConfigRepository.deleteKeys -DELETE FROM "system_config" -WHERE - "key" IN ($1, $2, $3, $4, $5, $6, $7, $8, $9) diff --git a/server/src/queries/user.repository.sql b/server/src/queries/user.repository.sql index 30464da786..64d4e12643 100644 --- a/server/src/queries/user.repository.sql +++ b/server/src/queries/user.repository.sql @@ -4,7 +4,6 @@ SELECT "UserEntity"."id" AS "UserEntity_id", "UserEntity"."name" AS "UserEntity_name", - "UserEntity"."avatarColor" AS "UserEntity_avatarColor", "UserEntity"."isAdmin" AS "UserEntity_isAdmin", "UserEntity"."email" AS "UserEntity_email", "UserEntity"."storageLabel" AS "UserEntity_storageLabel", @@ -15,7 +14,6 @@ SELECT "UserEntity"."deletedAt" AS "UserEntity_deletedAt", "UserEntity"."status" AS "UserEntity_status", "UserEntity"."updatedAt" AS "UserEntity_updatedAt", - "UserEntity"."memoriesEnabled" AS "UserEntity_memoriesEnabled", "UserEntity"."quotaSizeInBytes" AS "UserEntity_quotaSizeInBytes", "UserEntity"."quotaUsageInBytes" AS "UserEntity_quotaUsageInBytes" FROM @@ -51,7 +49,6 @@ LIMIT SELECT "user"."id" AS "user_id", "user"."name" AS "user_name", - "user"."avatarColor" AS "user_avatarColor", "user"."isAdmin" AS "user_isAdmin", "user"."email" AS "user_email", "user"."storageLabel" AS "user_storageLabel", @@ -62,7 +59,6 @@ SELECT "user"."deletedAt" AS "user_deletedAt", "user"."status" AS "user_status", "user"."updatedAt" AS "user_updatedAt", - "user"."memoriesEnabled" AS "user_memoriesEnabled", "user"."quotaSizeInBytes" AS "user_quotaSizeInBytes", "user"."quotaUsageInBytes" AS "user_quotaUsageInBytes" FROM @@ -75,7 +71,6 @@ WHERE SELECT "UserEntity"."id" AS "UserEntity_id", "UserEntity"."name" AS "UserEntity_name", - "UserEntity"."avatarColor" AS "UserEntity_avatarColor", "UserEntity"."isAdmin" AS "UserEntity_isAdmin", "UserEntity"."email" AS "UserEntity_email", "UserEntity"."storageLabel" AS "UserEntity_storageLabel", @@ -86,7 +81,6 @@ SELECT "UserEntity"."deletedAt" AS "UserEntity_deletedAt", "UserEntity"."status" AS "UserEntity_status", "UserEntity"."updatedAt" AS "UserEntity_updatedAt", - "UserEntity"."memoriesEnabled" AS "UserEntity_memoriesEnabled", "UserEntity"."quotaSizeInBytes" AS "UserEntity_quotaSizeInBytes", "UserEntity"."quotaUsageInBytes" AS "UserEntity_quotaUsageInBytes" FROM @@ -101,7 +95,6 @@ LIMIT SELECT "UserEntity"."id" AS "UserEntity_id", "UserEntity"."name" AS "UserEntity_name", - "UserEntity"."avatarColor" AS "UserEntity_avatarColor", "UserEntity"."isAdmin" AS "UserEntity_isAdmin", "UserEntity"."email" AS "UserEntity_email", "UserEntity"."storageLabel" AS "UserEntity_storageLabel", @@ -112,7 +105,6 @@ SELECT "UserEntity"."deletedAt" AS "UserEntity_deletedAt", "UserEntity"."status" AS "UserEntity_status", "UserEntity"."updatedAt" AS "UserEntity_updatedAt", - "UserEntity"."memoriesEnabled" AS "UserEntity_memoriesEnabled", "UserEntity"."quotaSizeInBytes" AS "UserEntity_quotaSizeInBytes", "UserEntity"."quotaUsageInBytes" AS "UserEntity_quotaUsageInBytes" FROM @@ -167,12 +159,10 @@ SET COALESCE(SUM(exif."fileSizeInByte"), 0) FROM "assets" "assets" - LEFT JOIN "libraries" "library" ON "library"."id" = "assets"."libraryId" - AND ("library"."deletedAt" IS NULL) LEFT JOIN "exif" "exif" ON "exif"."assetId" = "assets"."id" WHERE "assets"."ownerId" = users.id - AND "library"."type" = 'UPLOAD' + AND "assets"."libraryId" IS NULL ), "updatedAt" = CURRENT_TIMESTAMP WHERE diff --git a/server/src/repositories/access.repository.ts b/server/src/repositories/access.repository.ts index 992f8f143f..9dd294cc21 100644 --- a/server/src/repositories/access.repository.ts +++ b/server/src/repositories/access.repository.ts @@ -20,7 +20,6 @@ type IActivityAccess = IAccessRepository['activity']; type IAlbumAccess = IAccessRepository['album']; type IAssetAccess = IAccessRepository['asset']; type IAuthDeviceAccess = IAccessRepository['authDevice']; -type ILibraryAccess = IAccessRepository['library']; type ITimelineAccess = IAccessRepository['timeline']; type IMemoryAccess = IAccessRepository['memory']; type IPersonAccess = IAccessRepository['person']; @@ -241,6 +240,7 @@ class AssetAccess implements IAssetAccess { .innerJoin('sharedBy.assets', 'asset') .select('asset.id', 'assetId') .where('partner.sharedWithId = :userId', { userId }) + .andWhere('asset.isArchived = false') .andWhere('asset.id IN (:...assetIds)', { assetIds: [...assetIds] }) .getRawMany() .then((rows) => new Set(rows.map((row) => row.assetId))); @@ -313,28 +313,6 @@ class AuthDeviceAccess implements IAuthDeviceAccess { } } -class LibraryAccess implements ILibraryAccess { - constructor(private libraryRepository: Repository) {} - - @GenerateSql({ params: [DummyValue.UUID, DummyValue.UUID_SET] }) - @ChunkedSet({ paramIndex: 1 }) - async checkOwnerAccess(userId: string, libraryIds: Set): Promise> { - if (libraryIds.size === 0) { - return new Set(); - } - - return this.libraryRepository - .find({ - select: { id: true }, - where: { - id: In([...libraryIds]), - ownerId: userId, - }, - }) - .then((libraries) => new Set(libraries.map((library) => library.id))); - } -} - class TimelineAccess implements ITimelineAccess { constructor(private partnerRepository: Repository) {} @@ -447,7 +425,6 @@ export class AccessRepository implements IAccessRepository { album: IAlbumAccess; asset: IAssetAccess; authDevice: IAuthDeviceAccess; - library: ILibraryAccess; memory: IMemoryAccess; person: IPersonAccess; partner: IPartnerAccess; @@ -469,7 +446,6 @@ export class AccessRepository implements IAccessRepository { this.album = new AlbumAccess(albumRepository, sharedLinkRepository); this.asset = new AssetAccess(albumRepository, assetRepository, partnerRepository, sharedLinkRepository); this.authDevice = new AuthDeviceAccess(sessionRepository); - this.library = new LibraryAccess(libraryRepository); this.memory = new MemoryAccess(memoryRepository); this.person = new PersonAccess(assetFaceRepository, personRepository); this.partner = new PartnerAccess(partnerRepository); diff --git a/server/src/repositories/asset-v1.repository.ts b/server/src/repositories/asset-v1.repository.ts index 4e346d5fdf..1278c17e95 100644 --- a/server/src/repositories/asset-v1.repository.ts +++ b/server/src/repositories/asset-v1.repository.ts @@ -1,9 +1,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { AssetSearchDto, CheckExistingAssetsDto } from 'src/dtos/asset-v1.dto'; import { AssetEntity } from 'src/entities/asset.entity'; -import { AssetCheck, AssetOwnerCheck, IAssetRepositoryV1 } from 'src/interfaces/asset-v1.interface'; -import { OptionalBetween } from 'src/utils/database'; +import { AssetCheck, IAssetRepositoryV1 } from 'src/interfaces/asset-v1.interface'; import { In } from 'typeorm/find-options/operator/In.js'; import { Repository } from 'typeorm/repository/Repository.js'; @@ -11,36 +9,6 @@ import { Repository } from 'typeorm/repository/Repository.js'; export class AssetRepositoryV1 implements IAssetRepositoryV1 { constructor(@InjectRepository(AssetEntity) private assetRepository: Repository) {} - /** - * Retrieves all assets by user ID. - * - * @param ownerId - The ID of the owner. - * @param dto - The AssetSearchDto object containing search criteria. - * @returns A Promise that resolves to an array of AssetEntity objects. - */ - getAllByUserId(ownerId: string, dto: AssetSearchDto): Promise { - return this.assetRepository.find({ - where: { - ownerId, - isVisible: true, - isFavorite: dto.isFavorite, - isArchived: dto.isArchived, - updatedAt: OptionalBetween(dto.updatedAfter, dto.updatedBefore), - }, - relations: { - exifInfo: true, - tags: true, - stack: { assets: true }, - }, - skip: dto.skip || 0, - take: dto.take, - order: { - fileCreatedAt: 'DESC', - }, - withDeleted: true, - }); - } - get(id: string): Promise { return this.assetRepository.findOne({ where: { id }, @@ -73,30 +41,4 @@ export class AssetRepositoryV1 implements IAssetRepositoryV1 { withDeleted: true, }); } - - async getExistingAssets(ownerId: string, checkDuplicateAssetDto: CheckExistingAssetsDto): Promise { - const assets = await this.assetRepository.find({ - select: { deviceAssetId: true }, - where: { - deviceAssetId: In(checkDuplicateAssetDto.deviceAssetIds), - deviceId: checkDuplicateAssetDto.deviceId, - ownerId, - }, - withDeleted: true, - }); - return assets.map((asset) => asset.deviceAssetId); - } - - getByOriginalPath(originalPath: string): Promise { - return this.assetRepository.findOne({ - select: { - id: true, - ownerId: true, - checksum: true, - }, - where: { - originalPath, - }, - }); - } } diff --git a/server/src/repositories/asset.repository.ts b/server/src/repositories/asset.repository.ts index 7c359aa895..356f78fee8 100644 --- a/server/src/repositories/asset.repository.ts +++ b/server/src/repositories/asset.repository.ts @@ -5,7 +5,6 @@ import { AlbumEntity, AssetOrder } from 'src/entities/album.entity'; import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity'; import { AssetEntity, AssetType } from 'src/entities/asset.entity'; import { ExifEntity } from 'src/entities/exif.entity'; -import { LibraryType } from 'src/entities/library.entity'; import { PartnerEntity } from 'src/entities/partner.entity'; import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { @@ -18,6 +17,7 @@ import { AssetStats, AssetStatsOptions, AssetUpdateAllOptions, + AssetUpdateDuplicateOptions, AssetUpdateOptions, IAssetRepository, LivePhotoSearchOptions, @@ -73,7 +73,7 @@ export class AssetRepository implements IAssetRepository { await this.exifRepository.upsert(exif, { conflictPaths: ['assetId'] }); } - async upsertJobStatus(jobStatus: Partial): Promise { + async upsertJobStatus(...jobStatus: Partial[]): Promise { await this.jobStatusRepository.upsert(jobStatus, { conflictPaths: ['assetId'] }); } @@ -157,6 +157,18 @@ export class AssetRepository implements IAssetRepository { }); } + getByDeviceIds(ownerId: string, deviceId: string, deviceAssetIds: string[]): Promise { + return this.repository.find({ + select: { deviceAssetId: true }, + where: { + deviceAssetId: In(deviceAssetIds), + deviceId, + ownerId, + }, + withDeleted: true, + }); + } + getByUserId( pagination: PaginationOptions, userId: string, @@ -257,6 +269,21 @@ export class AssetRepository implements IAssetRepository { await this.repository.update({ id: In(ids) }, options); } + @GenerateSql({ + params: [{ targetDuplicateId: DummyValue.UUID, duplicateIds: [DummyValue.UUID], assetIds: [DummyValue.UUID] }], + }) + async updateDuplicates(options: AssetUpdateDuplicateOptions): Promise { + await this.repository + .createQueryBuilder() + .update() + .set({ duplicateId: options.targetDuplicateId }) + .where({ + duplicateId: In(options.duplicateIds), + }) + .orWhere({ id: In(options.assetIds) }) + .execute(); + } + @Chunked() async softDeleteAll(ids: string[]): Promise { await this.repository.softDelete({ id: In(ids) }); @@ -276,8 +303,28 @@ export class AssetRepository implements IAssetRepository { } @GenerateSql({ params: [DummyValue.UUID, DummyValue.BUFFER] }) - getByChecksum(libraryId: string, checksum: Buffer): Promise { - return this.repository.findOne({ where: { libraryId, checksum } }); + getByChecksum(libraryId: string | null, checksum: Buffer): Promise { + return this.repository.findOne({ + where: { + libraryId: libraryId || IsNull(), + checksum, + }, + }); + } + + @GenerateSql({ params: [DummyValue.UUID, DummyValue.BUFFER] }) + getByChecksums(ownerId: string, checksums: Buffer[]): Promise { + return this.repository.find({ + select: { + id: true, + checksum: true, + }, + where: { + ownerId, + checksum: In(checksums), + }, + withDeleted: true, + }); } @GenerateSql({ params: [DummyValue.UUID, DummyValue.BUFFER] }) @@ -287,9 +334,7 @@ export class AssetRepository implements IAssetRepository { where: { ownerId, checksum, - library: { - type: LibraryType.UPLOAD, - }, + library: IsNull(), }, withDeleted: true, }); @@ -375,6 +420,18 @@ export class AssetRepository implements IAssetRepository { break; } + case WithoutProperty.DUPLICATE: { + where = { + previewPath: Not(IsNull()), + isVisible: true, + smartSearch: true, + jobStatus: { + duplicatesDetectedAt: IsNull(), + }, + }; + break; + } + case WithoutProperty.OBJECT_TAGS: { relations = { smartInfo: true, @@ -490,9 +547,24 @@ export class AssetRepository implements IAssetRepository { }); } - async getMapMarkers(ownerIds: string[], options: MapMarkerSearchOptions = {}): Promise { + async getMapMarkers( + ownerIds: string[], + albumIds: string[], + options: MapMarkerSearchOptions = {}, + ): Promise { const { isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore } = options; + const where = { + isVisible: true, + isArchived, + exifInfo: { + latitude: Not(IsNull()), + longitude: Not(IsNull()), + }, + isFavorite, + fileCreatedAt: OptionalBetween(fileCreatedAfter, fileCreatedBefore), + }; + const assets = await this.repository.find({ select: { id: true, @@ -504,17 +576,10 @@ export class AssetRepository implements IAssetRepository { longitude: true, }, }, - where: { - ownerId: In([...ownerIds]), - isVisible: true, - isArchived, - exifInfo: { - latitude: Not(IsNull()), - longitude: Not(IsNull()), - }, - isFavorite, - fileCreatedAt: OptionalBetween(fileCreatedAfter, fileCreatedBefore), - }, + where: [ + { ...where, ownerId: In([...ownerIds]) }, + { ...where, albums: { id: In([...albumIds]) } }, + ], relations: { exifInfo: true, }, @@ -606,6 +671,13 @@ export class AssetRepository implements IAssetRepository { ); } + @GenerateSql({ params: [{ userIds: [DummyValue.UUID, DummyValue.UUID] }] }) + getDuplicates(options: AssetBuilderOptions): Promise { + return this.getBuilder({ ...options, isDuplicate: true }) + .orderBy('asset.duplicateId') + .getMany(); + } + @GenerateSql({ params: [DummyValue.UUID, { minAssetsPerField: 5, maxFields: 12 }] }) async getAssetIdByCity( ownerId: string, @@ -665,16 +737,14 @@ export class AssetRepository implements IAssetRepository { } private getBuilder(options: AssetBuilderOptions) { - const { isArchived, isFavorite, isTrashed, albumId, personId, userIds, withStacked, exifInfo, assetType } = options; - const builder = this.repository.createQueryBuilder('asset').where('asset.isVisible = true'); - if (assetType !== undefined) { - builder.andWhere('asset.type = :assetType', { assetType }); + if (options.assetType !== undefined) { + builder.andWhere('asset.type = :assetType', { assetType: options.assetType }); } let stackJoined = false; - if (exifInfo !== false) { + if (options.exifInfo !== false) { stackJoined = true; builder .leftJoinAndSelect('asset.exifInfo', 'exifInfo') @@ -682,34 +752,38 @@ export class AssetRepository implements IAssetRepository { .leftJoinAndSelect('stack.assets', 'stackedAssets'); } - if (albumId) { - builder.leftJoin('asset.albums', 'album').andWhere('album.id = :albumId', { albumId }); + if (options.albumId) { + builder.leftJoin('asset.albums', 'album').andWhere('album.id = :albumId', { albumId: options.albumId }); } - if (userIds) { - builder.andWhere('asset.ownerId IN (:...userIds )', { userIds }); + if (options.userIds) { + builder.andWhere('asset.ownerId IN (:...userIds )', { userIds: options.userIds }); } - if (isArchived !== undefined) { - builder.andWhere('asset.isArchived = :isArchived', { isArchived }); + if (options.isArchived !== undefined) { + builder.andWhere('asset.isArchived = :isArchived', { isArchived: options.isArchived }); } - if (isFavorite !== undefined) { - builder.andWhere('asset.isFavorite = :isFavorite', { isFavorite }); + if (options.isFavorite !== undefined) { + builder.andWhere('asset.isFavorite = :isFavorite', { isFavorite: options.isFavorite }); } - if (isTrashed !== undefined) { - builder.andWhere(`asset.deletedAt ${isTrashed ? 'IS NOT NULL' : 'IS NULL'}`).withDeleted(); + if (options.isTrashed !== undefined) { + builder.andWhere(`asset.deletedAt ${options.isTrashed ? 'IS NOT NULL' : 'IS NULL'}`).withDeleted(); } - if (personId !== undefined) { + if (options.isDuplicate !== undefined) { + builder.andWhere(`asset.duplicateId ${options.isDuplicate ? 'IS NOT NULL' : 'IS NULL'}`); + } + + if (options.personId !== undefined) { builder .innerJoin('asset.faces', 'faces') .innerJoin('faces.person', 'person') - .andWhere('person.id = :personId', { personId }); + .andWhere('person.id = :personId', { personId: options.personId }); } - if (withStacked) { + if (options.withStacked) { if (!stackJoined) { builder.leftJoinAndSelect('asset.stack', 'stack').leftJoinAndSelect('stack.assets', 'stackedAssets'); } @@ -726,19 +800,18 @@ export class AssetRepository implements IAssetRepository { { ownerId: DummyValue.UUID, lastCreationDate: DummyValue.DATE, - lastId: DummyValue.STRING, + lastId: DummyValue.UUID, updatedUntil: DummyValue.DATE, limit: 10, }, ], }) getAllForUserFullSync(options: AssetFullSyncOptions): Promise { - const { ownerId, isArchived, withStacked, lastCreationDate, lastId, updatedUntil, limit } = options; + const { ownerId, lastCreationDate, lastId, updatedUntil, limit } = options; const builder = this.getBuilder({ userIds: [ownerId], - exifInfo: true, - withStacked, - isArchived, + exifInfo: true, // also joins stack information + withStacked: false, // return all assets individually as expected by the app }); if (lastCreationDate !== undefined && lastId !== undefined) { @@ -759,9 +832,9 @@ export class AssetRepository implements IAssetRepository { @GenerateSql({ params: [{ userIds: [DummyValue.UUID], updatedAfter: DummyValue.DATE }] }) getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise { - const builder = this.getBuilder({ userIds: options.userIds, exifInfo: true, withStacked: true }) + const builder = this.getBuilder({ userIds: options.userIds, exifInfo: true, withStacked: false }) .andWhere({ updatedAt: MoreThan(options.updatedAfter) }) - .take(options.limit) + .limit(options.limit) .withDeleted(); return builder.getMany(); diff --git a/server/src/repositories/audit.repository.ts b/server/src/repositories/audit.repository.ts index 6cf5b76e6e..deb0d0f6f1 100644 --- a/server/src/repositories/audit.repository.ts +++ b/server/src/repositories/audit.repository.ts @@ -10,8 +10,8 @@ import { In, LessThan, MoreThan, Repository } from 'typeorm'; export class AuditRepository implements IAuditRepository { constructor(@InjectRepository(AuditEntity) private repository: Repository) {} - getAfter(since: Date, options: AuditSearch): Promise { - return this.repository + async getAfter(since: Date, options: AuditSearch): Promise { + const records = await this.repository .createQueryBuilder('audit') .where({ createdAt: MoreThan(since), @@ -22,7 +22,9 @@ export class AuditRepository implements IAuditRepository { .distinctOn(['audit.entityId', 'audit.entityType']) .orderBy('audit.entityId, audit.entityType, audit.createdAt', 'DESC') .select('audit.entityId') - .getRawMany(); + .getMany(); + + return records.map((r) => r.entityId); } async removeBefore(before: Date): Promise { diff --git a/server/src/repositories/database.repository.ts b/server/src/repositories/database.repository.ts index b9a04bffc8..dc442e7017 100644 --- a/server/src/repositories/database.repository.ts +++ b/server/src/repositories/database.repository.ts @@ -1,19 +1,19 @@ import { Inject, Injectable } from '@nestjs/common'; import { InjectDataSource } from '@nestjs/typeorm'; import AsyncLock from 'async-lock'; -import { vectorExt } from 'src/database.config'; +import semver from 'semver'; +import { getVectorExtension } from 'src/database.config'; import { DatabaseExtension, DatabaseLock, + EXTENSION_NAMES, IDatabaseRepository, VectorExtension, VectorIndex, VectorUpdateResult, - extName, } from 'src/interfaces/database.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Instrumentation } from 'src/utils/instrumentation'; -import { Version, VersionType } from 'src/utils/version'; import { isValidInteger } from 'src/validation'; import { DataSource, EntityManager, QueryRunner } from 'typeorm'; @@ -29,22 +29,12 @@ export class DatabaseRepository implements IDatabaseRepository { this.logger.setContext(DatabaseRepository.name); } - async getExtensionVersion(extension: DatabaseExtension): Promise { + async getExtensionVersion(extension: DatabaseExtension): Promise { const res = await this.dataSource.query(`SELECT extversion FROM pg_extension WHERE extname = $1`, [extension]); - const extVersion = res[0]?.['extversion']; - if (extVersion == null) { - return null; - } - - const version = Version.fromString(extVersion); - if (version.isEqual(new Version(0, 1, 1))) { - return new Version(0, 1, 11); - } - - return version; + return res[0]?.['extversion']; } - async getAvailableExtensionVersion(extension: DatabaseExtension): Promise { + async getAvailableExtensionVersion(extension: DatabaseExtension): Promise { const res = await this.dataSource.query( ` SELECT version FROM pg_available_extension_versions @@ -52,45 +42,41 @@ export class DatabaseRepository implements IDatabaseRepository { ORDER BY version DESC`, [extension], ); - const version = res[0]?.['version']; - return version == null ? null : Version.fromString(version); + return res[0]?.['version']; } - getPreferredVectorExtension(): VectorExtension { - return vectorExt; - } - - async getPostgresVersion(): Promise { - const res = await this.dataSource.query(`SHOW server_version`); - return Version.fromString(res[0]['server_version']); + async getPostgresVersion(): Promise { + const [{ server_version: version }] = await this.dataSource.query(`SHOW server_version`); + return version; } async createExtension(extension: DatabaseExtension): Promise { await this.dataSource.query(`CREATE EXTENSION IF NOT EXISTS ${extension}`); } - async updateExtension(extension: DatabaseExtension, version?: Version): Promise { + async updateExtension(extension: DatabaseExtension, version?: string): Promise { await this.dataSource.query(`ALTER EXTENSION ${extension} UPDATE${version ? ` TO '${version}'` : ''}`); } - async updateVectorExtension(extension: VectorExtension, version?: Version): Promise { - const curVersion = await this.getExtensionVersion(extension); - if (!curVersion) { - throw new Error(`${extName[extension]} extension is not installed`); + async updateVectorExtension(extension: VectorExtension, targetVersion?: string): Promise { + const currentVersion = await this.getExtensionVersion(extension); + if (!currentVersion) { + throw new Error(`${EXTENSION_NAMES[extension]} extension is not installed`); } - const minorOrMajor = version && curVersion.isOlderThan(version) >= VersionType.MINOR; const isVectors = extension === DatabaseExtension.VECTORS; let restartRequired = false; await this.dataSource.manager.transaction(async (manager) => { await this.setSearchPath(manager); - if (minorOrMajor && isVectors) { - await this.updateVectorsSchema(manager, curVersion); + + const isSchemaUpgrade = targetVersion && semver.satisfies(targetVersion, '0.1.1 || 0.1.11'); + if (isSchemaUpgrade && isVectors) { + await this.updateVectorsSchema(manager, currentVersion); } - await manager.query(`ALTER EXTENSION ${extension} UPDATE${version ? ` TO '${version}'` : ''}`); + await manager.query(`ALTER EXTENSION ${extension} UPDATE${targetVersion ? ` TO '${targetVersion}'` : ''}`); - if (!minorOrMajor) { + if (!isSchemaUpgrade) { return; } @@ -110,7 +96,7 @@ export class DatabaseRepository implements IDatabaseRepository { try { await this.dataSource.query(`REINDEX INDEX ${index}`); } catch (error) { - if (vectorExt === DatabaseExtension.VECTORS) { + if (getVectorExtension() === DatabaseExtension.VECTORS) { this.logger.warn(`Could not reindex index ${index}. Attempting to auto-fix.`); const table = index === VectorIndex.CLIP ? 'smart_search' : 'asset_faces'; const dimSize = await this.getDimSize(table); @@ -132,7 +118,7 @@ export class DatabaseRepository implements IDatabaseRepository { } async shouldReindex(name: VectorIndex): Promise { - if (vectorExt !== DatabaseExtension.VECTORS) { + if (getVectorExtension() !== DatabaseExtension.VECTORS) { return false; } @@ -160,10 +146,10 @@ export class DatabaseRepository implements IDatabaseRepository { await manager.query(`SET search_path TO "$user", public, vectors`); } - private async updateVectorsSchema(manager: EntityManager, curVersion: Version): Promise { + private async updateVectorsSchema(manager: EntityManager, currentVersion: string): Promise { await manager.query('CREATE SCHEMA IF NOT EXISTS vectors'); await manager.query(`UPDATE pg_catalog.pg_extension SET extversion = $1 WHERE extname = $2`, [ - curVersion.toString(), + currentVersion, DatabaseExtension.VECTORS, ]); await manager.query('UPDATE pg_catalog.pg_extension SET extrelocatable = true WHERE extname = $1', [ diff --git a/server/src/repositories/index.ts b/server/src/repositories/index.ts index f21424e9d3..9ac9081c91 100644 --- a/server/src/repositories/index.ts +++ b/server/src/repositories/index.ts @@ -27,7 +27,6 @@ import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; import { ISessionRepository } from 'src/interfaces/session.interface'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ITagRepository } from 'src/interfaces/tag.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; @@ -60,7 +59,6 @@ import { ServerInfoRepository } from 'src/repositories/server-info.repository'; import { SessionRepository } from 'src/repositories/session.repository'; import { SharedLinkRepository } from 'src/repositories/shared-link.repository'; import { StorageRepository } from 'src/repositories/storage.repository'; -import { SystemConfigRepository } from 'src/repositories/system-config.repository'; import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository'; import { TagRepository } from 'src/repositories/tag.repository'; import { UserRepository } from 'src/repositories/user.repository'; @@ -94,7 +92,6 @@ export const repositories = [ { provide: ISearchRepository, useClass: SearchRepository }, { provide: ISessionRepository, useClass: SessionRepository }, { provide: IStorageRepository, useClass: StorageRepository }, - { provide: ISystemConfigRepository, useClass: SystemConfigRepository }, { provide: ISystemMetadataRepository, useClass: SystemMetadataRepository }, { provide: ITagRepository, useClass: TagRepository }, { provide: IMediaRepository, useClass: MediaRepository }, diff --git a/server/src/repositories/job.repository.ts b/server/src/repositories/job.repository.ts index 78729d5733..606549454d 100644 --- a/server/src/repositories/job.repository.ts +++ b/server/src/repositories/job.repository.ts @@ -65,6 +65,10 @@ export const JOBS_TO_QUEUE: Record = { [JobName.QUEUE_SMART_SEARCH]: QueueName.SMART_SEARCH, [JobName.SMART_SEARCH]: QueueName.SMART_SEARCH, + // duplicate detection + [JobName.QUEUE_DUPLICATE_DETECTION]: QueueName.DUPLICATE_DETECTION, + [JobName.DUPLICATE_DETECTION]: QueueName.DUPLICATE_DETECTION, + // XMP sidecars [JobName.QUEUE_SIDECAR]: QueueName.SIDECAR, [JobName.SIDECAR_DISCOVERY]: QueueName.SIDECAR, @@ -82,6 +86,9 @@ export const JOBS_TO_QUEUE: Record = { // Notification [JobName.SEND_EMAIL]: QueueName.NOTIFICATION, [JobName.NOTIFY_SIGNUP]: QueueName.NOTIFICATION, + + // Version check + [JobName.VERSION_CHECK]: QueueName.BACKGROUND_TASK, }; @Instrumentation() diff --git a/server/src/repositories/library.repository.ts b/server/src/repositories/library.repository.ts index b0350c14ec..963b0aaf73 100644 --- a/server/src/repositories/library.repository.ts +++ b/server/src/repositories/library.repository.ts @@ -2,10 +2,10 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { DummyValue, GenerateSql } from 'src/decorators'; import { LibraryStatsResponseDto } from 'src/dtos/library.dto'; -import { LibraryEntity, LibraryType } from 'src/entities/library.entity'; +import { LibraryEntity } from 'src/entities/library.entity'; import { ILibraryRepository } from 'src/interfaces/library.interface'; import { Instrumentation } from 'src/utils/instrumentation'; -import { EntityNotFoundError, IsNull, Not } from 'typeorm'; +import { IsNull, Not } from 'typeorm'; import { Repository } from 'typeorm/repository/Repository.js'; @Instrumentation() @@ -24,65 +24,9 @@ export class LibraryRepository implements ILibraryRepository { }); } - @GenerateSql({ params: [DummyValue.STRING] }) - existsByName(name: string, withDeleted = false): Promise { - return this.repository.exist({ - where: { - name, - }, - withDeleted, - }); - } - - @GenerateSql({ params: [DummyValue.UUID] }) - getCountForUser(ownerId: string): Promise { - return this.repository.countBy({ ownerId }); - } - - @GenerateSql({ params: [DummyValue.UUID] }) - getDefaultUploadLibrary(ownerId: string): Promise { - return this.repository.findOne({ - where: { - ownerId: ownerId, - type: LibraryType.UPLOAD, - }, - order: { - createdAt: 'ASC', - }, - }); - } - - @GenerateSql({ params: [DummyValue.UUID] }) - getUploadLibraryCount(ownerId: string): Promise { - return this.repository.count({ - where: { - ownerId: ownerId, - type: LibraryType.UPLOAD, - }, - }); - } - - @GenerateSql({ params: [DummyValue.UUID] }) - getAllByUserId(ownerId: string, type?: LibraryType): Promise { - return this.repository.find({ - where: { - ownerId, - isVisible: true, - type, - }, - relations: { - owner: true, - }, - order: { - createdAt: 'ASC', - }, - }); - } - @GenerateSql({ params: [] }) - getAll(withDeleted = false, type?: LibraryType): Promise { + getAll(withDeleted = false): Promise { return this.repository.find({ - where: { type }, relations: { owner: true, }, @@ -97,7 +41,6 @@ export class LibraryRepository implements ILibraryRepository { getAllDeleted(): Promise { return this.repository.find({ where: { - isVisible: true, deletedAt: Not(IsNull()), }, relations: { @@ -127,7 +70,7 @@ export class LibraryRepository implements ILibraryRepository { } @GenerateSql({ params: [DummyValue.UUID] }) - async getStatistics(id: string): Promise { + async getStatistics(id: string): Promise { const stats = await this.repository .createQueryBuilder('libraries') .addSelect(`COUNT(assets.id) FILTER (WHERE assets.type = 'IMAGE' AND assets.isVisible)`, 'photos') @@ -140,7 +83,7 @@ export class LibraryRepository implements ILibraryRepository { .getRawOne(); if (!stats) { - throw new EntityNotFoundError(LibraryEntity, { where: { id } }); + return; } return { @@ -151,26 +94,6 @@ export class LibraryRepository implements ILibraryRepository { }; } - @GenerateSql({ params: [DummyValue.UUID] }) - async getOnlineAssetPaths(libraryId: string): Promise { - // Return all non-offline asset paths for a given library - const rawResults = await this.repository - .createQueryBuilder('library') - .innerJoinAndSelect('library.assets', 'assets') - .where('library.id = :id', { id: libraryId }) - .andWhere('assets.isOffline = false') - .select('assets.originalPath') - .getRawMany(); - - const results: string[] = []; - - for (const rawPath of rawResults) { - results.push(rawPath.assets_originalPath); - } - - return results; - } - @GenerateSql({ params: [DummyValue.UUID] }) async getAssetIds(libraryId: string, withDeleted = false): Promise { const builder = this.repository diff --git a/server/src/repositories/logger.repository.ts b/server/src/repositories/logger.repository.ts index 65ccd8ea47..0f82c6ee0f 100644 --- a/server/src/repositories/logger.repository.ts +++ b/server/src/repositories/logger.repository.ts @@ -1,15 +1,34 @@ -import { Injectable, Scope } from '@nestjs/common'; +import { ConsoleLogger, Injectable, Scope } from '@nestjs/common'; +import { isLogLevelEnabled } from '@nestjs/common/services/utils/is-log-level-enabled.util'; import { ClsService } from 'nestjs-cls'; -import { LogLevel } from 'src/entities/system-config.entity'; +import { LogLevel } from 'src/config'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; -import { ImmichLogger } from 'src/utils/logger'; +import { LogColor } from 'src/utils/logger-colors'; + +const LOG_LEVELS = [LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]; @Injectable({ scope: Scope.TRANSIENT }) -export class LoggerRepository extends ImmichLogger implements ILoggerRepository { +export class LoggerRepository extends ConsoleLogger implements ILoggerRepository { + private static logLevels: LogLevel[] = [LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]; + constructor(private cls: ClsService) { super(LoggerRepository.name); } + private static appName?: string = undefined; + + setAppName(name: string): void { + LoggerRepository.appName = name; + } + + isLevelEnabled(level: LogLevel) { + return isLogLevelEnabled(level, LoggerRepository.logLevels); + } + + setLogLevel(level: LogLevel): void { + LoggerRepository.logLevels = LOG_LEVELS.slice(LOG_LEVELS.indexOf(level)); + } + protected formatContext(context: string): string { let formattedContext = super.formatContext(context); @@ -18,10 +37,10 @@ export class LoggerRepository extends ImmichLogger implements ILoggerRepository formattedContext += `[${correlationId}] `; } + if (LoggerRepository.appName) { + formattedContext = LogColor.blue(`[${LoggerRepository.appName}] `) + formattedContext; + } + return formattedContext; } - - setLogLevel(level: LogLevel): void { - ImmichLogger.setLogLevel(level); - } } diff --git a/server/src/repositories/machine-learning.repository.ts b/server/src/repositories/machine-learning.repository.ts index 3d8f0cac1e..bff22b9507 100644 --- a/server/src/repositories/machine-learning.repository.ts +++ b/server/src/repositories/machine-learning.repository.ts @@ -19,9 +19,11 @@ export class MachineLearningRepository implements IMachineLearningRepository { private async predict(url: string, input: TextModelInput | VisionModelInput, config: ModelConfig): Promise { const formData = await this.getFormData(input, config); - const res = await fetch(`${url}/predict`, { method: 'POST', body: formData }).catch((error: Error | any) => { - throw new Error(`${errorPrefix} to "${url}" failed with ${error?.cause || error}`); - }); + const res = await fetch(new URL('/predict', url), { method: 'POST', body: formData }).catch( + (error: Error | any) => { + throw new Error(`${errorPrefix} to "${url}" failed with ${error?.cause || error}`); + }, + ); if (res.status >= 400) { const modelType = config.modelType ? ` for ${config.modelType.replace('-', ' ')}` : ''; diff --git a/server/src/repositories/media.repository.ts b/server/src/repositories/media.repository.ts index 71c58fd91e..04a9751223 100644 --- a/server/src/repositories/media.repository.ts +++ b/server/src/repositories/media.repository.ts @@ -5,7 +5,7 @@ import fs from 'node:fs/promises'; import { Writable } from 'node:stream'; import { promisify } from 'node:util'; import sharp from 'sharp'; -import { Colorspace } from 'src/entities/system-config.entity'; +import { Colorspace } from 'src/config'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMediaRepository, diff --git a/server/src/repositories/memory.repository.ts b/server/src/repositories/memory.repository.ts index 2a7997a0aa..a68d97152b 100644 --- a/server/src/repositories/memory.repository.ts +++ b/server/src/repositories/memory.repository.ts @@ -66,7 +66,7 @@ export class MemoryRepository implements IMemoryRepository { return new Set(results.map((row) => row['assetId'])); } - @GenerateSql({ params: [{ albumId: DummyValue.UUID, assetIds: [DummyValue.UUID] }] }) + @GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] }) async addAssetIds(id: string, assetIds: string[]): Promise { await this.dataSource .createQueryBuilder() diff --git a/server/src/repositories/notification.repository.ts b/server/src/repositories/notification.repository.ts index 23c81bb77b..e22198de80 100644 --- a/server/src/repositories/notification.repository.ts +++ b/server/src/repositories/notification.repository.ts @@ -59,7 +59,7 @@ export class NotificationRepository implements INotificationRepository { return createTransport({ host: options.host, port: options.port, - tls: { rejectUnauthorized: options.ignoreCert }, + tls: { rejectUnauthorized: !options.ignoreCert }, auth: options.username || options.password ? { diff --git a/server/src/repositories/search.repository.ts b/server/src/repositories/search.repository.ts index 6ac49a3190..072d452777 100644 --- a/server/src/repositories/search.repository.ts +++ b/server/src/repositories/search.repository.ts @@ -1,6 +1,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { vectorExt } from 'src/database.config'; +import { getVectorExtension } from 'src/database.config'; import { DummyValue, GenerateSql } from 'src/decorators'; import { AssetFaceEntity } from 'src/entities/asset-face.entity'; import { AssetEntity, AssetType } from 'src/entities/asset.entity'; @@ -10,6 +10,8 @@ import { SmartSearchEntity } from 'src/entities/smart-search.entity'; import { DatabaseExtension } from 'src/interfaces/database.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { + AssetDuplicateResult, + AssetDuplicateSearch, AssetSearchOptions, FaceEmbeddingSearch, FaceSearchResult, @@ -145,6 +147,44 @@ export class SearchRepository implements ISearchRepository { return results; } + @GenerateSql({ + params: [ + { + embedding: Array.from({ length: 512 }, Math.random), + maxDistance: 0.6, + userIds: [DummyValue.UUID], + }, + ], + }) + searchDuplicates({ + assetId, + embedding, + maxDistance, + userIds, + }: AssetDuplicateSearch): Promise { + const cte = this.assetRepository.createQueryBuilder('asset'); + cte + .select('search.assetId', 'assetId') + .addSelect('asset.duplicateId', 'duplicateId') + .addSelect(`search.embedding <=> :embedding`, 'distance') + .innerJoin('asset.smartSearch', 'search') + .where('asset.ownerId IN (:...userIds )') + .andWhere('asset.id != :assetId') + .andWhere('asset.isVisible = :isVisible') + .orderBy('search.embedding <=> :embedding') + .limit(64) + .setParameters({ assetId, embedding: asVector(embedding), isVisible: true, userIds }); + + const builder = this.assetRepository.manager + .createQueryBuilder() + .addCommonTableExpression(cte, 'cte') + .from('cte', 'res') + .select('res.*') + .where('res.distance <= :maxDistance', { maxDistance }); + + return builder.getRawMany() as any as Promise; + } + @GenerateSql({ params: [ { @@ -296,7 +336,7 @@ export class SearchRepository implements ISearchRepository { } private getRuntimeConfig(numResults?: number): string { - if (vectorExt === DatabaseExtension.VECTOR) { + if (getVectorExtension() === DatabaseExtension.VECTOR) { return 'SET LOCAL hnsw.ef_search = 1000;'; // mitigate post-filter recall } diff --git a/server/src/repositories/storage.repository.spec.ts b/server/src/repositories/storage.repository.spec.ts index 44c81d76a6..e770ce6c1b 100644 --- a/server/src/repositories/storage.repository.spec.ts +++ b/server/src/repositories/storage.repository.spec.ts @@ -76,17 +76,6 @@ const tests: Test[] = [ '/albums/image3.jpg': true, }, }, - { - test: 'should support globbing paths', - options: { - pathsToCrawl: ['/photos*'], - }, - files: { - '/photos1/image1.jpg': true, - '/photos2/image2.jpg': true, - '/images/image3.jpg': false, - }, - }, { test: 'should crawl a single path without trailing slash', options: { @@ -179,6 +168,15 @@ const tests: Test[] = [ [`/photos/3.jpg`]: false, }, }, + { + test: 'should support special characters in paths', + options: { + pathsToCrawl: ['/photos (new)'], + }, + files: { + ['/photos (new)/1.jpg']: true, + }, + }, ]; describe(StorageRepository.name, () => { diff --git a/server/src/repositories/storage.repository.ts b/server/src/repositories/storage.repository.ts index ae374ac812..0d0be5c062 100644 --- a/server/src/repositories/storage.repository.ts +++ b/server/src/repositories/storage.repository.ts @@ -1,7 +1,7 @@ import { Inject, Injectable } from '@nestjs/common'; import archiver from 'archiver'; import chokidar, { WatchOptions } from 'chokidar'; -import { glob, globStream } from 'fast-glob'; +import { escapePath, glob, globStream } from 'fast-glob'; import { constants, createReadStream, existsSync, mkdirSync } from 'node:fs'; import fs from 'node:fs/promises'; import path from 'node:path'; @@ -186,7 +186,8 @@ export class StorageRepository implements IStorageRepository { } private asGlob(pathsToCrawl: string[]): string { - const base = pathsToCrawl.length === 1 ? pathsToCrawl[0] : `{${pathsToCrawl.join(',')}}`; + const escapedPaths = pathsToCrawl.map((path) => escapePath(path)); + const base = escapedPaths.length === 1 ? escapedPaths[0] : `{${escapedPaths.join(',')}}`; const extensions = `*{${mimeTypes.getSupportedFileExtensions().join(',')}}`; return `${base}/**/${extensions}`; } diff --git a/server/src/repositories/system-config.repository.ts b/server/src/repositories/system-config.repository.ts deleted file mode 100644 index 3d2dbecbc8..0000000000 --- a/server/src/repositories/system-config.repository.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { readFile } from 'node:fs/promises'; -import { Chunked, DummyValue, GenerateSql } from 'src/decorators'; -import { SystemConfigEntity } from 'src/entities/system-config.entity'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { Instrumentation } from 'src/utils/instrumentation'; -import { In, Repository } from 'typeorm'; - -@Instrumentation() -@Injectable() -export class SystemConfigRepository implements ISystemConfigRepository { - constructor( - @InjectRepository(SystemConfigEntity) - private repository: Repository, - ) {} - - async fetchStyle(url: string) { - try { - const response = await fetch(url); - - if (!response.ok) { - throw new Error(`Failed to fetch data from ${url} with status ${response.status}: ${await response.text()}`); - } - - return response.json(); - } catch (error) { - throw new Error(`Failed to fetch data from ${url}: ${error}`); - } - } - - @GenerateSql() - load(): Promise { - return this.repository.find(); - } - - readFile(filename: string): Promise { - return readFile(filename, { encoding: 'utf8' }); - } - - saveAll(items: SystemConfigEntity[]): Promise { - return this.repository.save(items); - } - - @GenerateSql({ params: [DummyValue.STRING] }) - @Chunked() - async deleteKeys(keys: string[]): Promise { - await this.repository.delete({ key: In(keys) }); - } -} diff --git a/server/src/repositories/system-metadata.repository.ts b/server/src/repositories/system-metadata.repository.ts index 91b887a176..c8bf9489cb 100644 --- a/server/src/repositories/system-metadata.repository.ts +++ b/server/src/repositories/system-metadata.repository.ts @@ -1,5 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; +import { readFile } from 'node:fs/promises'; import { SystemMetadata, SystemMetadataEntity } from 'src/entities/system-metadata.entity'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { Instrumentation } from 'src/utils/instrumentation'; @@ -24,4 +25,22 @@ export class SystemMetadataRepository implements ISystemMetadataRepository { async set(key: T, value: SystemMetadata[T]): Promise { await this.repository.upsert({ key, value }, { conflictPaths: { key: true } }); } + + async fetchStyle(url: string) { + try { + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`Failed to fetch data from ${url} with status ${response.status}: ${await response.text()}`); + } + + return response.json(); + } catch (error) { + throw new Error(`Failed to fetch data from ${url}: ${error}`); + } + } + + readFile(filename: string): Promise { + return readFile(filename, { encoding: 'utf8' }); + } } diff --git a/server/src/repositories/user.repository.ts b/server/src/repositories/user.repository.ts index 4f62732e7b..7b7861a8de 100644 --- a/server/src/repositories/user.repository.ts +++ b/server/src/repositories/user.repository.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { DummyValue, GenerateSql } from 'src/decorators'; import { AssetEntity } from 'src/entities/asset.entity'; -import { LibraryType } from 'src/entities/library.entity'; +import { UserMetadata, UserMetadataEntity, UserMetadataKey } from 'src/entities/user-metadata.entity'; import { UserEntity } from 'src/entities/user.entity'; import { IUserRepository, @@ -19,6 +19,7 @@ export class UserRepository implements IUserRepository { constructor( @InjectRepository(AssetEntity) private assetRepository: Repository, @InjectRepository(UserEntity) private userRepository: Repository, + @InjectRepository(UserMetadataEntity) private metadataRepository: Repository, ) {} async get(userId: string, options: UserFindOptions): Promise { @@ -26,6 +27,9 @@ export class UserRepository implements IUserRepository { return this.userRepository.findOne({ where: { id: userId }, withDeleted: options.withDeleted, + relations: { + metadata: true, + }, }); } @@ -70,6 +74,9 @@ export class UserRepository implements IUserRepository { order: { createdAt: 'DESC', }, + relations: { + metadata: true, + }, }); } @@ -82,6 +89,13 @@ export class UserRepository implements IUserRepository { return this.save({ ...user, id }); } + async upsertMetadata( + id: string, + { key, value }: { key: T; value: UserMetadata[T] }, + ) { + await this.metadataRepository.upsert({ userId: id, key, value }, { conflictPaths: { userId: true, key: true } }); + } + async delete(user: UserEntity, hard?: boolean): Promise { return hard ? this.userRepository.remove(user) : this.userRepository.softRemove(user); } @@ -123,10 +137,9 @@ export class UserRepository implements IUserRepository { const subQuery = this.assetRepository .createQueryBuilder('assets') .select('COALESCE(SUM(exif."fileSizeInByte"), 0)') - .leftJoin('assets.library', 'library') .leftJoin('assets.exifInfo', 'exif') .where('assets.ownerId = users.id') - .andWhere(`library.type = '${LibraryType.UPLOAD}'`) + .andWhere(`assets.libraryId IS NULL`) .withDeleted(); const query = this.userRepository @@ -144,6 +157,12 @@ export class UserRepository implements IUserRepository { private async save(user: Partial) { const { id } = await this.userRepository.save(user); - return this.userRepository.findOneOrFail({ where: { id }, withDeleted: true }); + return this.userRepository.findOneOrFail({ + where: { id }, + withDeleted: true, + relations: { + metadata: true, + }, + }); } } diff --git a/server/src/services/album.service.spec.ts b/server/src/services/album.service.spec.ts index e2a7fc49c4..3d20a6a559 100644 --- a/server/src/services/album.service.spec.ts +++ b/server/src/services/album.service.spec.ts @@ -185,7 +185,7 @@ describe(AlbumService.name, () => { await sut.create(authStub.admin, { albumName: 'Empty album', - sharedWithUserIds: ['user-id'], + albumUsers: [{ userId: 'user-id', role: AlbumUserRole.EDITOR }], description: '', assetIds: ['123'], }); @@ -208,7 +208,7 @@ describe(AlbumService.name, () => { await expect( sut.create(authStub.admin, { albumName: 'Empty album', - sharedWithUserIds: ['user-3'], + albumUsers: [{ userId: 'user-3', role: AlbumUserRole.EDITOR }], }), ).rejects.toBeInstanceOf(BadRequestException); expect(userMock.get).toHaveBeenCalledWith('user-3', {}); diff --git a/server/src/services/album.service.ts b/server/src/services/album.service.ts index 38464bd75a..643d060494 100644 --- a/server/src/services/album.service.ts +++ b/server/src/services/album.service.ts @@ -14,7 +14,7 @@ import { } from 'src/dtos/album.dto'; import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; -import { AlbumUserEntity, AlbumUserRole } from 'src/entities/album-user.entity'; +import { AlbumUserEntity } from 'src/entities/album-user.entity'; import { AlbumEntity } from 'src/entities/album.entity'; import { AssetEntity } from 'src/entities/asset.entity'; import { IAccessRepository } from 'src/interfaces/access.interface'; @@ -115,9 +115,6 @@ export class AlbumService { async create(auth: AuthDto, dto: CreateAlbumDto): Promise { const albumUsers = dto.albumUsers || []; - for (const userId of dto.sharedWithUserIds || []) { - albumUsers.push({ userId, role: AlbumUserRole.EDITOR }); - } for (const { userId } of albumUsers) { const exists = await this.userRepository.get(userId, {}); @@ -216,15 +213,7 @@ export class AlbumService { return results; } - async addUsers(auth: AuthDto, id: string, { albumUsers, sharedUserIds }: AddUsersDto): Promise { - // Remove once deprecated sharedUserIds is removed - if (!albumUsers) { - if (!sharedUserIds) { - throw new BadRequestException('No users provided'); - } - albumUsers = sharedUserIds.map((userId) => ({ userId, role: AlbumUserRole.EDITOR })); - } - + async addUsers(auth: AuthDto, id: string, { albumUsers }: AddUsersDto): Promise { await this.access.requirePermission(auth, Permission.ALBUM_SHARE, id); const album = await this.findOrFail(id, { withAssets: false }); diff --git a/server/src/services/api.service.ts b/server/src/services/api.service.ts index fb9912da95..9c786a848f 100644 --- a/server/src/services/api.service.ts +++ b/server/src/services/api.service.ts @@ -12,6 +12,7 @@ import { ServerInfoService } from 'src/services/server-info.service'; import { SharedLinkService } from 'src/services/shared-link.service'; import { StorageService } from 'src/services/storage.service'; import { SystemConfigService } from 'src/services/system-config.service'; +import { VersionService } from 'src/services/version.service'; import { OpenGraphTags } from 'src/utils/misc'; const render = (index: string, meta: OpenGraphTags) => { @@ -44,6 +45,7 @@ export class ApiService { private sharedLinkService: SharedLinkService, private storageService: StorageService, private databaseService: DatabaseService, + private versionService: VersionService, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(ApiService.name); @@ -51,7 +53,7 @@ export class ApiService { @Interval(ONE_HOUR.as('milliseconds')) async onVersionCheck() { - await this.serverService.handleVersionCheck(); + await this.versionService.handleQueueVersionCheck(); } @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT) @@ -64,6 +66,7 @@ export class ApiService { await this.configService.init(); this.storageService.init(); await this.serverService.init(); + await this.versionService.init(); this.logger.log(`Feature Flags: ${JSON.stringify(await this.serverService.getFeatures(), null, 2)}`); } diff --git a/server/src/services/asset-media.service.spec.ts b/server/src/services/asset-media.service.spec.ts new file mode 100644 index 0000000000..a75ece42f5 --- /dev/null +++ b/server/src/services/asset-media.service.spec.ts @@ -0,0 +1,307 @@ +import { Stats } from 'node:fs'; +import { AssetMediaStatusEnum, AssetRejectReason, AssetUploadAction } from 'src/dtos/asset-media-response.dto'; +import { AssetMediaReplaceDto } from 'src/dtos/asset-media.dto'; +import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity, AssetType } from 'src/entities/asset.entity'; +import { ExifEntity } from 'src/entities/exif.entity'; +import { IAssetRepository } from 'src/interfaces/asset.interface'; +import { IEventRepository } from 'src/interfaces/event.interface'; +import { IJobRepository, JobName } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { IStorageRepository } from 'src/interfaces/storage.interface'; +import { IUserRepository } from 'src/interfaces/user.interface'; +import { AssetMediaService, UploadFile } from 'src/services/asset-media.service'; +import { mimeTypes } from 'src/utils/mime-types'; +import { authStub } from 'test/fixtures/auth.stub'; +import { fileStub } from 'test/fixtures/file.stub'; +import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock'; +import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; +import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; +import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; +import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; +import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; +import { QueryFailedError } from 'typeorm'; +import { Mocked } from 'vitest'; + +const _getUpdateAssetDto = (): AssetMediaReplaceDto => { + return Object.assign(new AssetMediaReplaceDto(), { + deviceAssetId: 'deviceAssetId', + deviceId: 'deviceId', + fileModifiedAt: new Date('2024-04-15T23:41:36.910Z'), + fileCreatedAt: new Date('2024-04-15T23:41:36.910Z'), + updatedAt: new Date('2024-04-15T23:41:36.910Z'), + }); +}; + +const _getAsset_1 = () => { + const asset_1 = new AssetEntity(); + + asset_1.id = 'id_1'; + asset_1.ownerId = 'user_id_1'; + asset_1.deviceAssetId = 'device_asset_id_1'; + asset_1.deviceId = 'device_id_1'; + asset_1.type = AssetType.VIDEO; + asset_1.originalPath = 'fake_path/asset_1.jpeg'; + asset_1.previewPath = ''; + asset_1.fileModifiedAt = new Date('2022-06-19T23:41:36.910Z'); + asset_1.fileCreatedAt = new Date('2022-06-19T23:41:36.910Z'); + asset_1.updatedAt = new Date('2022-06-19T23:41:36.910Z'); + asset_1.isFavorite = false; + asset_1.isArchived = false; + asset_1.thumbnailPath = ''; + asset_1.encodedVideoPath = ''; + asset_1.duration = '0:00:00.000000'; + asset_1.exifInfo = new ExifEntity(); + asset_1.exifInfo.latitude = 49.533_547; + asset_1.exifInfo.longitude = 10.703_075; + asset_1.livePhotoVideoId = null; + asset_1.sidecarPath = null; + return asset_1; +}; +const _getExistingAsset = () => { + return { + ..._getAsset_1(), + duration: null, + type: AssetType.IMAGE, + checksum: Buffer.from('_getExistingAsset', 'utf8'), + libraryId: 'libraryId', + } as AssetEntity; +}; +const _getExistingAssetWithSideCar = () => { + return { + ..._getExistingAsset(), + sidecarPath: 'sidecar-path', + checksum: Buffer.from('_getExistingAssetWithSideCar', 'utf8'), + } as AssetEntity; +}; +const _getCopiedAsset = () => { + return { + id: 'copied-asset', + originalPath: 'copied-path', + } as AssetEntity; +}; + +describe('AssetMediaService', () => { + let sut: AssetMediaService; + let accessMock: IAccessRepositoryMock; + let assetMock: Mocked; + let jobMock: Mocked; + let loggerMock: Mocked; + let storageMock: Mocked; + let userMock: Mocked; + let eventMock: Mocked; + + beforeEach(() => { + accessMock = newAccessRepositoryMock(); + assetMock = newAssetRepositoryMock(); + jobMock = newJobRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); + storageMock = newStorageRepositoryMock(); + userMock = newUserRepositoryMock(); + eventMock = newEventRepositoryMock(); + + sut = new AssetMediaService(accessMock, assetMock, jobMock, storageMock, userMock, eventMock, loggerMock); + }); + + describe('replaceAsset', () => { + const expectAssetUpdate = ( + existingAsset: AssetEntity, + uploadFile: UploadFile, + dto: AssetMediaReplaceDto, + livePhotoVideo?: AssetEntity, + sidecarPath?: UploadFile, + // eslint-disable-next-line unicorn/consistent-function-scoping + ) => { + expect(assetMock.update).toHaveBeenCalledWith({ + id: existingAsset.id, + checksum: uploadFile.checksum, + originalFileName: uploadFile.originalName, + originalPath: uploadFile.originalPath, + deviceAssetId: dto.deviceAssetId, + deviceId: dto.deviceId, + fileCreatedAt: dto.fileCreatedAt, + fileModifiedAt: dto.fileModifiedAt, + localDateTime: dto.fileCreatedAt, + type: mimeTypes.assetType(uploadFile.originalPath), + duration: dto.duration || null, + livePhotoVideo: livePhotoVideo ? { id: livePhotoVideo?.id } : null, + sidecarPath: sidecarPath?.originalPath || null, + }); + }; + + // eslint-disable-next-line unicorn/consistent-function-scoping + const expectAssetCreateCopy = (existingAsset: AssetEntity) => { + expect(assetMock.create).toHaveBeenCalledWith({ + ownerId: existingAsset.ownerId, + originalPath: existingAsset.originalPath, + originalFileName: existingAsset.originalFileName, + libraryId: existingAsset.libraryId, + deviceAssetId: existingAsset.deviceAssetId, + deviceId: existingAsset.deviceId, + type: existingAsset.type, + checksum: existingAsset.checksum, + fileCreatedAt: existingAsset.fileCreatedAt, + localDateTime: existingAsset.localDateTime, + fileModifiedAt: existingAsset.fileModifiedAt, + livePhotoVideoId: existingAsset.livePhotoVideoId || null, + sidecarPath: existingAsset.sidecarPath || null, + }); + }; + + it('should error when update photo does not exist', async () => { + const dto = _getUpdateAssetDto(); + assetMock.getById.mockResolvedValueOnce(null); + + await expect(sut.replaceAsset(authStub.user1, 'id', dto, fileStub.photo)).rejects.toThrow( + 'Not found or no asset.update access', + ); + + expect(assetMock.create).not.toHaveBeenCalled(); + }); + it('should update a photo with no sidecar to photo with no sidecar', async () => { + const existingAsset = _getExistingAsset(); + const updatedFile = fileStub.photo; + const updatedAsset = { ...existingAsset, ...updatedFile }; + const dto = _getUpdateAssetDto(); + assetMock.getById.mockResolvedValueOnce(existingAsset); + assetMock.getById.mockResolvedValueOnce(updatedAsset); + accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([existingAsset.id])); + // this is the original file size + storageMock.stat.mockResolvedValue({ size: 0 } as Stats); + // this is for the clone call + assetMock.create.mockResolvedValue(_getCopiedAsset()); + + await expect(sut.replaceAsset(authStub.user1, existingAsset.id, dto, updatedFile)).resolves.toEqual({ + status: AssetMediaStatusEnum.REPLACED, + id: _getCopiedAsset().id, + }); + + expectAssetUpdate(existingAsset, updatedFile, dto); + expectAssetCreateCopy(existingAsset); + + expect(assetMock.softDeleteAll).toHaveBeenCalledWith([_getCopiedAsset().id]); + expect(userMock.updateUsage).toHaveBeenCalledWith(authStub.user1.user.id, updatedFile.size); + expect(storageMock.utimes).toHaveBeenCalledWith( + updatedFile.originalPath, + expect.any(Date), + new Date(dto.fileModifiedAt), + ); + }); + it('should update a photo with sidecar to photo with sidecar', async () => { + const existingAsset = _getExistingAssetWithSideCar(); + + const updatedFile = fileStub.photo; + const sidecarFile = fileStub.photoSidecar; + const dto = _getUpdateAssetDto(); + const updatedAsset = { ...existingAsset, ...updatedFile }; + assetMock.getById.mockResolvedValueOnce(existingAsset); + assetMock.getById.mockResolvedValueOnce(updatedAsset); + accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([existingAsset.id])); + // this is the original file size + storageMock.stat.mockResolvedValue({ size: 0 } as Stats); + // this is for the clone call + assetMock.create.mockResolvedValue(_getCopiedAsset()); + + await expect(sut.replaceAsset(authStub.user1, existingAsset.id, dto, updatedFile, sidecarFile)).resolves.toEqual({ + status: AssetMediaStatusEnum.REPLACED, + id: _getCopiedAsset().id, + }); + + expectAssetUpdate(existingAsset, updatedFile, dto, undefined, sidecarFile); + expectAssetCreateCopy(existingAsset); + expect(assetMock.softDeleteAll).toHaveBeenCalledWith([_getCopiedAsset().id]); + expect(userMock.updateUsage).toHaveBeenCalledWith(authStub.user1.user.id, updatedFile.size); + expect(storageMock.utimes).toHaveBeenCalledWith( + updatedFile.originalPath, + expect.any(Date), + new Date(dto.fileModifiedAt), + ); + }); + it('should update a photo with a sidecar to photo with no sidecar', async () => { + const existingAsset = _getExistingAssetWithSideCar(); + const updatedFile = fileStub.photo; + + const dto = _getUpdateAssetDto(); + const updatedAsset = { ...existingAsset, ...updatedFile }; + assetMock.getById.mockResolvedValueOnce(existingAsset); + assetMock.getById.mockResolvedValueOnce(updatedAsset); + accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([existingAsset.id])); + // this is the original file size + storageMock.stat.mockResolvedValue({ size: 0 } as Stats); + // this is for the copy call + assetMock.create.mockResolvedValue(_getCopiedAsset()); + + await expect(sut.replaceAsset(authStub.user1, existingAsset.id, dto, updatedFile)).resolves.toEqual({ + status: AssetMediaStatusEnum.REPLACED, + id: _getCopiedAsset().id, + }); + + expectAssetUpdate(existingAsset, updatedFile, dto); + expectAssetCreateCopy(existingAsset); + expect(assetMock.softDeleteAll).toHaveBeenCalledWith([_getCopiedAsset().id]); + expect(userMock.updateUsage).toHaveBeenCalledWith(authStub.user1.user.id, updatedFile.size); + expect(storageMock.utimes).toHaveBeenCalledWith( + updatedFile.originalPath, + expect.any(Date), + new Date(dto.fileModifiedAt), + ); + }); + it('should handle a photo with sidecar to duplicate photo ', async () => { + const existingAsset = _getExistingAssetWithSideCar(); + const updatedFile = fileStub.photo; + const dto = _getUpdateAssetDto(); + const error = new QueryFailedError('', [], new Error('unique key violation')); + (error as any).constraint = ASSET_CHECKSUM_CONSTRAINT; + + assetMock.update.mockRejectedValue(error); + assetMock.getById.mockResolvedValueOnce(existingAsset); + assetMock.getUploadAssetIdByChecksum.mockResolvedValue(existingAsset.id); + accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([existingAsset.id])); + // this is the original file size + storageMock.stat.mockResolvedValue({ size: 0 } as Stats); + // this is for the clone call + assetMock.create.mockResolvedValue(_getCopiedAsset()); + + await expect(sut.replaceAsset(authStub.user1, existingAsset.id, dto, updatedFile)).resolves.toEqual({ + status: AssetMediaStatusEnum.DUPLICATE, + id: existingAsset.id, + }); + + expectAssetUpdate(existingAsset, updatedFile, dto); + expect(assetMock.create).not.toHaveBeenCalled(); + expect(assetMock.softDeleteAll).not.toHaveBeenCalled(); + expect(jobMock.queue).toHaveBeenCalledWith({ + name: JobName.DELETE_FILES, + data: { files: [updatedFile.originalPath, undefined] }, + }); + expect(userMock.updateUsage).not.toHaveBeenCalled(); + }); + }); + describe('bulkUploadCheck', () => { + it('should accept hex and base64 checksums', async () => { + const file1 = Buffer.from('d2947b871a706081be194569951b7db246907957', 'hex'); + const file2 = Buffer.from('53be335e99f18a66ff12e9a901c7a6171dd76573', 'hex'); + + assetMock.getByChecksums.mockResolvedValue([ + { id: 'asset-1', checksum: file1 } as AssetEntity, + { id: 'asset-2', checksum: file2 } as AssetEntity, + ]); + + await expect( + sut.bulkUploadCheck(authStub.admin, { + assets: [ + { id: '1', checksum: file1.toString('hex') }, + { id: '2', checksum: file2.toString('base64') }, + ], + }), + ).resolves.toEqual({ + results: [ + { id: '1', assetId: 'asset-1', action: AssetUploadAction.REJECT, reason: AssetRejectReason.DUPLICATE }, + { id: '2', assetId: 'asset-2', action: AssetUploadAction.REJECT, reason: AssetRejectReason.DUPLICATE }, + ], + }); + + expect(assetMock.getByChecksums).toHaveBeenCalledWith(authStub.admin.user.id, [file1, file2]); + }); + }); +}); diff --git a/server/src/services/asset-media.service.ts b/server/src/services/asset-media.service.ts new file mode 100644 index 0000000000..ddb8f105a3 --- /dev/null +++ b/server/src/services/asset-media.service.ts @@ -0,0 +1,234 @@ +import { BadRequestException, Inject, Injectable, InternalServerErrorException } from '@nestjs/common'; +import { AccessCore, Permission } from 'src/cores/access.core'; +import { + AssetBulkUploadCheckResponseDto, + AssetMediaResponseDto, + AssetMediaStatusEnum, + AssetRejectReason, + AssetUploadAction, + CheckExistingAssetsResponseDto, +} from 'src/dtos/asset-media-response.dto'; +import { + AssetBulkUploadCheckDto, + AssetMediaReplaceDto, + CheckExistingAssetsDto, + UploadFieldName, +} from 'src/dtos/asset-media.dto'; +import { AuthDto } from 'src/dtos/auth.dto'; +import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity } from 'src/entities/asset.entity'; +import { IAccessRepository } from 'src/interfaces/access.interface'; +import { IAssetRepository } from 'src/interfaces/asset.interface'; +import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface'; +import { IJobRepository, JobName } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { IStorageRepository } from 'src/interfaces/storage.interface'; +import { IUserRepository } from 'src/interfaces/user.interface'; +import { mimeTypes } from 'src/utils/mime-types'; +import { fromChecksum } from 'src/utils/request'; +import { QueryFailedError } from 'typeorm'; +export interface UploadRequest { + auth: AuthDto | null; + fieldName: UploadFieldName; + file: UploadFile; +} + +export interface UploadFile { + uuid: string; + checksum: Buffer; + originalPath: string; + originalName: string; + size: number; +} + +@Injectable() +export class AssetMediaService { + private access: AccessCore; + + constructor( + @Inject(IAccessRepository) accessRepository: IAccessRepository, + @Inject(IAssetRepository) private assetRepository: IAssetRepository, + @Inject(IJobRepository) private jobRepository: IJobRepository, + @Inject(IStorageRepository) private storageRepository: IStorageRepository, + @Inject(IUserRepository) private userRepository: IUserRepository, + @Inject(IEventRepository) private eventRepository: IEventRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(AssetMediaService.name); + this.access = AccessCore.create(accessRepository); + } + + public async replaceAsset( + auth: AuthDto, + id: string, + dto: AssetMediaReplaceDto, + file: UploadFile, + sidecarFile?: UploadFile, + ): Promise { + try { + await this.access.requirePermission(auth, Permission.ASSET_UPDATE, id); + const existingAssetEntity = (await this.assetRepository.getById(id)) as AssetEntity; + + this.requireQuota(auth, file.size); + + await this.replaceFileData(existingAssetEntity.id, dto, file, sidecarFile?.originalPath); + + // Next, create a backup copy of the existing record. The db record has already been updated above, + // but the local variable holds the original file data paths. + const copiedPhoto = await this.createCopy(existingAssetEntity); + // and immediate trash it + await this.assetRepository.softDeleteAll([copiedPhoto.id]); + this.eventRepository.clientSend(ClientEvent.ASSET_TRASH, auth.user.id, [copiedPhoto.id]); + + await this.userRepository.updateUsage(auth.user.id, file.size); + + return { status: AssetMediaStatusEnum.REPLACED, id: copiedPhoto.id }; + } catch (error: any) { + return await this.handleUploadError(error, auth, file, sidecarFile); + } + } + + private async handleUploadError( + error: any, + auth: AuthDto, + file: UploadFile, + sidecarFile?: UploadFile, + ): Promise { + // clean up files + await this.jobRepository.queue({ + name: JobName.DELETE_FILES, + data: { files: [file.originalPath, sidecarFile?.originalPath] }, + }); + + // handle duplicates with a success response + if (error instanceof QueryFailedError && (error as any).constraint === ASSET_CHECKSUM_CONSTRAINT) { + const duplicateId = await this.assetRepository.getUploadAssetIdByChecksum(auth.user.id, file.checksum); + if (!duplicateId) { + this.logger.error(`Error locating duplicate for checksum constraint`); + throw new InternalServerErrorException(); + } + return { status: AssetMediaStatusEnum.DUPLICATE, id: duplicateId }; + } + + this.logger.error(`Error uploading file ${error}`, error?.stack); + throw error; + } + + /** + * Updates the specified assetId to the specified photo data file properties: checksum, path, + * timestamps, deviceIds, and sidecar. Derived properties like: faces, smart search info, etc + * are UNTOUCHED. The photo data files modification times on the filesysytem are updated to + * the specified timestamps. The exif db record is upserted, and then A METADATA_EXTRACTION + * job is queued to update these derived properties. + */ + private async replaceFileData( + assetId: string, + dto: AssetMediaReplaceDto, + file: UploadFile, + sidecarPath?: string, + ): Promise { + await this.assetRepository.update({ + id: assetId, + + checksum: file.checksum, + originalPath: file.originalPath, + type: mimeTypes.assetType(file.originalPath), + originalFileName: file.originalName, + + deviceAssetId: dto.deviceAssetId, + deviceId: dto.deviceId, + fileCreatedAt: dto.fileCreatedAt, + fileModifiedAt: dto.fileModifiedAt, + localDateTime: dto.fileCreatedAt, + duration: dto.duration || null, + + livePhotoVideo: null, + sidecarPath: sidecarPath || null, + }); + + await this.storageRepository.utimes(file.originalPath, new Date(), new Date(dto.fileModifiedAt)); + await this.assetRepository.upsertExif({ assetId, fileSizeInByte: file.size }); + await this.jobRepository.queue({ + name: JobName.METADATA_EXTRACTION, + data: { id: assetId, source: 'upload' }, + }); + } + + /** + * Create a 'shallow' copy of the specified asset record creating a new asset record in the database. + * Uses only vital properties excluding things like: stacks, faces, smart search info, etc, + * and then queues a METADATA_EXTRACTION job. + */ + private async createCopy(asset: AssetEntity): Promise { + const created = await this.assetRepository.create({ + ownerId: asset.ownerId, + originalPath: asset.originalPath, + originalFileName: asset.originalFileName, + libraryId: asset.libraryId, + deviceAssetId: asset.deviceAssetId, + deviceId: asset.deviceId, + type: asset.type, + checksum: asset.checksum, + fileCreatedAt: asset.fileCreatedAt, + localDateTime: asset.localDateTime, + fileModifiedAt: asset.fileModifiedAt, + livePhotoVideoId: asset.livePhotoVideoId, + sidecarPath: asset.sidecarPath, + }); + + const { size } = await this.storageRepository.stat(created.originalPath); + await this.assetRepository.upsertExif({ assetId: created.id, fileSizeInByte: size }); + await this.jobRepository.queue({ name: JobName.METADATA_EXTRACTION, data: { id: created.id, source: 'copy' } }); + return created; + } + + private requireQuota(auth: AuthDto, size: number) { + if (auth.user.quotaSizeInBytes && auth.user.quotaSizeInBytes < auth.user.quotaUsageInBytes + size) { + throw new BadRequestException('Quota has been exceeded!'); + } + } + + async checkExistingAssets( + auth: AuthDto, + checkExistingAssetsDto: CheckExistingAssetsDto, + ): Promise { + const assets = await this.assetRepository.getByDeviceIds( + auth.user.id, + checkExistingAssetsDto.deviceId, + checkExistingAssetsDto.deviceAssetIds, + ); + return { + existingIds: assets.map((asset) => asset.id), + }; + } + + async bulkUploadCheck(auth: AuthDto, dto: AssetBulkUploadCheckDto): Promise { + const checksums: Buffer[] = dto.assets.map((asset) => fromChecksum(asset.checksum)); + const results = await this.assetRepository.getByChecksums(auth.user.id, checksums); + const checksumMap: Record = {}; + + for (const { id, checksum } of results) { + checksumMap[checksum.toString('hex')] = id; + } + + return { + results: dto.assets.map(({ id, checksum }) => { + const duplicate = checksumMap[fromChecksum(checksum).toString('hex')]; + if (duplicate) { + return { + id, + assetId: duplicate, + action: AssetUploadAction.REJECT, + reason: AssetRejectReason.DUPLICATE, + }; + } + + // TODO mime-check + + return { + id, + action: AssetUploadAction.ACCEPT, + }; + }), + }; + } +} diff --git a/server/src/services/asset-v1.service.spec.ts b/server/src/services/asset-v1.service.spec.ts index 40211ee40a..b359bbf487 100644 --- a/server/src/services/asset-v1.service.spec.ts +++ b/server/src/services/asset-v1.service.spec.ts @@ -1,4 +1,3 @@ -import { AssetRejectReason, AssetUploadAction } from 'src/dtos/asset-v1-response.dto'; import { CreateAssetDto } from 'src/dtos/asset-v1.dto'; import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity, AssetType } from 'src/entities/asset.entity'; import { ExifEntity } from 'src/entities/exif.entity'; @@ -32,7 +31,6 @@ const _getCreateAssetDto = (): CreateAssetDto => { createAssetDto.isFavorite = false; createAssetDto.isArchived = false; createAssetDto.duration = '0:00:00.000000'; - createAssetDto.libraryId = 'libraryId'; return createAssetDto; }; @@ -75,10 +73,7 @@ describe('AssetService', () => { beforeEach(() => { assetRepositoryMockV1 = { get: vitest.fn(), - getAllByUserId: vitest.fn(), getAssetsByChecksums: vitest.fn(), - getExistingAssets: vitest.fn(), - getByOriginalPath: vitest.fn(), }; accessMock = newAccessRepositoryMock(); @@ -121,7 +116,6 @@ describe('AssetService', () => { const dto = _getCreateAssetDto(); assetMock.create.mockResolvedValue(assetEntity); - accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([dto.libraryId!])); await expect(sut.uploadFile(authStub.user1, dto, file)).resolves.toEqual({ duplicate: false, id: 'id_1' }); @@ -149,7 +143,6 @@ describe('AssetService', () => { assetMock.create.mockRejectedValue(error); assetRepositoryMockV1.getAssetsByChecksums.mockResolvedValue([_getAsset_1()]); - accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([dto.libraryId!])); await expect(sut.uploadFile(authStub.user1, dto, file)).resolves.toEqual({ duplicate: true, id: 'id_1' }); @@ -167,7 +160,6 @@ describe('AssetService', () => { assetMock.create.mockResolvedValueOnce(assetStub.livePhotoMotionAsset); assetMock.create.mockResolvedValueOnce(assetStub.livePhotoStillAsset); - accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([dto.libraryId!])); await expect( sut.uploadFile(authStub.user1, dto, fileStub.livePhotoStill, fileStub.livePhotoMotion), @@ -198,32 +190,4 @@ describe('AssetService', () => { ); }); }); - - describe('bulkUploadCheck', () => { - it('should accept hex and base64 checksums', async () => { - const file1 = Buffer.from('d2947b871a706081be194569951b7db246907957', 'hex'); - const file2 = Buffer.from('53be335e99f18a66ff12e9a901c7a6171dd76573', 'hex'); - - assetRepositoryMockV1.getAssetsByChecksums.mockResolvedValue([ - { id: 'asset-1', checksum: file1 }, - { id: 'asset-2', checksum: file2 }, - ]); - - await expect( - sut.bulkUploadCheck(authStub.admin, { - assets: [ - { id: '1', checksum: file1.toString('hex') }, - { id: '2', checksum: file2.toString('base64') }, - ], - }), - ).resolves.toEqual({ - results: [ - { id: '1', assetId: 'asset-1', action: AssetUploadAction.REJECT, reason: AssetRejectReason.DUPLICATE }, - { id: '2', assetId: 'asset-2', action: AssetUploadAction.REJECT, reason: AssetRejectReason.DUPLICATE }, - ], - }); - - expect(assetRepositoryMockV1.getAssetsByChecksums).toHaveBeenCalledWith(authStub.admin.user.id, [file1, file2]); - }); - }); }); diff --git a/server/src/services/asset-v1.service.ts b/server/src/services/asset-v1.service.ts index 9667730fb3..32841b0214 100644 --- a/server/src/services/asset-v1.service.ts +++ b/server/src/services/asset-v1.service.ts @@ -6,26 +6,10 @@ import { NotFoundException, } from '@nestjs/common'; import { AccessCore, Permission } from 'src/cores/access.core'; -import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; -import { - AssetBulkUploadCheckResponseDto, - AssetFileUploadResponseDto, - AssetRejectReason, - AssetUploadAction, - CheckExistingAssetsResponseDto, -} from 'src/dtos/asset-v1-response.dto'; -import { - AssetBulkUploadCheckDto, - AssetSearchDto, - CheckExistingAssetsDto, - CreateAssetDto, - GetAssetThumbnailDto, - GetAssetThumbnailFormatEnum, - ServeFileDto, -} from 'src/dtos/asset-v1.dto'; +import { AssetFileUploadResponseDto } from 'src/dtos/asset-v1-response.dto'; +import { CreateAssetDto, GetAssetThumbnailDto, GetAssetThumbnailFormatEnum, ServeFileDto } from 'src/dtos/asset-v1.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity, AssetType } from 'src/entities/asset.entity'; -import { LibraryType } from 'src/entities/library.entity'; import { IAccessRepository } from 'src/interfaces/access.interface'; import { IAssetRepositoryV1 } from 'src/interfaces/asset-v1.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface'; @@ -34,10 +18,9 @@ import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; -import { UploadFile } from 'src/services/asset.service'; +import { UploadFile } from 'src/services/asset-media.service'; import { CacheControl, ImmichFileResponse, getLivePhotoMotionFilename } from 'src/utils/file'; import { mimeTypes } from 'src/utils/mime-types'; -import { fromChecksum } from 'src/utils/request'; import { QueryFailedError } from 'typeorm'; @Injectable() @@ -76,15 +59,20 @@ export class AssetServiceV1 { let livePhotoAsset: AssetEntity | null = null; try { - const libraryId = await this.getLibraryId(auth, dto.libraryId); - await this.access.requirePermission(auth, Permission.ASSET_UPLOAD, libraryId); + await this.access.requirePermission( + auth, + Permission.ASSET_UPLOAD, + // do not need an id here, but the interface requires it + auth.user.id, + ); + this.requireQuota(auth, file.size); if (livePhotoFile) { - const livePhotoDto = { ...dto, assetType: AssetType.VIDEO, isVisible: false, libraryId }; + const livePhotoDto = { ...dto, assetType: AssetType.VIDEO, isVisible: false }; livePhotoAsset = await this.create(auth, livePhotoDto, livePhotoFile); } - const asset = await this.create(auth, { ...dto, libraryId }, file, livePhotoAsset?.id, sidecarFile?.originalPath); + const asset = await this.create(auth, dto, file, livePhotoAsset?.id, sidecarFile?.originalPath); await this.userRepository.updateUsage(auth.user.id, (livePhotoFile?.size || 0) + file.size); @@ -108,13 +96,6 @@ export class AssetServiceV1 { } } - public async getAllAssets(auth: AuthDto, dto: AssetSearchDto): Promise { - const userId = dto.userId || auth.user.id; - await this.access.requirePermission(auth, Permission.TIMELINE_READ, userId); - const assets = await this.assetRepositoryV1.getAllByUserId(userId, dto); - return assets.map((asset) => mapAsset(asset, { withStack: true, auth })); - } - async serveThumbnail(auth: AuthDto, assetId: string, dto: GetAssetThumbnailDto): Promise { await this.access.requirePermission(auth, Permission.ASSET_VIEW, assetId); @@ -155,46 +136,6 @@ export class AssetServiceV1 { }); } - async checkExistingAssets( - auth: AuthDto, - checkExistingAssetsDto: CheckExistingAssetsDto, - ): Promise { - return { - existingIds: await this.assetRepositoryV1.getExistingAssets(auth.user.id, checkExistingAssetsDto), - }; - } - - async bulkUploadCheck(auth: AuthDto, dto: AssetBulkUploadCheckDto): Promise { - const checksums: Buffer[] = dto.assets.map((asset) => fromChecksum(asset.checksum)); - const results = await this.assetRepositoryV1.getAssetsByChecksums(auth.user.id, checksums); - const checksumMap: Record = {}; - - for (const { id, checksum } of results) { - checksumMap[checksum.toString('hex')] = id; - } - - return { - results: dto.assets.map(({ id, checksum }) => { - const duplicate = checksumMap[fromChecksum(checksum).toString('hex')]; - if (duplicate) { - return { - id, - assetId: duplicate, - action: AssetUploadAction.REJECT, - reason: AssetRejectReason.DUPLICATE, - }; - } - - // TODO mime-check - - return { - id, - action: AssetUploadAction.ACCEPT, - }; - }), - }; - } - private getThumbnailPath(asset: AssetEntity, format: GetAssetThumbnailFormatEnum) { switch (format) { case GetAssetThumbnailFormatEnum.WEBP: { @@ -245,37 +186,16 @@ export class AssetServiceV1 { return asset.previewPath; } - private async getLibraryId(auth: AuthDto, libraryId?: string) { - if (libraryId) { - return libraryId; - } - - let library = await this.libraryRepository.getDefaultUploadLibrary(auth.user.id); - if (!library) { - library = await this.libraryRepository.create({ - ownerId: auth.user.id, - name: 'Default Library', - assets: [], - type: LibraryType.UPLOAD, - importPaths: [], - exclusionPatterns: [], - isVisible: true, - }); - } - - return library.id; - } - private async create( auth: AuthDto, - dto: CreateAssetDto & { libraryId: string }, + dto: CreateAssetDto, file: UploadFile, livePhotoAssetId?: string, sidecarPath?: string, ): Promise { const asset = await this.assetRepository.create({ ownerId: auth.user.id, - libraryId: dto.libraryId, + libraryId: null, checksum: file.checksum, originalPath: file.originalPath, diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts index 5a61f70da8..ca13adf31c 100755 --- a/server/src/services/asset.service.spec.ts +++ b/server/src/services/asset.service.spec.ts @@ -2,6 +2,7 @@ import { BadRequestException, UnauthorizedException } from '@nestjs/common'; import { mapAsset } from 'src/dtos/asset-response.dto'; import { AssetJobName, AssetStatsResponseDto, UploadFieldName } from 'src/dtos/asset.dto'; import { AssetEntity, AssetType } from 'src/entities/asset.entity'; +import { IAlbumRepository } from 'src/interfaces/album.interface'; import { IAssetStackRepository } from 'src/interfaces/asset-stack.interface'; import { AssetStats, IAssetRepository } from 'src/interfaces/asset.interface'; import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface'; @@ -9,7 +10,7 @@ import { IJobRepository, JobName } from 'src/interfaces/job.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { AssetService } from 'src/services/asset.service'; import { assetStackStub, assetStub } from 'test/fixtures/asset.stub'; @@ -18,6 +19,7 @@ import { faceStub } from 'test/fixtures/face.stub'; import { partnerStub } from 'test/fixtures/partner.stub'; import { userStub } from 'test/fixtures/user.stub'; import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock'; +import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock'; import { newAssetStackRepositoryMock } from 'test/repositories/asset-stack.repository.mock'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; @@ -25,7 +27,7 @@ import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; import { Mocked, vitest } from 'vitest'; @@ -157,9 +159,10 @@ describe(AssetService.name, () => { let storageMock: Mocked; let userMock: Mocked; let eventMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let partnerMock: Mocked; let assetStackMock: Mocked; + let albumMock: Mocked; let loggerMock: Mocked; it('should work', () => { @@ -179,21 +182,23 @@ describe(AssetService.name, () => { jobMock = newJobRepositoryMock(); storageMock = newStorageRepositoryMock(); userMock = newUserRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); partnerMock = newPartnerRepositoryMock(); assetStackMock = newAssetStackRepositoryMock(); + albumMock = newAlbumRepositoryMock(); loggerMock = newLoggerRepositoryMock(); sut = new AssetService( accessMock, assetMock, jobMock, - configMock, + systemMock, storageMock, userMock, eventMock, partnerMock, assetStackMock, + albumMock, loggerMock, ); diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index 5e3cec27a7..9fdba64b1d 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -27,8 +27,8 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { MapMarkerDto, MapMarkerResponseDto, MemoryLaneDto } from 'src/dtos/search.dto'; import { UpdateStackParentDto } from 'src/dtos/stack.dto'; import { AssetEntity } from 'src/entities/asset.entity'; -import { LibraryType } from 'src/entities/library.entity'; import { IAccessRepository } from 'src/interfaces/access.interface'; +import { IAlbumRepository } from 'src/interfaces/album.interface'; import { IAssetStackRepository } from 'src/interfaces/asset-stack.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface'; @@ -44,26 +44,13 @@ import { import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; +import { UploadRequest } from 'src/services/asset-media.service'; import { mimeTypes } from 'src/utils/mime-types'; import { usePagination } from 'src/utils/pagination'; import { fromChecksum } from 'src/utils/request'; -export interface UploadRequest { - auth: AuthDto | null; - fieldName: UploadFieldName; - file: UploadFile; -} - -export interface UploadFile { - uuid: string; - checksum: Buffer; - originalPath: string; - originalName: string; - size: number; -} - export class AssetService { private access: AccessCore; private configCore: SystemConfigCore; @@ -72,17 +59,18 @@ export class AssetService { @Inject(IAccessRepository) accessRepository: IAccessRepository, @Inject(IAssetRepository) private assetRepository: IAssetRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IUserRepository) private userRepository: IUserRepository, @Inject(IEventRepository) private eventRepository: IEventRepository, @Inject(IPartnerRepository) private partnerRepository: IPartnerRepository, @Inject(IAssetStackRepository) private assetStackRepository: IAssetStackRepository, + @Inject(IAlbumRepository) private albumRepository: IAlbumRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(AssetService.name); this.access = AccessCore.create(accessRepository); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); } async getUploadAssetIdByChecksum(auth: AuthDto, checksum?: string): Promise { @@ -167,6 +155,7 @@ export class AssetService { async getMapMarkers(auth: AuthDto, options: MapMarkerDto): Promise { const userIds: string[] = [auth.user.id]; + // TODO convert to SQL join if (options.withPartners) { const partners = await this.partnerRepository.getAll(auth.user.id); const partnersIds = partners @@ -174,7 +163,18 @@ export class AssetService { .map((partner) => partner.sharedById); userIds.push(...partnersIds); } - return this.assetRepository.getMapMarkers(userIds, options); + + // TODO convert to SQL join + const albumIds: string[] = []; + if (options.withSharedAlbums) { + const [ownedAlbums, sharedAlbums] = await Promise.all([ + this.albumRepository.getOwned(auth.user.id), + this.albumRepository.getShared(auth.user.id), + ]); + albumIds.push(...ownedAlbums.map((album) => album.id), ...sharedAlbums.map((album) => album.id)); + } + + return this.assetRepository.getMapMarkers(userIds, albumIds, options); } async getMemoryLane(auth: AuthDto, dto: MemoryLaneDto): Promise { @@ -410,7 +410,7 @@ export class AssetService { } await this.assetRepository.remove(asset); - if (asset.library.type === LibraryType.UPLOAD) { + if (!asset.libraryId) { await this.userRepository.updateUsage(asset.ownerId, -(asset.exifInfo?.fileSizeInByte || 0)); } this.eventRepository.clientSend(ClientEvent.ASSET_DELETE, asset.ownerId, id); @@ -420,12 +420,13 @@ export class AssetService { await this.jobRepository.queue({ name: JobName.ASSET_DELETION, data: { id: asset.livePhotoVideoId } }); } - await this.jobRepository.queue({ - name: JobName.DELETE_FILES, - data: { - files: [asset.thumbnailPath, asset.previewPath, asset.encodedVideoPath, asset.sidecarPath, asset.originalPath], - }, - }); + const files = [asset.thumbnailPath, asset.previewPath, asset.encodedVideoPath]; + // skip originals if the user deleted the whole library + if (!asset.library?.deletedAt) { + files.push(asset.sidecarPath, asset.originalPath); + } + + await this.jobRepository.queue({ name: JobName.DELETE_FILES, data: { files } }); return JobStatus.SUCCESS; } diff --git a/server/src/services/auth.service.spec.ts b/server/src/services/auth.service.spec.ts index f00e10b13c..aef0f04668 100644 --- a/server/src/services/auth.service.spec.ts +++ b/server/src/services/auth.service.spec.ts @@ -4,14 +4,14 @@ import { Issuer, generators } from 'openid-client'; import { Socket } from 'socket.io'; import { AuthType } from 'src/constants'; import { AuthDto, SignUpDto } from 'src/dtos/auth.dto'; +import { UserMetadataEntity } from 'src/entities/user-metadata.entity'; import { UserEntity } from 'src/entities/user.entity'; import { IKeyRepository } from 'src/interfaces/api-key.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; -import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ISessionRepository } from 'src/interfaces/session.interface'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { AuthService } from 'src/services/auth.service'; import { keyStub } from 'test/fixtures/api-key.stub'; @@ -20,14 +20,12 @@ import { sessionStub } from 'test/fixtures/session.stub'; import { sharedLinkStub } from 'test/fixtures/shared-link.stub'; import { systemConfigStub } from 'test/fixtures/system-config.stub'; import { userStub } from 'test/fixtures/user.stub'; -import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock'; import { newKeyRepositoryMock } from 'test/repositories/api-key.repository.mock'; import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; -import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newSessionRepositoryMock } from 'test/repositories/session.repository.mock'; import { newSharedLinkRepositoryMock } from 'test/repositories/shared-link.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; import { Mock, Mocked, vitest } from 'vitest'; @@ -59,12 +57,10 @@ const oauthUserWithDefaultQuota = { describe('AuthService', () => { let sut: AuthService; - let accessMock: Mocked; let cryptoMock: Mocked; let userMock: Mocked; - let libraryMock: Mocked; let loggerMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let sessionMock: Mocked; let shareMock: Mocked; let keyMock: Mocked; @@ -92,27 +88,15 @@ describe('AuthService', () => { }), } as any); - accessMock = newAccessRepositoryMock(); cryptoMock = newCryptoRepositoryMock(); userMock = newUserRepositoryMock(); - libraryMock = newLibraryRepositoryMock(); loggerMock = newLoggerRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); sessionMock = newSessionRepositoryMock(); shareMock = newSharedLinkRepositoryMock(); keyMock = newKeyRepositoryMock(); - sut = new AuthService( - accessMock, - cryptoMock, - configMock, - libraryMock, - loggerMock, - userMock, - sessionMock, - shareMock, - keyMock, - ); + sut = new AuthService(cryptoMock, systemMock, loggerMock, userMock, sessionMock, shareMock, keyMock); }); it('should be defined', () => { @@ -121,7 +105,7 @@ describe('AuthService', () => { describe('login', () => { it('should throw an error if password login is disabled', async () => { - configMock.load.mockResolvedValue(systemConfigStub.disabled); + systemMock.get.mockResolvedValue(systemConfigStub.disabled); await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(UnauthorizedException); }); @@ -199,7 +183,7 @@ describe('AuthService', () => { describe('logout', () => { it('should return the end session endpoint', async () => { - configMock.load.mockResolvedValue(systemConfigStub.enabled); + systemMock.get.mockResolvedValue(systemConfigStub.enabled); const auth = { user: { id: '123' } } as AuthDto; await expect(sut.logout(auth, AuthType.OAUTH)).resolves.toEqual({ successful: true, @@ -248,8 +232,13 @@ describe('AuthService', () => { it('should sign up the admin', async () => { userMock.getAdmin.mockResolvedValue(null); - userMock.create.mockResolvedValue({ ...dto, id: 'admin', createdAt: new Date('2021-01-01') } as UserEntity); - await expect(sut.adminSignUp(dto)).resolves.toEqual({ + userMock.create.mockResolvedValue({ + ...dto, + id: 'admin', + createdAt: new Date('2021-01-01'), + metadata: [] as UserMetadataEntity[], + } as UserEntity); + await expect(sut.adminSignUp(dto)).resolves.toMatchObject({ avatarColor: expect.any(String), id: 'admin', createdAt: new Date('2021-01-01'), @@ -377,7 +366,7 @@ describe('AuthService', () => { }); it('should not allow auto registering', async () => { - configMock.load.mockResolvedValue(systemConfigStub.noAutoRegister); + systemMock.get.mockResolvedValue(systemConfigStub.oauthEnabled); userMock.getByEmail.mockResolvedValue(null); await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).rejects.toBeInstanceOf( BadRequestException, @@ -386,7 +375,7 @@ describe('AuthService', () => { }); it('should link an existing user', async () => { - configMock.load.mockResolvedValue(systemConfigStub.noAutoRegister); + systemMock.get.mockResolvedValue(systemConfigStub.oauthEnabled); userMock.getByEmail.mockResolvedValue(userStub.user1); userMock.update.mockResolvedValue(userStub.user1); sessionMock.create.mockResolvedValue(sessionStub.valid); @@ -399,8 +388,22 @@ describe('AuthService', () => { expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { oauthId: sub }); }); + it('should not link to a user with a different oauth sub', async () => { + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithAutoRegister); + userMock.getByEmail.mockResolvedValueOnce({ ...userStub.user1, oauthId: 'existing-sub' }); + userMock.getAdmin.mockResolvedValue(userStub.user1); + userMock.create.mockResolvedValue(userStub.user1); + + await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).resolves.toEqual( + loginResponseStub.user1oauth, + ); + + expect(userMock.update).not.toHaveBeenCalled(); + expect(userMock.create).toHaveBeenCalled(); + }); + it('should allow auto registering by default', async () => { - configMock.load.mockResolvedValue(systemConfigStub.enabled); + systemMock.get.mockResolvedValue(systemConfigStub.enabled); userMock.getByEmail.mockResolvedValue(null); userMock.getAdmin.mockResolvedValue(userStub.user1); userMock.create.mockResolvedValue(userStub.user1); @@ -415,7 +418,7 @@ describe('AuthService', () => { }); it('should use the mobile redirect override', async () => { - configMock.load.mockResolvedValue(systemConfigStub.override); + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithMobileOverride); userMock.getByOAuthId.mockResolvedValue(userStub.user1); sessionMock.create.mockResolvedValue(sessionStub.valid); @@ -425,7 +428,7 @@ describe('AuthService', () => { }); it('should use the mobile redirect override for ios urls with multiple slashes', async () => { - configMock.load.mockResolvedValue(systemConfigStub.override); + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithMobileOverride); userMock.getByOAuthId.mockResolvedValue(userStub.user1); sessionMock.create.mockResolvedValue(sessionStub.valid); @@ -435,7 +438,7 @@ describe('AuthService', () => { }); it('should use the default quota', async () => { - configMock.load.mockResolvedValue(systemConfigStub.withDefaultStorageQuota); + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); userMock.getByEmail.mockResolvedValue(null); userMock.getAdmin.mockResolvedValue(userStub.user1); userMock.create.mockResolvedValue(userStub.user1); @@ -448,7 +451,7 @@ describe('AuthService', () => { }); it('should ignore an invalid storage quota', async () => { - configMock.load.mockResolvedValue(systemConfigStub.withDefaultStorageQuota); + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); userMock.getByEmail.mockResolvedValue(null); userMock.getAdmin.mockResolvedValue(userStub.user1); userMock.create.mockResolvedValue(userStub.user1); @@ -462,7 +465,7 @@ describe('AuthService', () => { }); it('should ignore a negative quota', async () => { - configMock.load.mockResolvedValue(systemConfigStub.withDefaultStorageQuota); + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); userMock.getByEmail.mockResolvedValue(null); userMock.getAdmin.mockResolvedValue(userStub.user1); userMock.create.mockResolvedValue(userStub.user1); @@ -476,7 +479,7 @@ describe('AuthService', () => { }); it('should not set quota for 0 quota', async () => { - configMock.load.mockResolvedValue(systemConfigStub.withDefaultStorageQuota); + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); userMock.getByEmail.mockResolvedValue(null); userMock.getAdmin.mockResolvedValue(userStub.user1); userMock.create.mockResolvedValue(userStub.user1); @@ -496,7 +499,7 @@ describe('AuthService', () => { }); it('should use a valid storage quota', async () => { - configMock.load.mockResolvedValue(systemConfigStub.withDefaultStorageQuota); + systemMock.get.mockResolvedValue(systemConfigStub.oauthWithStorageQuota); userMock.getByEmail.mockResolvedValue(null); userMock.getAdmin.mockResolvedValue(userStub.user1); userMock.create.mockResolvedValue(userStub.user1); @@ -518,7 +521,7 @@ describe('AuthService', () => { describe('link', () => { it('should link an account', async () => { - configMock.load.mockResolvedValue(systemConfigStub.enabled); + systemMock.get.mockResolvedValue(systemConfigStub.enabled); userMock.update.mockResolvedValue(userStub.user1); await sut.link(authStub.user1, { url: 'http://immich/user-settings?code=abc123' }); @@ -527,7 +530,7 @@ describe('AuthService', () => { }); it('should not link an already linked oauth.sub', async () => { - configMock.load.mockResolvedValue(systemConfigStub.enabled); + systemMock.get.mockResolvedValue(systemConfigStub.enabled); userMock.getByOAuthId.mockResolvedValue({ id: 'other-user' } as UserEntity); await expect(sut.link(authStub.user1, { url: 'http://immich/user-settings?code=abc123' })).rejects.toBeInstanceOf( @@ -540,7 +543,7 @@ describe('AuthService', () => { describe('unlink', () => { it('should unlink an account', async () => { - configMock.load.mockResolvedValue(systemConfigStub.enabled); + systemMock.get.mockResolvedValue(systemConfigStub.enabled); userMock.update.mockResolvedValue(userStub.user1); await sut.unlink(authStub.user1); diff --git a/server/src/services/auth.service.ts b/server/src/services/auth.service.ts index b2c524decd..5e61cad187 100644 --- a/server/src/services/auth.service.ts +++ b/server/src/services/auth.service.ts @@ -10,8 +10,8 @@ import cookieParser from 'cookie'; import { DateTime } from 'luxon'; import { IncomingHttpHeaders } from 'node:http'; import { ClientMetadata, Issuer, UserinfoResponse, custom, generators } from 'openid-client'; +import { SystemConfig } from 'src/config'; import { AuthType, LOGIN_URL, MOBILE_REDIRECT } from 'src/constants'; -import { AccessCore } from 'src/cores/access.core'; import { SystemConfigCore } from 'src/cores/system-config.core'; import { UserCore } from 'src/cores/user.core'; import { @@ -28,16 +28,13 @@ import { mapLoginResponse, } from 'src/dtos/auth.dto'; import { UserResponseDto, mapUser } from 'src/dtos/user.dto'; -import { SystemConfig } from 'src/entities/system-config.entity'; import { UserEntity } from 'src/entities/user.entity'; -import { IAccessRepository } from 'src/interfaces/access.interface'; import { IKeyRepository } from 'src/interfaces/api-key.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; -import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ISessionRepository } from 'src/interfaces/session.interface'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { HumanReadableSize } from 'src/utils/bytes'; @@ -60,15 +57,12 @@ interface ClaimOptions { @Injectable() export class AuthService { - private access: AccessCore; private configCore: SystemConfigCore; private userCore: UserCore; constructor( - @Inject(IAccessRepository) accessRepository: IAccessRepository, @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, - @Inject(ILibraryRepository) libraryRepository: ILibraryRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, @Inject(IUserRepository) private userRepository: IUserRepository, @Inject(ISessionRepository) private sessionRepository: ISessionRepository, @@ -76,9 +70,8 @@ export class AuthService { @Inject(IKeyRepository) private keyRepository: IKeyRepository, ) { this.logger.setContext(AuthService.name); - this.access = AccessCore.create(accessRepository); - this.configCore = SystemConfigCore.create(configRepository, logger); - this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository); + this.configCore = SystemConfigCore.create(systemMetadataRepository, logger); + this.userCore = UserCore.create(cryptoRepository, userRepository); custom.setHttpOptionsDefaults({ timeout: 30_000 }); } @@ -201,7 +194,7 @@ export class AuthService { // link existing user if (!user) { const emailUser = await this.userRepository.getByEmail(profile.email); - if (emailUser) { + if (emailUser && !emailUser.oauthId) { user = await this.userRepository.update(emailUser.id, { oauthId: profile.sub }); } } diff --git a/server/src/services/cli.service.spec.ts b/server/src/services/cli.service.spec.ts new file mode 100644 index 0000000000..e52c648664 --- /dev/null +++ b/server/src/services/cli.service.spec.ts @@ -0,0 +1,68 @@ +import { ICryptoRepository } from 'src/interfaces/crypto.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { IUserRepository } from 'src/interfaces/user.interface'; +import { CliService } from 'src/services/cli.service'; +import { userStub } from 'test/fixtures/user.stub'; +import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; +import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; +import { Mocked, describe, it } from 'vitest'; + +describe(CliService.name, () => { + let sut: CliService; + + let userMock: Mocked; + let cryptoMock: Mocked; + let systemMock: Mocked; + let loggerMock: Mocked; + + beforeEach(() => { + cryptoMock = newCryptoRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); + userMock = newUserRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); + + sut = new CliService(cryptoMock, systemMock, userMock, loggerMock); + }); + + describe('resetAdminPassword', () => { + it('should only work when there is an admin account', async () => { + userMock.getAdmin.mockResolvedValue(null); + const ask = vitest.fn().mockResolvedValue('new-password'); + + await expect(sut.resetAdminPassword(ask)).rejects.toThrowError('Admin account does not exist'); + + expect(ask).not.toHaveBeenCalled(); + }); + + it('should default to a random password', async () => { + userMock.getAdmin.mockResolvedValue(userStub.admin); + const ask = vitest.fn().mockImplementation(() => {}); + + const response = await sut.resetAdminPassword(ask); + + const [id, update] = userMock.update.mock.calls[0]; + + expect(response.provided).toBe(false); + expect(ask).toHaveBeenCalled(); + expect(id).toEqual(userStub.admin.id); + expect(update.password).toBeDefined(); + }); + + it('should use the supplied password', async () => { + userMock.getAdmin.mockResolvedValue(userStub.admin); + const ask = vitest.fn().mockResolvedValue('new-password'); + + const response = await sut.resetAdminPassword(ask); + + const [id, update] = userMock.update.mock.calls[0]; + + expect(response.provided).toBe(true); + expect(ask).toHaveBeenCalled(); + expect(id).toEqual(userStub.admin.id); + expect(update.password).toBeDefined(); + }); + }); +}); diff --git a/server/src/services/cli.service.ts b/server/src/services/cli.service.ts new file mode 100644 index 0000000000..459dde1888 --- /dev/null +++ b/server/src/services/cli.service.ts @@ -0,0 +1,68 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { SystemConfigCore } from 'src/cores/system-config.core'; +import { UserCore } from 'src/cores/user.core'; +import { UserResponseDto, mapUser } from 'src/dtos/user.dto'; +import { ICryptoRepository } from 'src/interfaces/crypto.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { IUserRepository } from 'src/interfaces/user.interface'; + +@Injectable() +export class CliService { + private configCore: SystemConfigCore; + private userCore: UserCore; + + constructor( + @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, + @Inject(IUserRepository) private userRepository: IUserRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.userCore = UserCore.create(cryptoRepository, userRepository); + this.logger.setContext(CliService.name); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); + } + + async listUsers(): Promise { + const users = await this.userRepository.getList({ withDeleted: true }); + return users.map((user) => mapUser(user)); + } + + async resetAdminPassword(ask: (admin: UserResponseDto) => Promise) { + const admin = await this.userRepository.getAdmin(); + if (!admin) { + throw new Error('Admin account does not exist'); + } + + const providedPassword = await ask(mapUser(admin)); + const password = providedPassword || this.cryptoRepository.newPassword(24); + + await this.userCore.updateUser(admin, admin.id, { password }); + + return { admin, password, provided: !!providedPassword }; + } + + async disablePasswordLogin(): Promise { + const config = await this.configCore.getConfig(); + config.passwordLogin.enabled = false; + await this.configCore.updateConfig(config); + } + + async enablePasswordLogin(): Promise { + const config = await this.configCore.getConfig(); + config.passwordLogin.enabled = true; + await this.configCore.updateConfig(config); + } + + async disableOAuthLogin(): Promise { + const config = await this.configCore.getConfig(); + config.oauth.enabled = false; + await this.configCore.updateConfig(config); + } + + async enableOAuthLogin(): Promise { + const config = await this.configCore.getConfig(); + config.oauth.enabled = true; + await this.configCore.updateConfig(config); + } +} diff --git a/server/src/services/database.service.spec.ts b/server/src/services/database.service.spec.ts index 778422c1bb..814325ef45 100644 --- a/server/src/services/database.service.spec.ts +++ b/server/src/services/database.service.spec.ts @@ -1,7 +1,6 @@ -import { DatabaseExtension, IDatabaseRepository, VectorIndex } from 'src/interfaces/database.interface'; +import { DatabaseExtension, IDatabaseRepository } from 'src/interfaces/database.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { DatabaseService } from 'src/services/database.service'; -import { Version, VersionType } from 'src/utils/version'; import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { Mocked } from 'vitest'; @@ -13,137 +12,174 @@ describe(DatabaseService.name, () => { beforeEach(() => { delete process.env.DB_SKIP_MIGRATIONS; + delete process.env.DB_VECTOR_EXTENSION; databaseMock = newDatabaseRepositoryMock(); loggerMock = newLoggerRepositoryMock(); sut = new DatabaseService(databaseMock, loggerMock); + + databaseMock.getExtensionVersion.mockResolvedValue('0.2.0'); }); it('should work', () => { expect(sut).toBeDefined(); }); - describe.each([ - [{ vectorExt: DatabaseExtension.VECTORS, extName: 'pgvecto.rs', minVersion: new Version(0, 1, 1) }], - [{ vectorExt: DatabaseExtension.VECTOR, extName: 'pgvector', minVersion: new Version(0, 5, 0) }], - ] as const)('init', ({ vectorExt, extName, minVersion }) => { - beforeEach(() => { - databaseMock.getPreferredVectorExtension.mockReturnValue(vectorExt); - databaseMock.getExtensionVersion.mockResolvedValue(minVersion); + it('should throw an error if PostgreSQL version is below minimum supported version', async () => { + databaseMock.getPostgresVersion.mockResolvedValueOnce('13.10.0'); - sut = new DatabaseService(databaseMock, loggerMock); + await expect(sut.init()).rejects.toThrow('Invalid PostgreSQL version. Found 13.10.0'); - sut.minVectorVersion = minVersion; - sut.minVectorsVersion = minVersion; - sut.vectorVersionPin = VersionType.MINOR; - sut.vectorsVersionPin = VersionType.MINOR; - }); + expect(databaseMock.getPostgresVersion).toHaveBeenCalledTimes(1); + }); - it(`should resolve successfully if minimum supported PostgreSQL and ${extName} version are installed`, async () => { - databaseMock.getPostgresVersion.mockResolvedValueOnce(new Version(14, 0, 0)); + it(`should start up successfully with pgvectors`, async () => { + databaseMock.getPostgresVersion.mockResolvedValue('14.0.0'); + + await expect(sut.init()).resolves.toBeUndefined(); + + expect(databaseMock.getPostgresVersion).toHaveBeenCalled(); + expect(databaseMock.createExtension).toHaveBeenCalledWith(DatabaseExtension.VECTORS); + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.getExtensionVersion).toHaveBeenCalled(); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + }); + + it(`should start up successfully with pgvector`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getPostgresVersion.mockResolvedValue('14.0.0'); + databaseMock.getExtensionVersion.mockResolvedValue('0.5.0'); + + await expect(sut.init()).resolves.toBeUndefined(); + + expect(databaseMock.createExtension).toHaveBeenCalledWith(DatabaseExtension.VECTOR); + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + }); + + it(`should throw an error if the pgvecto.rs extension is not installed`, async () => { + databaseMock.getExtensionVersion.mockResolvedValue(''); + await expect(sut.init()).rejects.toThrow(`Unexpected: The pgvecto.rs extension is not installed.`); + + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + it(`should throw an error if the pgvector extension is not installed`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getExtensionVersion.mockResolvedValue(''); + await expect(sut.init()).rejects.toThrow(`Unexpected: The pgvector extension is not installed.`); + + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + it(`should throw an error if the pgvecto.rs extension version is below minimum supported version`, async () => { + databaseMock.getExtensionVersion.mockResolvedValue('0.1.0'); + + await expect(sut.init()).rejects.toThrow( + 'The pgvecto.rs extension version is 0.1.0, but Immich only supports 0.2.x.', + ); + + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + it(`should throw an error if the pgvector extension version is below minimum supported version`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getExtensionVersion.mockResolvedValue('0.1.0'); + + await expect(sut.init()).rejects.toThrow( + 'The pgvector extension version is 0.1.0, but Immich only supports >=0.5 <1', + ); + + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + it(`should throw an error if pgvecto.rs extension version is a nightly`, async () => { + databaseMock.getExtensionVersion.mockResolvedValue('0.0.0'); + + await expect(sut.init()).rejects.toThrow( + 'The pgvecto.rs extension version is 0.0.0, which means it is a nightly release.', + ); + + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + it(`should throw an error if pgvector extension version is a nightly`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getExtensionVersion.mockResolvedValue('0.0.0'); + + await expect(sut.init()).rejects.toThrow( + 'The pgvector extension version is 0.0.0, which means it is a nightly release.', + ); + + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + it(`should throw error if pgvecto.rs extension could not be created`, async () => { + databaseMock.createExtension.mockRejectedValue(new Error('Failed to create extension')); + + await expect(sut.init()).rejects.toThrow('Failed to create extension'); + + expect(loggerMock.fatal).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal.mock.calls[0][0]).toContain( + 'Alternatively, if your Postgres instance has pgvector, you may use this instead', + ); + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + it(`should throw error if pgvector extension could not be created`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getExtensionVersion.mockResolvedValue('0.0.0'); + databaseMock.createExtension.mockRejectedValue(new Error('Failed to create extension')); + + await expect(sut.init()).rejects.toThrow('Failed to create extension'); + + expect(loggerMock.fatal).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal.mock.calls[0][0]).toContain( + 'Alternatively, if your Postgres instance has pgvecto.rs, you may use this instead', + ); + expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); + }); + + for (const version of ['0.2.1', '0.2.0', '0.2.9']) { + it(`should update the pgvecto.rs extension to ${version}`, async () => { + databaseMock.getAvailableExtensionVersion.mockResolvedValue(version); + databaseMock.getExtensionVersion.mockResolvedValue(version); await expect(sut.init()).resolves.toBeUndefined(); - expect(databaseMock.getPostgresVersion).toHaveBeenCalled(); - expect(databaseMock.createExtension).toHaveBeenCalledWith(vectorExt); - expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith('vectors', version); + expect(databaseMock.updateVectorExtension).toHaveBeenCalledTimes(1); expect(databaseMock.getExtensionVersion).toHaveBeenCalled(); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); expect(loggerMock.fatal).not.toHaveBeenCalled(); }); + } - it('should throw an error if PostgreSQL version is below minimum supported version', async () => { - databaseMock.getPostgresVersion.mockResolvedValueOnce(new Version(13, 0, 0)); - - await expect(sut.init()).rejects.toThrow('PostgreSQL version is 13'); - - expect(databaseMock.getPostgresVersion).toHaveBeenCalledTimes(1); - }); - - it(`should resolve successfully if minimum supported ${extName} version is installed`, async () => { - await expect(sut.init()).resolves.toBeUndefined(); - - expect(databaseMock.createExtension).toHaveBeenCalledWith(vectorExt); - expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); - expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(loggerMock.fatal).not.toHaveBeenCalled(); - }); - - it(`should throw an error if ${extName} version is not installed even after createVectorExtension`, async () => { - databaseMock.getExtensionVersion.mockResolvedValue(null); - - await expect(sut.init()).rejects.toThrow(`Unexpected: ${extName} extension is not installed.`); - - expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); - expect(databaseMock.runMigrations).not.toHaveBeenCalled(); - }); - - it(`should throw an error if ${extName} version is below minimum supported version`, async () => { - databaseMock.getExtensionVersion.mockResolvedValue( - new Version(minVersion.major, minVersion.minor - 1, minVersion.patch), - ); - - await expect(sut.init()).rejects.toThrow(extName); - - expect(databaseMock.runMigrations).not.toHaveBeenCalled(); - }); - - it.each([ - { type: VersionType.EQUAL, max: 'no', actual: 'patch' }, - { type: VersionType.PATCH, max: 'patch', actual: 'minor' }, - { type: VersionType.MINOR, max: 'minor', actual: 'major' }, - ] as const)( - `should throw an error if $max upgrade from min version is allowed and ${extName} version is $actual`, - async ({ type, actual }) => { - const version = new Version(minVersion.major, minVersion.minor, minVersion.patch); - version[actual] = minVersion[actual] + 1; - databaseMock.getExtensionVersion.mockResolvedValue(version); - if (vectorExt === DatabaseExtension.VECTOR) { - sut.minVectorVersion = minVersion; - sut.vectorVersionPin = type; - } else { - sut.minVectorsVersion = minVersion; - sut.vectorsVersionPin = type; - } - - await expect(sut.init()).rejects.toThrow(extName); - - expect(databaseMock.runMigrations).not.toHaveBeenCalled(); - }, - ); - - it(`should throw an error if ${extName} version is a nightly`, async () => { - databaseMock.getExtensionVersion.mockResolvedValue(new Version(0, 0, 0)); - - await expect(sut.init()).rejects.toThrow(extName); - - expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); - expect(databaseMock.runMigrations).not.toHaveBeenCalled(); - }); - - it(`should throw error if ${extName} extension could not be created`, async () => { - databaseMock.createExtension.mockRejectedValue(new Error('Failed to create extension')); - - await expect(sut.init()).rejects.toThrow('Failed to create extension'); - - expect(loggerMock.fatal).toHaveBeenCalledTimes(1); - expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); - expect(databaseMock.runMigrations).not.toHaveBeenCalled(); - }); - - it(`should update ${extName} if a newer version is available`, async () => { - const version = new Version(minVersion.major, minVersion.minor + 1, minVersion.patch); + for (const version of ['0.5.1', '0.6.0', '0.7.10']) { + it(`should update the pgvectors extension to ${version}`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; databaseMock.getAvailableExtensionVersion.mockResolvedValue(version); + databaseMock.getExtensionVersion.mockResolvedValue(version); await expect(sut.init()).resolves.toBeUndefined(); - expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version); + expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith('vector', version); expect(databaseMock.updateVectorExtension).toHaveBeenCalledTimes(1); + expect(databaseMock.getExtensionVersion).toHaveBeenCalled(); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); expect(loggerMock.fatal).not.toHaveBeenCalled(); }); + } - it(`should not update ${extName} if a newer version is higher than the maximum`, async () => { - const version = new Version(minVersion.major + 1, minVersion.minor, minVersion.patch); + for (const version of ['0.1.0', '0.3.0', '1.0.0']) { + it(`should not upgrade pgvecto.rs to ${version}`, async () => { databaseMock.getAvailableExtensionVersion.mockResolvedValue(version); await expect(sut.init()).resolves.toBeUndefined(); @@ -152,72 +188,106 @@ describe(DatabaseService.name, () => { expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); expect(loggerMock.fatal).not.toHaveBeenCalled(); }); + } - it(`should warn if attempted to update ${extName} and failed`, async () => { - const version = new Version(minVersion.major, minVersion.minor, minVersion.patch + 1); + for (const version of ['0.4.0', '1.0.0']) { + it(`should not upgrade pgvector to ${version}`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getExtensionVersion.mockResolvedValue('0.5.0'); databaseMock.getAvailableExtensionVersion.mockResolvedValue(version); - databaseMock.updateVectorExtension.mockRejectedValue(new Error('Failed to update extension')); await expect(sut.init()).resolves.toBeUndefined(); - expect(loggerMock.warn).toHaveBeenCalledTimes(1); - expect(loggerMock.warn.mock.calls[0][0]).toContain(extName); - expect(loggerMock.error).toHaveBeenCalledTimes(1); - expect(loggerMock.fatal).not.toHaveBeenCalled(); - expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version); - expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - }); - - it(`should warn if ${extName} update requires restart`, async () => { - const version = new Version(minVersion.major, minVersion.minor, minVersion.patch + 1); - databaseMock.getAvailableExtensionVersion.mockResolvedValue(version); - databaseMock.updateVectorExtension.mockResolvedValue({ restartRequired: true }); - - await expect(sut.init()).resolves.toBeUndefined(); - - expect(loggerMock.warn).toHaveBeenCalledTimes(1); - expect(loggerMock.warn.mock.calls[0][0]).toContain(extName); - expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version); + expect(databaseMock.updateVectorExtension).not.toHaveBeenCalled(); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); expect(loggerMock.fatal).not.toHaveBeenCalled(); }); + } - it.each([{ index: VectorIndex.CLIP }, { index: VectorIndex.FACE }])( - `should reindex $index if necessary`, - async ({ index }) => { - databaseMock.shouldReindex.mockImplementation((indexArg) => Promise.resolve(indexArg === index)); + it(`should warn if the pgvecto.rs extension upgrade failed`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getExtensionVersion.mockResolvedValue('0.5.0'); + databaseMock.getAvailableExtensionVersion.mockResolvedValue('0.5.2'); + databaseMock.updateVectorExtension.mockRejectedValue(new Error('Failed to update extension')); - await expect(sut.init()).resolves.toBeUndefined(); + await expect(sut.init()).resolves.toBeUndefined(); - expect(databaseMock.shouldReindex).toHaveBeenCalledWith(index); - expect(databaseMock.shouldReindex).toHaveBeenCalledTimes(2); - expect(databaseMock.reindex).toHaveBeenCalledWith(index); - expect(databaseMock.reindex).toHaveBeenCalledTimes(1); - expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(loggerMock.fatal).not.toHaveBeenCalled(); - }, - ); + expect(loggerMock.warn.mock.calls[0][0]).toContain('The pgvector extension can be updated to 0.5.2.'); + expect(loggerMock.error).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith('vector', '0.5.2'); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + }); - it.each([{ index: VectorIndex.CLIP }, { index: VectorIndex.FACE }])( - `should not reindex $index if not necessary`, - async () => { - databaseMock.shouldReindex.mockResolvedValue(false); + it(`should warn if the pgvector extension upgrade failed`, async () => { + databaseMock.getAvailableExtensionVersion.mockResolvedValue('0.2.1'); + databaseMock.updateVectorExtension.mockRejectedValue(new Error('Failed to update extension')); - await expect(sut.init()).resolves.toBeUndefined(); + await expect(sut.init()).resolves.toBeUndefined(); - expect(databaseMock.shouldReindex).toHaveBeenCalledTimes(2); - expect(databaseMock.reindex).not.toHaveBeenCalled(); - expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(loggerMock.fatal).not.toHaveBeenCalled(); - }, - ); + expect(loggerMock.warn.mock.calls[0][0]).toContain('The pgvecto.rs extension can be updated to 0.2.1.'); + expect(loggerMock.error).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith('vectors', '0.2.1'); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + }); - it('should skip migrations if DB_SKIP_MIGRATIONS=true', async () => { - process.env.DB_SKIP_MIGRATIONS = 'true'; + it(`should warn if the pgvecto.rs extension update requires restart`, async () => { + databaseMock.getAvailableExtensionVersion.mockResolvedValue('0.2.1'); + databaseMock.updateVectorExtension.mockResolvedValue({ restartRequired: true }); - await expect(sut.init()).resolves.toBeUndefined(); + await expect(sut.init()).resolves.toBeUndefined(); - expect(databaseMock.runMigrations).not.toHaveBeenCalled(); - }); + expect(loggerMock.warn).toHaveBeenCalledTimes(1); + expect(loggerMock.warn.mock.calls[0][0]).toContain('pgvecto.rs'); + expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith('vectors', '0.2.1'); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + }); + + it(`should warn if the pgvector extension update requires restart`, async () => { + process.env.DB_VECTOR_EXTENSION = 'pgvector'; + databaseMock.getExtensionVersion.mockResolvedValue('0.5.0'); + databaseMock.getAvailableExtensionVersion.mockResolvedValue('0.5.1'); + databaseMock.updateVectorExtension.mockResolvedValue({ restartRequired: true }); + + await expect(sut.init()).resolves.toBeUndefined(); + + expect(loggerMock.warn).toHaveBeenCalledTimes(1); + expect(loggerMock.warn.mock.calls[0][0]).toContain('pgvector'); + expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith('vector', '0.5.1'); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + }); + + it('should reindex if needed', async () => { + databaseMock.shouldReindex.mockResolvedValue(true); + + await expect(sut.init()).resolves.toBeUndefined(); + + expect(databaseMock.shouldReindex).toHaveBeenCalledTimes(2); + expect(databaseMock.reindex).toHaveBeenCalledTimes(2); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + }); + + it('should not reindex if not needed', async () => { + databaseMock.shouldReindex.mockResolvedValue(false); + + await expect(sut.init()).resolves.toBeUndefined(); + + expect(databaseMock.shouldReindex).toHaveBeenCalledTimes(2); + expect(databaseMock.reindex).toHaveBeenCalledTimes(0); + expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); + }); + + it('should skip migrations if DB_SKIP_MIGRATIONS=true', async () => { + process.env.DB_SKIP_MIGRATIONS = 'true'; + databaseMock.getExtensionVersion.mockResolvedValue('0.2.0'); + + await expect(sut.init()).resolves.toBeUndefined(); + + expect(databaseMock.runMigrations).not.toHaveBeenCalled(); }); }); diff --git a/server/src/services/database.service.ts b/server/src/services/database.service.ts index 7a25238eaf..4b809faac5 100644 --- a/server/src/services/database.service.ts +++ b/server/src/services/database.service.ts @@ -1,38 +1,126 @@ import { Inject, Injectable } from '@nestjs/common'; +import semver from 'semver'; +import { POSTGRES_VERSION_RANGE, VECTORS_VERSION_RANGE, VECTOR_VERSION_RANGE } from 'src/constants'; +import { getVectorExtension } from 'src/database.config'; import { DatabaseExtension, DatabaseLock, + EXTENSION_NAMES, IDatabaseRepository, - VectorExtension, VectorIndex, - extName, } from 'src/interfaces/database.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; -import { Version, VersionType } from 'src/utils/version'; + +type CreateFailedArgs = { name: string; extension: string; otherName: string }; +type UpdateFailedArgs = { name: string; extension: string; availableVersion: string }; +type RestartRequiredArgs = { name: string; availableVersion: string }; +type NightlyVersionArgs = { name: string; extension: string; version: string }; +type OutOfRangeArgs = { name: string; extension: string; version: string; range: string }; + +const EXTENSION_RANGES = { + [DatabaseExtension.VECTOR]: VECTOR_VERSION_RANGE, + [DatabaseExtension.VECTORS]: VECTORS_VERSION_RANGE, +}; + +const messages = { + notInstalled: (name: string) => `Unexpected: The ${name} extension is not installed.`, + nightlyVersion: ({ name, extension, version }: NightlyVersionArgs) => ` + The ${name} extension version is ${version}, which means it is a nightly release. + + Please run 'DROP EXTENSION IF EXISTS ${extension}' and switch to a release version. + See https://immich.app/docs/guides/database-queries for how to query the database.`, + outOfRange: ({ name, extension, version, range }: OutOfRangeArgs) => ` + The ${name} extension version is ${version}, but Immich only supports ${range}. + + If the Postgres instance already has a compatible version installed, Immich may not have the necessary permissions to activate it. + In this case, please run 'ALTER EXTENSION UPDATE ${extension}' manually as a superuser. + See https://immich.app/docs/guides/database-queries for how to query the database. + + Otherwise, please update the version of ${name} in the Postgres instance to a compatible version.`, + createFailed: ({ name, extension, otherName }: CreateFailedArgs) => ` + Failed to activate ${name} extension. + Please ensure the Postgres instance has ${name} installed. + + If the Postgres instance already has ${name} installed, Immich may not have the necessary permissions to activate it. + In this case, please run 'CREATE EXTENSION IF NOT EXISTS ${extension}' manually as a superuser. + See https://immich.app/docs/guides/database-queries for how to query the database. + + Alternatively, if your Postgres instance has ${otherName}, you may use this instead by setting the environment variable 'DB_VECTOR_EXTENSION=${otherName}'. + Note that switching between the two extensions after a successful startup is not supported. + The exception is if your version of Immich prior to upgrading was 1.90.2 or earlier. + In this case, you may set either extension now, but you will not be able to switch to the other extension following a successful startup. + `, + updateFailed: ({ name, extension, availableVersion }: UpdateFailedArgs) => ` + The ${name} extension can be updated to ${availableVersion}. + Immich attempted to update the extension, but failed to do so. + This may be because Immich does not have the necessary permissions to update the extension. + + Please run 'ALTER EXTENSION ${extension} UPDATE' manually as a superuser. + See https://immich.app/docs/guides/database-queries for how to query the database.`, + restartRequired: ({ name, availableVersion }: RestartRequiredArgs) => ` + The ${name} extension has been updated to ${availableVersion}. + Please restart the Postgres instance to complete the update.`, +}; @Injectable() export class DatabaseService { - private vectorExt: VectorExtension; - minPostgresVersion = 14; - minVectorsVersion = new Version(0, 2, 0); - vectorsVersionPin = VersionType.MINOR; - minVectorVersion = new Version(0, 5, 0); - vectorVersionPin = VersionType.MAJOR; - constructor( @Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(DatabaseService.name); - this.vectorExt = this.databaseRepository.getPreferredVectorExtension(); } async init() { - await this.assertPostgresql(); + const version = await this.databaseRepository.getPostgresVersion(); + const current = semver.coerce(version); + if (!current || !semver.satisfies(current, POSTGRES_VERSION_RANGE)) { + throw new Error( + `Invalid PostgreSQL version. Found ${version}, but needed ${POSTGRES_VERSION_RANGE}. Please use a supported version.`, + ); + } + await this.databaseRepository.withLock(DatabaseLock.Migrations, async () => { - await this.createVectorExtension(); - await this.updateVectorExtension(); - await this.assertVectorExtension(); + const extension = getVectorExtension(); + const otherExtension = + extension === DatabaseExtension.VECTORS ? DatabaseExtension.VECTOR : DatabaseExtension.VECTORS; + const otherName = EXTENSION_NAMES[otherExtension]; + const name = EXTENSION_NAMES[extension]; + const extensionRange = EXTENSION_RANGES[extension]; + + try { + await this.databaseRepository.createExtension(extension); + } catch (error) { + this.logger.fatal(messages.createFailed({ name, extension, otherName })); + throw error; + } + + const availableVersion = await this.databaseRepository.getAvailableExtensionVersion(extension); + if (availableVersion && semver.satisfies(availableVersion, extensionRange)) { + try { + this.logger.log(`Updating ${name} extension to ${availableVersion}`); + const { restartRequired } = await this.databaseRepository.updateVectorExtension(extension, availableVersion); + if (restartRequired) { + this.logger.warn(messages.restartRequired({ name, availableVersion })); + } + } catch (error) { + this.logger.warn(messages.updateFailed({ name, extension, availableVersion })); + this.logger.error(error); + } + } + + const version = await this.databaseRepository.getExtensionVersion(extension); + if (!version) { + throw new Error(messages.notInstalled(name)); + } + + if (semver.eq(version, '0.0.0')) { + throw new Error(messages.nightlyVersion({ name, extension, version })); + } + + if (!semver.satisfies(version, extensionRange)) { + throw new Error(messages.outOfRange({ name, extension, version, range: extensionRange })); + } try { if (await this.databaseRepository.shouldReindex(VectorIndex.CLIP)) { @@ -54,110 +142,4 @@ export class DatabaseService { } }); } - - private async assertPostgresql() { - const { major } = await this.databaseRepository.getPostgresVersion(); - if (major < this.minPostgresVersion) { - throw new Error(` - The PostgreSQL version is ${major}, which is older than the minimum supported version ${this.minPostgresVersion}. - Please upgrade to this version or later.`); - } - } - - private async createVectorExtension() { - try { - await this.databaseRepository.createExtension(this.vectorExt); - } catch (error) { - const otherExt = - this.vectorExt === DatabaseExtension.VECTORS ? DatabaseExtension.VECTOR : DatabaseExtension.VECTORS; - this.logger.fatal(` - Failed to activate ${extName[this.vectorExt]} extension. - Please ensure the Postgres instance has ${extName[this.vectorExt]} installed. - - If the Postgres instance already has ${extName[this.vectorExt]} installed, Immich may not have the necessary permissions to activate it. - In this case, please run 'CREATE EXTENSION IF NOT EXISTS ${this.vectorExt}' manually as a superuser. - See https://immich.app/docs/guides/database-queries for how to query the database. - - Alternatively, if your Postgres instance has ${extName[otherExt]}, you may use this instead by setting the environment variable 'DB_VECTOR_EXTENSION=${extName[otherExt]}'. - Note that switching between the two extensions after a successful startup is not supported. - The exception is if your version of Immich prior to upgrading was 1.90.2 or earlier. - In this case, you may set either extension now, but you will not be able to switch to the other extension following a successful startup. - `); - throw error; - } - } - - private async updateVectorExtension() { - const [version, availableVersion] = await Promise.all([ - this.databaseRepository.getExtensionVersion(this.vectorExt), - this.databaseRepository.getAvailableExtensionVersion(this.vectorExt), - ]); - if (version == null) { - throw new Error(`Unexpected: ${extName[this.vectorExt]} extension is not installed.`); - } - - if (availableVersion == null) { - return; - } - - const maxVersion = this.vectorExt === DatabaseExtension.VECTOR ? this.vectorVersionPin : this.vectorsVersionPin; - const isNewer = availableVersion.isNewerThan(version); - if (isNewer == null || isNewer > maxVersion) { - return; - } - - try { - this.logger.log(`Updating ${extName[this.vectorExt]} extension to ${availableVersion}`); - const { restartRequired } = await this.databaseRepository.updateVectorExtension(this.vectorExt, availableVersion); - if (restartRequired) { - this.logger.warn(` - The ${extName[this.vectorExt]} extension has been updated to ${availableVersion}. - Please restart the Postgres instance to complete the update.`); - } - } catch (error) { - this.logger.warn(` - The ${extName[this.vectorExt]} extension version is ${version}, but ${availableVersion} is available. - Immich attempted to update the extension, but failed to do so. - This may be because Immich does not have the necessary permissions to update the extension. - - Please run 'ALTER EXTENSION ${this.vectorExt} UPDATE' manually as a superuser. - See https://immich.app/docs/guides/database-queries for how to query the database.`); - this.logger.error(error); - } - } - - private async assertVectorExtension() { - const version = await this.databaseRepository.getExtensionVersion(this.vectorExt); - if (version == null) { - throw new Error(`Unexpected: The ${extName[this.vectorExt]} extension is not installed.`); - } - - if (version.isEqual(new Version(0, 0, 0))) { - throw new Error(` - The ${extName[this.vectorExt]} extension version is ${version}, which means it is a nightly release. - - Please run 'DROP EXTENSION IF EXISTS ${this.vectorExt}' and switch to a release version. - See https://immich.app/docs/guides/database-queries for how to query the database.`); - } - - const minVersion = this.vectorExt === DatabaseExtension.VECTOR ? this.minVectorVersion : this.minVectorsVersion; - const maxVersion = this.vectorExt === DatabaseExtension.VECTOR ? this.vectorVersionPin : this.vectorsVersionPin; - - if (version.isOlderThan(minVersion) || version.isNewerThan(minVersion) > maxVersion) { - const allowedReleaseType = maxVersion === VersionType.MAJOR ? '' : ` ${VersionType[maxVersion].toLowerCase()}`; - const releases = - maxVersion === VersionType.EQUAL - ? minVersion.toString() - : `${minVersion} and later${allowedReleaseType} releases`; - - throw new Error(` - The ${extName[this.vectorExt]} extension version is ${version}, but Immich only supports ${releases}. - - If the Postgres instance already has a compatible version installed, Immich may not have the necessary permissions to activate it. - In this case, please run 'ALTER EXTENSION UPDATE ${this.vectorExt}' manually as a superuser. - See https://immich.app/docs/guides/database-queries for how to query the database. - - Otherwise, please update the version of ${extName[this.vectorExt]} in the Postgres instance to a compatible version.`); - } - } } diff --git a/server/src/services/download.service.spec.ts b/server/src/services/download.service.spec.ts index 331ddcaaa7..48231a11a8 100644 --- a/server/src/services/download.service.spec.ts +++ b/server/src/services/download.service.spec.ts @@ -180,7 +180,6 @@ describe(DownloadService.name, () => { }); it('should return a list of archives (userId)', async () => { - accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([authStub.admin.user.id])); assetMock.getByUserId.mockResolvedValue({ items: [assetStub.image, assetStub.video], hasNextPage: false, @@ -196,8 +195,6 @@ describe(DownloadService.name, () => { }); it('should split archives by size', async () => { - accessMock.library.checkOwnerAccess.mockResolvedValue(new Set([authStub.admin.user.id])); - assetMock.getByUserId.mockResolvedValue({ items: [ { ...assetStub.image, id: 'asset-1' }, diff --git a/server/src/services/duplicate.service.spec.ts b/server/src/services/duplicate.service.spec.ts new file mode 100644 index 0000000000..4560d9024c --- /dev/null +++ b/server/src/services/duplicate.service.spec.ts @@ -0,0 +1,269 @@ +import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; +import { ICryptoRepository } from 'src/interfaces/crypto.interface'; +import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { ISearchRepository } from 'src/interfaces/search.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { DuplicateService } from 'src/services/duplicate.service'; +import { SearchService } from 'src/services/search.service'; +import { assetStub } from 'test/fixtures/asset.stub'; +import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; +import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; +import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; +import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; +import { Mocked, beforeEach, vitest } from 'vitest'; + +vitest.useFakeTimers(); + +describe(SearchService.name, () => { + let sut: DuplicateService; + let assetMock: Mocked; + let systemMock: Mocked; + let searchMock: Mocked; + let loggerMock: Mocked; + let cryptoMock: Mocked; + let jobMock: Mocked; + + beforeEach(() => { + assetMock = newAssetRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); + searchMock = newSearchRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); + cryptoMock = newCryptoRepositoryMock(); + jobMock = newJobRepositoryMock(); + + sut = new DuplicateService(systemMock, searchMock, assetMock, loggerMock, cryptoMock, jobMock); + }); + + it('should work', () => { + expect(sut).toBeDefined(); + }); + + describe('handleQueueSearchDuplicates', () => { + beforeEach(() => { + systemMock.get.mockResolvedValue({ + machineLearning: { + enabled: true, + duplicateDetection: { + enabled: true, + }, + }, + }); + }); + + it('should skip if machine learning is disabled', async () => { + systemMock.get.mockResolvedValue({ + machineLearning: { + enabled: false, + duplicateDetection: { + enabled: true, + }, + }, + }); + + await expect(sut.handleQueueSearchDuplicates({})).resolves.toBe(JobStatus.SKIPPED); + expect(jobMock.queue).not.toHaveBeenCalled(); + expect(jobMock.queueAll).not.toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); + }); + + it('should skip if duplicate detection is disabled', async () => { + systemMock.get.mockResolvedValue({ + machineLearning: { + enabled: true, + duplicateDetection: { + enabled: false, + }, + }, + }); + + await expect(sut.handleQueueSearchDuplicates({})).resolves.toBe(JobStatus.SKIPPED); + expect(jobMock.queue).not.toHaveBeenCalled(); + expect(jobMock.queueAll).not.toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); + }); + + it('should queue missing assets', async () => { + assetMock.getWithout.mockResolvedValue({ + items: [assetStub.image], + hasNextPage: false, + }); + + await sut.handleQueueSearchDuplicates({}); + + expect(assetMock.getWithout).toHaveBeenCalledWith({ skip: 0, take: 1000 }, WithoutProperty.DUPLICATE); + expect(jobMock.queueAll).toHaveBeenCalledWith([ + { + name: JobName.DUPLICATE_DETECTION, + data: { id: assetStub.image.id }, + }, + ]); + }); + + it('should queue all assets', async () => { + assetMock.getAll.mockResolvedValue({ + items: [assetStub.image], + hasNextPage: false, + }); + + await sut.handleQueueSearchDuplicates({ force: true }); + + expect(assetMock.getAll).toHaveBeenCalled(); + expect(jobMock.queueAll).toHaveBeenCalledWith([ + { + name: JobName.DUPLICATE_DETECTION, + data: { id: assetStub.image.id }, + }, + ]); + }); + }); + + describe('handleSearchDuplicates', () => { + beforeEach(() => { + systemMock.get.mockResolvedValue({ + machineLearning: { + enabled: true, + duplicateDetection: { + enabled: true, + }, + }, + }); + }); + + it('should skip if machine learning is disabled', async () => { + systemMock.get.mockResolvedValue({ + machineLearning: { + enabled: false, + duplicateDetection: { + enabled: true, + }, + }, + }); + const id = assetStub.livePhotoMotionAsset.id; + assetMock.getById.mockResolvedValue(assetStub.livePhotoMotionAsset); + + const result = await sut.handleSearchDuplicates({ id }); + + expect(result).toBe(JobStatus.SKIPPED); + }); + + it('should skip if duplicate detection is disabled', async () => { + systemMock.get.mockResolvedValue({ + machineLearning: { + enabled: true, + duplicateDetection: { + enabled: false, + }, + }, + }); + const id = assetStub.livePhotoMotionAsset.id; + assetMock.getById.mockResolvedValue(assetStub.livePhotoMotionAsset); + + const result = await sut.handleSearchDuplicates({ id }); + + expect(result).toBe(JobStatus.SKIPPED); + }); + + it('should fail if asset is not found', async () => { + const result = await sut.handleSearchDuplicates({ id: assetStub.image.id }); + + expect(result).toBe(JobStatus.FAILED); + expect(loggerMock.error).toHaveBeenCalledWith(`Asset ${assetStub.image.id} not found`); + }); + + it('should skip if asset is not visible', async () => { + const id = assetStub.livePhotoMotionAsset.id; + assetMock.getById.mockResolvedValue(assetStub.livePhotoMotionAsset); + + const result = await sut.handleSearchDuplicates({ id }); + + expect(result).toBe(JobStatus.SKIPPED); + expect(loggerMock.debug).toHaveBeenCalledWith(`Asset ${id} is not visible, skipping`); + }); + + it('should fail if asset is missing preview image', async () => { + assetMock.getById.mockResolvedValue(assetStub.noResizePath); + + const result = await sut.handleSearchDuplicates({ id: assetStub.noResizePath.id }); + + expect(result).toBe(JobStatus.FAILED); + expect(loggerMock.warn).toHaveBeenCalledWith(`Asset ${assetStub.noResizePath.id} is missing preview image`); + }); + + it('should fail if asset is missing embedding', async () => { + assetMock.getById.mockResolvedValue(assetStub.image); + + const result = await sut.handleSearchDuplicates({ id: assetStub.image.id }); + + expect(result).toBe(JobStatus.FAILED); + expect(loggerMock.debug).toHaveBeenCalledWith(`Asset ${assetStub.image.id} is missing embedding`); + }); + + it('should search for duplicates and update asset with duplicateId', async () => { + assetMock.getById.mockResolvedValue(assetStub.hasEmbedding); + searchMock.searchDuplicates.mockResolvedValue([ + { assetId: assetStub.image.id, distance: 0.01, duplicateId: null }, + ]); + const expectedAssetIds = [assetStub.image.id, assetStub.hasEmbedding.id]; + + const result = await sut.handleSearchDuplicates({ id: assetStub.hasEmbedding.id }); + + expect(result).toBe(JobStatus.SUCCESS); + expect(searchMock.searchDuplicates).toHaveBeenCalledWith({ + assetId: assetStub.hasEmbedding.id, + embedding: assetStub.hasEmbedding.smartSearch!.embedding, + maxDistance: 0.03, + userIds: [assetStub.hasEmbedding.ownerId], + }); + expect(assetMock.updateDuplicates).toHaveBeenCalledWith({ + assetIds: expectedAssetIds, + targetDuplicateId: expect.any(String), + duplicateIds: [], + }); + expect(assetMock.upsertJobStatus).toHaveBeenCalledWith( + ...expectedAssetIds.map((assetId) => ({ assetId, duplicatesDetectedAt: expect.any(Date) })), + ); + }); + + it('should use existing duplicate ID among matched duplicates', async () => { + const duplicateId = assetStub.hasDupe.duplicateId; + assetMock.getById.mockResolvedValue(assetStub.hasEmbedding); + searchMock.searchDuplicates.mockResolvedValue([{ assetId: assetStub.hasDupe.id, distance: 0.01, duplicateId }]); + const expectedAssetIds = [assetStub.hasEmbedding.id]; + + const result = await sut.handleSearchDuplicates({ id: assetStub.hasEmbedding.id }); + + expect(result).toBe(JobStatus.SUCCESS); + expect(searchMock.searchDuplicates).toHaveBeenCalledWith({ + assetId: assetStub.hasEmbedding.id, + embedding: assetStub.hasEmbedding.smartSearch!.embedding, + maxDistance: 0.03, + userIds: [assetStub.hasEmbedding.ownerId], + }); + expect(assetMock.updateDuplicates).toHaveBeenCalledWith({ + assetIds: expectedAssetIds, + targetDuplicateId: assetStub.hasDupe.duplicateId, + duplicateIds: [], + }); + expect(assetMock.upsertJobStatus).toHaveBeenCalledWith( + ...expectedAssetIds.map((assetId) => ({ assetId, duplicatesDetectedAt: expect.any(Date) })), + ); + }); + + it('should remove duplicateId if no duplicates found and asset has duplicateId', async () => { + assetMock.getById.mockResolvedValue(assetStub.hasDupe); + searchMock.searchDuplicates.mockResolvedValue([]); + + const result = await sut.handleSearchDuplicates({ id: assetStub.hasDupe.id }); + + expect(result).toBe(JobStatus.SUCCESS); + expect(assetMock.update).toHaveBeenCalledWith({ id: assetStub.hasDupe.id, duplicateId: null }); + expect(assetMock.upsertJobStatus).toHaveBeenCalledWith({ + assetId: assetStub.hasDupe.id, + duplicatesDetectedAt: expect.any(Date), + }); + }); + }); +}); diff --git a/server/src/services/duplicate.service.ts b/server/src/services/duplicate.service.ts new file mode 100644 index 0000000000..95a12bd18e --- /dev/null +++ b/server/src/services/duplicate.service.ts @@ -0,0 +1,135 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { SystemConfigCore } from 'src/cores/system-config.core'; +import { mapAsset } from 'src/dtos/asset-response.dto'; +import { AuthDto } from 'src/dtos/auth.dto'; +import { DuplicateResponseDto, mapDuplicateResponse } from 'src/dtos/duplicate.dto'; +import { AssetEntity } from 'src/entities/asset.entity'; +import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; +import { ICryptoRepository } from 'src/interfaces/crypto.interface'; +import { + IBaseJob, + IEntityJob, + IJobRepository, + JOBS_ASSET_PAGINATION_SIZE, + JobName, + JobStatus, +} from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { AssetDuplicateResult, ISearchRepository } from 'src/interfaces/search.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { isDuplicateDetectionEnabled } from 'src/utils/misc'; +import { usePagination } from 'src/utils/pagination'; + +@Injectable() +export class DuplicateService { + private configCore: SystemConfigCore; + + constructor( + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, + @Inject(ISearchRepository) private searchRepository: ISearchRepository, + @Inject(IAssetRepository) private assetRepository: IAssetRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, + @Inject(IJobRepository) private jobRepository: IJobRepository, + ) { + this.logger.setContext(DuplicateService.name); + this.configCore = SystemConfigCore.create(systemMetadataRepository, logger); + } + + async getDuplicates(auth: AuthDto): Promise { + const res = await this.assetRepository.getDuplicates({ userIds: [auth.user.id] }); + + return mapDuplicateResponse(res.map((a) => mapAsset(a, { auth }))); + } + + async handleQueueSearchDuplicates({ force }: IBaseJob): Promise { + const { machineLearning } = await this.configCore.getConfig(); + if (!isDuplicateDetectionEnabled(machineLearning)) { + return JobStatus.SKIPPED; + } + + const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) => { + return force + ? this.assetRepository.getAll(pagination, { isVisible: true }) + : this.assetRepository.getWithout(pagination, WithoutProperty.DUPLICATE); + }); + + for await (const assets of assetPagination) { + await this.jobRepository.queueAll( + assets.map((asset) => ({ name: JobName.DUPLICATE_DETECTION, data: { id: asset.id } })), + ); + } + + return JobStatus.SUCCESS; + } + + async handleSearchDuplicates({ id }: IEntityJob): Promise { + const { machineLearning } = await this.configCore.getConfig(); + if (!isDuplicateDetectionEnabled(machineLearning)) { + return JobStatus.SKIPPED; + } + + const asset = await this.assetRepository.getById(id, { smartSearch: true }); + if (!asset) { + this.logger.error(`Asset ${id} not found`); + return JobStatus.FAILED; + } + + if (!asset.isVisible) { + this.logger.debug(`Asset ${id} is not visible, skipping`); + return JobStatus.SKIPPED; + } + + if (!asset.previewPath) { + this.logger.warn(`Asset ${id} is missing preview image`); + return JobStatus.FAILED; + } + + if (!asset.smartSearch?.embedding) { + this.logger.debug(`Asset ${id} is missing embedding`); + return JobStatus.FAILED; + } + + const duplicateAssets = await this.searchRepository.searchDuplicates({ + assetId: asset.id, + embedding: asset.smartSearch.embedding, + maxDistance: machineLearning.duplicateDetection.maxDistance, + userIds: [asset.ownerId], + }); + + let assetIds = [asset.id]; + if (duplicateAssets.length > 0) { + this.logger.debug( + `Found ${duplicateAssets.length} duplicate${duplicateAssets.length === 1 ? '' : 's'} for asset ${asset.id}`, + ); + assetIds = await this.updateDuplicates(asset, duplicateAssets); + } else if (asset.duplicateId) { + this.logger.debug(`No duplicates found for asset ${asset.id}, removing duplicateId`); + await this.assetRepository.update({ id: asset.id, duplicateId: null }); + } + + const duplicatesDetectedAt = new Date(); + await this.assetRepository.upsertJobStatus(...assetIds.map((assetId) => ({ assetId, duplicatesDetectedAt }))); + + return JobStatus.SUCCESS; + } + + private async updateDuplicates(asset: AssetEntity, duplicateAssets: AssetDuplicateResult[]): Promise { + const duplicateIds = [ + ...new Set( + duplicateAssets + .filter((asset): asset is AssetDuplicateResult & { duplicateId: string } => !!asset.duplicateId) + .map((duplicate) => duplicate.duplicateId), + ), + ]; + + const targetDuplicateId = asset.duplicateId ?? duplicateIds.shift() ?? this.cryptoRepository.randomUUID(); + const assetIdsToUpdate = duplicateAssets + .filter((asset) => asset.duplicateId !== targetDuplicateId) + .map((duplicate) => duplicate.assetId); + assetIdsToUpdate.push(asset.id); + + await this.assetRepository.updateDuplicates({ targetDuplicateId, assetIds: assetIdsToUpdate, duplicateIds }); + return assetIdsToUpdate; + } +} diff --git a/server/src/services/index.ts b/server/src/services/index.ts index 95f048ba3c..5ea16d9e4b 100644 --- a/server/src/services/index.ts +++ b/server/src/services/index.ts @@ -2,12 +2,15 @@ import { ActivityService } from 'src/services/activity.service'; import { AlbumService } from 'src/services/album.service'; import { APIKeyService } from 'src/services/api-key.service'; import { ApiService } from 'src/services/api.service'; +import { AssetMediaService } from 'src/services/asset-media.service'; import { AssetServiceV1 } from 'src/services/asset-v1.service'; import { AssetService } from 'src/services/asset.service'; import { AuditService } from 'src/services/audit.service'; import { AuthService } from 'src/services/auth.service'; +import { CliService } from 'src/services/cli.service'; import { DatabaseService } from 'src/services/database.service'; import { DownloadService } from 'src/services/download.service'; +import { DuplicateService } from 'src/services/duplicate.service'; import { JobService } from 'src/services/job.service'; import { LibraryService } from 'src/services/library.service'; import { MediaService } from 'src/services/media.service'; @@ -31,6 +34,7 @@ import { TagService } from 'src/services/tag.service'; import { TimelineService } from 'src/services/timeline.service'; import { TrashService } from 'src/services/trash.service'; import { UserService } from 'src/services/user.service'; +import { VersionService } from 'src/services/version.service'; export const services = [ ApiService, @@ -38,12 +42,15 @@ export const services = [ APIKeyService, ActivityService, AlbumService, + AssetMediaService, AssetService, AssetServiceV1, AuditService, AuthService, + CliService, DatabaseService, DownloadService, + DuplicateService, JobService, LibraryService, MediaService, @@ -66,4 +73,5 @@ export const services = [ TimelineService, TrashService, UserService, + VersionService, ]; diff --git a/server/src/services/job.service.spec.ts b/server/src/services/job.service.spec.ts index 92fc60141a..20e52ac28e 100644 --- a/server/src/services/job.service.spec.ts +++ b/server/src/services/job.service.spec.ts @@ -1,6 +1,6 @@ import { BadRequestException } from '@nestjs/common'; -import { FeatureFlag, SystemConfigCore } from 'src/cores/system-config.core'; -import { SystemConfig, SystemConfigKey, SystemConfigKeyPaths } from 'src/entities/system-config.entity'; +import { SystemConfig } from 'src/config'; +import { SystemConfigCore } from 'src/cores/system-config.core'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IEventRepository } from 'src/interfaces/event.interface'; import { @@ -15,7 +15,7 @@ import { import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMetricRepository } from 'src/interfaces/metric.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { JobService } from 'src/services/job.service'; import { assetStub } from 'test/fixtures/asset.stub'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; @@ -24,7 +24,7 @@ import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMetricRepositoryMock } from 'test/repositories/metric.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { Mocked, vitest } from 'vitest'; const makeMockHandlers = (status: JobStatus) => { @@ -38,22 +38,22 @@ const makeMockHandlers = (status: JobStatus) => { describe(JobService.name, () => { let sut: JobService; let assetMock: Mocked; - let configMock: Mocked; let eventMock: Mocked; let jobMock: Mocked; let personMock: Mocked; let metricMock: Mocked; + let systemMock: Mocked; let loggerMock: Mocked; beforeEach(() => { assetMock = newAssetRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); eventMock = newEventRepositoryMock(); jobMock = newJobRepositoryMock(); personMock = newPersonRepositoryMock(); metricMock = newMetricRepositoryMock(); loggerMock = newLoggerRepositoryMock(); - sut = new JobService(assetMock, eventMock, jobMock, configMock, personMock, metricMock, loggerMock); + sut = new JobService(assetMock, eventMock, jobMock, systemMock, personMock, metricMock, loggerMock); }); it('should work', () => { @@ -109,6 +109,7 @@ describe(JobService.name, () => { await expect(sut.getAllJobsStatus()).resolves.toEqual({ [QueueName.BACKGROUND_TASK]: expectedJobStatus, + [QueueName.DUPLICATE_DETECTION]: expectedJobStatus, [QueueName.SMART_SEARCH]: expectedJobStatus, [QueueName.METADATA_EXTRACTION]: expectedJobStatus, [QueueName.SEARCH]: expectedJobStatus, @@ -234,14 +235,14 @@ describe(JobService.name, () => { describe('init', () => { it('should register a handler for each queue', async () => { await sut.init(makeMockHandlers(JobStatus.SUCCESS)); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); expect(jobMock.addHandler).toHaveBeenCalledTimes(Object.keys(QueueName).length); }); it('should subscribe to config changes', async () => { await sut.init(makeMockHandlers(JobStatus.FAILED)); - SystemConfigCore.create(newSystemConfigRepositoryMock(false), newLoggerRepositoryMock()).config$.next({ + SystemConfigCore.create(newSystemMetadataRepositoryMock(false), newLoggerRepositoryMock()).config$.next({ job: { [QueueName.BACKGROUND_TASK]: { concurrency: 10 }, [QueueName.SMART_SEARCH]: { concurrency: 10 }, @@ -367,32 +368,5 @@ describe(JobService.name, () => { expect(jobMock.queueAll).not.toHaveBeenCalled(); }); } - - const featureTests: Array<{ queue: QueueName; feature: FeatureFlag; configKey: SystemConfigKeyPaths }> = [ - { - queue: QueueName.SMART_SEARCH, - feature: FeatureFlag.SMART_SEARCH, - configKey: SystemConfigKey.MACHINE_LEARNING_CLIP_ENABLED, - }, - { - queue: QueueName.FACE_DETECTION, - feature: FeatureFlag.FACIAL_RECOGNITION, - configKey: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_ENABLED, - }, - { - queue: QueueName.FACIAL_RECOGNITION, - feature: FeatureFlag.FACIAL_RECOGNITION, - configKey: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_ENABLED, - }, - ]; - - for (const { queue, feature, configKey } of featureTests) { - it(`should throw an error if attempting to queue ${queue} when ${feature} is disabled`, async () => { - configMock.load.mockResolvedValue([{ key: configKey, value: false }]); - jobMock.getQueueStatus.mockResolvedValue({ isActive: false, isPaused: false }); - - await expect(sut.handleCommand(queue, { command: JobCommand.START, force: false })).rejects.toThrow(); - }); - } }); }); diff --git a/server/src/services/job.service.ts b/server/src/services/job.service.ts index 7a56cd61dd..dabbf4259b 100644 --- a/server/src/services/job.service.ts +++ b/server/src/services/job.service.ts @@ -1,6 +1,6 @@ import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { snakeCase } from 'lodash'; -import { FeatureFlag, SystemConfigCore } from 'src/cores/system-config.core'; +import { SystemConfigCore } from 'src/cores/system-config.core'; import { mapAsset } from 'src/dtos/asset-response.dto'; import { AllJobStatusResponseDto, JobCommandDto, JobStatusDto } from 'src/dtos/job.dto'; import { AssetType } from 'src/entities/asset.entity'; @@ -20,7 +20,7 @@ import { import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMetricRepository } from 'src/interfaces/metric.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; @Injectable() export class JobService { @@ -30,13 +30,13 @@ export class JobService { @Inject(IAssetRepository) private assetRepository: IAssetRepository, @Inject(IEventRepository) private eventRepository: IEventRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IPersonRepository) private personRepository: IPersonRepository, @Inject(IMetricRepository) private metricRepository: IMetricRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(JobService.name); - this.configCore = SystemConfigCore.create(configRepository, logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, logger); } async handleCommand(queueName: QueueName, dto: JobCommandDto): Promise { @@ -112,16 +112,18 @@ export class JobService { } case QueueName.SMART_SEARCH: { - await this.configCore.requireFeature(FeatureFlag.SMART_SEARCH); return this.jobRepository.queue({ name: JobName.QUEUE_SMART_SEARCH, data: { force } }); } + case QueueName.DUPLICATE_DETECTION: { + return this.jobRepository.queue({ name: JobName.QUEUE_DUPLICATE_DETECTION, data: { force } }); + } + case QueueName.METADATA_EXTRACTION: { return this.jobRepository.queue({ name: JobName.QUEUE_METADATA_EXTRACTION, data: { force } }); } case QueueName.SIDECAR: { - await this.configCore.requireFeature(FeatureFlag.SIDECAR); return this.jobRepository.queue({ name: JobName.QUEUE_SIDECAR, data: { force } }); } @@ -130,12 +132,10 @@ export class JobService { } case QueueName.FACE_DETECTION: { - await this.configCore.requireFeature(FeatureFlag.FACIAL_RECOGNITION); return this.jobRepository.queue({ name: JobName.QUEUE_FACE_DETECTION, data: { force } }); } case QueueName.FACIAL_RECOGNITION: { - await this.configCore.requireFeature(FeatureFlag.FACIAL_RECOGNITION); return this.jobRepository.queue({ name: JobName.QUEUE_FACIAL_RECOGNITION, data: { force } }); } @@ -195,7 +195,11 @@ export class JobService { } private isConcurrentQueue(name: QueueName): name is ConcurrentQueueName { - return ![QueueName.FACIAL_RECOGNITION, QueueName.STORAGE_TEMPLATE_MIGRATION].includes(name); + return ![ + QueueName.FACIAL_RECOGNITION, + QueueName.STORAGE_TEMPLATE_MIGRATION, + QueueName.DUPLICATE_DETECTION, + ].includes(name); } async handleNightlyJobs() { @@ -246,7 +250,7 @@ export class JobService { } case JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE: { - if (item.data.source === 'upload') { + if (item.data.source === 'upload' || item.data.source === 'copy') { await this.jobRepository.queue({ name: JobName.GENERATE_PREVIEW, data: item.data }); } break; @@ -298,6 +302,13 @@ export class JobService { break; } + case JobName.SMART_SEARCH: { + if (item.data.source === 'upload') { + await this.jobRepository.queue({ name: JobName.DUPLICATE_DETECTION, data: item.data }); + } + break; + } + case JobName.USER_DELETION: { this.eventRepository.clientBroadcast(ClientEvent.USER_DELETE, item.data.id); break; diff --git a/server/src/services/library.service.spec.ts b/server/src/services/library.service.spec.ts index 59f2c5a1d3..b63df692a4 100644 --- a/server/src/services/library.service.spec.ts +++ b/server/src/services/library.service.spec.ts @@ -1,10 +1,9 @@ import { BadRequestException } from '@nestjs/common'; import { Stats } from 'node:fs'; +import { SystemConfig } from 'src/config'; import { SystemConfigCore } from 'src/cores/system-config.core'; import { mapLibrary } from 'src/dtos/library.dto'; import { AssetType } from 'src/entities/asset.entity'; -import { LibraryType } from 'src/entities/library.entity'; -import { SystemConfig, SystemConfigKey } from 'src/entities/system-config.entity'; import { UserEntity } from 'src/entities/user.entity'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; @@ -13,7 +12,7 @@ import { IJobRepository, ILibraryFileJob, ILibraryRefreshJob, JobName, JobStatus import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { LibraryService } from 'src/services/library.service'; import { assetStub } from 'test/fixtures/asset.stub'; import { authStub } from 'test/fixtures/auth.stub'; @@ -27,14 +26,14 @@ import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { makeMockWatcher, newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { Mocked, vitest } from 'vitest'; describe(LibraryService.name, () => { let sut: LibraryService; let assetMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let cryptoMock: Mocked; let jobMock: Mocked; let libraryMock: Mocked; @@ -43,7 +42,7 @@ describe(LibraryService.name, () => { let loggerMock: Mocked; beforeEach(() => { - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); libraryMock = newLibraryRepositoryMock(); assetMock = newAssetRepositoryMock(); jobMock = newJobRepositoryMock(); @@ -54,7 +53,7 @@ describe(LibraryService.name, () => { sut = new LibraryService( assetMock, - configMock, + systemMock, cryptoMock, jobMock, libraryMock, @@ -72,16 +71,13 @@ describe(LibraryService.name, () => { describe('init', () => { it('should init cron job and subscribe to config changes', async () => { - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.LIBRARY_SCAN_ENABLED, value: true }, - { key: SystemConfigKey.LIBRARY_SCAN_CRON_EXPRESSION, value: '0 0 * * *' }, - ]); + systemMock.get.mockResolvedValue(systemConfigStub.libraryScan); await sut.init(); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); expect(jobMock.addCronJob).toHaveBeenCalled(); - SystemConfigCore.create(newSystemConfigRepositoryMock(false), newLoggerRepositoryMock()).config$.next({ + SystemConfigCore.create(newSystemMetadataRepositoryMock(false), newLoggerRepositoryMock()).config$.next({ library: { scan: { enabled: true, @@ -100,7 +96,7 @@ describe(LibraryService.name, () => { libraryStub.externalLibraryWithImportPaths2, ]); - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled); libraryMock.get.mockImplementation((id) => Promise.resolve( [libraryStub.externalLibraryWithImportPaths1, libraryStub.externalLibraryWithImportPaths2].find( @@ -120,7 +116,7 @@ describe(LibraryService.name, () => { }); it('should not initialize watcher when watching is disabled', async () => { - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchDisabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchDisabled); await sut.init(); @@ -128,7 +124,7 @@ describe(LibraryService.name, () => { }); it('should not initialize watcher when lock is taken', async () => { - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled); databaseMock.tryLock.mockResolvedValue(false); await sut.init(); @@ -216,18 +212,6 @@ describe(LibraryService.name, () => { ]); }); - it('should not scan upload libraries', async () => { - const mockLibraryJob: ILibraryRefreshJob = { - id: libraryStub.externalLibrary1.id, - refreshModifiedFiles: false, - refreshAllFiles: false, - }; - - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); - - await expect(sut.handleQueueAssetRefresh(mockLibraryJob)).resolves.toBe(JobStatus.FAILED); - }); - it('should ignore import paths that do not exist', async () => { storageMock.stat.mockImplementation((path): Promise => { if (path === libraryStub.externalLibraryWithImportPaths1.importPaths[0]) { @@ -710,7 +694,6 @@ describe(LibraryService.name, () => { describe('delete', () => { it('should delete a library', async () => { assetMock.getByLibraryIdAndOriginalPath.mockResolvedValue(assetStub.image); - libraryMock.getUploadLibraryCount.mockResolvedValue(2); libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); await sut.delete(libraryStub.externalLibrary1.id); @@ -723,21 +706,8 @@ describe(LibraryService.name, () => { expect(libraryMock.softDelete).toHaveBeenCalledWith(libraryStub.externalLibrary1.id); }); - it('should throw error if the last upload library is deleted', async () => { - assetMock.getByLibraryIdAndOriginalPath.mockResolvedValue(assetStub.image); - libraryMock.getUploadLibraryCount.mockResolvedValue(1); - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); - - await expect(sut.delete(libraryStub.uploadLibrary1.id)).rejects.toBeInstanceOf(BadRequestException); - - expect(jobMock.queue).not.toHaveBeenCalled(); - expect(jobMock.queueAll).not.toHaveBeenCalled(); - expect(libraryMock.softDelete).not.toHaveBeenCalled(); - }); - it('should allow an external library to be deleted', async () => { assetMock.getByLibraryIdAndOriginalPath.mockResolvedValue(assetStub.image); - libraryMock.getUploadLibraryCount.mockResolvedValue(1); libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); await sut.delete(libraryStub.externalLibrary1.id); @@ -752,11 +722,10 @@ describe(LibraryService.name, () => { it('should unwatch an external library when deleted', async () => { assetMock.getByLibraryIdAndOriginalPath.mockResolvedValue(assetStub.image); - libraryMock.getUploadLibraryCount.mockResolvedValue(1); libraryMock.get.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1); libraryMock.getAll.mockResolvedValue([libraryStub.externalLibraryWithImportPaths1]); - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled); const mockClose = vitest.fn(); storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose })); @@ -770,37 +739,37 @@ describe(LibraryService.name, () => { describe('get', () => { it('should return a library', async () => { - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); - await expect(sut.get(libraryStub.uploadLibrary1.id)).resolves.toEqual( + libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); + await expect(sut.get(libraryStub.externalLibrary1.id)).resolves.toEqual( expect.objectContaining({ - id: libraryStub.uploadLibrary1.id, - name: libraryStub.uploadLibrary1.name, - ownerId: libraryStub.uploadLibrary1.ownerId, + id: libraryStub.externalLibrary1.id, + name: libraryStub.externalLibrary1.name, + ownerId: libraryStub.externalLibrary1.ownerId, }), ); - expect(libraryMock.get).toHaveBeenCalledWith(libraryStub.uploadLibrary1.id); + expect(libraryMock.get).toHaveBeenCalledWith(libraryStub.externalLibrary1.id); }); it('should throw an error when a library is not found', async () => { libraryMock.get.mockResolvedValue(null); - await expect(sut.get(libraryStub.uploadLibrary1.id)).rejects.toBeInstanceOf(BadRequestException); - expect(libraryMock.get).toHaveBeenCalledWith(libraryStub.uploadLibrary1.id); + await expect(sut.get(libraryStub.externalLibrary1.id)).rejects.toBeInstanceOf(BadRequestException); + expect(libraryMock.get).toHaveBeenCalledWith(libraryStub.externalLibrary1.id); }); }); describe('getStatistics', () => { it('should return library statistics', async () => { - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); + libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); libraryMock.getStatistics.mockResolvedValue({ photos: 10, videos: 0, total: 10, usage: 1337 }); - await expect(sut.getStatistics(libraryStub.uploadLibrary1.id)).resolves.toEqual({ + await expect(sut.getStatistics(libraryStub.externalLibrary1.id)).resolves.toEqual({ photos: 10, videos: 0, total: 10, usage: 1337, }); - expect(libraryMock.getStatistics).toHaveBeenCalledWith(libraryStub.uploadLibrary1.id); + expect(libraryMock.getStatistics).toHaveBeenCalledWith(libraryStub.externalLibrary1.id); }); }); @@ -808,10 +777,9 @@ describe(LibraryService.name, () => { describe('external library', () => { it('should create with default settings', async () => { libraryMock.create.mockResolvedValue(libraryStub.externalLibrary1); - await expect(sut.create({ ownerId: authStub.admin.user.id, type: LibraryType.EXTERNAL })).resolves.toEqual( + await expect(sut.create({ ownerId: authStub.admin.user.id })).resolves.toEqual( expect.objectContaining({ id: libraryStub.externalLibrary1.id, - type: LibraryType.EXTERNAL, name: libraryStub.externalLibrary1.name, ownerId: libraryStub.externalLibrary1.ownerId, assetCount: 0, @@ -826,22 +794,17 @@ describe(LibraryService.name, () => { expect(libraryMock.create).toHaveBeenCalledWith( expect.objectContaining({ name: expect.any(String), - type: LibraryType.EXTERNAL, importPaths: [], exclusionPatterns: [], - isVisible: true, }), ); }); it('should create with name', async () => { libraryMock.create.mockResolvedValue(libraryStub.externalLibrary1); - await expect( - sut.create({ ownerId: authStub.admin.user.id, type: LibraryType.EXTERNAL, name: 'My Awesome Library' }), - ).resolves.toEqual( + await expect(sut.create({ ownerId: authStub.admin.user.id, name: 'My Awesome Library' })).resolves.toEqual( expect.objectContaining({ id: libraryStub.externalLibrary1.id, - type: LibraryType.EXTERNAL, name: libraryStub.externalLibrary1.name, ownerId: libraryStub.externalLibrary1.ownerId, assetCount: 0, @@ -856,40 +819,8 @@ describe(LibraryService.name, () => { expect(libraryMock.create).toHaveBeenCalledWith( expect.objectContaining({ name: 'My Awesome Library', - type: LibraryType.EXTERNAL, importPaths: [], exclusionPatterns: [], - isVisible: true, - }), - ); - }); - - it('should create invisible', async () => { - libraryMock.create.mockResolvedValue(libraryStub.externalLibrary1); - await expect( - sut.create({ ownerId: authStub.admin.user.id, type: LibraryType.EXTERNAL, isVisible: false }), - ).resolves.toEqual( - expect.objectContaining({ - id: libraryStub.externalLibrary1.id, - type: LibraryType.EXTERNAL, - name: libraryStub.externalLibrary1.name, - ownerId: libraryStub.externalLibrary1.ownerId, - assetCount: 0, - importPaths: [], - exclusionPatterns: [], - createdAt: libraryStub.externalLibrary1.createdAt, - updatedAt: libraryStub.externalLibrary1.updatedAt, - refreshedAt: null, - }), - ); - - expect(libraryMock.create).toHaveBeenCalledWith( - expect.objectContaining({ - name: expect.any(String), - type: LibraryType.EXTERNAL, - importPaths: [], - exclusionPatterns: [], - isVisible: false, }), ); }); @@ -899,13 +830,11 @@ describe(LibraryService.name, () => { await expect( sut.create({ ownerId: authStub.admin.user.id, - type: LibraryType.EXTERNAL, importPaths: ['/data/images', '/data/videos'], }), ).resolves.toEqual( expect.objectContaining({ id: libraryStub.externalLibrary1.id, - type: LibraryType.EXTERNAL, name: libraryStub.externalLibrary1.name, ownerId: libraryStub.externalLibrary1.ownerId, assetCount: 0, @@ -920,16 +849,14 @@ describe(LibraryService.name, () => { expect(libraryMock.create).toHaveBeenCalledWith( expect.objectContaining({ name: expect.any(String), - type: LibraryType.EXTERNAL, importPaths: ['/data/images', '/data/videos'], exclusionPatterns: [], - isVisible: true, }), ); }); it('should create watched with import paths', async () => { - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled); libraryMock.create.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1); libraryMock.get.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1); libraryMock.getAll.mockResolvedValue([]); @@ -937,7 +864,6 @@ describe(LibraryService.name, () => { await sut.init(); await sut.create({ ownerId: authStub.admin.user.id, - type: LibraryType.EXTERNAL, importPaths: libraryStub.externalLibraryWithImportPaths1.importPaths, }); }); @@ -947,13 +873,11 @@ describe(LibraryService.name, () => { await expect( sut.create({ ownerId: authStub.admin.user.id, - type: LibraryType.EXTERNAL, exclusionPatterns: ['*.tmp', '*.bak'], }), ).resolves.toEqual( expect.objectContaining({ id: libraryStub.externalLibrary1.id, - type: LibraryType.EXTERNAL, name: libraryStub.externalLibrary1.name, ownerId: libraryStub.externalLibrary1.ownerId, assetCount: 0, @@ -968,124 +892,38 @@ describe(LibraryService.name, () => { expect(libraryMock.create).toHaveBeenCalledWith( expect.objectContaining({ name: expect.any(String), - type: LibraryType.EXTERNAL, importPaths: [], exclusionPatterns: ['*.tmp', '*.bak'], - isVisible: true, }), ); }); }); - - describe('upload library', () => { - it('should create with default settings', async () => { - libraryMock.create.mockResolvedValue(libraryStub.uploadLibrary1); - await expect(sut.create({ ownerId: authStub.admin.user.id, type: LibraryType.UPLOAD })).resolves.toEqual( - expect.objectContaining({ - id: libraryStub.uploadLibrary1.id, - type: LibraryType.UPLOAD, - name: libraryStub.uploadLibrary1.name, - ownerId: libraryStub.uploadLibrary1.ownerId, - assetCount: 0, - importPaths: [], - exclusionPatterns: [], - createdAt: libraryStub.uploadLibrary1.createdAt, - updatedAt: libraryStub.uploadLibrary1.updatedAt, - refreshedAt: null, - }), - ); - - expect(libraryMock.create).toHaveBeenCalledWith( - expect.objectContaining({ - name: 'New Upload Library', - type: LibraryType.UPLOAD, - importPaths: [], - exclusionPatterns: [], - isVisible: true, - }), - ); - }); - - it('should create with name', async () => { - libraryMock.create.mockResolvedValue(libraryStub.uploadLibrary1); - await expect( - sut.create({ ownerId: authStub.admin.user.id, type: LibraryType.UPLOAD, name: 'My Awesome Library' }), - ).resolves.toEqual( - expect.objectContaining({ - id: libraryStub.uploadLibrary1.id, - type: LibraryType.UPLOAD, - name: libraryStub.uploadLibrary1.name, - ownerId: libraryStub.uploadLibrary1.ownerId, - assetCount: 0, - importPaths: [], - exclusionPatterns: [], - createdAt: libraryStub.uploadLibrary1.createdAt, - updatedAt: libraryStub.uploadLibrary1.updatedAt, - refreshedAt: null, - }), - ); - - expect(libraryMock.create).toHaveBeenCalledWith( - expect.objectContaining({ - name: 'My Awesome Library', - type: LibraryType.UPLOAD, - importPaths: [], - exclusionPatterns: [], - isVisible: true, - }), - ); - }); - - it('should not create with import paths', async () => { - await expect( - sut.create({ - ownerId: authStub.admin.user.id, - type: LibraryType.UPLOAD, - importPaths: ['/data/images', '/data/videos'], - }), - ).rejects.toBeInstanceOf(BadRequestException); - - expect(libraryMock.create).not.toHaveBeenCalled(); - }); - - it('should not create with exclusion patterns', async () => { - await expect( - sut.create({ - ownerId: authStub.admin.user.id, - type: LibraryType.UPLOAD, - exclusionPatterns: ['*.tmp', '*.bak'], - }), - ).rejects.toBeInstanceOf(BadRequestException); - - expect(libraryMock.create).not.toHaveBeenCalled(); - }); - }); }); describe('handleQueueCleanup', () => { it('should queue cleanup jobs', async () => { - libraryMock.getAllDeleted.mockResolvedValue([libraryStub.uploadLibrary1, libraryStub.externalLibrary1]); + libraryMock.getAllDeleted.mockResolvedValue([libraryStub.externalLibrary1, libraryStub.externalLibrary2]); await expect(sut.handleQueueCleanup()).resolves.toBe(JobStatus.SUCCESS); expect(jobMock.queueAll).toHaveBeenCalledWith([ - { name: JobName.LIBRARY_DELETE, data: { id: libraryStub.uploadLibrary1.id } }, { name: JobName.LIBRARY_DELETE, data: { id: libraryStub.externalLibrary1.id } }, + { name: JobName.LIBRARY_DELETE, data: { id: libraryStub.externalLibrary2.id } }, ]); }); }); describe('update', () => { beforeEach(async () => { - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled); libraryMock.getAll.mockResolvedValue([]); await sut.init(); }); it('should update library', async () => { - libraryMock.update.mockResolvedValue(libraryStub.uploadLibrary1); - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); - await expect(sut.update('library-id', {})).resolves.toEqual(mapLibrary(libraryStub.uploadLibrary1)); + libraryMock.update.mockResolvedValue(libraryStub.externalLibrary1); + libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); + await expect(sut.update('library-id', {})).resolves.toEqual(mapLibrary(libraryStub.externalLibrary1)); expect(libraryMock.update).toHaveBeenCalledWith(expect.objectContaining({ id: 'library-id' })); }); }); @@ -1093,7 +931,7 @@ describe(LibraryService.name, () => { describe('watchAll', () => { describe('watching disabled', () => { beforeEach(async () => { - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchDisabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchDisabled); await sut.init(); }); @@ -1109,7 +947,7 @@ describe(LibraryService.name, () => { describe('watching enabled', () => { beforeEach(async () => { - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled); libraryMock.getAll.mockResolvedValue([]); await sut.init(); }); @@ -1148,15 +986,6 @@ describe(LibraryService.name, () => { expect(storageMock.watch).not.toHaveBeenCalled(); }); - it('should throw error when watching upload library', async () => { - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); - libraryMock.getAll.mockResolvedValue([libraryStub.uploadLibrary1]); - - await expect(sut.watchAll()).rejects.toThrow('Can only watch external libraries'); - - expect(storageMock.watch).not.toHaveBeenCalled(); - }); - it('should handle a new file event', async () => { libraryMock.get.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1); libraryMock.getAll.mockResolvedValue([libraryStub.externalLibraryWithImportPaths1]); @@ -1264,7 +1093,7 @@ describe(LibraryService.name, () => { libraryStub.externalLibraryWithImportPaths2, ]); - configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled); + systemMock.get.mockResolvedValue(systemConfigStub.libraryWatchEnabled); libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); libraryMock.get.mockImplementation((id) => @@ -1292,25 +1121,25 @@ describe(LibraryService.name, () => { libraryMock.getAssetIds.mockResolvedValue([]); libraryMock.delete.mockImplementation(async () => {}); - await expect(sut.handleDeleteLibrary({ id: libraryStub.uploadLibrary1.id })).resolves.toBe(JobStatus.FAILED); + await expect(sut.handleDeleteLibrary({ id: libraryStub.externalLibrary1.id })).resolves.toBe(JobStatus.FAILED); }); it('should delete an empty library', async () => { - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); + libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); libraryMock.getAssetIds.mockResolvedValue([]); libraryMock.delete.mockImplementation(async () => {}); - await expect(sut.handleDeleteLibrary({ id: libraryStub.uploadLibrary1.id })).resolves.toBe(JobStatus.SUCCESS); + await expect(sut.handleDeleteLibrary({ id: libraryStub.externalLibrary1.id })).resolves.toBe(JobStatus.SUCCESS); }); it('should delete a library with assets', async () => { - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); + libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); libraryMock.getAssetIds.mockResolvedValue([assetStub.image1.id]); libraryMock.delete.mockImplementation(async () => {}); assetMock.getById.mockResolvedValue(assetStub.image1); - await expect(sut.handleDeleteLibrary({ id: libraryStub.uploadLibrary1.id })).resolves.toBe(JobStatus.SUCCESS); + await expect(sut.handleDeleteLibrary({ id: libraryStub.externalLibrary1.id })).resolves.toBe(JobStatus.SUCCESS); }); }); @@ -1334,14 +1163,6 @@ describe(LibraryService.name, () => { ]); }); - it('should not queue a library scan of upload library', async () => { - libraryMock.get.mockResolvedValue(libraryStub.uploadLibrary1); - - await expect(sut.queueScan(libraryStub.uploadLibrary1.id, {})).rejects.toBeInstanceOf(BadRequestException); - - expect(jobMock.queue).not.toBeCalled(); - }); - it('should queue a library scan of all modified assets', async () => { libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1); diff --git a/server/src/services/library.service.ts b/server/src/services/library.service.ts index a0d9b70d65..9a01f2325f 100644 --- a/server/src/services/library.service.ts +++ b/server/src/services/library.service.ts @@ -12,7 +12,6 @@ import { LibraryResponseDto, LibraryStatsResponseDto, ScanLibraryDto, - SearchLibraryDto, UpdateLibraryDto, ValidateLibraryDto, ValidateLibraryImportPathResponseDto, @@ -20,7 +19,7 @@ import { mapLibrary, } from 'src/dtos/library.dto'; import { AssetType } from 'src/entities/asset.entity'; -import { LibraryEntity, LibraryType } from 'src/entities/library.entity'; +import { LibraryEntity } from 'src/entities/library.entity'; import { IAssetRepository, WithProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { DatabaseLock, IDatabaseRepository } from 'src/interfaces/database.interface'; @@ -38,7 +37,7 @@ import { import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { mimeTypes } from 'src/utils/mime-types'; import { handlePromiseError } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; @@ -55,7 +54,7 @@ export class LibraryService { constructor( @Inject(IAssetRepository) private assetRepository: IAssetRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(ILibraryRepository) private repository: ILibraryRepository, @@ -64,7 +63,7 @@ export class LibraryService { @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(LibraryService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); } async init() { @@ -118,10 +117,7 @@ export class LibraryService { } const library = await this.findOrFail(id); - - if (library.type !== LibraryType.EXTERNAL) { - throw new BadRequestException('Can only watch external libraries'); - } else if (library.importPaths.length === 0) { + if (library.importPaths.length === 0) { return false; } @@ -212,16 +208,18 @@ export class LibraryService { return false; } - const libraries = await this.repository.getAll(false, LibraryType.EXTERNAL); - + const libraries = await this.repository.getAll(false); for (const library of libraries) { await this.watch(library.id); } } async getStatistics(id: string): Promise { - await this.findOrFail(id); - return this.repository.getStatistics(id); + const statistics = await this.repository.getStatistics(id); + if (!statistics) { + throw new BadRequestException('Library not found'); + } + return statistics; } async get(id: string): Promise { @@ -229,8 +227,8 @@ export class LibraryService { return mapLibrary(library); } - async getAll(dto: SearchLibraryDto): Promise { - const libraries = await this.repository.getAll(false, dto.type); + async getAll(): Promise { + const libraries = await this.repository.getAll(false); return libraries.map((library) => mapLibrary(library)); } @@ -244,38 +242,12 @@ export class LibraryService { } async create(dto: CreateLibraryDto): Promise { - switch (dto.type) { - case LibraryType.EXTERNAL: { - if (!dto.name) { - dto.name = 'New External Library'; - } - break; - } - case LibraryType.UPLOAD: { - if (!dto.name) { - dto.name = 'New Upload Library'; - } - if (dto.importPaths && dto.importPaths.length > 0) { - throw new BadRequestException('Upload libraries cannot have import paths'); - } - if (dto.exclusionPatterns && dto.exclusionPatterns.length > 0) { - throw new BadRequestException('Upload libraries cannot have exclusion patterns'); - } - break; - } - } - const library = await this.repository.create({ ownerId: dto.ownerId, - name: dto.name, - type: dto.type, + name: dto.name ?? 'New External Library', importPaths: dto.importPaths ?? [], exclusionPatterns: dto.exclusionPatterns ?? [], - isVisible: dto.isVisible ?? true, }); - - this.logger.log(`Creating ${dto.type} library for ${dto.ownerId}}`); - return mapLibrary(library); } @@ -363,11 +335,7 @@ export class LibraryService { } async delete(id: string) { - const library = await this.findOrFail(id); - const uploadCount = await this.repository.getUploadLibraryCount(library.ownerId); - if (library.type === LibraryType.UPLOAD && uploadCount <= 1) { - throw new BadRequestException('Cannot delete the last upload library'); - } + await this.findOrFail(id); if (this.watchLibraries) { await this.unwatch(id); @@ -530,10 +498,7 @@ export class LibraryService { } async queueScan(id: string, dto: ScanLibraryDto) { - const library = await this.findOrFail(id); - if (library.type !== LibraryType.EXTERNAL) { - throw new BadRequestException('Can only refresh external libraries'); - } + await this.findOrFail(id); await this.jobRepository.queue({ name: JobName.LIBRARY_SCAN, @@ -557,7 +522,7 @@ export class LibraryService { await this.jobRepository.queue({ name: JobName.LIBRARY_QUEUE_CLEANUP, data: {} }); // Queue all library refresh - const libraries = await this.repository.getAll(true, LibraryType.EXTERNAL); + const libraries = await this.repository.getAll(true); await this.jobRepository.queueAll( libraries.map((library) => ({ name: JobName.LIBRARY_SCAN, @@ -588,8 +553,8 @@ export class LibraryService { async handleQueueAssetRefresh(job: ILibraryRefreshJob): Promise { const library = await this.repository.get(job.id); - if (!library || library.type !== LibraryType.EXTERNAL) { - this.logger.warn('Can only refresh external libraries'); + if (!library) { + this.logger.warn('Library not found'); return JobStatus.FAILED; } diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index 637e5fa248..9fe0038232 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -1,16 +1,15 @@ import { Stats } from 'node:fs'; -import { AssetType } from 'src/entities/asset.entity'; -import { ExifEntity } from 'src/entities/exif.entity'; import { AudioCodec, Colorspace, ImageFormat, - SystemConfigKey, ToneMapping, TranscodeHWAccel, TranscodePolicy, VideoCodec, -} from 'src/entities/system-config.entity'; +} from 'src/config'; +import { AssetType } from 'src/entities/asset.entity'; +import { ExifEntity } from 'src/entities/exif.entity'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; @@ -19,7 +18,7 @@ import { IMediaRepository } from 'src/interfaces/media.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { MediaService } from 'src/services/media.service'; import { assetStub } from 'test/fixtures/asset.stub'; import { faceStub } from 'test/fixtures/face.stub'; @@ -33,24 +32,24 @@ import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock' import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { Mocked } from 'vitest'; describe(MediaService.name, () => { let sut: MediaService; let assetMock: Mocked; - let configMock: Mocked; let jobMock: Mocked; let mediaMock: Mocked; let moveMock: Mocked; let personMock: Mocked; let storageMock: Mocked; + let systemMock: Mocked; let cryptoMock: Mocked; let loggerMock: Mocked; beforeEach(() => { assetMock = newAssetRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); jobMock = newJobRepositoryMock(); mediaMock = newMediaRepositoryMock(); moveMock = newMoveRepositoryMock(); @@ -65,7 +64,7 @@ describe(MediaService.name, () => { jobMock, mediaMock, storageMock, - configMock, + systemMock, moveMock, cryptoMock, loggerMock, @@ -235,7 +234,7 @@ describe(MediaService.name, () => { }); it.each(Object.values(ImageFormat))('should generate a %s preview for an image when specified', async (format) => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_PREVIEW_FORMAT, value: format }]); + systemMock.get.mockResolvedValue({ image: { previewFormat: format } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); const previewPath = `upload/thumbs/user-id/as/se/asset-id-preview.${format}`; @@ -254,7 +253,7 @@ describe(MediaService.name, () => { it('should delete previous preview if different path', async () => { const previousPreviewPath = assetStub.image.previewPath; - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_THUMBNAIL_FORMAT, value: ImageFormat.WEBP }]); + systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); await sut.handleGeneratePreview({ id: assetStub.image.id }); @@ -337,10 +336,9 @@ describe(MediaService.name, () => { it('should always generate video thumbnail in one pass', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TWO_PASS, value: true }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '5000k' }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { twoPass: true, maxBitrate: '5000k' }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleGeneratePreview({ id: assetStub.video.id }); @@ -385,7 +383,7 @@ describe(MediaService.name, () => { it.each(Object.values(ImageFormat))( 'should generate a %s thumbnail for an image when specified', async (format) => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_THUMBNAIL_FORMAT, value: format }]); + systemMock.get.mockResolvedValue({ image: { thumbnailFormat: format } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); const thumbnailPath = `upload/thumbs/user-id/as/se/asset-id-thumbnail.${format}`; @@ -405,7 +403,7 @@ describe(MediaService.name, () => { it('should delete previous thumbnail if different path', async () => { const previousThumbnailPath = assetStub.image.thumbnailPath; - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_THUMBNAIL_FORMAT, value: ImageFormat.WEBP }]); + systemMock.get.mockResolvedValue({ image: { thumbnailFormat: ImageFormat.WEBP } }); assetMock.getByIds.mockResolvedValue([assetStub.image]); await sut.handleGenerateThumbnail({ id: assetStub.image.id }); @@ -438,7 +436,7 @@ describe(MediaService.name, () => { it('should extract embedded image if enabled and available', async () => { mediaMock.extract.mockResolvedValue(true); mediaMock.getImageDimensions.mockResolvedValue({ width: 3840, height: 2160 }); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: true }]); + systemMock.get.mockResolvedValue({ image: { extractEmbedded: true } }); assetMock.getByIds.mockResolvedValue([assetStub.imageDng]); await sut.handleGenerateThumbnail({ id: assetStub.image.id }); @@ -463,7 +461,7 @@ describe(MediaService.name, () => { it('should resize original image if embedded image is too small', async () => { mediaMock.extract.mockResolvedValue(true); mediaMock.getImageDimensions.mockResolvedValue({ width: 1000, height: 1000 }); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: true }]); + systemMock.get.mockResolvedValue({ image: { extractEmbedded: true } }); assetMock.getByIds.mockResolvedValue([assetStub.imageDng]); await sut.handleGenerateThumbnail({ id: assetStub.image.id }); @@ -486,7 +484,7 @@ describe(MediaService.name, () => { }); it('should resize original image if embedded image not found', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: true }]); + systemMock.get.mockResolvedValue({ image: { extractEmbedded: true } }); assetMock.getByIds.mockResolvedValue([assetStub.imageDng]); await sut.handleGenerateThumbnail({ id: assetStub.image.id }); @@ -505,7 +503,7 @@ describe(MediaService.name, () => { }); it('should resize original image if embedded image extraction is not enabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.IMAGE_EXTRACT_EMBEDDED, value: false }]); + systemMock.get.mockResolvedValue({ image: { extractEmbedded: false } }); assetMock.getByIds.mockResolvedValue([assetStub.imageDng]); await sut.handleGenerateThumbnail({ id: assetStub.image.id }); @@ -626,25 +624,14 @@ describe(MediaService.name, () => { await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.probe).toHaveBeenCalledWith('/original/path.ext'); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); expect(storageMock.mkdirSync).toHaveBeenCalled(); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-map 0:0', '-map 0:1']), twoPass: false, }, ); @@ -666,26 +653,15 @@ describe(MediaService.name, () => { it('should transcode when set to all', async () => { mediaMock.probe.mockResolvedValue(probeStub.multipleVideoStreams); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.ALL }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.ALL } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a aac', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.any(Array), twoPass: false, }, ); @@ -693,25 +669,14 @@ describe(MediaService.name, () => { it('should transcode when optimal and too big', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.OPTIMAL }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.OPTIMAL } }); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.any(Array), twoPass: false, }, ); @@ -719,30 +684,14 @@ describe(MediaService.name, () => { it('should transcode when policy Bitrate and bitrate higher than max bitrate', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStream40Mbps); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.BITRATE }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '30M' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.BITRATE, maxBitrate: '30M' } }); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - '-maxrate 30M', - '-bufsize 60M', - ], + inputOptions: expect.any(Array), + outputOptions: expect.any(Array), twoPass: false, }, ); @@ -750,55 +699,46 @@ describe(MediaService.name, () => { it('should not scale resolution if no target resolution', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.ALL }, - { key: SystemConfigKey.FFMPEG_TARGET_RESOLUTION, value: 'original' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.ALL, targetResolution: 'original' } }); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a aac', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.not.arrayContaining([expect.stringContaining('scale')]), twoPass: false, }, ); }); - it('should transcode with alternate scaling video is vertical', async () => { - mediaMock.probe.mockResolvedValue(probeStub.videoStreamVertical2160p); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.OPTIMAL }]); + it('should scale horizontally when video is horizontal', async () => { + mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.OPTIMAL } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=720:-2,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([expect.stringMatching(/scale(_.+)?=-2:720/)]), + twoPass: false, + }, + ); + }); + + it('should scale vertically when video is vertical', async () => { + mediaMock.probe.mockResolvedValue(probeStub.videoStreamVertical2160p); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.OPTIMAL } }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([expect.stringMatching(/scale(_.+)?=720:-2/)]), twoPass: false, }, ); @@ -806,29 +746,15 @@ describe(MediaService.name, () => { it('should always scale video if height is uneven', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamOddHeight); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.ALL }, - { key: SystemConfigKey.FFMPEG_TARGET_RESOLUTION, value: 'original' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.ALL, targetResolution: 'original' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a aac', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - `-vf scale=-2:354,format=yuv420p`, - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([expect.stringMatching(/scale(_.+)?=-2:354/)]), twoPass: false, }, ); @@ -836,29 +762,15 @@ describe(MediaService.name, () => { it('should always scale video if width is uneven', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamOddWidth); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.ALL }, - { key: SystemConfigKey.FFMPEG_TARGET_RESOLUTION, value: 'original' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.ALL, targetResolution: 'original' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a aac', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - `-vf scale=354:-2,format=yuv420p`, - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([expect.stringMatching(/scale(_.+)?=354:-2/)]), twoPass: false, }, ); @@ -866,29 +778,17 @@ describe(MediaService.name, () => { it('should copy video stream when video matches target', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC }, - { key: SystemConfigKey.FFMPEG_ACCEPTED_AUDIO_CODECS, value: [AudioCodec.AAC] }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { targetVideoCodec: VideoCodec.HEVC, acceptedAudioCodecs: [AudioCodec.AAC] }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v copy', - '-c:a aac', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-tag:v hvc1', - '-v verbose', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v copy', '-c:a aac']), twoPass: false, }, ); @@ -896,29 +796,21 @@ describe(MediaService.name, () => { it('should not include hevc tag when target is hevc and video stream is copied from a different codec', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamH264); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC }, - { key: SystemConfigKey.FFMPEG_ACCEPTED_VIDEO_CODECS, value: [VideoCodec.H264, VideoCodec.HEVC] }, - { key: SystemConfigKey.FFMPEG_ACCEPTED_AUDIO_CODECS, value: [AudioCodec.AAC] }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { + targetVideoCodec: VideoCodec.HEVC, + acceptedVideoCodecs: [VideoCodec.H264, VideoCodec.HEVC], + acceptedAudioCodecs: [AudioCodec.AAC], + }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v copy', - '-c:a aac', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.not.arrayContaining(['-tag:v hvc1']), twoPass: false, }, ); @@ -926,30 +818,21 @@ describe(MediaService.name, () => { it('should include hevc tag when target is hevc and copying hevc video stream', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC }, - { key: SystemConfigKey.FFMPEG_ACCEPTED_VIDEO_CODECS, value: [VideoCodec.H264, VideoCodec.HEVC] }, - { key: SystemConfigKey.FFMPEG_ACCEPTED_AUDIO_CODECS, value: [AudioCodec.AAC] }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { + targetVideoCodec: VideoCodec.HEVC, + acceptedVideoCodecs: [VideoCodec.H264, VideoCodec.HEVC], + acceptedAudioCodecs: [AudioCodec.AAC], + }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v copy', - '-c:a aac', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-tag:v hvc1', - '-v verbose', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v copy', '-tag:v hvc1']), twoPass: false, }, ); @@ -957,53 +840,15 @@ describe(MediaService.name, () => { it('should copy audio stream when audio matches target', async () => { mediaMock.probe.mockResolvedValue(probeStub.audioStreamAac); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.OPTIMAL }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.OPTIMAL } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], - twoPass: false, - }, - ); - }); - - it('should transcode when container doesnt match target', async () => { - mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.OPTIMAL }]); - assetMock.getByIds.mockResolvedValue([assetStub.video]); - await sut.handleVideoConversion({ id: assetStub.video.id }); - expect(mediaMock.transcode).toHaveBeenCalledWith( - '/original/path.ext', - 'upload/encoded-video/user-id/as/se/asset-id.mp4', - { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v h264', '-c:a copy']), twoPass: false, }, ); @@ -1011,7 +856,7 @@ describe(MediaService.name, () => { it('should throw an exception if transcode value is invalid', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: 'invalid' }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: 'invalid' as any } }); await expect(sut.handleVideoConversion({ id: assetStub.video.id })).rejects.toThrow(); expect(mediaMock.transcode).not.toHaveBeenCalled(); @@ -1019,7 +864,7 @@ describe(MediaService.name, () => { it('should not transcode if transcoding is disabled', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.DISABLED }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.DISABLED } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).not.toHaveBeenCalled(); @@ -1027,7 +872,7 @@ describe(MediaService.name, () => { it('should not transcode if target codec is invalid', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: 'invalid' }]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: 'invalid' as any } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).not.toHaveBeenCalled(); @@ -1036,7 +881,7 @@ describe(MediaService.name, () => { it('should delete existing transcode if current policy does not require transcoding', async () => { const asset = assetStub.hasEncodedVideo; mediaMock.probe.mockResolvedValue(probeStub.videoStream2160p); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.DISABLED }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.DISABLED } }); assetMock.getByIds.mockResolvedValue([asset]); await sut.handleVideoConversion({ id: asset.id }); @@ -1050,28 +895,15 @@ describe(MediaService.name, () => { it('should set max bitrate if above 0', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '4500k' }]); + systemMock.get.mockResolvedValue({ ffmpeg: { maxBitrate: '4500k' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - '-maxrate 4500k', - '-bufsize 9000k', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v h264', '-maxrate 4500k', '-bufsize 9000k']), twoPass: false, }, ); @@ -1079,31 +911,15 @@ describe(MediaService.name, () => { it('should transcode in two passes for h264/h265 when enabled and max bitrate is above 0', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '4500k' }, - { key: SystemConfigKey.FFMPEG_TWO_PASS, value: true }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { twoPass: true, maxBitrate: '4500k' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-b:v 3104k', - '-minrate 1552k', - '-maxrate 4500k', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v h264', '-b:v 3104k', '-minrate 1552k', '-maxrate 4500k']), twoPass: true, }, ); @@ -1111,26 +927,15 @@ describe(MediaService.name, () => { it('should fallback to one pass for h264/h265 if two-pass is enabled but no max bitrate is set', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TWO_PASS, value: true }]); + systemMock.get.mockResolvedValue({ ffmpeg: { twoPass: true } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v h264', '-c:a copy']), twoPass: false, }, ); @@ -1138,33 +943,21 @@ describe(MediaService.name, () => { it('should transcode by bitrate in two passes for vp9 when two pass mode and max bitrate are enabled', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '4500k' }, - { key: SystemConfigKey.FFMPEG_TWO_PASS, value: true }, - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.VP9 }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { + maxBitrate: '4500k', + twoPass: true, + targetVideoCodec: VideoCodec.VP9, + }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v vp9', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-cpu-used 5', - '-row-mt 1', - '-b:v 3104k', - '-minrate 1552k', - '-maxrate 4500k', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-b:v 3104k', '-minrate 1552k', '-maxrate 4500k']), twoPass: true, }, ); @@ -1172,32 +965,21 @@ describe(MediaService.name, () => { it('should transcode by crf in two passes for vp9 when two pass mode is enabled and max bitrate is disabled', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '0' }, - { key: SystemConfigKey.FFMPEG_TWO_PASS, value: true }, - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.VP9 }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { + maxBitrate: '0', + twoPass: true, + targetVideoCodec: VideoCodec.VP9, + }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v vp9', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-cpu-used 5', - '-row-mt 1', - '-crf 23', - '-b:v 0', - ], + inputOptions: expect.any(Array), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-maxrate')]), twoPass: true, }, ); @@ -1205,31 +987,15 @@ describe(MediaService.name, () => { it('should configure preset for vp9', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.VP9 }, - { key: SystemConfigKey.FFMPEG_PRESET, value: 'slow' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: VideoCodec.VP9, preset: 'slow' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v vp9', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-cpu-used 2', - '-row-mt 1', - '-crf 23', - '-b:v 0', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-cpu-used 2']), twoPass: false, }, ); @@ -1237,30 +1003,15 @@ describe(MediaService.name, () => { it('should not configure preset for vp9 if invalid', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.VP9 }, - { key: SystemConfigKey.FFMPEG_PRESET, value: 'invalid' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { preset: 'invalid', targetVideoCodec: VideoCodec.VP9 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v vp9', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-row-mt 1', - '-crf 23', - '-b:v 0', - ], + inputOptions: expect.any(Array), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-cpu-used')]), twoPass: false, }, ); @@ -1268,32 +1019,15 @@ describe(MediaService.name, () => { it('should configure threads if above 0', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.VP9 }, - { key: SystemConfigKey.FFMPEG_THREADS, value: 2 }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: VideoCodec.VP9, threads: 2 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v vp9', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-cpu-used 5', - '-row-mt 1', - '-threads 2', - '-crf 23', - '-b:v 0', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-threads 2']), twoPass: false, }, ); @@ -1301,28 +1035,15 @@ describe(MediaService.name, () => { it('should disable thread pooling for h264 if thread limit is 1', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_THREADS, value: 1 }]); + systemMock.get.mockResolvedValue({ ffmpeg: { threads: 1 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-threads 1', - '-x264-params frame-threads=1:pools=none', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-threads 1', '-x264-params frame-threads=1:pools=none']), twoPass: false, }, ); @@ -1330,26 +1051,15 @@ describe(MediaService.name, () => { it('should omit thread flags for h264 if thread limit is at or below 0', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_THREADS, value: 0 }]); + systemMock.get.mockResolvedValue({ ffmpeg: { threads: 0 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-threads')]), twoPass: false, }, ); @@ -1357,32 +1067,15 @@ describe(MediaService.name, () => { it('should disable thread pooling for hevc if thread limit is 1', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_THREADS, value: 1 }, - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { threads: 1, targetVideoCodec: VideoCodec.HEVC } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v hevc', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-tag:v hvc1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-threads 1', - '-x265-params frame-threads=1:pools=none', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v hevc', '-threads 1', '-x265-params frame-threads=1:pools=none']), twoPass: false, }, ); @@ -1390,30 +1083,15 @@ describe(MediaService.name, () => { it('should omit thread flags for hevc if thread limit is at or below 0', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_THREADS, value: 0 }, - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { threads: 0, targetVideoCodec: VideoCodec.HEVC } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v hevc', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-tag:v hvc1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-threads')]), twoPass: false, }, ); @@ -1421,17 +1099,16 @@ describe(MediaService.name, () => { it('should use av1 if specified', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.AV1 }]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: VideoCodec.AV1 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([ '-c:v av1', - '-c:a copy', '-movflags faststart', '-fps_mode passthrough', '-map 0:0', @@ -1440,7 +1117,7 @@ describe(MediaService.name, () => { '-vf scale=-2:720,format=yuv420p', '-preset 12', '-crf 23', - ], + ]), twoPass: false, }, ); @@ -1448,29 +1125,15 @@ describe(MediaService.name, () => { it('should map `veryslow` preset to 4 for av1', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.AV1 }, - { key: SystemConfigKey.FFMPEG_PRESET, value: 'veryslow' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: VideoCodec.AV1, preset: 'veryslow' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v av1', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset 4', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-preset 4']), twoPass: false, }, ); @@ -1478,30 +1141,15 @@ describe(MediaService.name, () => { it('should set max bitrate for av1 if specified', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.AV1 }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '2M' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: VideoCodec.AV1, maxBitrate: '2M' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v av1', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset 12', - '-crf 23', - '-svtav1-params mbr=2M', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-svtav1-params mbr=2M']), twoPass: false, }, ); @@ -1509,30 +1157,15 @@ describe(MediaService.name, () => { it('should set threads for av1 if specified', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.AV1 }, - { key: SystemConfigKey.FFMPEG_THREADS, value: 4 }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: VideoCodec.AV1, threads: 4 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v av1', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset 12', - '-crf 23', - '-svtav1-params lp=4', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-svtav1-params lp=4']), twoPass: false, }, ); @@ -1540,31 +1173,15 @@ describe(MediaService.name, () => { it('should set both bitrate and threads for av1 if specified', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.AV1 }, - { key: SystemConfigKey.FFMPEG_THREADS, value: 4 }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '2M' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { targetVideoCodec: VideoCodec.AV1, threads: 4, maxBitrate: '2M' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v av1', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset 12', - '-crf 23', - '-svtav1-params lp=4:mbr=2M', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-svtav1-params lp=4:mbr=2M']), twoPass: false, }, ); @@ -1572,11 +1189,13 @@ describe(MediaService.name, () => { it('should skip transcoding for audioless videos with optimal policy if video codec is correct', async () => { mediaMock.probe.mockResolvedValue(probeStub.noAudioStreams); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC }, - { key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.OPTIMAL }, - { key: SystemConfigKey.FFMPEG_TARGET_RESOLUTION, value: '1080p' }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { + targetVideoCodec: VideoCodec.HEVC, + transcode: TranscodePolicy.OPTIMAL, + targetResolution: '1080p', + }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).not.toHaveBeenCalled(); @@ -1584,10 +1203,7 @@ describe(MediaService.name, () => { it('should fail if hwaccel is enabled for an unsupported codec', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.NVENC }, - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.VP9 }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.NVENC, targetVideoCodec: VideoCodec.VP9 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await expect(sut.handleVideoConversion({ id: assetStub.video.id })).resolves.toBe(JobStatus.FAILED); expect(mediaMock.transcode).not.toHaveBeenCalled(); @@ -1595,27 +1211,23 @@ describe(MediaService.name, () => { it('should fail if hwaccel option is invalid', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: 'invalid' }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: 'invalid' as any } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await expect(sut.handleVideoConversion({ id: assetStub.video.id })).resolves.toBe(JobStatus.FAILED); expect(mediaMock.transcode).not.toHaveBeenCalled(); }); - it('should set two pass options for nvenc when enabled', async () => { + it('should set options for nvenc', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.NVENC }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '10000k' }, - { key: SystemConfigKey.FFMPEG_TWO_PASS, value: true }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.NVENC } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], - outputOptions: [ + inputOptions: expect.arrayContaining(['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda']), + outputOptions: expect.arrayContaining([ '-tune hq', '-qmin 0', '-rc-lookahead 20', @@ -1630,11 +1242,30 @@ describe(MediaService.name, () => { '-v verbose', '-vf format=nv12,hwupload_cuda,scale_cuda=-2:720', '-preset p1', - '-b:v 6897k', - '-maxrate 10000k', - '-bufsize 6897k', - '-multipass 2', - ], + '-cq:v 23', + ]), + twoPass: false, + }, + ); + }); + + it('should set two pass options for nvenc when enabled', async () => { + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + systemMock.get.mockResolvedValue({ + ffmpeg: { + accel: TranscodeHWAccel.NVENC, + maxBitrate: '10000k', + twoPass: true, + }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining(['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda']), + outputOptions: expect.arrayContaining([expect.stringContaining('-multipass')]), twoPass: false, }, ); @@ -1642,36 +1273,15 @@ describe(MediaService.name, () => { it('should set vbr options for nvenc when max bitrate is enabled', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.NVENC }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '10000k' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.NVENC, maxBitrate: '10000k' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], - outputOptions: [ - '-tune hq', - '-qmin 0', - '-rc-lookahead 20', - '-i_qfactor 0.75', - `-c:v h264_nvenc`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload_cuda,scale_cuda=-2:720', - '-preset p1', - '-cq:v 23', - '-maxrate 10000k', - '-bufsize 6897k', - ], + inputOptions: expect.arrayContaining(['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda']), + outputOptions: expect.arrayContaining(['-cq:v 23', '-maxrate 10000k', '-bufsize 6897k']), twoPass: false, }, ); @@ -1679,31 +1289,15 @@ describe(MediaService.name, () => { it('should set cq options for nvenc when max bitrate is disabled', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.NVENC }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.NVENC, maxBitrate: '10000k' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], - outputOptions: [ - '-tune hq', - '-qmin 0', - '-rc-lookahead 20', - '-i_qfactor 0.75', - `-c:v h264_nvenc`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload_cuda,scale_cuda=-2:720', - '-preset p1', - '-cq:v 23', - ], + inputOptions: expect.arrayContaining(['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda']), + outputOptions: expect.not.stringContaining('-maxrate'), twoPass: false, }, ); @@ -1711,33 +1305,15 @@ describe(MediaService.name, () => { it('should omit preset for nvenc if invalid', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.NVENC }, - { key: SystemConfigKey.FFMPEG_PRESET, value: 'invalid' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.NVENC, preset: 'invalid' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], - outputOptions: [ - '-tune hq', - '-qmin 0', - '-rc-lookahead 20', - '-i_qfactor 0.75', - `-c:v h264_nvenc`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload_cuda,scale_cuda=-2:720', - '-cq:v 23', - ], + inputOptions: expect.arrayContaining(['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda']), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-preset')]), twoPass: false, }, ); @@ -1745,31 +1321,60 @@ describe(MediaService.name, () => { it('should ignore two pass for nvenc if max bitrate is disabled', async () => { mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.NVENC }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.NVENC } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], - outputOptions: [ - '-tune hq', - '-qmin 0', - '-rc-lookahead 20', - '-i_qfactor 0.75', - `-c:v h264_nvenc`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload_cuda,scale_cuda=-2:720', - '-preset p1', - '-cq:v 23', - ], + inputOptions: expect.arrayContaining(['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda']), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-multipass')]), + twoPass: false, + }, + ); + }); + + it('should use hardware decoding for nvenc if enabled', async () => { + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.NVENC, accelDecode: true }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining([ + '-hwaccel cuda', + '-hwaccel_output_format cuda', + '-noautorotate', + '-threads 1', + ]), + outputOptions: expect.arrayContaining([expect.stringContaining('scale_cuda=-2:720:format=nv12')]), + twoPass: false, + }, + ); + }); + + it('should use hardware tone-mapping for nvenc if hardware decoding is enabled and should tone map', async () => { + mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.NVENC, accelDecode: true }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining(['-hwaccel cuda', '-hwaccel_output_format cuda']), + outputOptions: expect.arrayContaining([ + expect.stringContaining( + 'tonemap_cuda=desat=0:matrix=bt709:primaries=bt709:range=pc:tonemap=hable:transfer=bt709:format=nv12', + ), + ]), twoPass: false, }, ); @@ -1778,18 +1383,15 @@ describe(MediaService.name, () => { it('should set options for qsv', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.QSV }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '10000k' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.QSV, maxBitrate: '10000k' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'], - outputOptions: [ + inputOptions: expect.arrayContaining(['-init_hw_device qsv=hw', '-filter_hw_device hw']), + outputOptions: expect.arrayContaining([ `-c:v h264_qsv`, '-c:a copy', '-movflags faststart', @@ -1805,7 +1407,7 @@ describe(MediaService.name, () => { '-global_quality 23', '-maxrate 10000k', '-bufsize 20000k', - ], + ]), twoPass: false, }, ); @@ -1814,35 +1416,24 @@ describe(MediaService.name, () => { it('should set options for qsv with custom dri node', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.QSV }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '10000k' }, - { key: SystemConfigKey.FFMPEG_PREFERRED_HW_DEVICE, value: '/dev/dri/renderD128' }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { + accel: TranscodeHWAccel.QSV, + maxBitrate: '10000k', + preferredHwDevice: '/dev/dri/renderD128', + }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device qsv=hw,child_device=/dev/dri/renderD128', '-filter_hw_device hw'], - outputOptions: [ - `-c:v h264_qsv`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-bf 7', - '-refs 5', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload=extra_hw_frames=64,scale_qsv=-1:720', - '-preset 7', - '-global_quality 23', - '-maxrate 10000k', - '-bufsize 20000k', - ], + inputOptions: expect.arrayContaining([ + '-init_hw_device qsv=hw,child_device=/dev/dri/renderD128', + '-filter_hw_device hw', + ]), + outputOptions: expect.any(Array), twoPass: false, }, ); @@ -1851,31 +1442,15 @@ describe(MediaService.name, () => { it('should omit preset for qsv if invalid', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.QSV }, - { key: SystemConfigKey.FFMPEG_PRESET, value: 'invalid' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.QSV, preset: 'invalid' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'], - outputOptions: [ - `-c:v h264_qsv`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-bf 7', - '-refs 5', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload=extra_hw_frames=64,scale_qsv=-1:720', - '-global_quality 23', - ], + inputOptions: expect.arrayContaining(['-init_hw_device qsv=hw', '-filter_hw_device hw']), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-preset')]), twoPass: false, }, ); @@ -1884,33 +1459,15 @@ describe(MediaService.name, () => { it('should set low power mode for qsv if target video codec is vp9', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.QSV }, - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.VP9 }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.QSV, targetVideoCodec: VideoCodec.VP9 } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'], - outputOptions: [ - `-c:v vp9_qsv`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-bf 7', - '-refs 5', - '-g 256', - '-low_power 1', - '-v verbose', - '-vf format=nv12,hwupload=extra_hw_frames=64,scale_qsv=-1:720', - '-preset 7', - '-q:v 23', - ], + inputOptions: expect.arrayContaining(['-init_hw_device qsv=hw', '-filter_hw_device hw']), + outputOptions: expect.arrayContaining(['-low_power 1']), twoPass: false, }, ); @@ -1919,27 +1476,105 @@ describe(MediaService.name, () => { it('should fail for qsv if no hw devices', async () => { storageMock.readdir.mockResolvedValue([]); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.QSV }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.QSV } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await expect(sut.handleVideoConversion({ id: assetStub.video.id })).resolves.toBe(JobStatus.FAILED); expect(mediaMock.transcode).not.toHaveBeenCalled(); }); - it('should set vbr options for vaapi when max bitrate is enabled', async () => { + it('should use hardware decoding for qsv if enabled', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '10000k' }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.QSV, accelDecode: true }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + + await sut.handleVideoConversion({ id: assetStub.video.id }); + + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining([ + '-hwaccel qsv', + '-hwaccel_output_format qsv', + '-async_depth 4', + '-threads 1', + ]), + outputOptions: expect.arrayContaining([ + expect.stringContaining('scale_qsv=-1:720:async_depth=4:mode=hq:format=nv12'), + ]), + twoPass: false, + }, + ); + }); + + it('should use hardware tone-mapping for qsv if hardware decoding is enabled and should tone map', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.QSV, accelDecode: true }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + + await sut.handleVideoConversion({ id: assetStub.video.id }); + + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining([ + '-hwaccel qsv', + '-hwaccel_output_format qsv', + '-async_depth 4', + '-threads 1', + ]), + outputOptions: expect.arrayContaining([ + expect.stringContaining( + 'hwmap=derive_device=opencl,tonemap_opencl=desat=0:format=nv12:matrix=bt709:primaries=bt709:range=pc:tonemap=hable:transfer=bt709,hwmap=derive_device=qsv:reverse=1,format=qsv', + ), + ]), + twoPass: false, + }, + ); + }); + + it('should use preferred device for qsv when hardware decoding', async () => { + storageMock.readdir.mockResolvedValue(['renderD128', 'renderD129', 'renderD130']); + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.QSV, accelDecode: true, preferredHwDevice: 'renderD129' }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining(['-hwaccel qsv', '-qsv_device /dev/dri/renderD129']), + outputOptions: expect.any(Array), + twoPass: false, + }, + ); + }); + + it('should set options for vaapi', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'], - outputOptions: [ + inputOptions: expect.arrayContaining([ + '-init_hw_device vaapi=accel:/dev/dri/renderD128', + '-filter_hw_device accel', + ]), + outputOptions: expect.arrayContaining([ `-c:v h264_vaapi`, '-c:a copy', '-movflags faststart', @@ -1950,11 +1585,34 @@ describe(MediaService.name, () => { '-v verbose', '-vf format=nv12,hwupload,scale_vaapi=-2:720', '-compression_level 7', + '-rc_mode 1', + ]), + twoPass: false, + }, + ); + }); + + it('should set vbr options for vaapi when max bitrate is enabled', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI, maxBitrate: '10000k' } }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining([ + '-init_hw_device vaapi=accel:/dev/dri/renderD128', + '-filter_hw_device accel', + ]), + outputOptions: expect.arrayContaining([ + `-c:v h264_vaapi`, '-b:v 6897k', '-maxrate 10000k', '-minrate 3448.5k', '-rc_mode 3', - ], + ]), twoPass: false, }, ); @@ -1963,29 +1621,24 @@ describe(MediaService.name, () => { it('should set cq options for vaapi when max bitrate is disabled', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'], - outputOptions: [ + inputOptions: expect.arrayContaining([ + '-init_hw_device vaapi=accel:/dev/dri/renderD128', + '-filter_hw_device accel', + ]), + outputOptions: expect.arrayContaining([ `-c:v h264_vaapi`, '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload,scale_vaapi=-2:720', - '-compression_level 7', '-qp 23', '-global_quality 23', '-rc_mode 1', - ], + ]), twoPass: false, }, ); @@ -1994,31 +1647,18 @@ describe(MediaService.name, () => { it('should omit preset for vaapi if invalid', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }, - { key: SystemConfigKey.FFMPEG_PRESET, value: 'invalid' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI, preset: 'invalid' } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'], - outputOptions: [ - `-c:v h264_vaapi`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload,scale_vaapi=-2:720', - '-qp 23', - '-global_quality 23', - '-rc_mode 1', - ], + inputOptions: expect.arrayContaining([ + '-init_hw_device vaapi=accel:/dev/dri/renderD128', + '-filter_hw_device accel', + ]), + outputOptions: expect.not.arrayContaining([expect.stringContaining('-compression_level')]), twoPass: false, }, ); @@ -2027,55 +1667,38 @@ describe(MediaService.name, () => { it('should prefer gpu for vaapi if available', async () => { storageMock.readdir.mockResolvedValue(['renderD129', 'card1', 'card0', 'renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/card1', '-filter_hw_device accel'], - outputOptions: [ - `-c:v h264_vaapi`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload,scale_vaapi=-2:720', - '-compression_level 7', - '-qp 23', - '-global_quality 23', - '-rc_mode 1', - ], + inputOptions: expect.arrayContaining([ + '-init_hw_device vaapi=accel:/dev/dri/card1', + '-filter_hw_device accel', + ]), + outputOptions: expect.arrayContaining([`-c:v h264_vaapi`]), twoPass: false, }, ); + }); - storageMock.readdir.mockResolvedValue(['renderD129', 'renderD128']); + it('should prefer higher index gpu node', async () => { + storageMock.readdir.mockResolvedValue(['renderD129', 'renderD130', 'renderD128']); + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI } }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD129', '-filter_hw_device accel'], - outputOptions: [ - `-c:v h264_vaapi`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload,scale_vaapi=-2:720', - '-compression_level 7', - '-qp 23', - '-global_quality 23', - '-rc_mode 1', - ], + inputOptions: expect.arrayContaining([ + '-init_hw_device vaapi=accel:/dev/dri/renderD130', + '-filter_hw_device accel', + ]), + outputOptions: expect.arrayContaining([`-c:v h264_vaapi`]), twoPass: false, }, ); @@ -2084,32 +1707,20 @@ describe(MediaService.name, () => { it('should select specific gpu node if selected', async () => { storageMock.readdir.mockResolvedValue(['renderD129', 'card1', 'card0', 'renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }, - { key: SystemConfigKey.FFMPEG_PREFERRED_HW_DEVICE, value: '/dev/dri/renderD128' }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.VAAPI, preferredHwDevice: '/dev/dri/renderD128' }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'], - outputOptions: [ - `-c:v h264_vaapi`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf format=nv12,hwupload,scale_vaapi=-2:720', - '-compression_level 7', - '-qp 23', - '-global_quality 23', - '-rc_mode 1', - ], + inputOptions: expect.arrayContaining([ + '-init_hw_device vaapi=accel:/dev/dri/renderD128', + '-filter_hw_device accel', + ]), + outputOptions: expect.arrayContaining([`-c:v h264_vaapi`]), twoPass: false, }, ); @@ -2118,7 +1729,7 @@ describe(MediaService.name, () => { it('should fallback to sw transcoding if hw transcoding fails', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); mediaMock.transcode.mockRejectedValueOnce(new Error('error')); await sut.handleVideoConversion({ id: assetStub.video.id }); @@ -2127,19 +1738,8 @@ describe(MediaService.name, () => { '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ - '-c:v h264', - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', - '-vf scale=-2:720,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining(['-c:v h264']), twoPass: false, }, ); @@ -2148,63 +1748,25 @@ describe(MediaService.name, () => { it('should fail for vaapi if no hw devices', async () => { storageMock.readdir.mockResolvedValue([]); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.VAAPI } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await expect(sut.handleVideoConversion({ id: assetStub.video.id })).resolves.toBe(JobStatus.FAILED); expect(mediaMock.transcode).not.toHaveBeenCalled(); }); - it('should set vbr options for rkmpp when max bitrate is enabled', async () => { - storageMock.readdir.mockResolvedValue(['renderD128']); - mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.RKMPP }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '10000k' }, - { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC }, - ]); - assetMock.getByIds.mockResolvedValue([assetStub.video]); - await sut.handleVideoConversion({ id: assetStub.video.id }); - expect(mediaMock.transcode).toHaveBeenCalledWith( - '/original/path.ext', - 'upload/encoded-video/user-id/as/se/asset-id.mp4', - { - inputOptions: ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga'], - outputOptions: [ - `-c:v hevc_rkmpp`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-tag:v hvc1', - '-v verbose', - '-vf scale_rkrga=-2:720:format=nv12:afbc=1', - '-level 153', - '-rc_mode AVBR', - '-b:v 10000k', - ], - twoPass: false, - }, - ); - }); - - it('should set cqp options for rkmpp when max bitrate is disabled', async () => { + it('should set options for rkmpp', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); + storageMock.stat.mockResolvedValue({ ...new Stats(), isFile: () => true, isCharacterDevice: () => true }); mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.RKMPP }, - { key: SystemConfigKey.FFMPEG_CRF, value: 30 }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '0' }, - ]); + systemMock.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHWAccel.RKMPP, accelDecode: true } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga'], - outputOptions: [ + inputOptions: expect.arrayContaining(['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']), + outputOptions: expect.arrayContaining([ `-c:v h264_rkmpp`, '-c:a copy', '-movflags faststart', @@ -2216,8 +1778,53 @@ describe(MediaService.name, () => { '-vf scale_rkrga=-2:720:format=nv12:afbc=1', '-level 51', '-rc_mode CQP', - '-qp_init 30', - ], + '-qp_init 23', + ]), + twoPass: false, + }, + ); + }); + + it('should set vbr options for rkmpp when max bitrate is enabled', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + storageMock.stat.mockResolvedValue({ ...new Stats(), isFile: () => true, isCharacterDevice: () => true }); + mediaMock.probe.mockResolvedValue(probeStub.videoStreamVp9); + systemMock.get.mockResolvedValue({ + ffmpeg: { + accel: TranscodeHWAccel.RKMPP, + accelDecode: true, + maxBitrate: '10000k', + targetVideoCodec: VideoCodec.HEVC, + }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining(['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']), + outputOptions: expect.arrayContaining([`-c:v hevc_rkmpp`, '-level 153', '-rc_mode AVBR', '-b:v 10000k']), + twoPass: false, + }, + ); + }); + + it('should set cqp options for rkmpp when max bitrate is disabled', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + storageMock.stat.mockResolvedValue({ ...new Stats(), isFile: () => true, isCharacterDevice: () => true }); + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.RKMPP, accelDecode: true, crf: 30, maxBitrate: '0' }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: expect.arrayContaining(['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']), + outputOptions: expect.arrayContaining([`-c:v h264_rkmpp`, '-level 51', '-rc_mode CQP', '-qp_init 30']), twoPass: false, }, ); @@ -2227,32 +1834,69 @@ describe(MediaService.name, () => { storageMock.readdir.mockResolvedValue(['renderD128']); storageMock.stat.mockResolvedValue({ ...new Stats(), isFile: () => true, isCharacterDevice: () => true }); mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.RKMPP }, - { key: SystemConfigKey.FFMPEG_CRF, value: 30 }, - { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '0' }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.RKMPP, accelDecode: true, crf: 30, maxBitrate: '0' }, + }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga'], - outputOptions: [ - `-c:v h264_rkmpp`, - '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-g 256', - '-v verbose', - '-vf scale_rkrga=-2:720:format=p010:afbc=1,hwmap=derive_device=opencl:mode=read,tonemap_opencl=format=nv12:r=pc:p=bt709:t=bt709:m=bt709:tonemap=hable:desat=0,hwmap=derive_device=rkmpp:mode=write:reverse=1,format=drm_prime', - '-level 51', - '-rc_mode CQP', - '-qp_init 30', - ], + inputOptions: expect.arrayContaining(['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']), + outputOptions: expect.arrayContaining([ + expect.stringContaining( + 'scale_rkrga=-2:720:format=p010:afbc=1,hwmap=derive_device=opencl:mode=read,tonemap_opencl=format=nv12:r=pc:p=bt709:t=bt709:m=bt709:tonemap=hable:desat=0,hwmap=derive_device=rkmpp:mode=write:reverse=1,format=drm_prime', + ), + ]), + twoPass: false, + }, + ); + }); + + it('should use software decoding and tone-mapping if hardware decoding is disabled', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + storageMock.stat.mockResolvedValue({ ...new Stats(), isFile: () => true, isCharacterDevice: () => true }); + mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.RKMPP, accelDecode: false, crf: 30, maxBitrate: '0' }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: [], + outputOptions: expect.arrayContaining([ + expect.stringContaining( + 'zscale=t=linear:npl=100,tonemap=hable:desat=0,zscale=p=bt709:t=bt709:m=bt709:range=pc,format=yuv420p', + ), + ]), + twoPass: false, + }, + ); + }); + + it('should use software decoding and tone-mapping if opencl is not available', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + storageMock.stat.mockResolvedValue({ ...new Stats(), isFile: () => false, isCharacterDevice: () => false }); + mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.RKMPP, accelDecode: true, crf: 30, maxBitrate: '0' }, + }); + assetMock.getByIds.mockResolvedValue([assetStub.video]); + await sut.handleVideoConversion({ id: assetStub.video.id }); + expect(mediaMock.transcode).toHaveBeenCalledWith( + '/original/path.ext', + 'upload/encoded-video/user-id/as/se/asset-id.mp4', + { + inputOptions: [], + outputOptions: expect.arrayContaining([ + expect.stringContaining( + 'zscale=t=linear:npl=100,tonemap=hable:desat=0,zscale=p=bt709:t=bt709:m=bt709:range=pc,format=yuv420p', + ), + ]), twoPass: false, }, ); @@ -2261,26 +1905,19 @@ describe(MediaService.name, () => { it('should tonemap when policy is required and video is hdr', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.REQUIRED }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.REQUIRED } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([ '-c:v h264', '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', '-vf zscale=t=linear:npl=100,tonemap=hable:desat=0,zscale=p=bt709:t=bt709:m=bt709:range=pc,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + ]), twoPass: false, }, ); @@ -2288,26 +1925,19 @@ describe(MediaService.name, () => { it('should tonemap when policy is optimal and video is hdr', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.OPTIMAL }]); + systemMock.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.OPTIMAL } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([ '-c:v h264', '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', '-vf zscale=t=linear:npl=100,tonemap=hable:desat=0,zscale=p=bt709:t=bt709:m=bt709:range=pc,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + ]), twoPass: false, }, ); @@ -2315,26 +1945,19 @@ describe(MediaService.name, () => { it('should set npl to 250 for reinhard and mobius tone-mapping algorithms', async () => { mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TONEMAP, value: ToneMapping.MOBIUS }]); + systemMock.get.mockResolvedValue({ ffmpeg: { tonemap: ToneMapping.MOBIUS } }); assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: [], - outputOptions: [ + inputOptions: expect.any(Array), + outputOptions: expect.arrayContaining([ '-c:v h264', '-c:a copy', - '-movflags faststart', - '-fps_mode passthrough', - '-map 0:0', - '-map 0:1', - '-v verbose', '-vf zscale=t=linear:npl=250,tonemap=mobius:desat=0,zscale=p=bt709:t=bt709:m=bt709:range=pc,format=yuv420p', - '-preset ultrafast', - '-crf 23', - ], + ]), twoPass: false, }, ); diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 00623cecbe..7e52fe384c 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -1,10 +1,5 @@ import { Inject, Injectable, UnsupportedMediaTypeException } from '@nestjs/common'; import { dirname } from 'node:path'; -import { GeneratedImageType, StorageCore, StorageFolder } from 'src/cores/storage.core'; -import { SystemConfigCore } from 'src/cores/system-config.core'; -import { SystemConfigFFmpegDto } from 'src/dtos/system-config.dto'; -import { AssetEntity, AssetType } from 'src/entities/asset.entity'; -import { AssetPathType } from 'src/entities/move.entity'; import { AudioCodec, Colorspace, @@ -13,7 +8,12 @@ import { TranscodePolicy, TranscodeTarget, VideoCodec, -} from 'src/entities/system-config.entity'; +} from 'src/config'; +import { GeneratedImageType, StorageCore, StorageFolder } from 'src/cores/storage.core'; +import { SystemConfigCore } from 'src/cores/system-config.core'; +import { SystemConfigFFmpegDto } from 'src/dtos/system-config.dto'; +import { AssetEntity, AssetType } from 'src/entities/asset.entity'; +import { AssetPathType } from 'src/entities/move.entity'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { @@ -31,14 +31,17 @@ import { AudioStreamInfo, IMediaRepository, VideoCodecHWConfig, VideoStreamInfo import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { AV1Config, H264Config, HEVCConfig, - NVENCConfig, - QSVConfig, - RKMPPConfig, + NvencHwDecodeConfig, + NvencSwDecodeConfig, + QsvHwDecodeConfig, + QsvSwDecodeConfig, + RkmppHwDecodeConfig, + RkmppSwDecodeConfig, ThumbnailConfig, VAAPIConfig, VP9Config, @@ -50,7 +53,8 @@ import { usePagination } from 'src/utils/pagination'; export class MediaService { private configCore: SystemConfigCore; private storageCore: StorageCore; - private hasOpenCL?: boolean = undefined; + private openCL: boolean | null = null; + private devices: string[] | null = null; constructor( @Inject(IAssetRepository) private assetRepository: IAssetRepository, @@ -58,20 +62,20 @@ export class MediaService { @Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(IMediaRepository) private mediaRepository: IMediaRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IMoveRepository) moveRepository: IMoveRepository, @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(MediaService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); this.storageCore = StorageCore.create( assetRepository, cryptoRepository, moveRepository, personRepository, storageRepository, - configRepository, + systemMetadataRepository, this.logger, ); } @@ -328,7 +332,6 @@ export class MediaService { } const { ffmpeg: config } = await this.configCore.getConfig(); - const target = this.getTranscodeTarget(config, mainVideoStream, mainAudioStream); if (target === TranscodeTarget.NONE) { if (asset.encodedVideoPath) { @@ -360,8 +363,7 @@ export class MediaService { `Error occurred during transcoding. Retrying with ${config.accel.toUpperCase()} acceleration disabled.`, ); } - config.accel = TranscodeHWAccel.DISABLED; - transcodeOptions = await this.getCodecConfig(config).then((c) => + transcodeOptions = await this.getCodecConfig({ ...config, accel: TranscodeHWAccel.DISABLED }).then((c) => c.getOptions(target, mainVideoStream, mainAudioStream), ); await this.mediaRepository.transcode(input, output, transcodeOptions); @@ -492,36 +494,26 @@ export class MediaService { private async getHWCodecConfig(config: SystemConfigFFmpegDto) { let handler: VideoCodecHWConfig; - let devices: string[]; switch (config.accel) { case TranscodeHWAccel.NVENC: { - handler = new NVENCConfig(config); + handler = config.accelDecode ? new NvencHwDecodeConfig(config) : new NvencSwDecodeConfig(config); break; } case TranscodeHWAccel.QSV: { - devices = await this.storageRepository.readdir('/dev/dri'); - handler = new QSVConfig(config, devices); + handler = config.accelDecode + ? new QsvHwDecodeConfig(config, await this.getDevices()) + : new QsvSwDecodeConfig(config, await this.getDevices()); break; } case TranscodeHWAccel.VAAPI: { - devices = await this.storageRepository.readdir('/dev/dri'); - handler = new VAAPIConfig(config, devices); + handler = new VAAPIConfig(config, await this.getDevices()); break; } case TranscodeHWAccel.RKMPP: { - if (this.hasOpenCL === undefined) { - try { - const maliIcdStat = await this.storageRepository.stat('/etc/OpenCL/vendors/mali.icd'); - const maliDeviceStat = await this.storageRepository.stat('/dev/mali0'); - this.hasOpenCL = maliIcdStat.isFile() && maliDeviceStat.isCharacterDevice(); - } catch { - this.logger.warn('OpenCL not available for transcoding, using CPU instead.'); - this.hasOpenCL = false; - } - } - - devices = await this.storageRepository.readdir('/dev/dri'); - handler = new RKMPPConfig(config, devices, this.hasOpenCL); + handler = + config.accelDecode && (await this.hasOpenCL()) + ? new RkmppHwDecodeConfig(config, await this.getDevices()) + : new RkmppSwDecodeConfig(config, await this.getDevices()); break; } default: { @@ -572,4 +564,27 @@ export class MediaService { return extractedSize >= targetSize; } + + private async getDevices() { + if (!this.devices) { + this.devices = await this.storageRepository.readdir('/dev/dri'); + } + + return this.devices; + } + + private async hasOpenCL() { + if (this.openCL === null) { + try { + const maliIcdStat = await this.storageRepository.stat('/etc/OpenCL/vendors/mali.icd'); + const maliDeviceStat = await this.storageRepository.stat('/dev/mali0'); + this.openCL = maliIcdStat.isFile() && maliDeviceStat.isCharacterDevice(); + } catch { + this.logger.warn('OpenCL not available for transcoding, using CPU instead.'); + this.openCL = false; + } + } + + return this.openCL; + } } diff --git a/server/src/services/metadata.service.spec.ts b/server/src/services/metadata.service.spec.ts index 5adeb1c774..59294bdcfc 100644 --- a/server/src/services/metadata.service.spec.ts +++ b/server/src/services/metadata.service.spec.ts @@ -4,7 +4,6 @@ import { Stats } from 'node:fs'; import { constants } from 'node:fs/promises'; import { AssetType } from 'src/entities/asset.entity'; import { ExifEntity } from 'src/entities/exif.entity'; -import { SystemConfigKey } from 'src/entities/system-config.entity'; import { IAlbumRepository } from 'src/interfaces/album.interface'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; @@ -17,7 +16,7 @@ import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interfa import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { MetadataService, Orientation } from 'src/services/metadata.service'; import { assetStub } from 'test/fixtures/asset.stub'; @@ -35,14 +34,14 @@ import { newMetadataRepositoryMock } from 'test/repositories/metadata.repository import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; import { Mocked } from 'vitest'; describe(MetadataService.name, () => { let albumMock: Mocked; let assetMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let cryptoRepository: Mocked; let jobMock: Mocked; let metadataMock: Mocked; @@ -59,7 +58,6 @@ describe(MetadataService.name, () => { beforeEach(() => { albumMock = newAlbumRepositoryMock(); assetMock = newAssetRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); cryptoRepository = newCryptoRepositoryMock(); jobMock = newJobRepositoryMock(); metadataMock = newMetadataRepositoryMock(); @@ -67,6 +65,7 @@ describe(MetadataService.name, () => { personMock = newPersonRepositoryMock(); eventMock = newEventRepositoryMock(); storageMock = newStorageRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); mediaMock = newMediaRepositoryMock(); databaseMock = newDatabaseRepositoryMock(); userMock = newUserRepositoryMock(); @@ -84,7 +83,7 @@ describe(MetadataService.name, () => { moveMock, personMock, storageMock, - configMock, + systemMock, userMock, loggerMock, ); @@ -99,20 +98,23 @@ describe(MetadataService.name, () => { }); describe('init', () => { - beforeEach(async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.REVERSE_GEOCODING_ENABLED, value: true }]); - + it('should pause and resume queue during init', async () => { await sut.init(); - }); - it('should return if reverse geocoding is disabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.REVERSE_GEOCODING_ENABLED, value: false }]); - - await sut.init(); expect(jobMock.pause).toHaveBeenCalledTimes(1); expect(metadataMock.init).toHaveBeenCalledTimes(1); expect(jobMock.resume).toHaveBeenCalledTimes(1); }); + + it('should return if reverse geocoding is disabled', async () => { + systemMock.get.mockResolvedValue({ reverseGeocoding: { enabled: false } }); + + await sut.init(); + + expect(jobMock.pause).not.toHaveBeenCalled(); + expect(metadataMock.init).not.toHaveBeenCalled(); + expect(jobMock.resume).not.toHaveBeenCalled(); + }); }); describe('handleLivePhotoLinking', () => { @@ -294,7 +296,7 @@ describe(MetadataService.name, () => { it('should apply reverse geocoding', async () => { assetMock.getByIds.mockResolvedValue([assetStub.withLocation]); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.REVERSE_GEOCODING_ENABLED, value: true }]); + systemMock.get.mockResolvedValue({ reverseGeocoding: { enabled: true } }); metadataMock.reverseGeocode.mockResolvedValue({ city: 'City', state: 'State', country: 'Country' }); metadataMock.readTags.mockResolvedValue({ GPSLatitude: assetStub.withLocation.exifInfo!.latitude!, @@ -354,7 +356,7 @@ describe(MetadataService.name, () => { }); it('should extract the MotionPhotoVideo tag from Samsung HEIC motion photos', async () => { - assetMock.getByIds.mockResolvedValue([{ ...assetStub.livePhotoStillAsset, livePhotoVideoId: null }]); + assetMock.getByIds.mockResolvedValue([{ ...assetStub.livePhotoWithOriginalFileName, livePhotoVideoId: null }]); metadataMock.readTags.mockResolvedValue({ Directory: 'foo/bar/', MotionPhotoVideo: new BinaryField(0, ''), @@ -370,23 +372,23 @@ describe(MetadataService.name, () => { const video = randomBytes(512); metadataMock.extractBinaryTag.mockResolvedValue(video); - await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id }); + await sut.handleMetadataExtraction({ id: assetStub.livePhotoWithOriginalFileName.id }); expect(metadataMock.extractBinaryTag).toHaveBeenCalledWith( - assetStub.livePhotoStillAsset.originalPath, + assetStub.livePhotoWithOriginalFileName.originalPath, 'MotionPhotoVideo', ); - expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.livePhotoStillAsset.id]); + expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.livePhotoWithOriginalFileName.id]); expect(assetMock.create).toHaveBeenCalled(); // This could have arguments added expect(userMock.updateUsage).toHaveBeenCalledWith(assetStub.livePhotoMotionAsset.ownerId, 512); expect(storageMock.writeFile).toHaveBeenCalledWith(assetStub.livePhotoMotionAsset.originalPath, video); expect(assetMock.update).toHaveBeenNthCalledWith(1, { - id: assetStub.livePhotoStillAsset.id, + id: assetStub.livePhotoWithOriginalFileName.id, livePhotoVideoId: fileStub.livePhotoMotion.uuid, }); }); it('should extract the EmbeddedVideo tag from Samsung JPEG motion photos', async () => { - assetMock.getByIds.mockResolvedValue([{ ...assetStub.livePhotoStillAsset, livePhotoVideoId: null }]); + assetMock.getByIds.mockResolvedValue([{ ...assetStub.livePhotoWithOriginalFileName, livePhotoVideoId: null }]); metadataMock.readTags.mockResolvedValue({ Directory: 'foo/bar/', EmbeddedVideoFile: new BinaryField(0, ''), @@ -399,23 +401,23 @@ describe(MetadataService.name, () => { const video = randomBytes(512); metadataMock.extractBinaryTag.mockResolvedValue(video); - await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id }); + await sut.handleMetadataExtraction({ id: assetStub.livePhotoWithOriginalFileName.id }); expect(metadataMock.extractBinaryTag).toHaveBeenCalledWith( - assetStub.livePhotoStillAsset.originalPath, + assetStub.livePhotoWithOriginalFileName.originalPath, 'EmbeddedVideoFile', ); - expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.livePhotoStillAsset.id]); + expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.livePhotoWithOriginalFileName.id]); expect(assetMock.create).toHaveBeenCalled(); // This could have arguments added expect(userMock.updateUsage).toHaveBeenCalledWith(assetStub.livePhotoMotionAsset.ownerId, 512); expect(storageMock.writeFile).toHaveBeenCalledWith(assetStub.livePhotoMotionAsset.originalPath, video); expect(assetMock.update).toHaveBeenNthCalledWith(1, { - id: assetStub.livePhotoStillAsset.id, + id: assetStub.livePhotoWithOriginalFileName.id, livePhotoVideoId: fileStub.livePhotoMotion.uuid, }); }); it('should extract the motion photo video from the XMP directory entry ', async () => { - assetMock.getByIds.mockResolvedValue([{ ...assetStub.livePhotoStillAsset, livePhotoVideoId: null }]); + assetMock.getByIds.mockResolvedValue([{ ...assetStub.livePhotoWithOriginalFileName, livePhotoVideoId: null }]); metadataMock.readTags.mockResolvedValue({ Directory: 'foo/bar/', MotionPhoto: 1, @@ -429,20 +431,23 @@ describe(MetadataService.name, () => { const video = randomBytes(512); storageMock.readFile.mockResolvedValue(video); - await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id }); - expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.livePhotoStillAsset.id]); - expect(storageMock.readFile).toHaveBeenCalledWith(assetStub.livePhotoStillAsset.originalPath, expect.any(Object)); + await sut.handleMetadataExtraction({ id: assetStub.livePhotoWithOriginalFileName.id }); + expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.livePhotoWithOriginalFileName.id]); + expect(storageMock.readFile).toHaveBeenCalledWith( + assetStub.livePhotoWithOriginalFileName.originalPath, + expect.any(Object), + ); expect(assetMock.create).toHaveBeenCalled(); // This could have arguments added expect(userMock.updateUsage).toHaveBeenCalledWith(assetStub.livePhotoMotionAsset.ownerId, 512); expect(storageMock.writeFile).toHaveBeenCalledWith(assetStub.livePhotoMotionAsset.originalPath, video); expect(assetMock.update).toHaveBeenNthCalledWith(1, { - id: assetStub.livePhotoStillAsset.id, + id: assetStub.livePhotoWithOriginalFileName.id, livePhotoVideoId: fileStub.livePhotoMotion.uuid, }); }); it('should delete old motion photo video assets if they do not match what is extracted', async () => { - assetMock.getByIds.mockResolvedValue([assetStub.livePhotoStillAsset]); + assetMock.getByIds.mockResolvedValue([assetStub.livePhotoWithOriginalFileName]); metadataMock.readTags.mockResolvedValue({ Directory: 'foo/bar/', MotionPhoto: 1, @@ -455,10 +460,14 @@ describe(MetadataService.name, () => { const video = randomBytes(512); storageMock.readFile.mockResolvedValue(video); - await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id }); - expect(jobMock.queue).toHaveBeenNthCalledWith(2, { + await sut.handleMetadataExtraction({ id: assetStub.livePhotoWithOriginalFileName.id }); + expect(jobMock.queue).toHaveBeenNthCalledWith(1, { name: JobName.ASSET_DELETION, - data: { id: assetStub.livePhotoStillAsset.livePhotoVideoId }, + data: { id: assetStub.livePhotoWithOriginalFileName.livePhotoVideoId }, + }); + expect(jobMock.queue).toHaveBeenNthCalledWith(2, { + name: JobName.METADATA_EXTRACTION, + data: { id: 'random-uuid' }, }); }); @@ -474,6 +483,7 @@ describe(MetadataService.name, () => { assetMock.getByChecksum.mockResolvedValue(assetStub.livePhotoMotionAsset); const video = randomBytes(512); storageMock.readFile.mockResolvedValue(video); + storageMock.checkFileExists.mockResolvedValue(true); await sut.handleMetadataExtraction({ id: assetStub.livePhotoStillAsset.id }); expect(assetMock.create).toHaveBeenCalledTimes(0); diff --git a/server/src/services/metadata.service.ts b/server/src/services/metadata.service.ts index 4b013fb663..a0b46ccbaa 100644 --- a/server/src/services/metadata.service.ts +++ b/server/src/services/metadata.service.ts @@ -7,7 +7,7 @@ import { constants } from 'node:fs/promises'; import path from 'node:path'; import { Subscription } from 'rxjs'; import { StorageCore } from 'src/cores/storage.core'; -import { FeatureFlag, SystemConfigCore } from 'src/cores/system-config.core'; +import { SystemConfigCore } from 'src/cores/system-config.core'; import { AssetEntity, AssetType } from 'src/entities/asset.entity'; import { ExifEntity } from 'src/entities/exif.entity'; import { IAlbumRepository } from 'src/interfaces/album.interface'; @@ -31,7 +31,7 @@ import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interfa import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { handlePromiseError } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; @@ -70,10 +70,9 @@ export enum Orientation { Rotate270CW = '8', } -type ExifEntityWithoutGeocodeAndTypeOrm = Omit< - ExifEntity, - 'city' | 'state' | 'country' | 'description' | 'exifTextSearchableColumn' -> & { dateTimeOriginal: Date }; +type ExifEntityWithoutGeocodeAndTypeOrm = Omit & { + dateTimeOriginal: Date; +}; const exifDate = (dt: ExifDateTime | string | undefined) => (dt instanceof ExifDateTime ? dt?.toDate() : null); const tzOffset = (dt: ExifDateTime | string | undefined) => (dt instanceof ExifDateTime ? dt?.tzoffsetMinutes : null); @@ -114,19 +113,19 @@ export class MetadataService { @Inject(IMoveRepository) moveRepository: IMoveRepository, @Inject(IPersonRepository) personRepository: IPersonRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IUserRepository) private userRepository: IUserRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(MetadataService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); this.storageCore = StorageCore.create( assetRepository, cryptoRepository, moveRepository, personRepository, storageRepository, - configRepository, + systemMetadataRepository, this.logger, ); } @@ -332,7 +331,8 @@ export class MetadataService { private async applyReverseGeocoding(asset: AssetEntity, exifData: ExifEntityWithoutGeocodeAndTypeOrm) { const { latitude, longitude } = exifData; - if (!(await this.configCore.hasFeature(FeatureFlag.REVERSE_GEOCODING)) || !longitude || !latitude) { + const { reverseGeocoding } = await this.configCore.getConfig(); + if (!reverseGeocoding.enabled || !longitude || !latitude) { return; } @@ -409,7 +409,7 @@ export class MetadataService { } const checksum = this.cryptoRepository.hashSha1(video); - let motionAsset = await this.assetRepository.getByChecksum(asset.libraryId, checksum); + let motionAsset = await this.assetRepository.getByChecksum(asset.libraryId ?? null, checksum); if (motionAsset) { this.logger.debug( `Asset ${asset.id}'s motion photo video with checksum ${checksum.toString( @@ -423,10 +423,7 @@ export class MetadataService { this.logger.log(`Hid unlinked motion photo video asset (${motionAsset.id})`); } } else { - // We create a UUID in advance so that each extracted video can have a unique filename - // (allowing us to delete old ones if necessary) const motionAssetId = this.cryptoRepository.randomUUID(); - const motionPath = StorageCore.getAndroidMotionPath(asset, motionAssetId); const createdAt = asset.fileCreatedAt ?? asset.createdAt; motionAsset = await this.assetRepository.create({ id: motionAssetId, @@ -437,16 +434,13 @@ export class MetadataService { localDateTime: createdAt, checksum, ownerId: asset.ownerId, - originalPath: motionPath, - originalFileName: asset.originalFileName, + originalPath: StorageCore.getAndroidMotionPath(asset, motionAssetId), + originalFileName: `${path.parse(asset.originalFileName).name}.mp4`, isVisible: false, deviceAssetId: 'NONE', deviceId: 'NONE', }); - this.storageCore.ensureFolders(motionPath); - await this.storageRepository.writeFile(motionAsset.originalPath, video); - await this.jobRepository.queue({ name: JobName.METADATA_EXTRACTION, data: { id: motionAsset.id } }); if (!asset.isExternal) { await this.userRepository.updateUsage(asset.ownerId, video.byteLength); } @@ -465,6 +459,15 @@ export class MetadataService { } } + // write extracted motion video to disk, especially if the encoded-video folder has been deleted + const existsOnDisk = await this.storageRepository.checkFileExists(motionAsset.originalPath); + if (!existsOnDisk) { + this.storageCore.ensureFolders(motionAsset.originalPath); + await this.storageRepository.writeFile(motionAsset.originalPath, video); + this.logger.log(`Wrote motion photo video to ${motionAsset.originalPath}`); + await this.jobRepository.queue({ name: JobName.METADATA_EXTRACTION, data: { id: motionAsset.id } }); + } + this.logger.debug(`Finished motion photo video extraction (${asset.id})`); } catch (error: Error | any) { this.logger.error(`Failed to extract live photo ${asset.originalPath}: ${error}`, error?.stack); diff --git a/server/src/services/microservices.service.ts b/server/src/services/microservices.service.ts index d1f94c5bdf..1b6abe68f4 100644 --- a/server/src/services/microservices.service.ts +++ b/server/src/services/microservices.service.ts @@ -3,6 +3,7 @@ import { IDeleteFilesJob, JobName } from 'src/interfaces/job.interface'; import { AssetService } from 'src/services/asset.service'; import { AuditService } from 'src/services/audit.service'; import { DatabaseService } from 'src/services/database.service'; +import { DuplicateService } from 'src/services/duplicate.service'; import { JobService } from 'src/services/job.service'; import { LibraryService } from 'src/services/library.service'; import { MediaService } from 'src/services/media.service'; @@ -15,6 +16,7 @@ import { StorageTemplateService } from 'src/services/storage-template.service'; import { StorageService } from 'src/services/storage.service'; import { SystemConfigService } from 'src/services/system-config.service'; import { UserService } from 'src/services/user.service'; +import { VersionService } from 'src/services/version.service'; import { otelSDK } from 'src/utils/instrumentation'; @Injectable() @@ -35,6 +37,8 @@ export class MicroservicesService { private storageTemplateService: StorageTemplateService, private storageService: StorageService, private userService: UserService, + private duplicateService: DuplicateService, + private versionService: VersionService, ) {} async init() { @@ -53,6 +57,8 @@ export class MicroservicesService { [JobName.USER_SYNC_USAGE]: () => this.userService.handleUserSyncUsage(), [JobName.QUEUE_SMART_SEARCH]: (data) => this.smartInfoService.handleQueueEncodeClip(data), [JobName.SMART_SEARCH]: (data) => this.smartInfoService.handleEncodeClip(data), + [JobName.QUEUE_DUPLICATE_DETECTION]: (data) => this.duplicateService.handleQueueSearchDuplicates(data), + [JobName.DUPLICATE_DETECTION]: (data) => this.duplicateService.handleSearchDuplicates(data), [JobName.STORAGE_TEMPLATE_MIGRATION]: () => this.storageTemplateService.handleMigration(), [JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE]: (data) => this.storageTemplateService.handleMigrationSingle(data), [JobName.QUEUE_MIGRATION]: () => this.mediaService.handleQueueMigration(), @@ -85,6 +91,7 @@ export class MicroservicesService { [JobName.LIBRARY_QUEUE_CLEANUP]: () => this.libraryService.handleQueueCleanup(), [JobName.SEND_EMAIL]: (data) => this.notificationService.handleSendEmail(data), [JobName.NOTIFY_SIGNUP]: (data) => this.notificationService.handleUserSignup(data), + [JobName.VERSION_CHECK]: () => this.versionService.handleVersionCheck(), }); await this.metadataService.init(); diff --git a/server/src/services/notification.service.ts b/server/src/services/notification.service.ts index dc5d89056b..503fe4afdd 100644 --- a/server/src/services/notification.service.ts +++ b/server/src/services/notification.service.ts @@ -5,7 +5,7 @@ import { ServerAsyncEvent, ServerAsyncEventMap } from 'src/interfaces/event.inte import { IEmailJob, IJobRepository, INotifySignupJob, JobName, JobStatus } from 'src/interfaces/job.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { EmailTemplate, INotificationRepository } from 'src/interfaces/notification.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; @Injectable() @@ -13,14 +13,14 @@ export class NotificationService { private configCore: SystemConfigCore; constructor( - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(INotificationRepository) private notificationRepository: INotificationRepository, @Inject(IUserRepository) private userRepository: IUserRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(NotificationService.name); - this.configCore = SystemConfigCore.create(configRepository, logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, logger); } init() { diff --git a/server/src/services/partner.service.spec.ts b/server/src/services/partner.service.spec.ts index 70c73b0d94..8fe93e7961 100644 --- a/server/src/services/partner.service.spec.ts +++ b/server/src/services/partner.service.spec.ts @@ -1,6 +1,6 @@ import { BadRequestException } from '@nestjs/common'; import { PartnerResponseDto } from 'src/dtos/partner.dto'; -import { UserAvatarColor } from 'src/entities/user.entity'; +import { UserAvatarColor } from 'src/entities/user-metadata.entity'; import { IAccessRepository } from 'src/interfaces/access.interface'; import { IPartnerRepository, PartnerDirection } from 'src/interfaces/partner.interface'; import { PartnerService } from 'src/services/partner.service'; @@ -23,7 +23,7 @@ const responseDto = { deletedAt: null, updatedAt: new Date('2021-01-01'), memoriesEnabled: true, - avatarColor: UserAvatarColor.PRIMARY, + avatarColor: UserAvatarColor.GRAY, quotaSizeInBytes: null, inTimeline: true, quotaUsageInBytes: 0, diff --git a/server/src/services/person.service.spec.ts b/server/src/services/person.service.spec.ts index cc7340f8a9..914904a778 100644 --- a/server/src/services/person.service.spec.ts +++ b/server/src/services/person.service.spec.ts @@ -1,8 +1,8 @@ import { BadRequestException, NotFoundException } from '@nestjs/common'; +import { Colorspace } from 'src/config'; import { BulkIdErrorReason } from 'src/dtos/asset-ids.response.dto'; import { PersonResponseDto, mapFaces, mapPerson } from 'src/dtos/person.dto'; import { AssetFaceEntity } from 'src/entities/asset-face.entity'; -import { Colorspace, SystemConfigKey } from 'src/entities/system-config.entity'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; @@ -13,13 +13,14 @@ import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { FaceSearchResult, ISearchRepository } from 'src/interfaces/search.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { PersonService } from 'src/services/person.service'; import { CacheControl, ImmichFileResponse } from 'src/utils/file'; import { assetStub } from 'test/fixtures/asset.stub'; import { authStub } from 'test/fixtures/auth.stub'; import { faceStub } from 'test/fixtures/face.stub'; import { personStub } from 'test/fixtures/person.stub'; +import { systemConfigStub } from 'test/fixtures/system-config.stub'; import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; @@ -31,7 +32,7 @@ import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { IsNull } from 'typeorm'; import { Mocked } from 'vitest'; @@ -63,7 +64,7 @@ const detectFaceMock = { describe(PersonService.name, () => { let accessMock: IAccessRepositoryMock; let assetMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let jobMock: Mocked; let machineLearningMock: Mocked; let mediaMock: Mocked; @@ -78,7 +79,7 @@ describe(PersonService.name, () => { beforeEach(() => { accessMock = newAccessRepositoryMock(); assetMock = newAssetRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); jobMock = newJobRepositoryMock(); machineLearningMock = newMachineLearningRepositoryMock(); moveMock = newMoveRepositoryMock(); @@ -95,7 +96,7 @@ describe(PersonService.name, () => { moveMock, mediaMock, personMock, - configMock, + systemMock, storageMock, jobMock, searchMock, @@ -504,12 +505,12 @@ describe(PersonService.name, () => { describe('handleQueueDetectFaces', () => { it('should skip if machine learning is disabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.MACHINE_LEARNING_ENABLED, value: false }]); + systemMock.get.mockResolvedValue(systemConfigStub.machineLearningDisabled); await expect(sut.handleQueueDetectFaces({})).resolves.toBe(JobStatus.SKIPPED); expect(jobMock.queue).not.toHaveBeenCalled(); expect(jobMock.queueAll).not.toHaveBeenCalled(); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); }); it('should queue missing assets', async () => { @@ -581,11 +582,11 @@ describe(PersonService.name, () => { describe('handleQueueRecognizeFaces', () => { it('should skip if machine learning is disabled', async () => { jobMock.getJobCounts.mockResolvedValue({ active: 1, waiting: 0, paused: 0, completed: 0, failed: 0, delayed: 0 }); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.MACHINE_LEARNING_ENABLED, value: false }]); + systemMock.get.mockResolvedValue(systemConfigStub.machineLearningDisabled); await expect(sut.handleQueueRecognizeFaces({})).resolves.toBe(JobStatus.SKIPPED); expect(jobMock.queueAll).not.toHaveBeenCalled(); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); }); it('should skip if recognition jobs are already queued', async () => { @@ -665,11 +666,11 @@ describe(PersonService.name, () => { describe('handleDetectFaces', () => { it('should skip if machine learning is disabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.MACHINE_LEARNING_ENABLED, value: false }]); + systemMock.get.mockResolvedValue(systemConfigStub.machineLearningDisabled); await expect(sut.handleDetectFaces({ id: 'foo' })).resolves.toBe(JobStatus.SKIPPED); expect(assetMock.getByIds).not.toHaveBeenCalled(); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); }); it('should skip when no resize path', async () => { @@ -796,9 +797,7 @@ describe(PersonService.name, () => { { face: faceStub.face1, distance: 0.4 }, ] as FaceSearchResult[]; - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 1 }, - ]); + systemMock.get.mockResolvedValue({ machineLearning: { facialRecognition: { minFaces: 1 } } }); searchMock.searchFaces.mockResolvedValue(faces); personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1); personMock.create.mockResolvedValue(faceStub.primaryFace1.person); @@ -823,9 +822,7 @@ describe(PersonService.name, () => { { face: faceStub.noPerson2, distance: 0.3 }, ] as FaceSearchResult[]; - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 1 }, - ]); + systemMock.get.mockResolvedValue({ machineLearning: { facialRecognition: { minFaces: 1 } } }); searchMock.searchFaces.mockResolvedValue(faces); personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1); personMock.create.mockResolvedValue(personStub.withName); @@ -863,9 +860,7 @@ describe(PersonService.name, () => { { face: faceStub.noPerson2, distance: 0.4 }, ] as FaceSearchResult[]; - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 3 }, - ]); + systemMock.get.mockResolvedValue({ machineLearning: { facialRecognition: { minFaces: 3 } } }); searchMock.searchFaces.mockResolvedValue(faces); personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1); personMock.create.mockResolvedValue(personStub.withName); @@ -887,9 +882,7 @@ describe(PersonService.name, () => { { face: faceStub.noPerson2, distance: 0.4 }, ] as FaceSearchResult[]; - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_FACES, value: 3 }, - ]); + systemMock.get.mockResolvedValue({ machineLearning: { facialRecognition: { minFaces: 3 } } }); searchMock.searchFaces.mockResolvedValueOnce(faces).mockResolvedValueOnce([]); personMock.getFaceByIdWithAssets.mockResolvedValue(faceStub.noPerson1); personMock.create.mockResolvedValue(personStub.withName); @@ -905,11 +898,11 @@ describe(PersonService.name, () => { describe('handleGeneratePersonThumbnail', () => { it('should skip if machine learning is disabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.MACHINE_LEARNING_ENABLED, value: false }]); + systemMock.get.mockResolvedValue(systemConfigStub.machineLearningDisabled); await expect(sut.handleGeneratePersonThumbnail({ id: 'person-1' })).resolves.toBe(JobStatus.SKIPPED); expect(assetMock.getByIds).not.toHaveBeenCalled(); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); }); it('should skip a person not found', async () => { diff --git a/server/src/services/person.service.ts b/server/src/services/person.service.ts index eed488e407..a0c1b7b3df 100644 --- a/server/src/services/person.service.ts +++ b/server/src/services/person.service.ts @@ -1,4 +1,5 @@ import { BadRequestException, Inject, Injectable, NotFoundException } from '@nestjs/common'; +import { ImageFormat } from 'src/config'; import { FACE_THUMBNAIL_SIZE } from 'src/constants'; import { AccessCore, Permission } from 'src/cores/access.core'; import { StorageCore } from 'src/cores/storage.core'; @@ -23,7 +24,6 @@ import { } from 'src/dtos/person.dto'; import { PersonPathType } from 'src/entities/move.entity'; import { PersonEntity } from 'src/entities/person.entity'; -import { ImageFormat } from 'src/entities/system-config.entity'; import { IAccessRepository } from 'src/interfaces/access.interface'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; @@ -45,10 +45,11 @@ import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository, UpdateFacesData } from 'src/interfaces/person.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { Orientation } from 'src/services/metadata.service'; import { CacheControl, ImmichFileResponse } from 'src/utils/file'; import { mimeTypes } from 'src/utils/mime-types'; +import { isFacialRecognitionEnabled } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; import { IsNull } from 'typeorm'; @@ -65,7 +66,7 @@ export class PersonService { @Inject(IMoveRepository) moveRepository: IMoveRepository, @Inject(IMediaRepository) private mediaRepository: IMediaRepository, @Inject(IPersonRepository) private repository: IPersonRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(ISearchRepository) private smartInfoRepository: ISearchRepository, @@ -74,14 +75,14 @@ export class PersonService { ) { this.access = AccessCore.create(accessRepository); this.logger.setContext(PersonService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); this.storageCore = StorageCore.create( assetRepository, cryptoRepository, moveRepository, repository, storageRepository, - configRepository, + systemMetadataRepository, this.logger, ); } @@ -326,7 +327,7 @@ export class PersonService { async handleQueueDetectFaces({ force }: IBaseJob): Promise { const { machineLearning } = await this.configCore.getConfig(); - if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) { + if (!isFacialRecognitionEnabled(machineLearning)) { return JobStatus.SKIPPED; } @@ -357,7 +358,7 @@ export class PersonService { async handleDetectFaces({ id }: IEntityJob): Promise { const { machineLearning } = await this.configCore.getConfig(); - if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) { + if (!isFacialRecognitionEnabled(machineLearning)) { return JobStatus.SKIPPED; } @@ -413,7 +414,7 @@ export class PersonService { async handleQueueRecognizeFaces({ force }: IBaseJob): Promise { const { machineLearning } = await this.configCore.getConfig(); - if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) { + if (!isFacialRecognitionEnabled(machineLearning)) { return JobStatus.SKIPPED; } @@ -444,7 +445,7 @@ export class PersonService { async handleRecognizeFaces({ id, deferred }: IDeferrableJob): Promise { const { machineLearning } = await this.configCore.getConfig(); - if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) { + if (!isFacialRecognitionEnabled(machineLearning)) { return JobStatus.SKIPPED; } @@ -528,7 +529,7 @@ export class PersonService { async handleGeneratePersonThumbnail(data: IEntityJob): Promise { const { machineLearning, image } = await this.configCore.getConfig(); - if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) { + if (!isFacialRecognitionEnabled(machineLearning)) { return JobStatus.SKIPPED; } diff --git a/server/src/services/search.service.spec.ts b/server/src/services/search.service.spec.ts index bf4cd7c679..afc98b69de 100644 --- a/server/src/services/search.service.spec.ts +++ b/server/src/services/search.service.spec.ts @@ -6,7 +6,7 @@ import { IMetadataRepository } from 'src/interfaces/metadata.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { SearchService } from 'src/services/search.service'; import { assetStub } from 'test/fixtures/asset.stub'; import { authStub } from 'test/fixtures/auth.stub'; @@ -18,15 +18,15 @@ import { newMetadataRepositoryMock } from 'test/repositories/metadata.repository import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; -import { Mocked, vitest } from 'vitest'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; +import { Mocked, beforeEach, vitest } from 'vitest'; vitest.useFakeTimers(); describe(SearchService.name, () => { let sut: SearchService; let assetMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let machineMock: Mocked; let personMock: Mocked; let searchMock: Mocked; @@ -36,7 +36,7 @@ describe(SearchService.name, () => { beforeEach(() => { assetMock = newAssetRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); machineMock = newMachineLearningRepositoryMock(); personMock = newPersonRepositoryMock(); searchMock = newSearchRepositoryMock(); @@ -45,7 +45,7 @@ describe(SearchService.name, () => { loggerMock = newLoggerRepositoryMock(); sut = new SearchService( - configMock, + systemMock, machineMock, personMock, searchMock, @@ -76,15 +76,15 @@ describe(SearchService.name, () => { describe('getExploreData', () => { it('should get assets by city and tag', async () => { - assetMock.getAssetIdByCity.mockResolvedValueOnce({ + assetMock.getAssetIdByCity.mockResolvedValue({ fieldName: 'exifInfo.city', items: [{ value: 'Paris', data: assetStub.image.id }], }); - assetMock.getAssetIdByTag.mockResolvedValueOnce({ + assetMock.getAssetIdByTag.mockResolvedValue({ fieldName: 'smartInfo.tags', items: [{ value: 'train', data: assetStub.imageFrom2015.id }], }); - assetMock.getByIdsWithAllRelations.mockResolvedValueOnce([assetStub.image, assetStub.imageFrom2015]); + assetMock.getByIdsWithAllRelations.mockResolvedValue([assetStub.image, assetStub.imageFrom2015]); const expectedResponse = [ { fieldName: 'exifInfo.city', items: [{ value: 'Paris', data: mapAsset(assetStub.image) }] }, { fieldName: 'smartInfo.tags', items: [{ value: 'train', data: mapAsset(assetStub.imageFrom2015) }] }, diff --git a/server/src/services/search.service.ts b/server/src/services/search.service.ts index d2636b91cf..8c89218138 100644 --- a/server/src/services/search.service.ts +++ b/server/src/services/search.service.ts @@ -1,5 +1,5 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { FeatureFlag, SystemConfigCore } from 'src/cores/system-config.core'; +import { BadRequestException, Inject, Injectable } from '@nestjs/common'; +import { SystemConfigCore } from 'src/cores/system-config.core'; import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { PersonResponseDto } from 'src/dtos/person.dto'; @@ -23,14 +23,15 @@ import { IMetadataRepository } from 'src/interfaces/metadata.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { ISearchRepository, SearchExploreItem } from 'src/interfaces/search.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { isSmartSearchEnabled } from 'src/utils/misc'; @Injectable() export class SearchService { private configCore: SystemConfigCore; constructor( - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IMachineLearningRepository) private machineLearning: IMachineLearningRepository, @Inject(IPersonRepository) private personRepository: IPersonRepository, @Inject(ISearchRepository) private searchRepository: ISearchRepository, @@ -40,7 +41,7 @@ export class SearchService { @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(SearchService.name); - this.configCore = SystemConfigCore.create(configRepository, logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, logger); } async searchPerson(auth: AuthDto, dto: SearchPeopleDto): Promise { @@ -53,7 +54,6 @@ export class SearchService { } async getExploreData(auth: AuthDto): Promise[]> { - await this.configCore.requireFeature(FeatureFlag.SEARCH); const options = { maxFields: 12, minAssetsPerField: 5 }; const results = await Promise.all([ this.assetRepository.getAssetIdByCity(auth.user.id, options), @@ -78,9 +78,6 @@ export class SearchService { checksum = Buffer.from(dto.checksum, encoding); } - dto.previewPath ??= dto.resizePath; - dto.thumbnailPath ??= dto.webpPath; - const page = dto.page ?? 1; const size = dto.size || 250; const enumToOrder = { [AssetOrder.ASC]: 'ASC', [AssetOrder.DESC]: 'DESC' } as const; @@ -98,8 +95,11 @@ export class SearchService { } async searchSmart(auth: AuthDto, dto: SmartSearchDto): Promise { - await this.configCore.requireFeature(FeatureFlag.SMART_SEARCH); const { machineLearning } = await this.configCore.getConfig(); + if (!isSmartSearchEnabled(machineLearning)) { + throw new BadRequestException('Smart search is not enabled'); + } + const userIds = await this.getUserIdsToSearch(auth); const embedding = await this.machineLearning.encodeText( diff --git a/server/src/services/server-info.service.spec.ts b/server/src/services/server-info.service.spec.ts index a007498b40..57beb165db 100644 --- a/server/src/services/server-info.service.spec.ts +++ b/server/src/services/server-info.service.spec.ts @@ -1,60 +1,39 @@ -import { serverVersion } from 'src/constants'; -import { IEventRepository } from 'src/interfaces/event.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; -import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { ServerInfoService } from 'src/services/server-info.service'; -import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; -import { newServerInfoRepositoryMock } from 'test/repositories/system-info.repository.mock'; import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; import { Mocked } from 'vitest'; describe(ServerInfoService.name, () => { let sut: ServerInfoService; - let eventMock: Mocked; - let configMock: Mocked; - let serverInfoMock: Mocked; let storageMock: Mocked; let userMock: Mocked; - let systemMetadataMock: Mocked; + let systemMock: Mocked; let loggerMock: Mocked; beforeEach(() => { - configMock = newSystemConfigRepositoryMock(); - eventMock = newEventRepositoryMock(); - serverInfoMock = newServerInfoRepositoryMock(); storageMock = newStorageRepositoryMock(); userMock = newUserRepositoryMock(); - systemMetadataMock = newSystemMetadataRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); loggerMock = newLoggerRepositoryMock(); - sut = new ServerInfoService( - eventMock, - configMock, - userMock, - serverInfoMock, - storageMock, - systemMetadataMock, - loggerMock, - ); + sut = new ServerInfoService(userMock, storageMock, systemMock, loggerMock); }); it('should work', () => { expect(sut).toBeDefined(); }); - describe('getInfo', () => { + describe('getStorage', () => { it('should return the disk space as B', async () => { storageMock.checkDiskUsage.mockResolvedValue({ free: 200, available: 300, total: 500 }); - await expect(sut.getInfo()).resolves.toEqual({ + await expect(sut.getStorage()).resolves.toEqual({ diskAvailable: '300 B', diskAvailableRaw: 300, diskSize: '500 B', @@ -70,7 +49,7 @@ describe(ServerInfoService.name, () => { it('should return the disk space as KiB', async () => { storageMock.checkDiskUsage.mockResolvedValue({ free: 200_000, available: 300_000, total: 500_000 }); - await expect(sut.getInfo()).resolves.toEqual({ + await expect(sut.getStorage()).resolves.toEqual({ diskAvailable: '293.0 KiB', diskAvailableRaw: 300_000, diskSize: '488.3 KiB', @@ -86,7 +65,7 @@ describe(ServerInfoService.name, () => { it('should return the disk space as MiB', async () => { storageMock.checkDiskUsage.mockResolvedValue({ free: 200_000_000, available: 300_000_000, total: 500_000_000 }); - await expect(sut.getInfo()).resolves.toEqual({ + await expect(sut.getStorage()).resolves.toEqual({ diskAvailable: '286.1 MiB', diskAvailableRaw: 300_000_000, diskSize: '476.8 MiB', @@ -106,7 +85,7 @@ describe(ServerInfoService.name, () => { total: 500_000_000_000, }); - await expect(sut.getInfo()).resolves.toEqual({ + await expect(sut.getStorage()).resolves.toEqual({ diskAvailable: '279.4 GiB', diskAvailableRaw: 300_000_000_000, diskSize: '465.7 GiB', @@ -126,7 +105,7 @@ describe(ServerInfoService.name, () => { total: 500_000_000_000_000, }); - await expect(sut.getInfo()).resolves.toEqual({ + await expect(sut.getStorage()).resolves.toEqual({ diskAvailable: '272.8 TiB', diskAvailableRaw: 300_000_000_000_000, diskSize: '454.7 TiB', @@ -146,7 +125,7 @@ describe(ServerInfoService.name, () => { total: 500_000_000_000_000_000, }); - await expect(sut.getInfo()).resolves.toEqual({ + await expect(sut.getStorage()).resolves.toEqual({ diskAvailable: '266.5 PiB', diskAvailableRaw: 300_000_000_000_000_000, diskSize: '444.1 PiB', @@ -166,16 +145,11 @@ describe(ServerInfoService.name, () => { }); }); - describe('getVersion', () => { - it('should respond the server version', () => { - expect(sut.getVersion()).toEqual(serverVersion); - }); - }); - describe('getFeatures', () => { it('should respond the server features', async () => { await expect(sut.getFeatures()).resolves.toEqual({ smartSearch: true, + duplicateDetection: false, facialRecognition: true, map: true, reverseGeocoding: true, @@ -188,7 +162,7 @@ describe(ServerInfoService.name, () => { trash: true, email: false, }); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); }); }); @@ -203,7 +177,7 @@ describe(ServerInfoService.name, () => { isOnboarded: false, externalDomain: '', }); - expect(configMock.load).toHaveBeenCalled(); + expect(systemMock.get).toHaveBeenCalled(); }); }); diff --git a/server/src/services/server-info.service.ts b/server/src/services/server-info.service.ts index 52bf8bd1d3..89e095ba5d 100644 --- a/server/src/services/server-info.service.ts +++ b/server/src/services/server-info.service.ts @@ -1,54 +1,39 @@ import { Inject, Injectable } from '@nestjs/common'; -import { DateTime } from 'luxon'; -import { isDev, serverVersion } from 'src/constants'; import { StorageCore, StorageFolder } from 'src/cores/storage.core'; import { SystemConfigCore } from 'src/cores/system-config.core'; -import { OnServerEvent } from 'src/decorators'; import { ServerConfigDto, ServerFeaturesDto, - ServerInfoResponseDto, ServerMediaTypesResponseDto, ServerPingResponse, ServerStatsResponseDto, + ServerStorageResponseDto, UsageByUserDto, } from 'src/dtos/server-info.dto'; import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; -import { ClientEvent, IEventRepository, ServerEvent, ServerEventMap } from 'src/interfaces/event.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; -import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository, UserStatsQueryResponse } from 'src/interfaces/user.interface'; import { asHumanReadable } from 'src/utils/bytes'; import { mimeTypes } from 'src/utils/mime-types'; -import { Version } from 'src/utils/version'; +import { isDuplicateDetectionEnabled, isFacialRecognitionEnabled, isSmartSearchEnabled } from 'src/utils/misc'; @Injectable() export class ServerInfoService { private configCore: SystemConfigCore; - private releaseVersion = serverVersion; - private releaseVersionCheckedAt: DateTime | null = null; constructor( - @Inject(IEventRepository) private eventRepository: IEventRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(IUserRepository) private userRepository: IUserRepository, - @Inject(IServerInfoRepository) private repository: IServerInfoRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(ISystemMetadataRepository) private systemMetadataRepository: ISystemMetadataRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(ServerInfoService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); } - onConnect() {} - async init(): Promise { - await this.handleVersionCheck(); - const featureFlags = await this.getFeatures(); if (featureFlags.configFile) { await this.systemMetadataRepository.set(SystemMetadataKey.ADMIN_ONBOARDING, { @@ -57,13 +42,13 @@ export class ServerInfoService { } } - async getInfo(): Promise { + async getStorage(): Promise { const libraryBase = StorageCore.getBaseFolder(StorageFolder.LIBRARY); const diskInfo = await this.storageRepository.checkDiskUsage(libraryBase); const usagePercentage = (((diskInfo.total - diskInfo.free) / diskInfo.total) * 100).toFixed(2); - const serverInfo = new ServerInfoResponseDto(); + const serverInfo = new ServerStorageResponseDto(); serverInfo.diskAvailable = asHumanReadable(diskInfo.available); serverInfo.diskSize = asHumanReadable(diskInfo.total); serverInfo.diskUse = asHumanReadable(diskInfo.total - diskInfo.free); @@ -78,12 +63,25 @@ export class ServerInfoService { return { res: 'pong' }; } - getVersion() { - return serverVersion; - } + async getFeatures(): Promise { + const { reverseGeocoding, map, machineLearning, trash, oauth, passwordLogin, notifications } = + await this.configCore.getConfig(); - getFeatures(): Promise { - return this.configCore.getFeatures(); + return { + smartSearch: isSmartSearchEnabled(machineLearning), + facialRecognition: isFacialRecognitionEnabled(machineLearning), + duplicateDetection: isDuplicateDetectionEnabled(machineLearning), + map: map.enabled, + reverseGeocoding: reverseGeocoding.enabled, + sidecar: true, + search: true, + trash: trash.enabled, + oauth: oauth.enabled, + oauthAutoLaunch: oauth.autoLaunch, + passwordLogin: passwordLogin.enabled, + configFile: this.configCore.isUsingConfigFile(), + email: notifications.smtp.enabled, + }; } async getTheme() { @@ -136,57 +134,4 @@ export class ServerInfoService { sidecar: Object.keys(mimeTypes.sidecar), }; } - - async handleVersionCheck(): Promise { - try { - if (isDev) { - return true; - } - - const { newVersionCheck } = await this.configCore.getConfig(); - if (!newVersionCheck.enabled) { - return true; - } - - // check once per hour (max) - if (this.releaseVersionCheckedAt && DateTime.now().diff(this.releaseVersionCheckedAt).as('minutes') < 60) { - return true; - } - - const githubRelease = await this.repository.getGitHubRelease(); - const githubVersion = Version.fromString(githubRelease.tag_name); - const publishedAt = new Date(githubRelease.published_at); - this.releaseVersion = githubVersion; - this.releaseVersionCheckedAt = DateTime.now(); - - if (githubVersion.isNewerThan(serverVersion)) { - this.logger.log(`Found ${githubVersion.toString()}, released at ${publishedAt.toLocaleString()}`); - this.newReleaseNotification(); - } - } catch (error: Error | any) { - this.logger.warn(`Unable to run version check: ${error}`, error?.stack); - } - - return true; - } - - @OnServerEvent(ServerEvent.WEBSOCKET_CONNECT) - onWebsocketConnection({ userId }: ServerEventMap[ServerEvent.WEBSOCKET_CONNECT]) { - this.eventRepository.clientSend(ClientEvent.SERVER_VERSION, userId, serverVersion); - this.newReleaseNotification(userId); - } - - private newReleaseNotification(userId?: string) { - const event = ClientEvent.NEW_RELEASE; - const payload = { - isAvailable: this.releaseVersion.isNewerThan(serverVersion), - checkedAt: this.releaseVersionCheckedAt, - serverVersion, - releaseVersion: this.releaseVersion, - }; - - userId - ? this.eventRepository.clientSend(event, userId, payload) - : this.eventRepository.clientBroadcast(event, payload); - } } diff --git a/server/src/services/smart-info.service.spec.ts b/server/src/services/smart-info.service.spec.ts index 8dedcb5c5f..7ac6dac414 100644 --- a/server/src/services/smart-info.service.spec.ts +++ b/server/src/services/smart-info.service.spec.ts @@ -1,27 +1,27 @@ -import { SystemConfigKey } from 'src/entities/system-config.entity'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { IDatabaseRepository } from 'src/interfaces/database.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { SmartInfoService } from 'src/services/smart-info.service'; import { getCLIPModelInfo } from 'src/utils/misc'; import { assetStub } from 'test/fixtures/asset.stub'; +import { systemConfigStub } from 'test/fixtures/system-config.stub'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock'; import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { Mocked } from 'vitest'; describe(SmartInfoService.name, () => { let sut: SmartInfoService; let assetMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let jobMock: Mocked; let searchMock: Mocked; let machineMock: Mocked; @@ -30,13 +30,13 @@ describe(SmartInfoService.name, () => { beforeEach(() => { assetMock = newAssetRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); searchMock = newSearchRepositoryMock(); jobMock = newJobRepositoryMock(); machineMock = newMachineLearningRepositoryMock(); databaseMock = newDatabaseRepositoryMock(); loggerMock = newLoggerRepositoryMock(); - sut = new SmartInfoService(assetMock, databaseMock, jobMock, machineMock, searchMock, configMock, loggerMock); + sut = new SmartInfoService(assetMock, databaseMock, jobMock, machineMock, searchMock, systemMock, loggerMock); assetMock.getByIds.mockResolvedValue([assetStub.image]); }); @@ -47,7 +47,7 @@ describe(SmartInfoService.name, () => { describe('handleQueueEncodeClip', () => { it('should do nothing if machine learning is disabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.MACHINE_LEARNING_ENABLED, value: false }]); + systemMock.get.mockResolvedValue(systemConfigStub.machineLearningDisabled); await sut.handleQueueEncodeClip({}); @@ -84,7 +84,7 @@ describe(SmartInfoService.name, () => { describe('handleEncodeClip', () => { it('should do nothing if machine learning is disabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.MACHINE_LEARNING_ENABLED, value: false }]); + systemMock.get.mockResolvedValue(systemConfigStub.machineLearningDisabled); expect(await sut.handleEncodeClip({ id: '123' })).toEqual(JobStatus.SKIPPED); diff --git a/server/src/services/smart-info.service.ts b/server/src/services/smart-info.service.ts index 929d15beca..f902aa7e57 100644 --- a/server/src/services/smart-info.service.ts +++ b/server/src/services/smart-info.service.ts @@ -14,7 +14,8 @@ import { import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { isSmartSearchEnabled } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; @Injectable() @@ -27,11 +28,11 @@ export class SmartInfoService { @Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(IMachineLearningRepository) private machineLearning: IMachineLearningRepository, @Inject(ISearchRepository) private repository: ISearchRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(SmartInfoService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); } async init() { @@ -50,7 +51,7 @@ export class SmartInfoService { async handleQueueEncodeClip({ force }: IBaseJob): Promise { const { machineLearning } = await this.configCore.getConfig(); - if (!machineLearning.enabled || !machineLearning.clip.enabled) { + if (!isSmartSearchEnabled(machineLearning)) { return JobStatus.SKIPPED; } @@ -75,7 +76,7 @@ export class SmartInfoService { async handleEncodeClip({ id }: IEntityJob): Promise { const { machineLearning } = await this.configCore.getConfig(); - if (!machineLearning.enabled || !machineLearning.clip.enabled) { + if (!isSmartSearchEnabled(machineLearning)) { return JobStatus.SKIPPED; } diff --git a/server/src/services/storage-template.service.spec.ts b/server/src/services/storage-template.service.spec.ts index 0ee0204357..c1a47cdcf0 100644 --- a/server/src/services/storage-template.service.spec.ts +++ b/server/src/services/storage-template.service.spec.ts @@ -1,8 +1,8 @@ import { Stats } from 'node:fs'; -import { SystemConfigCore, defaults } from 'src/cores/system-config.core'; +import { SystemConfig, defaults } from 'src/config'; +import { SystemConfigCore } from 'src/cores/system-config.core'; import { AssetEntity } from 'src/entities/asset.entity'; import { AssetPathType } from 'src/entities/move.entity'; -import { SystemConfig, SystemConfigKey } from 'src/entities/system-config.entity'; import { IAlbumRepository } from 'src/interfaces/album.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; @@ -12,7 +12,7 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { StorageTemplateService } from 'src/services/storage-template.service'; import { assetStub } from 'test/fixtures/asset.stub'; @@ -25,7 +25,7 @@ import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.moc import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; import { Mocked } from 'vitest'; @@ -33,13 +33,13 @@ describe(StorageTemplateService.name, () => { let sut: StorageTemplateService; let albumMock: Mocked; let assetMock: Mocked; - let configMock: Mocked; + let cryptoMock: Mocked; + let databaseMock: Mocked; let moveMock: Mocked; let personMock: Mocked; let storageMock: Mocked; + let systemMock: Mocked; let userMock: Mocked; - let cryptoMock: Mocked; - let databaseMock: Mocked; let loggerMock: Mocked; it('should work', () => { @@ -47,23 +47,23 @@ describe(StorageTemplateService.name, () => { }); beforeEach(() => { - configMock = newSystemConfigRepositoryMock(); assetMock = newAssetRepositoryMock(); albumMock = newAlbumRepositoryMock(); + cryptoMock = newCryptoRepositoryMock(); + databaseMock = newDatabaseRepositoryMock(); moveMock = newMoveRepositoryMock(); personMock = newPersonRepositoryMock(); storageMock = newStorageRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); userMock = newUserRepositoryMock(); - cryptoMock = newCryptoRepositoryMock(); - databaseMock = newDatabaseRepositoryMock(); loggerMock = newLoggerRepositoryMock(); - configMock.load.mockResolvedValue([{ key: SystemConfigKey.STORAGE_TEMPLATE_ENABLED, value: true }]); + systemMock.get.mockResolvedValue({ storageTemplate: { enabled: true } }); sut = new StorageTemplateService( albumMock, assetMock, - configMock, + systemMock, moveMock, personMock, storageMock, @@ -73,7 +73,7 @@ describe(StorageTemplateService.name, () => { loggerMock, ); - SystemConfigCore.create(configMock, loggerMock).config$.next(defaults); + SystemConfigCore.create(systemMock, loggerMock).config$.next(defaults); }); describe('onValidateConfig', () => { @@ -107,7 +107,7 @@ describe(StorageTemplateService.name, () => { describe('handleMigrationSingle', () => { it('should skip when storage template is disabled', async () => { - configMock.load.mockResolvedValue([{ key: SystemConfigKey.STORAGE_TEMPLATE_ENABLED, value: false }]); + systemMock.get.mockResolvedValue({ storageTemplate: { enabled: false } }); await expect(sut.handleMigrationSingle({ id: assetStub.image.id })).resolves.toBe(JobStatus.SKIPPED); expect(assetMock.getByIds).not.toHaveBeenCalled(); expect(storageMock.checkFileExists).not.toHaveBeenCalled(); diff --git a/server/src/services/storage-template.service.ts b/server/src/services/storage-template.service.ts index 1a3c61a4b8..945b6f4500 100644 --- a/server/src/services/storage-template.service.ts +++ b/server/src/services/storage-template.service.ts @@ -3,6 +3,7 @@ import handlebar from 'handlebars'; import { DateTime } from 'luxon'; import path from 'node:path'; import sanitize from 'sanitize-filename'; +import { SystemConfig } from 'src/config'; import { supportedDayTokens, supportedHourTokens, @@ -17,7 +18,6 @@ import { SystemConfigCore } from 'src/cores/system-config.core'; import { OnServerEvent } from 'src/decorators'; import { AssetEntity, AssetType } from 'src/entities/asset.entity'; import { AssetPathType } from 'src/entities/move.entity'; -import { SystemConfig } from 'src/entities/system-config.entity'; import { IAlbumRepository } from 'src/interfaces/album.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; @@ -28,7 +28,7 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { getLivePhotoMotionFilename } from 'src/utils/file'; import { usePagination } from 'src/utils/pagination'; @@ -65,7 +65,7 @@ export class StorageTemplateService { constructor( @Inject(IAlbumRepository) private albumRepository: IAlbumRepository, @Inject(IAssetRepository) private assetRepository: IAssetRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IMoveRepository) moveRepository: IMoveRepository, @Inject(IPersonRepository) personRepository: IPersonRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @@ -75,7 +75,7 @@ export class StorageTemplateService { @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.logger.setContext(StorageTemplateService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); this.configCore.config$.subscribe((config) => this.onConfig(config)); this.storageCore = StorageCore.create( assetRepository, @@ -83,7 +83,7 @@ export class StorageTemplateService { moveRepository, personRepository, storageRepository, - configRepository, + systemMetadataRepository, this.logger, ); } diff --git a/server/src/services/sync.service.spec.ts b/server/src/services/sync.service.spec.ts index 9a7dbbc152..a0ded6dba3 100644 --- a/server/src/services/sync.service.spec.ts +++ b/server/src/services/sync.service.spec.ts @@ -44,7 +44,6 @@ describe(SyncService.name, () => { mapAsset(assetStub.hasEncodedVideo, mapAssetOpts), ]); expect(assetMock.getAllForUserFullSync).toHaveBeenCalledWith({ - withStacked: true, ownerId: authStub.user1.user.id, updatedUntil: untilDate, limit: 2, diff --git a/server/src/services/sync.service.ts b/server/src/services/sync.service.ts index 88a4e172a6..c0ac362d89 100644 --- a/server/src/services/sync.service.ts +++ b/server/src/services/sync.service.ts @@ -32,10 +32,6 @@ export class SyncService { await this.access.requirePermission(auth, Permission.TIMELINE_READ, userId); const assets = await this.assetRepository.getAllForUserFullSync({ ownerId: userId, - // no archived assets for partner user - isArchived: userId === auth.user.id ? undefined : false, - // no stack for partner user - withStacked: userId === auth.user.id ? true : undefined, lastCreationDate: dto.lastCreationDate, updatedUntil: dto.updatedUntil, lastId: dto.lastId, diff --git a/server/src/services/system-config.service.spec.ts b/server/src/services/system-config.service.spec.ts index 23ec2a2432..878916b0d2 100644 --- a/server/src/services/system-config.service.spec.ts +++ b/server/src/services/system-config.service.spec.ts @@ -1,5 +1,4 @@ import { BadRequestException } from '@nestjs/common'; -import { defaults } from 'src/cores/system-config.core'; import { AudioCodec, CQMode, @@ -7,30 +6,31 @@ import { ImageFormat, LogLevel, SystemConfig, - SystemConfigEntity, - SystemConfigKey, ToneMapping, TranscodeHWAccel, TranscodePolicy, VideoCodec, -} from 'src/entities/system-config.entity'; + defaults, +} from 'src/config'; +import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; import { IEventRepository, ServerEvent } from 'src/interfaces/event.interface'; import { QueueName } from 'src/interfaces/job.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { SystemConfigService } from 'src/services/system-config.service'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; +import { DeepPartial } from 'typeorm'; import { Mocked } from 'vitest'; -const updates: SystemConfigEntity[] = [ - { key: SystemConfigKey.FFMPEG_CRF, value: 30 }, - { key: SystemConfigKey.OAUTH_AUTO_LAUNCH, value: true }, - { key: SystemConfigKey.TRASH_DAYS, value: 10 }, - { key: SystemConfigKey.USER_DELETE_DELAY, value: 15 }, -]; +const partialConfig = { + ffmpeg: { crf: 30 }, + oauth: { autoLaunch: true }, + trash: { days: 10 }, + user: { deleteDelay: 15 }, +} satisfies DeepPartial; const updatedConfig = Object.freeze({ job: { @@ -66,6 +66,7 @@ const updatedConfig = Object.freeze({ preferredHwDevice: 'auto', transcode: TranscodePolicy.REQUIRED, accel: TranscodeHWAccel.DISABLED, + accelDecode: false, tonemap: ToneMapping.HABLE, }, logging: { @@ -79,6 +80,10 @@ const updatedConfig = Object.freeze({ enabled: true, modelName: 'ViT-B-32__openai', }, + duplicateDetection: { + enabled: false, + maxDistance: 0.03, + }, facialRecognition: { enabled: true, modelName: 'buffalo_l', @@ -172,17 +177,17 @@ const updatedConfig = Object.freeze({ describe(SystemConfigService.name, () => { let sut: SystemConfigService; - let configMock: Mocked; + let systemMock: Mocked; let eventMock: Mocked; let loggerMock: Mocked; let smartInfoMock: Mocked; beforeEach(() => { delete process.env.IMMICH_CONFIG_FILE; - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); eventMock = newEventRepositoryMock(); loggerMock = newLoggerRepositoryMock(); - sut = new SystemConfigService(configMock, eventMock, loggerMock, smartInfoMock); + sut = new SystemConfigService(systemMock, eventMock, loggerMock, smartInfoMock); }); it('should work', () => { @@ -191,44 +196,54 @@ describe(SystemConfigService.name, () => { describe('getDefaults', () => { it('should return the default config', () => { - configMock.load.mockResolvedValue(updates); + systemMock.get.mockResolvedValue(partialConfig); expect(sut.getDefaults()).toEqual(defaults); - expect(configMock.load).not.toHaveBeenCalled(); + expect(systemMock.get).not.toHaveBeenCalled(); }); }); describe('getConfig', () => { it('should return the default config', async () => { - configMock.load.mockResolvedValue([]); + systemMock.get.mockResolvedValue({}); await expect(sut.getConfig()).resolves.toEqual(defaults); }); it('should merge the overrides', async () => { - configMock.load.mockResolvedValue([ - { key: SystemConfigKey.FFMPEG_CRF, value: 30 }, - { key: SystemConfigKey.OAUTH_AUTO_LAUNCH, value: true }, - { key: SystemConfigKey.TRASH_DAYS, value: 10 }, - { key: SystemConfigKey.USER_DELETE_DELAY, value: 15 }, - ]); + systemMock.get.mockResolvedValue({ + ffmpeg: { crf: 30 }, + oauth: { autoLaunch: true }, + trash: { days: 10 }, + user: { deleteDelay: 15 }, + }); await expect(sut.getConfig()).resolves.toEqual(updatedConfig); }); it('should load the config from a json file', async () => { process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; - const partialConfig = { - ffmpeg: { crf: 30 }, - oauth: { autoLaunch: true }, - trash: { days: 10 }, - user: { deleteDelay: 15 }, - }; - configMock.readFile.mockResolvedValue(JSON.stringify(partialConfig)); + + systemMock.readFile.mockResolvedValue(JSON.stringify(partialConfig)); await expect(sut.getConfig()).resolves.toEqual(updatedConfig); - expect(configMock.readFile).toHaveBeenCalledWith('immich-config.json'); + expect(systemMock.readFile).toHaveBeenCalledWith('immich-config.json'); + }); + + it('should log errors with the config file', async () => { + process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; + + systemMock.readFile.mockResolvedValue(`{ "ffmpeg2": true, "ffmpeg2": true }`); + + await expect(sut.getConfig()).rejects.toBeInstanceOf(Error); + + expect(systemMock.readFile).toHaveBeenCalledWith('immich-config.json'); + expect(loggerMock.error).toHaveBeenCalledTimes(2); + expect(loggerMock.error.mock.calls[0][0]).toEqual('Unable to load configuration file: immich-config.json'); + expect(loggerMock.error.mock.calls[1][0].toString()).toEqual( + expect.stringContaining('YAMLException: duplicated mapping key (1:20)'), + ); }); it('should load the config from a yaml file', async () => { @@ -243,26 +258,26 @@ describe(SystemConfigService.name, () => { user: deleteDelay: 15 `; - configMock.readFile.mockResolvedValue(partialConfig); + systemMock.readFile.mockResolvedValue(partialConfig); await expect(sut.getConfig()).resolves.toEqual(updatedConfig); - expect(configMock.readFile).toHaveBeenCalledWith('immich-config.yaml'); + expect(systemMock.readFile).toHaveBeenCalledWith('immich-config.yaml'); }); it('should accept an empty configuration file', async () => { process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; - configMock.readFile.mockResolvedValue(JSON.stringify({})); + systemMock.readFile.mockResolvedValue(JSON.stringify({})); await expect(sut.getConfig()).resolves.toEqual(defaults); - expect(configMock.readFile).toHaveBeenCalledWith('immich-config.json'); + expect(systemMock.readFile).toHaveBeenCalledWith('immich-config.json'); }); it('should allow underscores in the machine learning url', async () => { process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; const partialConfig = { machineLearning: { url: 'immich_machine_learning' } }; - configMock.readFile.mockResolvedValue(JSON.stringify(partialConfig)); + systemMock.readFile.mockResolvedValue(JSON.stringify(partialConfig)); const config = await sut.getConfig(); expect(config.machineLearning.url).toEqual('immich_machine_learning'); @@ -273,7 +288,7 @@ describe(SystemConfigService.name, () => { const partialConfig = ` unknownOption: true `; - configMock.readFile.mockResolvedValue(partialConfig); + systemMock.readFile.mockResolvedValue(partialConfig); await sut.getConfig(); expect(loggerMock.warn).toHaveBeenCalled(); @@ -291,7 +306,7 @@ describe(SystemConfigService.name, () => { for (const test of tests) { it(`should ${test.should}`, async () => { process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; - configMock.readFile.mockResolvedValue(JSON.stringify(test.config)); + systemMock.readFile.mockResolvedValue(JSON.stringify(test.config)); if (test.warn) { await sut.getConfig(); @@ -339,20 +354,20 @@ describe(SystemConfigService.name, () => { describe('updateConfig', () => { it('should update the config and emit client and server events', async () => { - configMock.load.mockResolvedValue(updates); + systemMock.get.mockResolvedValue(partialConfig); await expect(sut.updateConfig(updatedConfig)).resolves.toEqual(updatedConfig); expect(eventMock.clientBroadcast).toHaveBeenCalled(); expect(eventMock.serverSend).toHaveBeenCalledWith(ServerEvent.CONFIG_UPDATE, null); - expect(configMock.saveAll).toHaveBeenCalledWith(updates); + expect(systemMock.set).toHaveBeenCalledWith(SystemMetadataKey.SYSTEM_CONFIG, partialConfig); }); it('should throw an error if a config file is in use', async () => { process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; - configMock.readFile.mockResolvedValue(JSON.stringify({})); + systemMock.readFile.mockResolvedValue(JSON.stringify({})); await expect(sut.updateConfig(defaults)).rejects.toBeInstanceOf(BadRequestException); - expect(configMock.saveAll).not.toHaveBeenCalled(); + expect(systemMock.set).not.toHaveBeenCalled(); }); }); diff --git a/server/src/services/system-config.service.ts b/server/src/services/system-config.service.ts index 2203f7a687..e198888020 100644 --- a/server/src/services/system-config.service.ts +++ b/server/src/services/system-config.service.ts @@ -1,6 +1,7 @@ import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { instanceToPlain } from 'class-transformer'; import _ from 'lodash'; +import { LogLevel, SystemConfig, defaults } from 'src/config'; import { supportedDayTokens, supportedHourTokens, @@ -14,7 +15,6 @@ import { import { SystemConfigCore } from 'src/cores/system-config.core'; import { OnServerEvent } from 'src/decorators'; import { SystemConfigDto, SystemConfigTemplateStorageOptionDto, mapConfig } from 'src/dtos/system-config.dto'; -import { LogLevel, SystemConfig } from 'src/entities/system-config.entity'; import { ClientEvent, IEventRepository, @@ -24,14 +24,14 @@ import { } from 'src/interfaces/event.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; @Injectable() export class SystemConfigService { private core: SystemConfigCore; constructor( - @Inject(ISystemConfigRepository) private repository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) private repository: ISystemMetadataRepository, @Inject(IEventRepository) private eventRepository: IEventRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, @Inject(ISearchRepository) private smartInfoRepository: ISearchRepository, @@ -56,18 +56,21 @@ export class SystemConfigService { } getDefaults(): SystemConfigDto { - const config = this.core.getDefaults(); - return mapConfig(config); + return mapConfig(defaults); } @OnServerEvent(ServerAsyncEvent.CONFIG_VALIDATE) onValidateConfig({ newConfig, oldConfig }: ServerAsyncEventMap[ServerAsyncEvent.CONFIG_VALIDATE]) { if (!_.isEqual(instanceToPlain(newConfig.logging), oldConfig.logging) && this.getEnvLogLevel()) { - throw new Error('Logging cannot be changed while the environment variable LOG_LEVEL is set.'); + throw new Error('Logging cannot be changed while the environment variable IMMICH_LOG_LEVEL is set.'); } } async updateConfig(dto: SystemConfigDto): Promise { + if (this.core.isUsingConfigFile()) { + throw new BadRequestException('Cannot update configuration while IMMICH_CONFIG_FILE is in use'); + } + const oldConfig = await this.core.getConfig(); try { @@ -132,10 +135,10 @@ export class SystemConfigService { const configLevel = logging.enabled ? logging.level : false; const level = envLevel ?? configLevel; this.logger.setLogLevel(level); - this.logger.log(`LogLevel=${level} ${envLevel ? '(set via LOG_LEVEL)' : '(set via system config)'}`); + this.logger.log(`LogLevel=${level} ${envLevel ? '(set via IMMICH_LOG_LEVEL)' : '(set via system config)'}`); } private getEnvLogLevel() { - return process.env.LOG_LEVEL as LogLevel; + return process.env.IMMICH_LOG_LEVEL as LogLevel; } } diff --git a/server/src/services/user.service.spec.ts b/server/src/services/user.service.spec.ts index 1bf4fc1012..0b0cdb5699 100644 --- a/server/src/services/user.service.spec.ts +++ b/server/src/services/user.service.spec.ts @@ -9,10 +9,9 @@ import { UserEntity, UserStatus } from 'src/entities/user.entity'; import { IAlbumRepository } from 'src/interfaces/album.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IJobRepository, JobName } from 'src/interfaces/job.interface'; -import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { UserService } from 'src/services/user.service'; import { CacheControl, ImmichFileResponse } from 'src/utils/file'; @@ -22,12 +21,11 @@ import { userStub } from 'test/fixtures/user.stub'; import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock'; import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; -import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; -import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; -import { Mocked, vitest } from 'vitest'; +import { Mocked } from 'vitest'; const makeDeletedAt = (daysAgo: number) => { const deletedAt = new Date(); @@ -42,31 +40,20 @@ describe(UserService.name, () => { let albumMock: Mocked; let jobMock: Mocked; - let libraryMock: Mocked; let storageMock: Mocked; - let configMock: Mocked; + let systemMock: Mocked; let loggerMock: Mocked; beforeEach(() => { albumMock = newAlbumRepositoryMock(); - configMock = newSystemConfigRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); cryptoRepositoryMock = newCryptoRepositoryMock(); jobMock = newJobRepositoryMock(); - libraryMock = newLibraryRepositoryMock(); storageMock = newStorageRepositoryMock(); userMock = newUserRepositoryMock(); loggerMock = newLoggerRepositoryMock(); - sut = new UserService( - albumMock, - cryptoRepositoryMock, - jobMock, - libraryMock, - storageMock, - configMock, - userMock, - loggerMock, - ); + sut = new UserService(albumMock, cryptoRepositoryMock, jobMock, storageMock, systemMock, userMock, loggerMock); userMock.get.mockImplementation((userId) => Promise.resolve([userStub.admin, userStub.user1].find((user) => user.id === userId) ?? null), @@ -138,13 +125,17 @@ describe(UserService.name, () => { expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { id: userStub.user1.id, storageLabel: null, + updatedAt: expect.any(Date), }); }); it('should omit a storage label set by non-admin users', async () => { userMock.update.mockResolvedValue(userStub.user1); await sut.update({ user: userStub.user1 }, { id: userStub.user1.id, storageLabel: 'admin' }); - expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { id: userStub.user1.id }); + expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { + id: userStub.user1.id, + updatedAt: expect.any(Date), + }); }); it('user can only update its information', async () => { @@ -174,6 +165,7 @@ describe(UserService.name, () => { expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { id: 'user-id', email: 'updated@test.com', + updatedAt: expect.any(Date), }); }); @@ -210,6 +202,7 @@ describe(UserService.name, () => { expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, { id: 'user-id', shouldChangePassword: true, + updatedAt: expect.any(Date), }); }); @@ -231,7 +224,7 @@ describe(UserService.name, () => { await sut.update(authStub.admin, dto); - expect(userMock.update).toHaveBeenCalledWith(userStub.admin.id, dto); + expect(userMock.update).toHaveBeenCalledWith(userStub.admin.id, { ...dto, updatedAt: expect.any(Date) }); }); it('should not let the another user become an admin', async () => { @@ -430,45 +423,6 @@ describe(UserService.name, () => { }); }); - describe('resetAdminPassword', () => { - it('should only work when there is an admin account', async () => { - userMock.getAdmin.mockResolvedValue(null); - const ask = vitest.fn().mockResolvedValue('new-password'); - - await expect(sut.resetAdminPassword(ask)).rejects.toBeInstanceOf(BadRequestException); - - expect(ask).not.toHaveBeenCalled(); - }); - - it('should default to a random password', async () => { - userMock.getAdmin.mockResolvedValue(userStub.admin); - const ask = vitest.fn().mockImplementation(() => {}); - - const response = await sut.resetAdminPassword(ask); - - const [id, update] = userMock.update.mock.calls[0]; - - expect(response.provided).toBe(false); - expect(ask).toHaveBeenCalled(); - expect(id).toEqual(userStub.admin.id); - expect(update.password).toBeDefined(); - }); - - it('should use the supplied password', async () => { - userMock.getAdmin.mockResolvedValue(userStub.admin); - const ask = vitest.fn().mockResolvedValue('new-password'); - - const response = await sut.resetAdminPassword(ask); - - const [id, update] = userMock.update.mock.calls[0]; - - expect(response.provided).toBe(true); - expect(ask).toHaveBeenCalled(); - expect(id).toEqual(userStub.admin.id); - expect(update.password).toBeDefined(); - }); - }); - describe('handleQueueUserDelete', () => { it('should skip users not ready for deletion', async () => { userMock.getDeletedUsers.mockResolvedValue([ @@ -486,7 +440,7 @@ describe(UserService.name, () => { }); it('should skip users not ready for deletion - deleteDelay30', async () => { - configMock.load.mockResolvedValue(systemConfigStub.deleteDelay30); + systemMock.get.mockResolvedValue(systemConfigStub.deleteDelay30); userMock.getDeletedUsers.mockResolvedValue([ {}, { deletedAt: undefined }, diff --git a/server/src/services/user.service.ts b/server/src/services/user.service.ts index c367e3985f..bb3313e4a9 100644 --- a/server/src/services/user.service.ts +++ b/server/src/services/user.service.ts @@ -6,16 +6,17 @@ import { UserCore } from 'src/cores/user.core'; import { AuthDto } from 'src/dtos/auth.dto'; import { CreateProfileImageResponseDto, mapCreateProfileImageResponse } from 'src/dtos/user-profile.dto'; import { CreateUserDto, DeleteUserDto, UpdateUserDto, UserResponseDto, mapUser } from 'src/dtos/user.dto'; +import { UserMetadataKey } from 'src/entities/user-metadata.entity'; import { UserEntity, UserStatus } from 'src/entities/user.entity'; import { IAlbumRepository } from 'src/interfaces/album.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IEntityJob, IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; -import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository, UserFindOptions } from 'src/interfaces/user.interface'; import { CacheControl, ImmichFileResponse } from 'src/utils/file'; +import { getPreferences, getPreferencesPartial } from 'src/utils/preferences'; @Injectable() export class UserService { @@ -24,17 +25,16 @@ export class UserService { constructor( @Inject(IAlbumRepository) private albumRepository: IAlbumRepository, - @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, + @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository, @Inject(IJobRepository) private jobRepository: IJobRepository, - @Inject(ILibraryRepository) libraryRepository: ILibraryRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, - @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ISystemMetadataRepository) systemMetadataRepository: ISystemMetadataRepository, @Inject(IUserRepository) private userRepository: IUserRepository, @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository); + this.userCore = UserCore.create(cryptoRepository, userRepository); this.logger.setContext(UserService.name); - this.configCore = SystemConfigCore.create(configRepository, this.logger); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); } async listUsers(): Promise { @@ -61,9 +61,21 @@ export class UserService { } async create(dto: CreateUserDto): Promise { - const user = await this.userCore.createUser(dto); - const tempPassword = user.shouldChangePassword ? dto.password : undefined; - if (dto.notify) { + const { memoriesEnabled, notify, ...rest } = dto; + let user = await this.userCore.createUser(rest); + + // TODO remove and replace with entire dto.preferences config + if (memoriesEnabled === false) { + await this.userRepository.upsertMetadata(user.id, { + key: UserMetadataKey.PREFERENCES, + value: { memories: { enabled: false } }, + }); + + user = await this.findOrFail(user.id, {}); + } + + const tempPassword = user.shouldChangePassword ? rest.password : undefined; + if (notify) { await this.jobRepository.queue({ name: JobName.NOTIFY_SIGNUP, data: { id: user.id, tempPassword } }); } return mapUser(user); @@ -76,7 +88,28 @@ export class UserService { await this.userRepository.syncUsage(dto.id); } - return this.userCore.updateUser(auth.user, dto.id, dto).then(mapUser); + // TODO replace with entire preferences object + if (dto.memoriesEnabled !== undefined || dto.avatarColor) { + const newPreferences = getPreferences(user); + if (dto.memoriesEnabled !== undefined) { + newPreferences.memories.enabled = dto.memoriesEnabled; + delete dto.memoriesEnabled; + } + + if (dto.avatarColor) { + newPreferences.avatar.color = dto.avatarColor; + delete dto.avatarColor; + } + + await this.userRepository.upsertMetadata(dto.id, { + key: UserMetadataKey.PREFERENCES, + value: getPreferencesPartial(user, newPreferences), + }); + } + + const updatedUser = await this.userCore.updateUser(auth.user, dto.id, dto); + + return mapUser(updatedUser); } async delete(auth: AuthDto, id: string, dto: DeleteUserDto): Promise { @@ -135,20 +168,6 @@ export class UserService { }); } - async resetAdminPassword(ask: (admin: UserResponseDto) => Promise) { - const admin = await this.userRepository.getAdmin(); - if (!admin) { - throw new BadRequestException('Admin account does not exist'); - } - - const providedPassword = await ask(mapUser(admin)); - const password = providedPassword || this.cryptoRepository.newPassword(24); - - await this.userCore.updateUser(admin, admin.id, { password }); - - return { admin, password, provided: !!providedPassword }; - } - async handleUserSyncUsage(): Promise { await this.userRepository.syncUsage(); return JobStatus.SUCCESS; diff --git a/server/src/services/version.service.spec.ts b/server/src/services/version.service.spec.ts new file mode 100644 index 0000000000..3bf6a24e11 --- /dev/null +++ b/server/src/services/version.service.spec.ts @@ -0,0 +1,114 @@ +import { DateTime } from 'luxon'; +import { serverVersion } from 'src/constants'; +import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; +import { IEventRepository } from 'src/interfaces/event.interface'; +import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; +import { VersionService } from 'src/services/version.service'; +import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; +import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; +import { newServerInfoRepositoryMock } from 'test/repositories/system-info.repository.mock'; +import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock'; +import { Mocked } from 'vitest'; + +const mockRelease = (version: string) => ({ + id: 1, + url: 'https://api.github.com/repos/owner/repo/releases/1', + tag_name: version, + name: 'Release 1000', + created_at: DateTime.utc().toISO(), + published_at: DateTime.utc().toISO(), + body: '', +}); + +describe(VersionService.name, () => { + let sut: VersionService; + let eventMock: Mocked; + let jobMock: Mocked; + let serverMock: Mocked; + let systemMock: Mocked; + let loggerMock: Mocked; + + beforeEach(() => { + eventMock = newEventRepositoryMock(); + jobMock = newJobRepositoryMock(); + serverMock = newServerInfoRepositoryMock(); + systemMock = newSystemMetadataRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); + + sut = new VersionService(eventMock, jobMock, serverMock, systemMock, loggerMock); + }); + + it('should work', () => { + expect(sut).toBeDefined(); + }); + + describe('getVersion', () => { + it('should respond the server version', () => { + expect(sut.getVersion()).toEqual({ + major: serverVersion.major, + minor: serverVersion.minor, + patch: serverVersion.patch, + }); + }); + }); + + describe('handQueueVersionCheck', () => { + it('should queue a version check job', async () => { + await expect(sut.handleQueueVersionCheck()).resolves.toBeUndefined(); + expect(jobMock.queue).toHaveBeenCalledWith({ name: JobName.VERSION_CHECK, data: {} }); + }); + }); + + describe('handVersionCheck', () => { + beforeEach(() => { + process.env.IMMICH_ENV = 'production'; + }); + + it('should not run in dev mode', async () => { + process.env.IMMICH_ENV = 'development'; + await expect(sut.handleVersionCheck()).resolves.toEqual(JobStatus.SKIPPED); + }); + + it('should not run if the last check was < 60 minutes ago', async () => { + systemMock.get.mockResolvedValue({ + checkedAt: DateTime.utc().minus({ minutes: 5 }).toISO(), + releaseVersion: '1.0.0', + }); + await expect(sut.handleVersionCheck()).resolves.toEqual(JobStatus.SKIPPED); + }); + + it('should run if it has been > 60 minutes', async () => { + serverMock.getGitHubRelease.mockResolvedValue(mockRelease('v100.0.0')); + systemMock.get.mockResolvedValue({ + checkedAt: DateTime.utc().minus({ minutes: 65 }).toISO(), + releaseVersion: '1.0.0', + }); + await expect(sut.handleVersionCheck()).resolves.toEqual(JobStatus.SUCCESS); + expect(systemMock.set).toHaveBeenCalled(); + expect(loggerMock.log).toHaveBeenCalled(); + expect(eventMock.clientBroadcast).toHaveBeenCalled(); + }); + + it('should not notify if the version is equal', async () => { + serverMock.getGitHubRelease.mockResolvedValue(mockRelease(serverVersion.toString())); + await expect(sut.handleVersionCheck()).resolves.toEqual(JobStatus.SUCCESS); + expect(systemMock.set).toHaveBeenCalledWith(SystemMetadataKey.VERSION_CHECK_STATE, { + checkedAt: expect.any(String), + releaseVersion: serverVersion.toString(), + }); + expect(eventMock.clientBroadcast).not.toHaveBeenCalled(); + }); + + it('should handle a github error', async () => { + serverMock.getGitHubRelease.mockRejectedValue(new Error('GitHub is down')); + await expect(sut.handleVersionCheck()).resolves.toEqual(JobStatus.FAILED); + expect(systemMock.set).not.toHaveBeenCalled(); + expect(eventMock.clientBroadcast).not.toHaveBeenCalled(); + expect(loggerMock.warn).toHaveBeenCalled(); + }); + }); +}); diff --git a/server/src/services/version.service.ts b/server/src/services/version.service.ts new file mode 100644 index 0000000000..fdfe78991f --- /dev/null +++ b/server/src/services/version.service.ts @@ -0,0 +1,99 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { DateTime } from 'luxon'; +import semver, { SemVer } from 'semver'; +import { isDev, serverVersion } from 'src/constants'; +import { SystemConfigCore } from 'src/cores/system-config.core'; +import { OnServerEvent } from 'src/decorators'; +import { ReleaseNotification, ServerVersionResponseDto } from 'src/dtos/server-info.dto'; +import { SystemMetadataKey, VersionCheckMetadata } from 'src/entities/system-metadata.entity'; +import { ClientEvent, IEventRepository, ServerEvent, ServerEventMap } from 'src/interfaces/event.interface'; +import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; +import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; + +const asNotification = ({ checkedAt, releaseVersion }: VersionCheckMetadata): ReleaseNotification => { + return { + isAvailable: semver.gt(releaseVersion, serverVersion), + checkedAt, + serverVersion: ServerVersionResponseDto.fromSemVer(serverVersion), + releaseVersion: ServerVersionResponseDto.fromSemVer(new SemVer(releaseVersion)), + }; +}; + +@Injectable() +export class VersionService { + private configCore: SystemConfigCore; + + constructor( + @Inject(IEventRepository) private eventRepository: IEventRepository, + @Inject(IJobRepository) private jobRepository: IJobRepository, + @Inject(IServerInfoRepository) private repository: IServerInfoRepository, + @Inject(ISystemMetadataRepository) private systemMetadataRepository: ISystemMetadataRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(VersionService.name); + this.configCore = SystemConfigCore.create(systemMetadataRepository, this.logger); + } + + async init(): Promise { + await this.handleVersionCheck(); + } + + getVersion() { + return ServerVersionResponseDto.fromSemVer(serverVersion); + } + + async handleQueueVersionCheck() { + await this.jobRepository.queue({ name: JobName.VERSION_CHECK, data: {} }); + } + + async handleVersionCheck(): Promise { + try { + this.logger.debug('Running version check'); + + if (isDev()) { + return JobStatus.SKIPPED; + } + + const { newVersionCheck } = await this.configCore.getConfig(); + if (!newVersionCheck.enabled) { + return JobStatus.SKIPPED; + } + + const versionCheck = await this.systemMetadataRepository.get(SystemMetadataKey.VERSION_CHECK_STATE); + if (versionCheck?.checkedAt) { + const lastUpdate = DateTime.fromISO(versionCheck.checkedAt); + const elapsedTime = DateTime.now().diff(lastUpdate).as('minutes'); + // check once per hour (max) + if (elapsedTime < 60) { + return JobStatus.SKIPPED; + } + } + + const { tag_name: releaseVersion, published_at: publishedAt } = await this.repository.getGitHubRelease(); + const metadata: VersionCheckMetadata = { checkedAt: DateTime.utc().toISO(), releaseVersion }; + + await this.systemMetadataRepository.set(SystemMetadataKey.VERSION_CHECK_STATE, metadata); + + if (semver.gt(releaseVersion, serverVersion)) { + this.logger.log(`Found ${releaseVersion}, released at ${new Date(publishedAt).toLocaleString()}`); + this.eventRepository.clientBroadcast(ClientEvent.NEW_RELEASE, asNotification(metadata)); + } + } catch (error: Error | any) { + this.logger.warn(`Unable to run version check: ${error}`, error?.stack); + return JobStatus.FAILED; + } + + return JobStatus.SUCCESS; + } + + @OnServerEvent(ServerEvent.WEBSOCKET_CONNECT) + async onWebsocketConnection({ userId }: ServerEventMap[ServerEvent.WEBSOCKET_CONNECT]) { + this.eventRepository.clientSend(ClientEvent.SERVER_VERSION, userId, serverVersion); + const metadata = await this.systemMetadataRepository.get(SystemMetadataKey.VERSION_CHECK_STATE); + if (metadata) { + this.eventRepository.clientSend(ClientEvent.NEW_RELEASE, userId, asNotification(metadata)); + } + } +} diff --git a/server/src/utils/asset.util.ts b/server/src/utils/asset.util.ts index 253073919f..a55156e679 100644 --- a/server/src/utils/asset.util.ts +++ b/server/src/utils/asset.util.ts @@ -36,6 +36,7 @@ export const addAssets = async ( continue; } + existingAssetIds.add(assetId); results.push({ id: assetId, success: true }); } @@ -79,6 +80,7 @@ export const removeAssets = async ( continue; } + existingAssetIds.delete(assetId); results.push({ id: assetId, success: true }); } diff --git a/server/src/utils/file.ts b/server/src/utils/file.ts index a80f17beae..8170fba4e9 100644 --- a/server/src/utils/file.ts +++ b/server/src/utils/file.ts @@ -3,8 +3,8 @@ import { NextFunction, Response } from 'express'; import { access, constants } from 'node:fs/promises'; import { basename, extname, isAbsolute } from 'node:path'; import { promisify } from 'node:util'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ImmichReadStream } from 'src/interfaces/storage.interface'; -import { ImmichLogger } from 'src/utils/logger'; import { isConnectionAborted } from 'src/utils/misc'; export function getFileNameWithoutExtension(path: string): string { @@ -33,12 +33,11 @@ export class ImmichFileResponse { type SendFile = Parameters; type SendFileOptions = SendFile[1]; -const logger = new ImmichLogger('SendFile'); - export const sendFile = async ( res: Response, next: NextFunction, handler: () => Promise, + logger: ILoggerRepository, ): Promise => { const _sendFile = (path: string, options: SendFileOptions) => promisify(res.sendFile).bind(res)(path, options); diff --git a/server/src/utils/healthcheck.ts b/server/src/utils/healthcheck.ts new file mode 100644 index 0000000000..df50636f45 --- /dev/null +++ b/server/src/utils/healthcheck.ts @@ -0,0 +1,29 @@ +#!/usr/bin/env node +const port = Number(process.env.IMMICH_PORT) || 3001; +const controller = new AbortController(); + +const main = async () => { + const timeout = setTimeout(() => controller.abort(), 2000); + try { + const response = await fetch(`http://localhost:${port}/api/server-info/ping`, { + signal: controller.signal, + }); + + if (response.ok) { + const body = await response.json(); + if (body.res === 'pong') { + process.exit(); + } + } + } catch (error) { + if (error instanceof DOMException === false) { + console.error(error); + } + } finally { + clearTimeout(timeout); + } + + process.exit(1); +}; + +void main(); diff --git a/server/src/utils/lifecycle.ts b/server/src/utils/lifecycle.ts index 9639ab609e..16793f6922 100644 --- a/server/src/utils/lifecycle.ts +++ b/server/src/utils/lifecycle.ts @@ -3,8 +3,8 @@ import { OpenAPIObject } from '@nestjs/swagger'; import { SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.interface'; import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; +import { SemVer } from 'semver'; import { ADDED_IN_PREFIX, DEPRECATED_IN_PREFIX, LIFECYCLE_EXTENSION, NEXT_RELEASE } from 'src/constants'; -import { Version } from 'src/utils/version'; const outputPath = resolve(process.cwd(), '../open-api/immich-openapi-specs.json'); const spec = JSON.parse(readFileSync(outputPath).toString()) as OpenAPIObject; @@ -69,9 +69,7 @@ const sortedVersions = Object.keys(metadata).sort((a, b) => { return 1; } - const versionA = Version.fromString(a); - const versionB = Version.fromString(b); - return versionB.compareTo(versionA); + return new SemVer(b).compare(new SemVer(a)); }); for (const version of sortedVersions) { diff --git a/server/src/utils/logger-colors.ts b/server/src/utils/logger-colors.ts new file mode 100644 index 0000000000..36104ee520 --- /dev/null +++ b/server/src/utils/logger-colors.ts @@ -0,0 +1,17 @@ +type ColorTextFn = (text: string) => string; + +const isColorAllowed = () => !process.env.NO_COLOR; +const colorIfAllowed = (colorFn: ColorTextFn) => (text: string) => (isColorAllowed() ? colorFn(text) : text); + +export const LogColor = { + red: colorIfAllowed((text: string) => `\u001B[31m${text}\u001B[39m`), + green: colorIfAllowed((text: string) => `\u001B[32m${text}\u001B[39m`), + yellow: colorIfAllowed((text: string) => `\u001B[33m${text}\u001B[39m`), + blue: colorIfAllowed((text: string) => `\u001B[34m${text}\u001B[39m`), + magentaBright: colorIfAllowed((text: string) => `\u001B[95m${text}\u001B[39m`), + cyanBright: colorIfAllowed((text: string) => `\u001B[96m${text}\u001B[39m`), +}; + +export const LogStyle = { + bold: colorIfAllowed((text: string) => `\u001B[1m${text}\u001B[0m`), +}; diff --git a/server/src/utils/logger.ts b/server/src/utils/logger.ts deleted file mode 100644 index 05e8feb498..0000000000 --- a/server/src/utils/logger.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ConsoleLogger } from '@nestjs/common'; -import { isLogLevelEnabled } from '@nestjs/common/services/utils/is-log-level-enabled.util'; -import { LogLevel } from 'src/entities/system-config.entity'; - -const LOG_LEVELS = [LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]; - -// TODO move implementation to logger.repository.ts -export class ImmichLogger extends ConsoleLogger { - private static logLevels: LogLevel[] = [LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]; - - constructor(context: string) { - super(context); - } - - isLevelEnabled(level: LogLevel) { - return isLogLevelEnabled(level, ImmichLogger.logLevels); - } - - static setLogLevel(level: LogLevel | false): void { - ImmichLogger.logLevels = level === false ? [] : LOG_LEVELS.slice(LOG_LEVELS.indexOf(level)); - } -} diff --git a/server/src/utils/media.ts b/server/src/utils/media.ts index ff38ded631..5a57f0f0cf 100644 --- a/server/src/utils/media.ts +++ b/server/src/utils/media.ts @@ -1,5 +1,5 @@ +import { CQMode, ToneMapping, TranscodeHWAccel, TranscodeTarget, VideoCodec } from 'src/config'; import { SystemConfigFFmpegDto } from 'src/dtos/system-config.dto'; -import { CQMode, ToneMapping, TranscodeHWAccel, TranscodeTarget, VideoCodec } from 'src/entities/system-config.entity'; import { AudioStreamInfo, BitrateDistribution, @@ -26,14 +26,18 @@ class BaseConfig implements VideoCodecSWConfig { } } - options.outputOptions.push(...this.getPresetOptions(), ...this.getThreadOptions(), ...this.getBitrateOptions()); + options.outputOptions.push( + ...this.getPresetOptions(), + ...this.getOutputThreadOptions(), + ...this.getBitrateOptions(), + ); return options; } // eslint-disable-next-line @typescript-eslint/no-unused-vars getBaseInputOptions(videoStream: VideoStreamInfo): string[] { - return []; + return this.getInputThreadOptions(); } getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) { @@ -80,11 +84,7 @@ class BaseConfig implements VideoCodecSWConfig { options.push(`scale=${this.getScaling(videoStream)}`); } - if (this.shouldToneMap(videoStream)) { - options.push(...this.getToneMapping()); - } - options.push('format=yuv420p'); - + options.push(...this.getToneMapping(videoStream), 'format=yuv420p'); return options; } @@ -112,7 +112,11 @@ class BaseConfig implements VideoCodecSWConfig { } } - getThreadOptions(): Array { + getInputThreadOptions(): Array { + return []; + } + + getOutputThreadOptions(): Array { if (this.config.threads <= 0) { return []; } @@ -218,7 +222,11 @@ class BaseConfig implements VideoCodecSWConfig { } } - getToneMapping() { + getToneMapping(videoStream: VideoStreamInfo) { + if (!this.shouldToneMap(videoStream)) { + return []; + } + const colors = this.getColors(); return [ @@ -294,10 +302,10 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig { return this.config.gopSize; } - getPreferredHardwareDevice(): string | null { + getPreferredHardwareDevice(): string | undefined { const device = this.config.preferredHwDevice; if (device === 'auto') { - return null; + return; } const deviceName = device.replace('/dev/dri/', ''); @@ -305,7 +313,7 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig { throw new Error(`Device '${device}' does not exist`); } - return device; + return `/dev/dri/${deviceName}`; } } @@ -348,8 +356,8 @@ export class ThumbnailConfig extends BaseConfig { } export class H264Config extends BaseConfig { - getThreadOptions() { - const options = super.getThreadOptions(); + getOutputThreadOptions() { + const options = super.getOutputThreadOptions(); if (this.config.threads === 1) { options.push('-x264-params frame-threads=1:pools=none'); } @@ -359,8 +367,8 @@ export class H264Config extends BaseConfig { } export class HEVCConfig extends BaseConfig { - getThreadOptions() { - const options = super.getThreadOptions(); + getOutputThreadOptions() { + const options = super.getOutputThreadOptions(); if (this.config.threads === 1) { options.push('-x265-params frame-threads=1:pools=none'); } @@ -391,8 +399,8 @@ export class VP9Config extends BaseConfig { return [`-${this.useCQP() ? 'q:v' : 'crf'} ${this.config.crf}`, `-b:v ${bitrates.max}${bitrates.unit}`]; } - getThreadOptions() { - return ['-row-mt 1', ...super.getThreadOptions()]; + getOutputThreadOptions() { + return ['-row-mt 1', ...super.getOutputThreadOptions()]; } eligibleForTwoPass() { @@ -425,7 +433,7 @@ export class AV1Config extends BaseConfig { return options; } - getThreadOptions() { + getOutputThreadOptions() { return []; // Already set above with svtav1-params } @@ -434,7 +442,7 @@ export class AV1Config extends BaseConfig { } } -export class NVENCConfig extends BaseHWConfig { +export class NvencSwDecodeConfig extends BaseHWConfig { getSupportedCodecs() { return [VideoCodec.H264, VideoCodec.HEVC, VideoCodec.AV1]; } @@ -462,7 +470,7 @@ export class NVENCConfig extends BaseHWConfig { } getFilterOptions(videoStream: VideoStreamInfo) { - const options = this.shouldToneMap(videoStream) ? this.getToneMapping() : []; + const options = this.getToneMapping(videoStream); options.push('format=nv12', 'hwupload_cuda'); if (this.shouldScale(videoStream)) { options.push(`scale_cuda=${this.getScaling(videoStream)}`); @@ -513,7 +521,53 @@ export class NVENCConfig extends BaseHWConfig { } } -export class QSVConfig extends BaseHWConfig { +export class NvencHwDecodeConfig extends NvencSwDecodeConfig { + getBaseInputOptions() { + return ['-hwaccel cuda', '-hwaccel_output_format cuda', '-noautorotate', ...this.getInputThreadOptions()]; + } + + getFilterOptions(videoStream: VideoStreamInfo) { + const options = []; + if (this.shouldScale(videoStream)) { + options.push(`scale_cuda=${this.getScaling(videoStream)}`); + } + options.push(...this.getToneMapping(videoStream)); + if (options.length > 0) { + options[options.length - 1] += ':format=nv12'; + } else { + options.push('format=nv12'); + } + return options; + } + + getToneMapping(videoStream: VideoStreamInfo) { + if (!this.shouldToneMap(videoStream)) { + return []; + } + + const colors = this.getColors(); + const tonemapOptions = [ + 'desat=0', + `matrix=${colors.matrix}`, + `primaries=${colors.primaries}`, + 'range=pc', + `tonemap=${this.config.tonemap}`, + `transfer=${colors.transfer}`, + ]; + + return [`tonemap_cuda=${tonemapOptions.join(':')}`]; + } + + getInputThreadOptions() { + return [`-threads ${this.config.threads <= 0 ? 1 : this.config.threads}`]; + } + + getOutputThreadOptions() { + return []; + } +} + +export class QsvSwDecodeConfig extends BaseHWConfig { getBaseInputOptions() { if (this.devices.length === 0) { throw new Error('No QSV device found'); @@ -521,7 +575,7 @@ export class QSVConfig extends BaseHWConfig { let qsvString = ''; const hwDevice = this.getPreferredHardwareDevice(); - if (hwDevice !== null) { + if (hwDevice) { qsvString = `,child_device=${hwDevice}`; } @@ -538,7 +592,7 @@ export class QSVConfig extends BaseHWConfig { } getFilterOptions(videoStream: VideoStreamInfo) { - const options = this.shouldToneMap(videoStream) ? this.getToneMapping() : []; + const options = this.getToneMapping(videoStream); options.push('format=nv12', 'hwupload=extra_hw_frames=64'); if (this.shouldScale(videoStream)) { options.push(`scale_qsv=${this.getScaling(videoStream)}`); @@ -589,6 +643,59 @@ export class QSVConfig extends BaseHWConfig { } } +export class QsvHwDecodeConfig extends QsvSwDecodeConfig { + getBaseInputOptions() { + if (this.devices.length === 0) { + throw new Error('No QSV device found'); + } + + const options = ['-hwaccel qsv', '-hwaccel_output_format qsv', '-async_depth 4', '-threads 1']; + const hwDevice = this.getPreferredHardwareDevice(); + if (hwDevice) { + options.push(`-qsv_device ${hwDevice}`); + } + + return options; + } + + getFilterOptions(videoStream: VideoStreamInfo) { + const options = []; + if (this.shouldScale(videoStream) || !this.shouldToneMap(videoStream)) { + let scaling = `scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq`; + if (!this.shouldToneMap(videoStream)) { + scaling += ':format=nv12'; + } + options.push(scaling); + } + + options.push(...this.getToneMapping(videoStream)); + return options; + } + + getToneMapping(videoStream: VideoStreamInfo): string[] { + if (!this.shouldToneMap(videoStream)) { + return []; + } + + const colors = this.getColors(); + const tonemapOptions = [ + 'desat=0', + 'format=nv12', + `matrix=${colors.matrix}`, + `primaries=${colors.primaries}`, + 'range=pc', + `tonemap=${this.config.tonemap}`, + `transfer=${colors.transfer}`, + ]; + + return [ + 'hwmap=derive_device=opencl', + `tonemap_opencl=${tonemapOptions.join(':')}`, + 'hwmap=derive_device=qsv:reverse=1,format=qsv', + ]; + } +} + export class VAAPIConfig extends BaseHWConfig { getBaseInputOptions() { if (this.devices.length === 0) { @@ -596,7 +703,7 @@ export class VAAPIConfig extends BaseHWConfig { } let hwDevice = this.getPreferredHardwareDevice(); - if (hwDevice === null) { + if (!hwDevice) { hwDevice = `/dev/dri/${this.devices[0]}`; } @@ -604,7 +711,7 @@ export class VAAPIConfig extends BaseHWConfig { } getFilterOptions(videoStream: VideoStreamInfo) { - const options = this.shouldToneMap(videoStream) ? this.getToneMapping() : []; + const options = this.getToneMapping(videoStream); options.push('format=nv12', 'hwupload'); if (this.shouldScale(videoStream)) { options.push(`scale_vaapi=${this.getScaling(videoStream)}`); @@ -656,47 +763,22 @@ export class VAAPIConfig extends BaseHWConfig { } } -export class RKMPPConfig extends BaseHWConfig { - private hasOpenCL: boolean; - +export class RkmppSwDecodeConfig extends BaseHWConfig { constructor( protected config: SystemConfigFFmpegDto, devices: string[] = [], - hasOpenCL: boolean = false, ) { super(config, devices); - this.hasOpenCL = hasOpenCL; } eligibleForTwoPass(): boolean { return false; } - getBaseInputOptions(videoStream: VideoStreamInfo) { + getBaseInputOptions(): string[] { if (this.devices.length === 0) { throw new Error('No RKMPP device found'); } - return this.shouldToneMap(videoStream) && !this.hasOpenCL - ? [] // disable hardware decoding & filters - : ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']; - } - - getFilterOptions(videoStream: VideoStreamInfo) { - if (this.shouldToneMap(videoStream)) { - if (!this.hasOpenCL) { - return super.getFilterOptions(videoStream); - } - const colors = this.getColors(); - return [ - `scale_rkrga=${this.getScaling(videoStream)}:format=p010:afbc=1`, - 'hwmap=derive_device=opencl:mode=read', - `tonemap_opencl=format=nv12:r=pc:p=${colors.primaries}:t=${colors.transfer}:m=${colors.matrix}:tonemap=${this.config.tonemap}:desat=0`, - 'hwmap=derive_device=rkmpp:mode=write:reverse=1', - 'format=drm_prime', - ]; - } else if (this.shouldScale(videoStream)) { - return [`scale_rkrga=${this.getScaling(videoStream)}:format=nv12:afbc=1`]; - } return []; } @@ -734,3 +816,29 @@ export class RKMPPConfig extends BaseHWConfig { return `${this.config.targetVideoCodec}_rkmpp`; } } + +export class RkmppHwDecodeConfig extends RkmppSwDecodeConfig { + getBaseInputOptions() { + if (this.devices.length === 0) { + throw new Error('No RKMPP device found'); + } + + return ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']; + } + + getFilterOptions(videoStream: VideoStreamInfo) { + if (this.shouldToneMap(videoStream)) { + const colors = this.getColors(); + return [ + `scale_rkrga=${this.getScaling(videoStream)}:format=p010:afbc=1`, + 'hwmap=derive_device=opencl:mode=read', + `tonemap_opencl=format=nv12:r=pc:p=${colors.primaries}:t=${colors.transfer}:m=${colors.matrix}:tonemap=${this.config.tonemap}:desat=0`, + 'hwmap=derive_device=rkmpp:mode=write:reverse=1', + 'format=drm_prime', + ]; + } else if (this.shouldScale(videoStream)) { + return [`scale_rkrga=${this.getScaling(videoStream)}:format=nv12:afbc=1`]; + } + return []; + } +} diff --git a/server/src/utils/misc.spec.ts b/server/src/utils/misc.spec.ts new file mode 100644 index 0000000000..c36772ad43 --- /dev/null +++ b/server/src/utils/misc.spec.ts @@ -0,0 +1,52 @@ +import { getKeysDeep, unsetDeep } from 'src/utils/misc'; +import { describe, expect, it } from 'vitest'; + +describe('getKeysDeep', () => { + it('should handle an empty object', () => { + expect(getKeysDeep({})).toEqual([]); + }); + + it('should list properties', () => { + expect( + getKeysDeep({ + foo: 'bar', + flag: true, + count: 42, + }), + ).toEqual(['foo', 'flag', 'count']); + }); + + it('should skip undefined properties', () => { + expect(getKeysDeep({ foo: 'bar', hello: undefined })).toEqual(['foo']); + }); + + it('should skip array indices', () => { + expect(getKeysDeep({ foo: 'bar', hello: ['foo', 'bar'] })).toEqual(['foo', 'hello']); + expect(getKeysDeep({ foo: 'bar', nested: { hello: ['foo', 'bar'] } })).toEqual(['foo', 'nested.hello']); + }); + + it('should list nested properties', () => { + expect(getKeysDeep({ foo: 'bar', hello: { world: true } })).toEqual(['foo', 'hello.world']); + }); +}); + +describe('unsetDeep', () => { + it('should remove a property', () => { + expect(unsetDeep({ hello: 'world', foo: 'bar' }, 'foo')).toEqual({ hello: 'world' }); + }); + + it('should remove the last property', () => { + expect(unsetDeep({ foo: 'bar' }, 'foo')).toBeUndefined(); + }); + + it('should remove a nested property', () => { + expect(unsetDeep({ foo: 'bar', nested: { enabled: true, count: 42 } }, 'nested.enabled')).toEqual({ + foo: 'bar', + nested: { count: 42 }, + }); + }); + + it('should clean up an empty property', () => { + expect(unsetDeep({ foo: 'bar', nested: { enabled: true } }, 'nested.enabled')).toEqual({ foo: 'bar' }); + }); +}); diff --git a/server/src/utils/misc.ts b/server/src/utils/misc.ts index 95eefe7039..f5c0105c03 100644 --- a/server/src/utils/misc.ts +++ b/server/src/utils/misc.ts @@ -10,11 +10,61 @@ import { SchemaObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.inte import _ from 'lodash'; import { writeFileSync } from 'node:fs'; import path from 'node:path'; -import { CLIP_MODEL_INFO, serverVersion } from 'src/constants'; +import { SystemConfig } from 'src/config'; +import { CLIP_MODEL_INFO, isDev, serverVersion } from 'src/constants'; import { ImmichCookie, ImmichHeader } from 'src/dtos/auth.dto'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Metadata } from 'src/middleware/auth.guard'; +/** + * @returns a list of strings representing the keys of the object in dot notation + */ +export const getKeysDeep = (target: unknown, path: string[] = []) => { + if (!target || typeof target !== 'object') { + return []; + } + + const obj = target as object; + + const properties: string[] = []; + for (const key of Object.keys(obj as object)) { + const value = obj[key as keyof object]; + if (value === undefined) { + continue; + } + + if (_.isObject(value) && !_.isArray(value)) { + properties.push(...getKeysDeep(value, [...path, key])); + continue; + } + + properties.push([...path, key].join('.')); + } + + return properties; +}; + +export const unsetDeep = (object: unknown, key: string) => { + const parts = key.split('.'); + while (parts.length > 0) { + _.unset(object, parts); + parts.pop(); + if (!_.isEmpty(_.get(object, parts))) { + break; + } + } + + return _.isEmpty(object) ? undefined : object; +}; + +const isMachineLearningEnabled = (machineLearning: SystemConfig['machineLearning']) => machineLearning.enabled; +export const isSmartSearchEnabled = (machineLearning: SystemConfig['machineLearning']) => + isMachineLearningEnabled(machineLearning) && machineLearning.clip.enabled; +export const isFacialRecognitionEnabled = (machineLearning: SystemConfig['machineLearning']) => + isMachineLearningEnabled(machineLearning) && machineLearning.facialRecognition.enabled; +export const isDuplicateDetectionEnabled = (machineLearning: SystemConfig['machineLearning']) => + isSmartSearchEnabled(machineLearning) && machineLearning.duplicateDetection.enabled; + export const isConnectionAborted = (error: Error | any) => error.code === 'ECONNABORTED'; export const handlePromiseError = (promise: Promise, logger: ILoggerRepository): void => { @@ -124,7 +174,7 @@ const patchOpenAPI = (document: OpenAPIObject) => { return document; }; -export const useSwagger = (app: INestApplication, isDevelopment: boolean) => { +export const useSwagger = (app: INestApplication, force = false) => { const config = new DocumentBuilder() .setTitle('Immich') .setDescription('Immich API') @@ -161,7 +211,7 @@ export const useSwagger = (app: INestApplication, isDevelopment: boolean) => { SwaggerModule.setup('doc', app, specification, customOptions); - if (isDevelopment) { + if (isDev() || force) { // Generate API Documentation only in development mode const outputPath = path.resolve(process.cwd(), '../open-api/immich-openapi-specs.json'); writeFileSync(outputPath, JSON.stringify(patchOpenAPI(specification), null, 2), { encoding: 'utf8' }); diff --git a/server/src/utils/preferences.ts b/server/src/utils/preferences.ts new file mode 100644 index 0000000000..ae10c24fc9 --- /dev/null +++ b/server/src/utils/preferences.ts @@ -0,0 +1,39 @@ +import _ from 'lodash'; +import { UserMetadataKey, UserPreferences, getDefaultPreferences } from 'src/entities/user-metadata.entity'; +import { UserEntity } from 'src/entities/user.entity'; +import { getKeysDeep } from 'src/utils/misc'; +import { DeepPartial } from 'typeorm'; + +export const getPreferences = (user: UserEntity) => { + const preferences = getDefaultPreferences(user); + if (!user.metadata) { + return preferences; + } + + const item = user.metadata.find(({ key }) => key === UserMetadataKey.PREFERENCES); + const partial = item?.value || {}; + for (const property of getKeysDeep(partial)) { + _.set(preferences, property, _.get(partial, property)); + } + + return preferences; +}; + +export const getPreferencesPartial = (user: { email: string }, newPreferences: UserPreferences) => { + const defaultPreferences = getDefaultPreferences(user); + const partial: DeepPartial = {}; + for (const property of getKeysDeep(defaultPreferences)) { + const newValue = _.get(newPreferences, property); + const isEmpty = newValue === undefined || newValue === null || newValue === ''; + const defaultValue = _.get(defaultPreferences, property); + const isEqual = newValue === defaultValue || _.isEqual(newValue, defaultValue); + + if (isEmpty || isEqual) { + continue; + } + + _.set(partial, property, newValue); + } + + return partial; +}; diff --git a/server/src/utils/version.spec.ts b/server/src/utils/version.spec.ts deleted file mode 100644 index 34c8abb417..0000000000 --- a/server/src/utils/version.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Version, VersionType } from 'src/utils/version'; - -describe('Version', () => { - const tests = [ - { this: new Version(0, 0, 1), other: new Version(0, 0, 0), compare: 1, type: VersionType.PATCH }, - { this: new Version(0, 1, 0), other: new Version(0, 0, 0), compare: 1, type: VersionType.MINOR }, - { this: new Version(1, 0, 0), other: new Version(0, 0, 0), compare: 1, type: VersionType.MAJOR }, - { this: new Version(0, 0, 0), other: new Version(0, 0, 1), compare: -1, type: VersionType.PATCH }, - { this: new Version(0, 0, 0), other: new Version(0, 1, 0), compare: -1, type: VersionType.MINOR }, - { this: new Version(0, 0, 0), other: new Version(1, 0, 0), compare: -1, type: VersionType.MAJOR }, - { this: new Version(0, 0, 0), other: new Version(0, 0, 0), compare: 0, type: VersionType.EQUAL }, - { this: new Version(0, 0, 1), other: new Version(0, 0, 1), compare: 0, type: VersionType.EQUAL }, - { this: new Version(0, 1, 0), other: new Version(0, 1, 0), compare: 0, type: VersionType.EQUAL }, - { this: new Version(1, 0, 0), other: new Version(1, 0, 0), compare: 0, type: VersionType.EQUAL }, - { this: new Version(1, 0), other: new Version(1, 0, 0), compare: 0, type: VersionType.EQUAL }, - { this: new Version(1, 0), other: new Version(1, 0, 1), compare: -1, type: VersionType.PATCH }, - { this: new Version(1, 1), other: new Version(1, 0, 1), compare: 1, type: VersionType.MINOR }, - { this: new Version(1), other: new Version(1, 0, 0), compare: 0, type: VersionType.EQUAL }, - { this: new Version(1), other: new Version(1, 0, 1), compare: -1, type: VersionType.PATCH }, - ]; - - describe('isOlderThan', () => { - for (const { this: thisVersion, other: otherVersion, compare, type } of tests) { - const expected = compare < 0 ? type : VersionType.EQUAL; - it(`should return '${expected}' when comparing ${thisVersion} to ${otherVersion}`, () => { - expect(thisVersion.isOlderThan(otherVersion)).toEqual(expected); - }); - } - }); - - describe('isEqual', () => { - for (const { this: thisVersion, other: otherVersion, compare } of tests) { - const bool = compare === 0; - it(`should return ${bool} when comparing ${thisVersion} to ${otherVersion}`, () => { - expect(thisVersion.isEqual(otherVersion)).toEqual(bool); - }); - } - }); - - describe('isNewerThan', () => { - for (const { this: thisVersion, other: otherVersion, compare, type } of tests) { - const expected = compare > 0 ? type : VersionType.EQUAL; - it(`should return ${expected} when comparing ${thisVersion} to ${otherVersion}`, () => { - expect(thisVersion.isNewerThan(otherVersion)).toEqual(expected); - }); - } - }); - - describe('fromString', () => { - const tests = [ - { scenario: 'leading v', value: 'v1.72.2', expected: new Version(1, 72, 2) }, - { scenario: 'uppercase v', value: 'V1.72.2', expected: new Version(1, 72, 2) }, - { scenario: 'missing v', value: '1.72.2', expected: new Version(1, 72, 2) }, - { scenario: 'large patch', value: '1.72.123', expected: new Version(1, 72, 123) }, - { scenario: 'large minor', value: '1.123.0', expected: new Version(1, 123, 0) }, - { scenario: 'large major', value: '123.0.0', expected: new Version(123, 0, 0) }, - { scenario: 'major bump', value: 'v2.0.0', expected: new Version(2, 0, 0) }, - { scenario: 'has dash', value: '14.10-1', expected: new Version(14, 10, 1) }, - { scenario: 'missing patch', value: '14.10', expected: new Version(14, 10, 0) }, - { scenario: 'only major', value: '14', expected: new Version(14, 0, 0) }, - ]; - - for (const { scenario, value, expected } of tests) { - it(`should correctly parse ${scenario}`, () => { - const actual = Version.fromString(value); - expect(actual.major).toEqual(expected.major); - expect(actual.minor).toEqual(expected.minor); - expect(actual.patch).toEqual(expected.patch); - }); - } - }); -}); diff --git a/server/src/utils/version.ts b/server/src/utils/version.ts deleted file mode 100644 index e53f64f9d9..0000000000 --- a/server/src/utils/version.ts +++ /dev/null @@ -1,72 +0,0 @@ -export type IVersion = { major: number; minor: number; patch: number }; - -export enum VersionType { - EQUAL = 0, - PATCH = 1, - MINOR = 2, - MAJOR = 3, -} - -export class Version implements IVersion { - public readonly types = ['major', 'minor', 'patch'] as const; - - constructor( - public major: number, - public minor: number = 0, - public patch: number = 0, - ) {} - - toString() { - return `${this.major}.${this.minor}.${this.patch}`; - } - - toJSON() { - const { major, minor, patch } = this; - return { major, minor, patch }; - } - - static fromString(version: string): Version { - const regex = /v?(?\d+)(?:\.(?\d+))?(?:[.-](?\d+))?/i; - const matchResult = version.match(regex); - if (matchResult) { - const { major, minor = '0', patch = '0' } = matchResult.groups as { [K in keyof IVersion]: string }; - return new Version(Number(major), Number(minor), Number(patch)); - } else { - throw new Error(`Invalid version format: ${version}`); - } - } - - private compare(version: Version): [number, VersionType] { - for (const [i, key] of this.types.entries()) { - const diff = this[key] - version[key]; - if (diff !== 0) { - return [diff > 0 ? 1 : -1, (VersionType.MAJOR - i) as VersionType]; - } - } - - return [0, VersionType.EQUAL]; - } - - isOlderThan(version: Version): VersionType { - const [bool, type] = this.compare(version); - return bool < 0 ? type : VersionType.EQUAL; - } - - isEqual(version: Version): boolean { - const [bool] = this.compare(version); - return bool === 0; - } - - isNewerThan(version: Version): VersionType { - const [bool, type] = this.compare(version); - return bool > 0 ? type : VersionType.EQUAL; - } - - compareTo(other: Version) { - if (this.isEqual(other)) { - return 0; - } - - return this.isNewerThan(other) ? 1 : -1; - } -} diff --git a/server/src/utils/workers.spec.ts b/server/src/utils/workers.spec.ts new file mode 100644 index 0000000000..1e4ff5e2d3 --- /dev/null +++ b/server/src/utils/workers.spec.ts @@ -0,0 +1,49 @@ +import { getWorkers } from 'src/utils/workers'; + +describe('getWorkers', () => { + beforeEach(() => { + process.env.IMMICH_WORKERS_INCLUDE = ''; + process.env.IMMICH_WORKERS_EXCLUDE = ''; + }); + + it('should return default workers', () => { + expect(getWorkers()).toEqual(['api', 'microservices']); + }); + + it('should return included workers', () => { + process.env.IMMICH_WORKERS_INCLUDE = 'api'; + expect(getWorkers()).toEqual(['api']); + }); + + it('should excluded workers from defaults', () => { + process.env.IMMICH_WORKERS_EXCLUDE = 'api'; + expect(getWorkers()).toEqual(['microservices']); + }); + + it('should exclude workers from include list', () => { + process.env.IMMICH_WORKERS_INCLUDE = 'api,microservices,randomservice'; + process.env.IMMICH_WORKERS_EXCLUDE = 'randomservice,microservices'; + expect(getWorkers()).toEqual(['api']); + }); + + it('should remove whitespace from included workers before parsing', () => { + process.env.IMMICH_WORKERS_INCLUDE = 'api, microservices'; + expect(getWorkers()).toEqual(['api', 'microservices']); + }); + + it('should remove whitespace from excluded workers before parsing', () => { + process.env.IMMICH_WORKERS_EXCLUDE = 'api, microservices'; + expect(getWorkers()).toEqual([]); + }); + + it('should remove whitespace from included and excluded workers before parsing', () => { + process.env.IMMICH_WORKERS_INCLUDE = 'api, microservices, randomservice,randomservice2'; + process.env.IMMICH_WORKERS_EXCLUDE = 'randomservice,microservices, randomservice2'; + expect(getWorkers()).toEqual(['api']); + }); + + it('should throw error for invalid workers', () => { + process.env.IMMICH_WORKERS_INCLUDE = 'api,microservices,randomservice'; + expect(getWorkers).toThrowError('Invalid worker(s) found: api,microservices,randomservice'); + }); +}); diff --git a/server/src/utils/workers.ts b/server/src/utils/workers.ts new file mode 100644 index 0000000000..14daa2620f --- /dev/null +++ b/server/src/utils/workers.ts @@ -0,0 +1,21 @@ +const WORKER_TYPES = new Set(['api', 'microservices']); + +export const getWorkers = () => { + let workers = ['api', 'microservices']; + const includedWorkers = process.env.IMMICH_WORKERS_INCLUDE?.replaceAll(/\s/g, ''); + const excludedWorkers = process.env.IMMICH_WORKERS_EXCLUDE?.replaceAll(/\s/g, ''); + + if (includedWorkers) { + workers = includedWorkers.split(','); + } + + if (excludedWorkers) { + workers = workers.filter((worker) => !excludedWorkers.split(',').includes(worker)); + } + + if (workers.some((worker) => !WORKER_TYPES.has(worker))) { + throw new Error(`Invalid worker(s) found: ${workers}`); + } + + return workers; +}; diff --git a/server/src/workers/api.ts b/server/src/workers/api.ts new file mode 100644 index 0000000000..96f06ffc9c --- /dev/null +++ b/server/src/workers/api.ts @@ -0,0 +1,68 @@ +import { NestFactory } from '@nestjs/core'; +import { NestExpressApplication } from '@nestjs/platform-express'; +import { json } from 'body-parser'; +import cookieParser from 'cookie-parser'; +import { existsSync } from 'node:fs'; +import { isMainThread } from 'node:worker_threads'; +import sirv from 'sirv'; +import { ApiModule } from 'src/app.module'; +import { envName, excludePaths, isDev, serverVersion, WEB_ROOT } from 'src/constants'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { WebSocketAdapter } from 'src/middleware/websocket.adapter'; +import { ApiService } from 'src/services/api.service'; +import { otelSDK } from 'src/utils/instrumentation'; +import { useSwagger } from 'src/utils/misc'; + +const host = process.env.HOST; + +async function bootstrap() { + otelSDK.start(); + + const port = Number(process.env.IMMICH_PORT) || 3001; + const app = await NestFactory.create(ApiModule, { bufferLogs: true }); + const logger = await app.resolve(ILoggerRepository); + + logger.setAppName('ImmichServer'); + logger.setContext('ImmichServer'); + app.useLogger(logger); + app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); + app.set('etag', 'strong'); + app.use(cookieParser()); + app.use(json({ limit: '10mb' })); + if (isDev()) { + app.enableCors(); + } + app.useWebSocketAdapter(new WebSocketAdapter(app)); + useSwagger(app); + + app.setGlobalPrefix('api', { exclude: excludePaths }); + if (existsSync(WEB_ROOT)) { + // copied from https://github.com/sveltejs/kit/blob/679b5989fe62e3964b9a73b712d7b41831aa1f07/packages/adapter-node/src/handler.js#L46 + // provides serving of precompressed assets and caching of immutable assets + app.use( + sirv(WEB_ROOT, { + etag: true, + gzip: true, + brotli: true, + setHeaders: (res, pathname) => { + if (pathname.startsWith(`/_app/immutable`) && res.statusCode === 200) { + res.setHeader('cache-control', 'public,max-age=31536000,immutable'); + } + }, + }), + ); + } + app.use(app.get(ApiService).ssr(excludePaths)); + + const server = await (host ? app.listen(port, host) : app.listen(port)); + server.requestTimeout = 30 * 60 * 1000; + + logger.log(`Immich Server is listening on ${await app.getUrl()} [v${serverVersion}] [${envName}] `); +} + +if (!isMainThread) { + bootstrap().catch((error) => { + console.error(error); + process.exit(1); + }); +} diff --git a/server/src/workers/microservices.ts b/server/src/workers/microservices.ts new file mode 100644 index 0000000000..de198d2e27 --- /dev/null +++ b/server/src/workers/microservices.ts @@ -0,0 +1,29 @@ +import { NestFactory } from '@nestjs/core'; +import { isMainThread } from 'node:worker_threads'; +import { MicroservicesModule } from 'src/app.module'; +import { envName, serverVersion } from 'src/constants'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; +import { WebSocketAdapter } from 'src/middleware/websocket.adapter'; +import { otelSDK } from 'src/utils/instrumentation'; + +export async function bootstrap() { + otelSDK.start(); + + const app = await NestFactory.create(MicroservicesModule, { bufferLogs: true }); + const logger = await app.resolve(ILoggerRepository); + logger.setAppName('ImmichMicroservices'); + logger.setContext('ImmichMicroservices'); + app.useLogger(logger); + app.useWebSocketAdapter(new WebSocketAdapter(app)); + + await app.listen(0); + + logger.log(`Immich Microservices is running [v${serverVersion}] [${envName}] `); +} + +if (!isMainThread) { + bootstrap().catch((error) => { + console.error(error); + process.exit(1); + }); +} diff --git a/server/start-microservices.sh b/server/start-microservices.sh deleted file mode 100755 index c9e2cb42fb..0000000000 --- a/server/start-microservices.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -./start.sh microservices diff --git a/server/start-server.sh b/server/start-server.sh deleted file mode 100755 index 7ef959f63c..0000000000 --- a/server/start-server.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -./start.sh immich diff --git a/server/test/fixtures/asset.stub.ts b/server/test/fixtures/asset.stub.ts index e5d30f72fa..56aeed9d81 100644 --- a/server/test/fixtures/asset.stub.ts +++ b/server/test/fixtures/asset.stub.ts @@ -48,8 +48,7 @@ export const assetStub = { deletedAt: null, isOffline: false, isExternal: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, + duplicateId: null, }), noWebpPath: Object.freeze({ @@ -83,12 +82,11 @@ export const assetStub = { sidecarPath: null, isOffline: false, isExternal: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, exifInfo: { fileSizeInByte: 123_000, } as ExifEntity, deletedAt: null, + duplicateId: null, }), noThumbhash: Object.freeze({ @@ -112,8 +110,6 @@ export const assetStub = { isFavorite: true, isArchived: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, isExternal: false, @@ -125,6 +121,7 @@ export const assetStub = { faces: [], sidecarPath: null, deletedAt: null, + duplicateId: null, }), primaryImage: Object.freeze({ @@ -153,8 +150,6 @@ export const assetStub = { livePhotoVideo: null, livePhotoVideoId: null, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, tags: [], sharedLinks: [], originalFileName: 'asset-id.jpg', @@ -171,6 +166,7 @@ export const assetStub = { { id: 'stack-child-asset-1' } as AssetEntity, { id: 'stack-child-asset-2' } as AssetEntity, ]), + duplicateId: null, }), image: Object.freeze({ @@ -199,8 +195,6 @@ export const assetStub = { livePhotoVideo: null, livePhotoVideoId: null, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, tags: [], sharedLinks: [], originalFileName: 'asset-id.jpg', @@ -212,6 +206,7 @@ export const assetStub = { exifImageHeight: 3840, exifImageWidth: 2160, } as ExifEntity, + duplicateId: null, }), external: Object.freeze({ @@ -251,6 +246,7 @@ export const assetStub = { exifInfo: { fileSizeInByte: 5000, } as ExifEntity, + duplicateId: null, }), offline: Object.freeze({ @@ -279,8 +275,6 @@ export const assetStub = { livePhotoVideo: null, livePhotoVideoId: null, isOffline: true, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, tags: [], sharedLinks: [], originalFileName: 'asset-id.jpg', @@ -290,6 +284,7 @@ export const assetStub = { fileSizeInByte: 5000, } as ExifEntity, deletedAt: null, + duplicateId: null, }), externalOffline: Object.freeze({ @@ -329,6 +324,7 @@ export const assetStub = { fileSizeInByte: 5000, } as ExifEntity, deletedAt: null, + duplicateId: null, }), image1: Object.freeze({ @@ -356,8 +352,6 @@ export const assetStub = { isVisible: true, livePhotoVideo: null, livePhotoVideoId: null, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, isExternal: false, isOffline: false, tags: [], @@ -368,6 +362,7 @@ export const assetStub = { exifInfo: { fileSizeInByte: 5000, } as ExifEntity, + duplicateId: null, }), imageFrom2015: Object.freeze({ @@ -392,8 +387,6 @@ export const assetStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, livePhotoVideo: null, @@ -407,6 +400,7 @@ export const assetStub = { fileSizeInByte: 5000, } as ExifEntity, deletedAt: null, + duplicateId: null, }), video: Object.freeze({ @@ -432,8 +426,6 @@ export const assetStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, livePhotoVideo: null, @@ -446,6 +438,7 @@ export const assetStub = { fileSizeInByte: 100_000, } as ExifEntity, deletedAt: null, + duplicateId: null, }), livePhotoMotionAsset: Object.freeze({ @@ -456,8 +449,6 @@ export const assetStub = { isVisible: false, fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'), fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'), - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, exifInfo: { fileSizeInByte: 100_000, timeZone: `America/New_York`, @@ -472,8 +463,6 @@ export const assetStub = { isVisible: false, fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'), fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'), - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, previewPath: '/uploads/user-id/thumbs/path.ext', thumbnailPath: '/uploads/user-id/webp/path.ext', exifInfo: { @@ -491,8 +480,22 @@ export const assetStub = { isVisible: true, fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'), fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'), - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, + exifInfo: { + fileSizeInByte: 25_000, + timeZone: `America/New_York`, + }, + } as AssetEntity), + + livePhotoWithOriginalFileName: Object.freeze({ + id: 'live-photo-still-asset', + originalPath: fileStub.livePhotoStill.originalPath, + originalFileName: fileStub.livePhotoStill.originalName, + ownerId: authStub.user1.user.id, + type: AssetType.IMAGE, + livePhotoVideoId: 'live-photo-motion-asset123', + isVisible: true, + fileModifiedAt: new Date('2022-06-19T23:41:36.910Z'), + fileCreatedAt: new Date('2022-06-19T23:41:36.910Z'), exifInfo: { fileSizeInByte: 25_000, timeZone: `America/New_York`, @@ -522,8 +525,6 @@ export const assetStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, livePhotoVideo: null, @@ -541,6 +542,7 @@ export const assetStub = { country: 'test-country', } as ExifEntity, deletedAt: null, + duplicateId: null, }), sidecar: Object.freeze({ id: 'asset-id', @@ -564,8 +566,6 @@ export const assetStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, livePhotoVideo: null, @@ -576,6 +576,7 @@ export const assetStub = { faces: [], sidecarPath: '/original/path.ext.xmp', deletedAt: null, + duplicateId: null, }), sidecarWithoutExt: Object.freeze({ id: 'asset-id', @@ -599,8 +600,6 @@ export const assetStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, livePhotoVideo: null, @@ -611,6 +610,7 @@ export const assetStub = { faces: [], sidecarPath: '/original/path.xmp', deletedAt: null, + duplicateId: null, }), readOnly: Object.freeze({ @@ -635,8 +635,6 @@ export const assetStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, livePhotoVideo: null, @@ -647,6 +645,7 @@ export const assetStub = { faces: [], sidecarPath: '/original/path.ext.xmp', deletedAt: null, + duplicateId: null, }), hasEncodedVideo: Object.freeze({ @@ -672,8 +671,6 @@ export const assetStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, duration: null, isVisible: true, livePhotoVideo: null, @@ -686,6 +683,7 @@ export const assetStub = { fileSizeInByte: 100_000, } as ExifEntity, deletedAt: null, + duplicateId: null, }), missingFileExtension: Object.freeze({ id: 'asset-id', @@ -724,6 +722,7 @@ export const assetStub = { exifInfo: { fileSizeInByte: 5000, } as ExifEntity, + duplicateId: null, }), hasFileExtension: Object.freeze({ id: 'asset-id', @@ -762,6 +761,7 @@ export const assetStub = { exifInfo: { fileSizeInByte: 5000, } as ExifEntity, + duplicateId: null, }), imageDng: Object.freeze({ id: 'asset-id', @@ -789,8 +789,6 @@ export const assetStub = { livePhotoVideo: null, livePhotoVideoId: null, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, tags: [], sharedLinks: [], originalFileName: 'asset-id.jpg', @@ -802,5 +800,88 @@ export const assetStub = { profileDescription: 'Adobe RGB', bitsPerSample: 14, } as ExifEntity, + duplicateId: null, + }), + hasEmbedding: Object.freeze({ + id: 'asset-id-embedding', + deviceAssetId: 'device-asset-id', + fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'), + fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'), + owner: userStub.user1, + ownerId: 'user-id', + deviceId: 'device-id', + originalPath: '/original/path.jpg', + previewPath: '/uploads/user-id/thumbs/path.jpg', + checksum: Buffer.from('file hash', 'utf8'), + type: AssetType.IMAGE, + thumbnailPath: '/uploads/user-id/webp/path.ext', + thumbhash: Buffer.from('blablabla', 'base64'), + encodedVideoPath: null, + createdAt: new Date('2023-02-23T05:06:29.716Z'), + updatedAt: new Date('2023-02-23T05:06:29.716Z'), + localDateTime: new Date('2023-02-23T05:06:29.716Z'), + isFavorite: true, + isArchived: false, + duration: null, + isVisible: true, + isExternal: false, + livePhotoVideo: null, + livePhotoVideoId: null, + isOffline: false, + tags: [], + sharedLinks: [], + originalFileName: 'asset-id.jpg', + faces: [], + deletedAt: null, + sidecarPath: null, + exifInfo: { + fileSizeInByte: 5000, + } as ExifEntity, + duplicateId: null, + smartSearch: { + assetId: 'asset-id', + embedding: Array.from({ length: 512 }, Math.random), + }, + }), + hasDupe: Object.freeze({ + id: 'asset-id-dupe', + deviceAssetId: 'device-asset-id', + fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'), + fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'), + owner: userStub.user1, + ownerId: 'user-id', + deviceId: 'device-id', + originalPath: '/original/path.jpg', + previewPath: '/uploads/user-id/thumbs/path.jpg', + checksum: Buffer.from('file hash', 'utf8'), + type: AssetType.IMAGE, + thumbnailPath: '/uploads/user-id/webp/path.ext', + thumbhash: Buffer.from('blablabla', 'base64'), + encodedVideoPath: null, + createdAt: new Date('2023-02-23T05:06:29.716Z'), + updatedAt: new Date('2023-02-23T05:06:29.716Z'), + localDateTime: new Date('2023-02-23T05:06:29.716Z'), + isFavorite: true, + isArchived: false, + duration: null, + isVisible: true, + isExternal: false, + livePhotoVideo: null, + livePhotoVideoId: null, + isOffline: false, + tags: [], + sharedLinks: [], + originalFileName: 'asset-id.jpg', + faces: [], + deletedAt: null, + sidecarPath: null, + exifInfo: { + fileSizeInByte: 5000, + } as ExifEntity, + duplicateId: 'duplicate-id', + smartSearch: { + assetId: 'asset-id', + embedding: Array.from({ length: 512 }, Math.random), + }, }), }; diff --git a/server/test/fixtures/auth.stub.ts b/server/test/fixtures/auth.stub.ts index 96a0bc0141..e260ee4e8f 100644 --- a/server/test/fixtures/auth.stub.ts +++ b/server/test/fixtures/auth.stub.ts @@ -3,24 +3,6 @@ import { SessionEntity } from 'src/entities/session.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity'; import { UserEntity } from 'src/entities/user.entity'; -export const adminSignupStub = { - name: 'Immich Admin', - email: 'admin@immich.app', - password: 'Password123', -}; - -export const userSignupStub = { - ...adminSignupStub, - memoriesEnabled: true, -}; - -export const loginStub = { - admin: { - email: 'admin@immich.app', - password: 'Password123', - }, -}; - export const authStub = { admin: Object.freeze({ user: { diff --git a/server/test/fixtures/error.stub.ts b/server/test/fixtures/error.stub.ts deleted file mode 100644 index cea514e26e..0000000000 --- a/server/test/fixtures/error.stub.ts +++ /dev/null @@ -1,57 +0,0 @@ -export const errorStub = { - unauthorized: { - error: 'Unauthorized', - statusCode: 401, - message: 'Authentication required', - }, - forbidden: { - error: 'Forbidden', - statusCode: 403, - message: expect.any(String), - }, - wrongPassword: { - error: 'Bad Request', - statusCode: 400, - message: 'Wrong password', - }, - invalidToken: { - error: 'Unauthorized', - statusCode: 401, - message: 'Invalid user token', - }, - invalidShareKey: { - error: 'Unauthorized', - statusCode: 401, - message: 'Invalid share key', - }, - invalidSharePassword: { - error: 'Unauthorized', - statusCode: 401, - message: 'Invalid password', - }, - badRequest: (message: any = null) => ({ - error: 'Bad Request', - statusCode: 400, - message: message ?? expect.anything(), - }), - noPermission: { - error: 'Bad Request', - statusCode: 400, - message: expect.stringContaining('Not found or no'), - }, - incorrectLogin: { - error: 'Unauthorized', - statusCode: 401, - message: 'Incorrect email or password', - }, - alreadyHasAdmin: { - error: 'Bad Request', - statusCode: 400, - message: 'The server already has an admin', - }, - noDeleteUploadLibrary: { - error: 'Bad Request', - statusCode: 400, - message: 'Cannot delete the last upload library', - }, -}; diff --git a/server/test/fixtures/file.stub.ts b/server/test/fixtures/file.stub.ts index c2c40633d9..f63d2d10fb 100644 --- a/server/test/fixtures/file.stub.ts +++ b/server/test/fixtures/file.stub.ts @@ -13,4 +13,19 @@ export const fileStub = { originalName: 'asset_1.mp4', size: 69, }), + photo: Object.freeze({ + uuid: 'photo', + originalPath: 'fake_path/photo1.jpeg', + mimeType: 'image/jpeg', + checksum: Buffer.from('photo file hash', 'utf8'), + originalName: 'photo1.jpeg', + size: 24, + }), + photoSidecar: Object.freeze({ + uuid: 'photo-sidecar', + originalPath: 'fake_path/photo1.jpeg.xmp', + originalName: 'photo1.jpeg.xmp', + checksum: Buffer.from('photo-sidecar file hash', 'utf8'), + size: 96, + }), }; diff --git a/server/test/fixtures/library.stub.ts b/server/test/fixtures/library.stub.ts index dde250a7a1..1a83ffe5d7 100644 --- a/server/test/fixtures/library.stub.ts +++ b/server/test/fixtures/library.stub.ts @@ -1,36 +1,20 @@ import { join } from 'node:path'; import { APP_MEDIA_LOCATION } from 'src/constants'; import { THUMBNAIL_DIR } from 'src/cores/storage.core'; -import { LibraryEntity, LibraryType } from 'src/entities/library.entity'; +import { LibraryEntity } from 'src/entities/library.entity'; import { userStub } from 'test/fixtures/user.stub'; export const libraryStub = { - uploadLibrary1: Object.freeze({ - id: 'library-id', - name: 'test_library', - assets: [], - owner: userStub.user1, - ownerId: 'user-id', - type: LibraryType.UPLOAD, - importPaths: [], - createdAt: new Date('2022-01-01'), - updatedAt: new Date('2022-01-01'), - refreshedAt: null, - isVisible: true, - exclusionPatterns: [], - }), externalLibrary1: Object.freeze({ id: 'library-id', name: 'test_library', assets: [], owner: userStub.admin, ownerId: 'admin_id', - type: LibraryType.EXTERNAL, importPaths: [], createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), refreshedAt: null, - isVisible: true, exclusionPatterns: [], }), externalLibrary2: Object.freeze({ @@ -39,12 +23,10 @@ export const libraryStub = { assets: [], owner: userStub.admin, ownerId: 'admin_id', - type: LibraryType.EXTERNAL, importPaths: [], createdAt: new Date('2021-01-01'), updatedAt: new Date('2022-01-01'), refreshedAt: null, - isVisible: true, exclusionPatterns: [], }), externalLibraryWithImportPaths1: Object.freeze({ @@ -53,12 +35,10 @@ export const libraryStub = { assets: [], owner: userStub.admin, ownerId: 'admin_id', - type: LibraryType.EXTERNAL, importPaths: ['/foo', '/bar'], createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), refreshedAt: null, - isVisible: true, exclusionPatterns: [], }), externalLibraryWithImportPaths2: Object.freeze({ @@ -67,12 +47,10 @@ export const libraryStub = { assets: [], owner: userStub.admin, ownerId: 'admin_id', - type: LibraryType.EXTERNAL, importPaths: ['/xyz', '/asdf'], createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), refreshedAt: null, - isVisible: true, exclusionPatterns: [], }), externalLibraryWithExclusionPattern: Object.freeze({ @@ -81,12 +59,10 @@ export const libraryStub = { assets: [], owner: userStub.admin, ownerId: 'user-id', - type: LibraryType.EXTERNAL, importPaths: [], createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), refreshedAt: null, - isVisible: true, exclusionPatterns: ['**/dir1/**'], }), patternPath: Object.freeze({ @@ -95,12 +71,10 @@ export const libraryStub = { assets: [], owner: userStub.admin, ownerId: 'user-id', - type: LibraryType.EXTERNAL, importPaths: ['/xyz', '/asdf'], createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), refreshedAt: null, - isVisible: true, exclusionPatterns: ['**/dir1/**'], }), hasImmichPaths: Object.freeze({ @@ -109,12 +83,10 @@ export const libraryStub = { assets: [], owner: userStub.admin, ownerId: 'user-id', - type: LibraryType.EXTERNAL, importPaths: [join(THUMBNAIL_DIR, 'library'), '/xyz', join(APP_MEDIA_LOCATION, 'library')], createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), refreshedAt: null, - isVisible: true, exclusionPatterns: ['**/dir1/**'], }), }; diff --git a/server/test/fixtures/shared-link.stub.ts b/server/test/fixtures/shared-link.stub.ts index cb16f07e11..3f54f2ebcd 100644 --- a/server/test/fixtures/shared-link.stub.ts +++ b/server/test/fixtures/shared-link.stub.ts @@ -9,7 +9,6 @@ import { SharedLinkEntity, SharedLinkType } from 'src/entities/shared-link.entit import { UserEntity } from 'src/entities/user.entity'; import { assetStub } from 'test/fixtures/asset.stub'; import { authStub } from 'test/fixtures/auth.stub'; -import { libraryStub } from 'test/fixtures/library.stub'; import { userStub } from 'test/fixtures/user.stub'; const today = new Date(); @@ -58,7 +57,6 @@ const assetResponse: AssetResponseDto = { resized: false, thumbhash: null, fileModifiedAt: today, - isExternal: false, isOffline: false, fileCreatedAt: today, localDateTime: today, @@ -101,7 +99,6 @@ const albumResponse: AlbumResponseDto = { id: 'album-123', ownerId: 'admin_id', owner: mapUser(userStub.admin), - sharedUsers: [], albumUsers: [], shared: false, hasSharedLink: false, @@ -210,8 +207,6 @@ export const sharedLinkStub = { isArchived: false, isExternal: false, isOffline: false, - libraryId: 'library-id', - library: libraryStub.uploadLibrary1, smartInfo: { assetId: 'id_1', tags: [], @@ -252,7 +247,6 @@ export const sharedLinkStub = { exposureTime: '1/16', fps: 100, asset: null as any, - exifTextSearchableColumn: '', profileDescription: 'sRGB', bitsPerSample: 8, colorspace: 'sRGB', @@ -263,6 +257,7 @@ export const sharedLinkStub = { faces: [], sidecarPath: null, deletedAt: null, + duplicateId: null, }, ], }, diff --git a/server/test/fixtures/system-config.stub.ts b/server/test/fixtures/system-config.stub.ts index b557644efa..be21fc4060 100644 --- a/server/test/fixtures/system-config.stub.ts +++ b/server/test/fixtures/system-config.stub.ts @@ -1,33 +1,82 @@ -import { SystemConfigEntity, SystemConfigKey } from 'src/entities/system-config.entity'; +import { SystemConfig } from 'src/config'; +import { DeepPartial } from 'typeorm'; -export const systemConfigStub: Record = { - defaults: [], - enabled: [ - { key: SystemConfigKey.OAUTH_ENABLED, value: true }, - { key: SystemConfigKey.OAUTH_AUTO_REGISTER, value: true }, - { key: SystemConfigKey.OAUTH_AUTO_LAUNCH, value: false }, - { key: SystemConfigKey.OAUTH_BUTTON_TEXT, value: 'OAuth' }, - ], - disabled: [{ key: SystemConfigKey.PASSWORD_LOGIN_ENABLED, value: false }], - noAutoRegister: [ - { key: SystemConfigKey.OAUTH_ENABLED, value: true }, - { key: SystemConfigKey.OAUTH_AUTO_LAUNCH, value: false }, - { key: SystemConfigKey.OAUTH_AUTO_REGISTER, value: false }, - { key: SystemConfigKey.OAUTH_BUTTON_TEXT, value: 'OAuth' }, - ], - override: [ - { key: SystemConfigKey.OAUTH_ENABLED, value: true }, - { key: SystemConfigKey.OAUTH_AUTO_REGISTER, value: true }, - { key: SystemConfigKey.OAUTH_MOBILE_OVERRIDE_ENABLED, value: true }, - { key: SystemConfigKey.OAUTH_MOBILE_REDIRECT_URI, value: 'http://mobile-redirect' }, - { key: SystemConfigKey.OAUTH_BUTTON_TEXT, value: 'OAuth' }, - ], - withDefaultStorageQuota: [ - { key: SystemConfigKey.OAUTH_ENABLED, value: true }, - { key: SystemConfigKey.OAUTH_AUTO_REGISTER, value: true }, - { key: SystemConfigKey.OAUTH_DEFAULT_STORAGE_QUOTA, value: 1 }, - ], - deleteDelay30: [{ key: SystemConfigKey.USER_DELETE_DELAY, value: 30 }], - libraryWatchEnabled: [{ key: SystemConfigKey.LIBRARY_WATCH_ENABLED, value: true }], - libraryWatchDisabled: [{ key: SystemConfigKey.LIBRARY_WATCH_ENABLED, value: false }], -}; +export const systemConfigStub = { + enabled: { + oauth: { + enabled: true, + autoRegister: true, + autoLaunch: false, + buttonText: 'OAuth', + }, + }, + disabled: { + passwordLogin: { + enabled: false, + }, + }, + oauthEnabled: { + oauth: { + enabled: true, + autoRegister: false, + autoLaunch: false, + buttonText: 'OAuth', + }, + }, + oauthWithAutoRegister: { + oauth: { + enabled: true, + autoRegister: true, + autoLaunch: false, + buttonText: 'OAuth', + }, + }, + oauthWithMobileOverride: { + oauth: { + enabled: true, + autoRegister: true, + mobileOverrideEnabled: true, + mobileRedirectUri: 'http://mobile-redirect', + buttonText: 'OAuth', + }, + }, + oauthWithStorageQuota: { + oauth: { + enabled: true, + autoRegister: true, + defaultStorageQuota: 1, + }, + }, + deleteDelay30: { + user: { + deleteDelay: 30, + }, + }, + libraryWatchEnabled: { + library: { + watch: { + enabled: true, + }, + }, + }, + libraryWatchDisabled: { + library: { + watch: { + enabled: false, + }, + }, + }, + libraryScan: { + library: { + scan: { + enabled: true, + cronExpression: '0 0 * * *', + }, + }, + }, + machineLearningDisabled: { + machineLearning: { + enabled: false, + }, + }, +} satisfies Record>; diff --git a/server/test/fixtures/user.stub.ts b/server/test/fixtures/user.stub.ts index 5cf5acfc3b..cb82dfe26c 100644 --- a/server/test/fixtures/user.stub.ts +++ b/server/test/fixtures/user.stub.ts @@ -1,4 +1,5 @@ -import { UserAvatarColor, UserEntity } from 'src/entities/user.entity'; +import { UserAvatarColor, UserMetadataKey } from 'src/entities/user-metadata.entity'; +import { UserEntity } from 'src/entities/user.entity'; import { authStub } from 'test/fixtures/auth.stub'; export const userDto = { @@ -39,8 +40,7 @@ export const userStub = { updatedAt: new Date('2021-01-01'), tags: [], assets: [], - memoriesEnabled: true, - avatarColor: UserAvatarColor.PRIMARY, + metadata: [], quotaSizeInBytes: null, quotaUsageInBytes: 0, }), @@ -57,8 +57,14 @@ export const userStub = { updatedAt: new Date('2021-01-01'), tags: [], assets: [], - memoriesEnabled: true, - avatarColor: UserAvatarColor.PRIMARY, + metadata: [ + { + user: authStub.user1.user, + userId: authStub.user1.user.id, + key: UserMetadataKey.PREFERENCES, + value: { avatar: { color: UserAvatarColor.PRIMARY } }, + }, + ], quotaSizeInBytes: null, quotaUsageInBytes: 0, }), @@ -75,8 +81,6 @@ export const userStub = { updatedAt: new Date('2021-01-01'), tags: [], assets: [], - memoriesEnabled: true, - avatarColor: UserAvatarColor.PRIMARY, quotaSizeInBytes: null, quotaUsageInBytes: 0, }), @@ -93,8 +97,6 @@ export const userStub = { updatedAt: new Date('2021-01-01'), tags: [], assets: [], - memoriesEnabled: true, - avatarColor: UserAvatarColor.PRIMARY, quotaSizeInBytes: null, quotaUsageInBytes: 0, }), @@ -111,8 +113,6 @@ export const userStub = { updatedAt: new Date('2021-01-01'), tags: [], assets: [], - memoriesEnabled: true, - avatarColor: UserAvatarColor.PRIMARY, quotaSizeInBytes: null, quotaUsageInBytes: 0, }), @@ -129,8 +129,6 @@ export const userStub = { updatedAt: new Date('2021-01-01'), tags: [], assets: [], - memoriesEnabled: true, - avatarColor: UserAvatarColor.PRIMARY, quotaSizeInBytes: null, quotaUsageInBytes: 0, }), diff --git a/server/test/fixtures/uuid.stub.ts b/server/test/fixtures/uuid.stub.ts deleted file mode 100644 index b10ef80da7..0000000000 --- a/server/test/fixtures/uuid.stub.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const uuidStub = { - invalid: 'invalid-uuid', - // valid uuid v4 - notFound: '00000000-0000-4000-a000-000000000000', -}; diff --git a/server/test/repositories/access.repository.mock.ts b/server/test/repositories/access.repository.mock.ts index 21d298599f..8d69e35c05 100644 --- a/server/test/repositories/access.repository.mock.ts +++ b/server/test/repositories/access.repository.mock.ts @@ -7,7 +7,6 @@ export interface IAccessRepositoryMock { asset: Mocked; album: Mocked; authDevice: Mocked; - library: Mocked; timeline: Mocked; memory: Mocked; person: Mocked; @@ -43,10 +42,6 @@ export const newAccessRepositoryMock = (reset = true): IAccessRepositoryMock => checkOwnerAccess: vitest.fn().mockResolvedValue(new Set()), }, - library: { - checkOwnerAccess: vitest.fn().mockResolvedValue(new Set()), - }, - timeline: { checkPartnerAccess: vitest.fn().mockResolvedValue(new Set()), }, diff --git a/server/test/repositories/asset.repository.mock.ts b/server/test/repositories/asset.repository.mock.ts index e22fc1f011..abe56495db 100644 --- a/server/test/repositories/asset.repository.mock.ts +++ b/server/test/repositories/asset.repository.mock.ts @@ -10,10 +10,12 @@ export const newAssetRepositoryMock = (): Mocked => { getByIds: vitest.fn().mockResolvedValue([]), getByIdsWithAllRelations: vitest.fn().mockResolvedValue([]), getByAlbumId: vitest.fn(), + getByDeviceIds: vitest.fn(), getByUserId: vitest.fn(), getById: vitest.fn(), getWithout: vitest.fn(), getByChecksum: vitest.fn(), + getByChecksums: vitest.fn(), getUploadAssetIdByChecksum: vitest.fn(), getWith: vitest.fn(), getRandom: vitest.fn(), @@ -22,6 +24,7 @@ export const newAssetRepositoryMock = (): Mocked => { getAll: vitest.fn().mockResolvedValue({ items: [], hasNextPage: false }), getAllByDeviceId: vitest.fn(), updateAll: vitest.fn(), + updateDuplicates: vitest.fn(), getExternalLibraryAssetPaths: vitest.fn(), getByLibraryIdAndOriginalPath: vitest.fn(), deleteAll: vitest.fn(), @@ -38,5 +41,6 @@ export const newAssetRepositoryMock = (): Mocked => { getAssetIdByTag: vitest.fn(), getAllForUserFullSync: vitest.fn(), getChangedDeltaSync: vitest.fn(), + getDuplicates: vitest.fn(), }; }; diff --git a/server/test/repositories/database.repository.mock.ts b/server/test/repositories/database.repository.mock.ts index b4109a8375..aef2e50ae8 100644 --- a/server/test/repositories/database.repository.mock.ts +++ b/server/test/repositories/database.repository.mock.ts @@ -1,14 +1,12 @@ import { IDatabaseRepository } from 'src/interfaces/database.interface'; -import { Version } from 'src/utils/version'; import { Mocked, vitest } from 'vitest'; export const newDatabaseRepositoryMock = (): Mocked => { return { getExtensionVersion: vitest.fn(), getAvailableExtensionVersion: vitest.fn(), - getPreferredVectorExtension: vitest.fn(), - getPostgresVersion: vitest.fn().mockResolvedValue(new Version(14, 0, 0)), - createExtension: vitest.fn().mockImplementation(() => Promise.resolve()), + getPostgresVersion: vitest.fn().mockResolvedValue('14.10 (Debian 14.10-1.pgdg120+1)'), + createExtension: vitest.fn().mockResolvedValue(void 0), updateExtension: vitest.fn(), updateVectorExtension: vitest.fn(), reindex: vitest.fn(), diff --git a/server/test/repositories/library.repository.mock.ts b/server/test/repositories/library.repository.mock.ts index 4280619862..e5b8e5c763 100644 --- a/server/test/repositories/library.repository.mock.ts +++ b/server/test/repositories/library.repository.mock.ts @@ -4,14 +4,11 @@ import { Mocked, vitest } from 'vitest'; export const newLibraryRepositoryMock = (): Mocked => { return { get: vitest.fn(), - getCountForUser: vitest.fn(), create: vitest.fn(), delete: vitest.fn(), softDelete: vitest.fn(), update: vitest.fn(), getStatistics: vitest.fn(), - getDefaultUploadLibrary: vitest.fn(), - getUploadLibraryCount: vitest.fn(), getAssetIds: vitest.fn(), getAllDeleted: vitest.fn(), getAll: vitest.fn(), diff --git a/server/test/repositories/logger.repository.mock.ts b/server/test/repositories/logger.repository.mock.ts index a8537bb2fa..5f7262c7e5 100644 --- a/server/test/repositories/logger.repository.mock.ts +++ b/server/test/repositories/logger.repository.mock.ts @@ -5,6 +5,7 @@ export const newLoggerRepositoryMock = (): Mocked => { return { setLogLevel: vitest.fn(), setContext: vitest.fn(), + setAppName: vitest.fn(), verbose: vitest.fn(), debug: vitest.fn(), diff --git a/server/test/repositories/search.repository.mock.ts b/server/test/repositories/search.repository.mock.ts index d43b2b9ce9..7da93e02af 100644 --- a/server/test/repositories/search.repository.mock.ts +++ b/server/test/repositories/search.repository.mock.ts @@ -6,6 +6,7 @@ export const newSearchRepositoryMock = (): Mocked => { init: vitest.fn(), searchMetadata: vitest.fn(), searchSmart: vitest.fn(), + searchDuplicates: vitest.fn(), searchFaces: vitest.fn(), upsert: vitest.fn(), searchPlaces: vitest.fn(), diff --git a/server/test/repositories/system-config.repository.mock.ts b/server/test/repositories/system-config.repository.mock.ts deleted file mode 100644 index 41135b7d74..0000000000 --- a/server/test/repositories/system-config.repository.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { SystemConfigCore } from 'src/cores/system-config.core'; -import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { Mocked, vitest } from 'vitest'; - -export const newSystemConfigRepositoryMock = (reset = true): Mocked => { - if (reset) { - SystemConfigCore.reset(); - } - - return { - fetchStyle: vitest.fn(), - load: vitest.fn().mockResolvedValue([]), - readFile: vitest.fn(), - saveAll: vitest.fn().mockResolvedValue([]), - deleteKeys: vitest.fn(), - }; -}; diff --git a/server/test/repositories/system-metadata.repository.mock.ts b/server/test/repositories/system-metadata.repository.mock.ts index 1044076ea8..d0cf4fe2e5 100644 --- a/server/test/repositories/system-metadata.repository.mock.ts +++ b/server/test/repositories/system-metadata.repository.mock.ts @@ -1,9 +1,16 @@ +import { SystemConfigCore } from 'src/cores/system-config.core'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { Mocked, vitest } from 'vitest'; -export const newSystemMetadataRepositoryMock = (): Mocked => { +export const newSystemMetadataRepositoryMock = (reset = true): Mocked => { + if (reset) { + SystemConfigCore.reset(); + } + return { get: vitest.fn() as any, set: vitest.fn(), + readFile: vitest.fn(), + fetchStyle: vitest.fn(), }; }; diff --git a/server/test/repositories/user.repository.mock.ts b/server/test/repositories/user.repository.mock.ts index 5f2e2f083e..c3b9dc0f3d 100644 --- a/server/test/repositories/user.repository.mock.ts +++ b/server/test/repositories/user.repository.mock.ts @@ -22,5 +22,6 @@ export const newUserRepositoryMock = (reset = true): Mocked => hasAdmin: vitest.fn(), updateUsage: vitest.fn(), syncUsage: vitest.fn(), + upsertMetadata: vitest.fn(), }; }; diff --git a/web/.nvmrc b/web/.nvmrc index 95267e9aae..973f49d55c 100644 --- a/web/.nvmrc +++ b/web/.nvmrc @@ -1 +1 @@ -v20.12 +20.13 diff --git a/web/Dockerfile b/web/Dockerfile index f64ae2b726..f28a5f883d 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -1,4 +1,4 @@ -FROM node:iron-alpine3.18@sha256:fe31b16ddfb4ba4ae1a42ea540e9e44b916d754e67c64642b090839a9b2ed0ee +FROM node:iron-alpine3.18@sha256:53108f67824964a573ea435fed258f6cee4d88343e9859a99d356883e71b490c RUN apk add --no-cache tini USER node diff --git a/web/package-lock.json b/web/package-lock.json index 3257e723b5..4597fd79c7 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "immich-web", - "version": "1.103.1", + "version": "1.105.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immich-web", - "version": "1.103.1", + "version": "1.105.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@immich/sdk": "file:../open-api/typescript-sdk", @@ -36,6 +36,7 @@ "@sveltejs/vite-plugin-svelte": "^3.0.2", "@testing-library/jest-dom": "^6.4.2", "@testing-library/svelte": "^5.0.0", + "@testing-library/user-event": "^14.5.2", "@types/dom-to-image": "^2.6.7", "@types/justified-layout": "^4.1.4", "@types/lodash-es": "^4.17.12", @@ -47,7 +48,7 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.35.1", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "factory.ts": "^1.4.1", "postcss": "^8.4.35", "prettier": "^3.2.5", @@ -65,7 +66,7 @@ }, "../open-api/typescript-sdk": { "name": "@immich/sdk", - "version": "1.103.1", + "version": "1.105.1", "license": "GNU Affero General Public License version 3", "dependencies": { "@oazapfts/runtime": "^1.0.2" @@ -318,9 +319,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1843,11 +1844,12 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.7.tgz", - "integrity": "sha512-6uedTzrb7nQrw6HALxnPrPaXdIN2jJJTzTIl96Z3P5NiG+OAfpdPbrWrvkJ3GN4CfWqrmU4dJqwMMRMTD/C7ow==", + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.8.tgz", + "integrity": "sha512-ZQXYaVHd1p0kDGwOi4l82i5kAiUQtrhMthDKtJi0zVzmNupKJ0ZlBVAoceuarCuIntPNctyQchW29h5DkFxd1Q==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^0.6.0", @@ -2012,9 +2014,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz", - "integrity": "sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==", + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz", + "integrity": "sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==", "dev": true, "dependencies": { "@adobe/css-tools": "^4.3.2", @@ -2023,7 +2025,7 @@ "chalk": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.15", + "lodash": "^4.17.21", "redent": "^3.0.0" }, "engines": { @@ -2154,6 +2156,19 @@ } } }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@types/aria-query": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.2.tgz", @@ -2190,12 +2205,6 @@ "@types/geojson": "*" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, "node_modules/@types/justified-layout": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/justified-layout/-/justified-layout-4.1.4.tgz", @@ -2271,12 +2280,6 @@ "integrity": "sha512-I469DU0UXNC1aHepwirWhu9YKg5fkxohZD95Ey/5A7lovC+Siu+MCLffva87lnfThaOrw9Vb1DUN5t55oULAAw==", "dev": true }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/supercluster": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", @@ -2286,21 +2289,20 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", - "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.9.0.tgz", + "integrity": "sha512-6e+X0X3sFe/G/54aC3jt0txuMTURqLyekmEHViqyA2VnxhLMpvA6nqmcjIy+Cr9tLDHPssA74BP5Mx9HQIxBEA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/type-utils": "7.9.0", + "@typescript-eslint/utils": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -2320,49 +2322,17 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/parser": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", - "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.9.0.tgz", + "integrity": "sha512-qHMJfkL5qvgQB2aLvhUSXxbK7OLnDkwPzFalg458pxQgfxKDfT1ZDbHQM/I6mDIf/svlMkj21kzKuQ2ixJlatQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4" }, "engines": { @@ -2382,13 +2352,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.9.0.tgz", + "integrity": "sha512-ZwPK4DeCDxr3GJltRz5iZejPFAAr4Wk3+2WIBaj1L5PYK5RgxExu/Y68FFVclN0y6GGwH8q+KgKRCvaTmFBbgQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0" + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2399,13 +2370,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", - "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.9.0.tgz", + "integrity": "sha512-6Qy8dfut0PFrFRAZsGzuLoM4hre4gjzWJB6sUvdunCYZsYemTkzZNwF1rnGea326PHPT3zn5Lmg32M/xfJfByA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/typescript-estree": "7.9.0", + "@typescript-eslint/utils": "7.9.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2426,10 +2398,11 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.9.0.tgz", + "integrity": "sha512-oZQD9HEWQanl9UfsbGVcZ2cGaR0YT5476xfWE0oE5kQa2sNK2frxOlkeacLOTh9po4AlUT5rtkGyYM5kew0z5w==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -2439,13 +2412,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.9.0.tgz", + "integrity": "sha512-zBCMCkrb2YjpKV3LA0ZJubtKCDxLttxfdGmwZvTqqWevUPN0FZvSI26FalGFFUZU/9YQK/A4xcQF9o/VVaCKAg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/visitor-keys": "7.9.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2471,27 +2445,17 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2503,13 +2467,11 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2517,25 +2479,17 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.9.0.tgz", + "integrity": "sha512-5KVRQCzZajmT4Ep+NEgjXCvjuypVvYHUW7RHlXzNPuak2oWpVoD1jf5xCP0dPAuNIchjC7uQyvbdaSTFaLqSdA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.9.0", + "@typescript-eslint/types": "7.9.0", + "@typescript-eslint/typescript-estree": "7.9.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -2548,46 +2502,14 @@ "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.9.0.tgz", + "integrity": "sha512-iESPx2TNLDNGQLyjKhUvIKprlP49XNEK+MvIf9nIO7ZZaZdbnfWKHnXAgufpxqfA0YryH8XToi4+CjBgVnFTSQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/types": "7.9.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2605,9 +2527,9 @@ "dev": true }, "node_modules/@vitest/coverage-v8": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.5.3.tgz", - "integrity": "sha512-DPyGSu/fPHOJuPxzFSQoT4N/Fu/2aJfZRtEpEp8GI7NHsXBGE94CQ+pbEGBUMFjatsHPDJw/+TAF9r4ens2CNw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", + "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -2628,17 +2550,17 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.5.3" + "vitest": "1.6.0" } }, "node_modules/@vitest/expect": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.3.tgz", - "integrity": "sha512-y+waPz31pOFr3rD7vWTbwiLe5+MgsMm40jTZbQE8p8/qXyBX3CQsIXRx9XK12IbY7q/t5a5aM/ckt33b4PxK2g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -2646,12 +2568,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.3.tgz", - "integrity": "sha512-7PlfuReN8692IKQIdCxwir1AOaP5THfNkp0Uc4BKr2na+9lALNit7ub9l3/R7MP8aV61+mHKRGiqEKRIwu6iiQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.5.3", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -2687,9 +2609,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.3.tgz", - "integrity": "sha512-K3mvIsjyKYBhNIDujMD2gfQEzddLe51nNOAf45yKRt/QFJcUIeTQd2trRvv6M6oCBHNVnZwFWbQ4yj96ibiDsA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -2733,9 +2655,9 @@ "dev": true }, "node_modules/@vitest/spy": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.3.tgz", - "integrity": "sha512-Llj7Jgs6lbnL55WoshJUUacdJfjU2honvGcAJBxhra5TPEzTJH8ZuhI3p/JwqqfnTr4PmP7nDmOXP53MS7GJlg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -2745,9 +2667,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.3.tgz", - "integrity": "sha512-rE9DTN1BRhzkzqNQO+kw8ZgfeEBCLXiHJwetk668shmNBpSagQxneT5eSqEBLP+cqSiAeecvQmbpFfdMyLcIQA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -2792,9 +2714,10 @@ "dev": true }, "node_modules/@zoom-image/core": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.34.0.tgz", - "integrity": "sha512-2gvhcxJ5J3c4ZAhTRC9opNRnPTnseM5w6IU+SbSSUOT+MN6+0/XX6Qsyebl+ADXdrgOU5Nu8wGfzeCm1QuQSNQ==", + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@zoom-image/core/-/core-0.34.4.tgz", + "integrity": "sha512-urTvlDhOo4Uo5I4M79E4tkZlOWO/zG/9IlXsHUoCnkqnknnzZPb6HfyJn0KLF7bwZRhrok1dM2ckzGhv+EIlCQ==", + "license": "MIT", "dependencies": { "@namnode/store": "^0.1.0" }, @@ -2804,11 +2727,12 @@ } }, "node_modules/@zoom-image/svelte": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.2.10.tgz", - "integrity": "sha512-t/zzAX1T5kLtWKgXz3kOw09+bNVOZn9enLV4+GaUWJPE6PuWPRx7JAaKKDwA+1IVhyo+pDys+0zFf0Rsn2G4jA==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/@zoom-image/svelte/-/svelte-0.2.14.tgz", + "integrity": "sha512-fq1jFSLQ9mAW9NfEWg9XtMxSHYcoQfjxuvXrQWKO/4aWFvpZkyvpBT/XFTY7dKcdHqB6uIF89pBQCab2Owgryg==", + "license": "MIT", "dependencies": { - "@zoom-image/core": "0.34.0" + "@zoom-image/core": "0.34.4" }, "funding": { "type": "github", @@ -2819,9 +2743,9 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "bin": { "acorn": "bin/acorn" }, @@ -2963,6 +2887,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3522,12 +3447,12 @@ "integrity": "sha512-3VCXVl2IpFfOyD8drv9DozcNlwmqBqxOlsgkEGyVAzadjlPk1go8YNZyy8QmTnwHPxSFpeCR9OdsStEdVK7qDA==" }, "node_modules/core-js-compat": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.1.tgz", - "integrity": "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==", + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", + "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", "dev": true, "dependencies": { - "browserslist": "^4.22.2" + "browserslist": "^4.23.0" }, "funding": { "type": "opencollective", @@ -3812,6 +3737,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -4126,23 +4052,24 @@ } }, "node_modules/eslint-plugin-svelte": { - "version": "2.38.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.38.0.tgz", - "integrity": "sha512-IwwxhHzitx3dr0/xo0z4jjDlb2AAHBPKt+juMyKKGTLlKi1rZfA4qixMwnveU20/JTHyipM6keX4Vr7LZFYc9g==", + "version": "2.39.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.39.0.tgz", + "integrity": "sha512-FXktBLXsrxbA+6ZvJK2z/sQOrUKyzSg3fNWK5h0reSCjr2fjAsc9ai/s/JvSl4Hgvz3nYVtTIMwarZH5RcB7BA==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@jridgewell/sourcemap-codec": "^1.4.15", "debug": "^4.3.4", "eslint-compat-utils": "^0.5.0", "esutils": "^2.0.3", - "known-css-properties": "^0.30.0", + "known-css-properties": "^0.31.0", "postcss": "^8.4.38", "postcss-load-config": "^3.1.4", "postcss-safe-parser": "^6.0.0", "postcss-selector-parser": "^6.0.16", "semver": "^7.6.0", - "svelte-eslint-parser": ">=0.35.0 <1.0.0" + "svelte-eslint-parser": ">=0.36.0 <1.0.0" }, "engines": { "node": "^14.17.0 || >=16.0.0" @@ -4160,26 +4087,12 @@ } } }, - "node_modules/eslint-plugin-svelte/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-plugin-svelte/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4187,24 +4100,18 @@ "node": ">=10" } }, - "node_modules/eslint-plugin-svelte/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/eslint-plugin-unicorn": { - "version": "52.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz", - "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==", + "version": "53.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-53.0.0.tgz", + "integrity": "sha512-kuTcNo9IwwUCfyHGwQFOK/HjJAYzbODHN3wP0PgqbW+jbXqpNWxNVpVhj2tO9SixBwuAdmal8rVcWKBxwFnGuw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "@eslint-community/eslint-utils": "^4.4.0", - "@eslint/eslintrc": "^2.1.4", + "@eslint/eslintrc": "^3.0.2", "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", - "core-js-compat": "^3.34.0", + "core-js-compat": "^3.37.0", "esquery": "^1.5.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.1", @@ -4213,11 +4120,11 @@ "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.27", "regjsparser": "^0.10.0", - "semver": "^7.5.4", + "semver": "^7.6.1", "strip-indent": "^3.0.0" }, "engines": { - "node": ">=16" + "node": ">=18.18" }, "funding": { "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" @@ -4226,6 +4133,70 @@ "eslint": ">=8.56.0" } }, + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/eslintrc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", @@ -4238,26 +4209,11 @@ "node": ">=6" } }, - "node_modules/eslint-plugin-unicorn/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-plugin-unicorn/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4265,12 +4221,6 @@ "node": ">=10" } }, - "node_modules/eslint-plugin-unicorn/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -4872,6 +4822,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -5882,10 +5833,11 @@ } }, "node_modules/known-css-properties": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.30.0.tgz", - "integrity": "sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==", - "dev": true + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.31.0.tgz", + "integrity": "sha512-sBPIUGTNF0czz0mwGGUoKKJC8Q7On1GPbCSFPfyEsfHb2DyBG0Y4QtV+EVWpINSaiGKZblDNuF5AezxSgOhesQ==", + "dev": true, + "license": "MIT" }, "node_modules/levn": { "version": "0.4.1", @@ -6635,6 +6587,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7694,6 +7647,7 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8042,9 +7996,10 @@ } }, "node_modules/svelte": { - "version": "4.2.15", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.15.tgz", - "integrity": "sha512-j9KJSccHgLeRERPlhMKrCXpk2TqL2m5Z+k+OBTQhZOhIdCCd3WfqV+ylPWeipEwq17P/ekiSFWwrVQv93i3bsg==", + "version": "4.2.17", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.17.tgz", + "integrity": "sha512-N7m1YnoXtRf5wya5Gyx3TWuTddI4nAyayyIWFojiWV5IayDYNV5i2mRp/7qNGol4DtxEYxljmrbgp1HM6hUbmQ==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", @@ -8088,10 +8043,11 @@ } }, "node_modules/svelte-eslint-parser": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.35.0.tgz", - "integrity": "sha512-CtbPseajW0gjwEvHiuzYJkPDjAcHz2FaHt540j6RVYrZgnE6xWkzUBodQ4I3nV+G5AS0Svt8K6aIA/CIU9xT2Q==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.36.0.tgz", + "integrity": "sha512-/6YmUSr0FAVxW8dXNdIMydBnddPMHzaHirAZ7RrT21XYdgGGZMh0LQG6CZsvAFS4r2Y4ItUuCQc8TQ3urB30mQ==", "dev": true, + "license": "MIT", "dependencies": { "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", @@ -8106,7 +8062,7 @@ "url": "https://github.com/sponsors/ota-meshi" }, "peerDependencies": { - "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.112" + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0-next.115" }, "peerDependenciesMeta": { "svelte": { @@ -8138,9 +8094,10 @@ } }, "node_modules/svelte-maplibre": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/svelte-maplibre/-/svelte-maplibre-0.9.1.tgz", - "integrity": "sha512-JuPcnncvomNMxvasgWpIXFZhpLQkVVAfHIj3BpBQZ+A/OYfH/Y/BknQ/52U2kIUtxIWYz4EFQcboIwav6SOkwQ==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/svelte-maplibre/-/svelte-maplibre-0.9.3.tgz", + "integrity": "sha512-yus9Sb1C/QMxbVMInlPcr7SdRpahC+I3dgF/13FUE95CHqYRrfpjaZjABKlR7dFFLvQwmeJlOynGPSX6SF5Klw==", + "license": "MIT", "dependencies": { "d3-geo": "^3.1.0", "just-compare": "^2.3.0", @@ -8758,9 +8715,9 @@ } }, "node_modules/vite-node": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.3.tgz", - "integrity": "sha512-axFo00qiCpU/JLd8N1gu9iEYL3xTbMbMrbe5nDp9GL0nb6gurIdZLkkFogZXWnE8Oyy5kfSLwNVIcVsnhE7lgQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -8794,16 +8751,16 @@ } }, "node_modules/vitest": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.3.tgz", - "integrity": "sha512-2oM7nLXylw3mQlW6GXnRriw+7YvZFk/YNV8AxIC3Z3MfFbuziLGWP9GPxxu/7nRlXhqyxBikpamr+lEEj1sUEw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.5.3", - "@vitest/runner": "1.5.3", - "@vitest/snapshot": "1.5.3", - "@vitest/spy": "1.5.3", - "@vitest/utils": "1.5.3", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -8817,7 +8774,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.5.3", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -8832,8 +8789,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.5.3", - "@vitest/ui": "1.5.3", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, diff --git a/web/package.json b/web/package.json index 45660b4052..980434ca67 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "immich-web", - "version": "1.103.1", + "version": "1.105.1", "license": "GNU Affero General Public License version 3", "scripts": { "dev": "vite dev --host 0.0.0.0 --port 3000", @@ -31,6 +31,7 @@ "@sveltejs/vite-plugin-svelte": "^3.0.2", "@testing-library/jest-dom": "^6.4.2", "@testing-library/svelte": "^5.0.0", + "@testing-library/user-event": "^14.5.2", "@types/dom-to-image": "^2.6.7", "@types/justified-layout": "^4.1.4", "@types/lodash-es": "^4.17.12", @@ -42,7 +43,7 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.35.1", - "eslint-plugin-unicorn": "^52.0.0", + "eslint-plugin-unicorn": "^53.0.0", "factory.ts": "^1.4.1", "postcss": "^8.4.35", "prettier": "^3.2.5", @@ -78,6 +79,6 @@ "thumbhash": "^0.1.1" }, "volta": { - "node": "20.12.2" + "node": "20.13.1" } } diff --git a/web/src/app.css b/web/src/app.css index 9db440e46c..94682ac905 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -89,7 +89,7 @@ html::-webkit-scrollbar-thumb:hover { body { margin: 0; - color: #5f6368; + color: #3a3a3a; } input:focus-visible { diff --git a/web/src/lib/utils/autogrow.ts b/web/src/lib/actions/autogrow.ts similarity index 100% rename from web/src/lib/utils/autogrow.ts rename to web/src/lib/actions/autogrow.ts diff --git a/web/src/lib/utils/click-outside.ts b/web/src/lib/actions/click-outside.ts similarity index 95% rename from web/src/lib/utils/click-outside.ts rename to web/src/lib/actions/click-outside.ts index e04bc11fdf..ddb648a4f2 100644 --- a/web/src/lib/utils/click-outside.ts +++ b/web/src/lib/actions/click-outside.ts @@ -1,5 +1,5 @@ +import { matchesShortcut } from '$lib/actions/shortcut'; import type { ActionReturn } from 'svelte/action'; -import { matchesShortcut } from './shortcut'; interface Attributes { /** @deprecated */ diff --git a/web/src/lib/utils/focus-outside.ts b/web/src/lib/actions/focus-outside.ts similarity index 100% rename from web/src/lib/utils/focus-outside.ts rename to web/src/lib/actions/focus-outside.ts diff --git a/web/src/lib/actions/focus.ts b/web/src/lib/actions/focus.ts new file mode 100644 index 0000000000..81185625f7 --- /dev/null +++ b/web/src/lib/actions/focus.ts @@ -0,0 +1,3 @@ +export const initInput = (element: HTMLInputElement) => { + element.focus(); +}; diff --git a/web/src/lib/utils/list-navigation.ts b/web/src/lib/actions/list-navigation.ts similarity index 95% rename from web/src/lib/utils/list-navigation.ts rename to web/src/lib/actions/list-navigation.ts index dff958d757..b981f67521 100644 --- a/web/src/lib/utils/list-navigation.ts +++ b/web/src/lib/actions/list-navigation.ts @@ -1,5 +1,5 @@ +import { shortcuts } from '$lib/actions/shortcut'; import type { Action } from 'svelte/action'; -import { shortcuts } from './shortcut'; export const listNavigation: Action = (node, container: HTMLElement) => { const moveFocus = (direction: 'up' | 'down') => { diff --git a/web/src/lib/utils/shortcut.ts b/web/src/lib/actions/shortcut.ts similarity index 100% rename from web/src/lib/utils/shortcut.ts rename to web/src/lib/actions/shortcut.ts diff --git a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte index 0d01e2c3e4..c7b177b05a 100644 --- a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte +++ b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte @@ -8,6 +8,7 @@ import { handleError } from '$lib/utils/handle-error'; import { JobCommand, JobName, sendJobCommand, type AllJobStatusResponseDto, type JobCommandDto } from '@immich/sdk'; import { + mdiContentDuplicate, mdiFaceRecognition, mdiFileJpgBox, mdiFileXmlBox, @@ -88,6 +89,12 @@ subtitle: 'Run machine learning on assets to support smart search', disabled: !$featureFlags.smartSearch, }, + [JobName.DuplicateDetection]: { + icon: mdiContentDuplicate, + title: getJobName(JobName.DuplicateDetection), + subtitle: 'Run machine learning on assets to detect similar images. Relies on Smart Search', + disabled: !$featureFlags.duplicateDetection, + }, [JobName.FaceDetection]: { icon: mdiFaceRecognition, title: getJobName(JobName.FaceDetection), diff --git a/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte new file mode 100644 index 0000000000..d9c879faff --- /dev/null +++ b/web/src/lib/components/admin-page/settings/auth/auth-settings.svelte @@ -0,0 +1,242 @@ + + +{#if isConfirmOpen} + (isConfirmOpen = false)} + onConfirm={() => handleSave(true)} + > + +
+

Are you sure you want to disable all login methods? Login will be completely disabled.

+

+ To re-enable, use a + + Server Command. +

+
+
+
+{/if} + +
+
+
+
+ +
+

+ For more details about this feature, refer to the docs. +

+ + + + {#if config.oauth.enabled} +
+ + + + + + + + + + + + + + + + + + + + + + + handleToggleOverride()} + bind:checked={config.oauth.mobileOverrideEnabled} + /> + + {#if config.oauth.mobileOverrideEnabled} + + {/if} + {/if} +
+
+ + +
+
+ +
+
+
+ + dispatch('reset', { ...detail, configKeys: ['passwordLogin', 'oauth'] })} + on:save={() => handleSave(false)} + /> +
+
+
+
diff --git a/web/src/lib/components/admin-page/settings/confirm-disable-login.svelte b/web/src/lib/components/admin-page/settings/confirm-disable-login.svelte deleted file mode 100644 index 621f51de9f..0000000000 --- a/web/src/lib/components/admin-page/settings/confirm-disable-login.svelte +++ /dev/null @@ -1,25 +0,0 @@ - - - - -
-

Are you sure you want to disable all login methods? Login will be completely disabled.

-

- To re-enable, use a - - Server Command. -

-
-
-
diff --git a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte index bc91c2c993..e194b48ab9 100644 --- a/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte +++ b/web/src/lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte @@ -276,6 +276,15 @@ isEdited={config.ffmpeg.accel !== savedConfig.ffmpeg.accel} /> + + + + +
+ + +
+ + +
+
+ - import type { SystemConfigDto } from '@immich/sdk'; - import { isEqual } from 'lodash-es'; - import { createEventDispatcher } from 'svelte'; - import { fade } from 'svelte/transition'; - import type { SettingsEventType } from '../admin-settings'; - import ConfirmDisableLogin from '../confirm-disable-login.svelte'; - import SettingButtonsRow from '$lib/components/shared-components/settings/setting-buttons-row.svelte'; - import SettingInputField, { - SettingInputFieldType, - } from '$lib/components/shared-components/settings/setting-input-field.svelte'; - import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte'; - - export let savedConfig: SystemConfigDto; - export let defaultConfig: SystemConfigDto; - export let config: SystemConfigDto; // this is the config that is being edited - export let disabled = false; - - const dispatch = createEventDispatcher(); - - const handleToggleOverride = () => { - // click runs before bind - const previouslyEnabled = config.oauth.mobileOverrideEnabled; - if (!previouslyEnabled && !config.oauth.mobileRedirectUri) { - config.oauth.mobileRedirectUri = window.location.origin + '/api/oauth/mobile-redirect'; - } - }; - - let isConfirmOpen = false; - let handleConfirm: (value: boolean) => void; - - const openConfirmModal = () => { - return new Promise((resolve) => { - handleConfirm = (value: boolean) => { - isConfirmOpen = false; - resolve(value); - }; - isConfirmOpen = true; - }); - }; - - const handleSave = async () => { - if (!savedConfig.passwordLogin.enabled && savedConfig.oauth.enabled && !config.oauth.enabled) { - const confirmed = await openConfirmModal(); - if (!confirmed) { - return; - } - } - - if (!config.oauth.mobileOverrideEnabled) { - config.oauth.mobileRedirectUri = ''; - } - - dispatch('save', { oauth: config.oauth }); - }; - - -{#if isConfirmOpen} - handleConfirm(false)} onConfirm={() => handleConfirm(true)} /> -{/if} - -
-
-
-

- For more details about this feature, refer to the docs. -

- - - - {#if config.oauth.enabled} -
- - - - - - - - - - - - - - - - - - - - - - - handleToggleOverride()} - bind:checked={config.oauth.mobileOverrideEnabled} - /> - - {#if config.oauth.mobileOverrideEnabled} - - {/if} - {/if} - - dispatch('reset', { ...detail, configKeys: ['oauth'] })} - on:save={() => handleSave()} - showResetToDefault={!isEqual(savedConfig.oauth, defaultConfig.oauth)} - {disabled} - /> - -
-
diff --git a/web/src/lib/components/admin-page/settings/password-login/password-login-settings.svelte b/web/src/lib/components/admin-page/settings/password-login/password-login-settings.svelte deleted file mode 100644 index a022583527..0000000000 --- a/web/src/lib/components/admin-page/settings/password-login/password-login-settings.svelte +++ /dev/null @@ -1,68 +0,0 @@ - - -{#if isConfirmOpen} - handleConfirm(false)} onConfirm={() => handleConfirm(true)} /> -{/if} - -
-
-
-
- - - dispatch('reset', { ...detail, configKeys: ['passwordLogin'] })} - on:save={() => handleSave()} - showResetToDefault={!isEqual(savedConfig.passwordLogin, defaultConfig.passwordLogin)} - {disabled} - /> -
-
-
-
diff --git a/web/src/lib/components/album-page/album-card-group.svelte b/web/src/lib/components/album-page/album-card-group.svelte index 4c303caa68..99347b3a02 100644 --- a/web/src/lib/components/album-page/album-card-group.svelte +++ b/web/src/lib/components/album-page/album-card-group.svelte @@ -29,17 +29,19 @@ {#if group}
- - -

toggleAlbumGroupCollapsing(group.id)} class="w-fit mt-2 pt-2 pr-2 mb-2 hover:cursor-pointer"> +


{/if} diff --git a/web/src/lib/components/album-page/album-card.svelte b/web/src/lib/components/album-page/album-card.svelte index fd0f231316..6d64783e38 100644 --- a/web/src/lib/components/album-page/album-card.svelte +++ b/web/src/lib/components/album-page/album-card.svelte @@ -7,6 +7,7 @@ import { getShortDateRange } from '$lib/utils/date-time'; import AlbumCover from '$lib/components/album-page/album-cover.svelte'; import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; + import { s } from '$lib/utils'; export let album: AlbumResponseDto; export let showOwner = false; @@ -61,11 +62,11 @@

{/if} - + {#if showItemCount}

{album.assetCount.toLocaleString($locale)} - {album.assetCount === 1 ? `item` : `items`} + item{s(album.assetCount)}

{/if} diff --git a/web/src/lib/components/album-page/album-description.svelte b/web/src/lib/components/album-page/album-description.svelte index 28e726593d..1d7add6883 100644 --- a/web/src/lib/components/album-page/album-description.svelte +++ b/web/src/lib/components/album-page/album-description.svelte @@ -1,8 +1,8 @@ -

{getDateRange(startDate, endDate)}

-

·

-

{album.assetCount} items

+ {getDateRange(startDate, endDate)} + + {album.assetCount} items
diff --git a/web/src/lib/components/album-page/album-title.svelte b/web/src/lib/components/album-page/album-title.svelte index 2725bb8921..1d32f3932f 100644 --- a/web/src/lib/components/album-page/album-title.svelte +++ b/web/src/lib/components/album-page/album-title.svelte @@ -1,7 +1,7 @@ + +{album.assetCount} items +{#if album.shared} + • Shared +{/if} diff --git a/web/src/lib/components/asset-viewer/album-list-item.svelte b/web/src/lib/components/asset-viewer/album-list-item.svelte index 7261b3910a..0cde7c8465 100644 --- a/web/src/lib/components/asset-viewer/album-list-item.svelte +++ b/web/src/lib/components/asset-viewer/album-list-item.svelte @@ -3,13 +3,13 @@ import { ThumbnailFormat, type AlbumResponseDto } from '@immich/sdk'; import { createEventDispatcher } from 'svelte'; import { normalizeSearchString } from '$lib/utils/string-utils.js'; + import AlbumListItemDetails from './album-list-item-details.svelte'; const dispatch = createEventDispatcher<{ album: void; }>(); export let album: AlbumResponseDto; - export let variant: 'simple' | 'full' = 'full'; export let searchQuery = ''; let albumNameArray: string[] = ['', '', '']; @@ -31,7 +31,7 @@ on:click={() => dispatch('album')} class="flex w-full gap-4 px-6 py-2 text-left transition-colors hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl" > -
+ {#if album.albumThumbnailAssetId} {/if} -
-
+ + {albumNameArray[0]}{albumNameArray[1]}{albumNameArray[2]} - {#if variant === 'simple'} - {album.shared ? 'Shared' : ''} - {:else} - {album.assetCount} items - {album.shared ? ' · Shared' : ''} - {/if} + -
+
diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte index 3ad17b1eed..4d2b397e51 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte @@ -3,9 +3,10 @@ import { user } from '$lib/stores/user.store'; import { photoZoomState } from '$lib/stores/zoom-image.store'; import { getAssetJobName } from '$lib/utils'; - import { clickOutside } from '$lib/utils/click-outside'; + import { clickOutside } from '$lib/actions/click-outside'; import { getContextMenuPosition } from '$lib/utils/context-menu'; - import { AssetJobName, AssetTypeEnum, type AssetResponseDto, type AlbumResponseDto } from '@immich/sdk'; + import { openFileUploadDialog } from '$lib/utils/file-uploader'; + import { AssetJobName, AssetTypeEnum, type AlbumResponseDto, type AssetResponseDto } from '@immich/sdk'; import { mdiAccountCircleOutline, mdiAlertOutline, @@ -32,6 +33,7 @@ mdiPlaySpeed, mdiPresentationPlay, mdiShareVariantOutline, + mdiUpload, } from '@mdi/js'; import { createEventDispatcher } from 'svelte'; import ContextMenu from '../shared-components/context-menu/context-menu.svelte'; @@ -49,7 +51,7 @@ export let showSlideshow = false; export let hasStackChildren = false; - $: isOwner = asset.ownerId === $user?.id; + $: isOwner = $user && asset.ownerId === $user?.id; type MenuItemEvent = | 'addToAlbum' @@ -107,7 +109,10 @@
dispatch('back')} />
-
+
{#if showShareButton} + openFileUploadDialog({ multiple: false, assetId: asset.id })} + text="Replace with upload" + />
void; @@ -98,7 +99,7 @@ let isLiked: ActivityResponseDto | null = null; let numberOfComments: number; let fullscreenElement: Element; - + let unsubscribe: () => void; $: isFullScreen = fullscreenElement !== null; $: { @@ -192,6 +193,11 @@ } onMount(async () => { + unsubscribe = websocketEvents.on('on_upload_success', (assetUpdate) => { + if (assetUpdate.id === asset.id) { + asset = assetUpdate; + } + }); await navigate({ targetRoute: 'current', assetId: asset.id }); slideshowStateUnsubscribe = slideshowState.subscribe((value) => { if (value === SlideshowState.PlaySlideshow) { @@ -237,6 +243,7 @@ if (shuffleSlideshowUnsubscribe) { shuffleSlideshowUnsubscribe(); } + unsubscribe?.(); }); $: asset.id && !sharedLink && handlePromiseError(handleGetAllAlbums()); // Update the album information when the asset ID changes @@ -574,7 +581,7 @@ showZoomButton={asset.type === AssetTypeEnum.Image} showMotionPlayButton={!!asset.livePhotoVideoId} showDownloadButton={shouldShowDownloadButton} - showDetailButton={shouldShowDetailButton} + showDetailButton={enableDetailPanel} showSlideshow={!!assetStore} hasStackChildren={$stackAssetsStore.length > 0} showShareButton={shouldShowShareModal} @@ -600,7 +607,7 @@ {/if} {#if $slideshowState === SlideshowState.None && showNavigation} -
+
navigateAsset('previous', e)} label="View previous asset"> @@ -633,7 +640,9 @@ {:else} navigateAsset()} on:onVideoStarted={handleVideoStarted} @@ -654,7 +663,9 @@ {#if shouldPlayMotionPhoto && asset.livePhotoVideoId} (shouldPlayMotionPhoto = false)} /> @@ -668,7 +679,9 @@ {:else} navigateAsset()} on:onVideoStarted={handleVideoStarted} @@ -691,14 +704,14 @@
{#if $slideshowState === SlideshowState.None && showNavigation} -
+
navigateAsset('next', e)} label="View next asset">
{/if} - {#if $slideshowState === SlideshowState.None && $isShowDetail} + {#if enableDetailPanel && $slideshowState === SlideshowState.None && $isShowDetail}
+ import { autoGrowHeight } from '$lib/actions/autogrow'; + import { clickOutside } from '$lib/actions/click-outside'; + import { shortcut } from '$lib/actions/shortcut'; + import { + NotificationType, + notificationController, + } from '$lib/components/shared-components/notification/notification'; + import { handleError } from '$lib/utils/handle-error'; + import { updateAsset, type AssetResponseDto } from '@immich/sdk'; + import { tick } from 'svelte'; + + export let asset: AssetResponseDto; + export let isOwner: boolean; + + let textarea: HTMLTextAreaElement; + $: description = asset.exifInfo?.description || ''; + $: newDescription = description; + + $: if (textarea) { + newDescription; + void tick().then(() => autoGrowHeight(textarea)); + } + + const handleFocusOut = async () => { + if (description === newDescription) { + return; + } + + try { + await updateAsset({ id: asset.id, updateAssetDto: { description: newDescription } }); + notificationController.show({ + type: NotificationType.Info, + message: 'Asset description has been updated', + }); + } catch (error) { + handleError(error, 'Cannot update the description'); + } + }; + + +{#if isOwner} +
+