mirror of
https://github.com/immich-app/immich.git
synced 2025-03-11 15:09:45 +02:00
Merge branch 'main' into refactor/mobile-user-entity
This commit is contained in:
commit
8e17ae0817
@ -4,7 +4,7 @@ FROM ${BASEIMAGE}
|
||||
# Flutter SDK
|
||||
# https://flutter.dev/docs/development/tools/sdk/releases?tab=linux
|
||||
ENV FLUTTER_CHANNEL="stable"
|
||||
ENV FLUTTER_VERSION="3.24.5"
|
||||
ENV FLUTTER_VERSION="3.29.1"
|
||||
ENV FLUTTER_HOME=/flutter
|
||||
ENV PATH=${PATH}:${FLUTTER_HOME}/bin
|
||||
|
||||
|
10
cli/package-lock.json
generated
10
cli/package-lock.json
generated
@ -27,7 +27,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
||||
"@typescript-eslint/parser": "^8.15.0",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
@ -62,7 +62,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@ -1502,9 +1502,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.8.tgz",
|
||||
"integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==",
|
||||
"version": "22.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
|
||||
"integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -21,7 +21,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
||||
"@typescript-eslint/parser": "^8.15.0",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
|
12
e2e/package-lock.json
generated
12
e2e/package-lock.json
generated
@ -15,7 +15,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
@ -67,7 +67,7 @@
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/micromatch": "^4.0.9",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
||||
"@typescript-eslint/parser": "^8.15.0",
|
||||
"@vitest/coverage-v8": "^3.0.0",
|
||||
@ -102,7 +102,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@ -1717,9 +1717,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.8.tgz",
|
||||
"integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==",
|
||||
"version": "22.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
|
||||
"integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -25,7 +25,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
|
@ -24,7 +24,7 @@ WORKDIR /usr/src/app
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends g++
|
||||
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest@sha256:562193a4a9d398f8aedddcb223e583da394ee735de36b5815f8f1d22cb49be15 /uv /uvx /bin/
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
--mount=type=bind,source=uv.lock,target=uv.lock \
|
||||
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
|
||||
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"flutter": "3.24.5"
|
||||
"flutter": "3.29.1"
|
||||
}
|
||||
|
1
mobile/.gitignore
vendored
1
mobile/.gitignore
vendored
@ -56,3 +56,4 @@ libisar.so
|
||||
|
||||
# FVM Version
|
||||
.fvm/
|
||||
app/
|
@ -71,7 +71,9 @@ class ImportRule extends DartLintRule {
|
||||
final path = resolver.path.substring(_rootOffset);
|
||||
|
||||
if ((_allowed != null && _allowed!.matches(path)) &&
|
||||
(_forbidden == null || !_forbidden!.matches(path))) return;
|
||||
(_forbidden == null || !_forbidden!.matches(path))) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.registry.addImportDirective((node) {
|
||||
final uri = node.uri.stringValue;
|
||||
|
@ -5,23 +5,23 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "73.0.0"
|
||||
version: "76.0.0"
|
||||
_macros:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
version: "0.3.3"
|
||||
analyzer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.8.0"
|
||||
version: "6.11.0"
|
||||
analyzer_plugin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -34,26 +34,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
version: "2.6.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
version: "2.13.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -74,82 +74,82 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
|
||||
sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.1"
|
||||
version: "0.4.2"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.0"
|
||||
version: "1.19.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
version: "3.1.2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
|
||||
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.6"
|
||||
custom_lint:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint
|
||||
sha256: "6e1ec47427ca968f22bce734d00028ae7084361999b41673291138945c5baca0"
|
||||
sha256: "4500e88854e7581ee43586abeaf4443cb22375d6d289241a87b1aadf678d5545"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
version: "0.6.10"
|
||||
custom_lint_builder:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: custom_lint_builder
|
||||
sha256: ba2f90fff4eff71d202d097eb14b14f87087eaaef742e956208c0eb9d3a40a21
|
||||
sha256: "5a95eff100da256fbf086b329c17c8b49058c261cdf56d3a4157d3c31c511d78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
version: "0.6.10"
|
||||
custom_lint_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: custom_lint_core
|
||||
sha256: "4ddbbdaa774265de44c97054dcec058a83d9081d071785ece601e348c18c267d"
|
||||
sha256: "76a4046cc71d976222a078a8fd4a65e198b70545a8d690a75196dd14f08510f6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.5"
|
||||
version: "0.6.10"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
|
||||
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.7"
|
||||
version: "2.3.8"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
version: "7.0.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
freezed_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -162,18 +162,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: glob
|
||||
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.3"
|
||||
hotreloader:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hotreloader
|
||||
sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e
|
||||
sha256: bc167a1163807b03bada490bfe2df25b0d744df359227880220a5cbd04e5734b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
version: "4.3.0"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -186,74 +186,74 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: lints
|
||||
sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413"
|
||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "5.1.1"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
macros:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
version: "0.1.3-main.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16+1"
|
||||
version: "0.12.17"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.16.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.9.1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.2.0"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
|
||||
sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.5.0"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -266,10 +266,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
version: "1.10.1"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -282,89 +282,89 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
version: "1.12.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.4"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.1.1"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
|
||||
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.3"
|
||||
version: "0.7.4"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.4.0"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
|
||||
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.0"
|
||||
version: "4.5.1"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
version: "15.0.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
|
@ -3,7 +3,6 @@ PODS:
|
||||
- Flutter
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- DKImagePickerController/Core (4.3.9):
|
||||
@ -43,7 +42,7 @@ PODS:
|
||||
- Flutter (1.0.0)
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- Flutter
|
||||
- flutter_native_splash (0.0.1):
|
||||
- flutter_native_splash (2.4.3):
|
||||
- Flutter
|
||||
- flutter_udid (0.0.1):
|
||||
- Flutter
|
||||
@ -52,7 +51,6 @@ PODS:
|
||||
- Flutter
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- Toast
|
||||
- geolocator_apple (1.2.0):
|
||||
- Flutter
|
||||
- image_picker_ios (0.0.1):
|
||||
@ -61,19 +59,16 @@ PODS:
|
||||
- Flutter
|
||||
- isar_flutter_libs (1.0.0):
|
||||
- Flutter
|
||||
- MapLibre (5.14.0-pre3)
|
||||
- MapLibre (6.5.0)
|
||||
- maplibre_gl (0.0.1):
|
||||
- Flutter
|
||||
- MapLibre (= 5.14.0-pre3)
|
||||
- MapLibre (= 6.5.0)
|
||||
- native_video_player (1.0.0):
|
||||
- Flutter
|
||||
- network_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- package_info_plus (0.4.5):
|
||||
- Flutter
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- path_provider_ios (0.0.1):
|
||||
- Flutter
|
||||
- permission_handler_apple (9.3.0):
|
||||
@ -82,9 +77,9 @@ PODS:
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- SAMKeychain (1.5.3)
|
||||
- SDWebImage (5.20.0):
|
||||
- SDWebImage/Core (= 5.20.0)
|
||||
- SDWebImage/Core (5.20.0)
|
||||
- SDWebImage (5.21.0):
|
||||
- SDWebImage/Core (= 5.21.0)
|
||||
- SDWebImage/Core (5.21.0)
|
||||
- share_handler_ios (0.0.14):
|
||||
- Flutter
|
||||
- share_handler_ios/share_handler_ios_models (= 0.0.14)
|
||||
@ -98,11 +93,10 @@ PODS:
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqflite (0.0.3):
|
||||
- sqflite_darwin (0.0.4):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- SwiftyGif (5.4.5)
|
||||
- Toast (4.1.1)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
@ -110,7 +104,7 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- background_downloader (from `.symlinks/plugins/background_downloader/ios`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
@ -127,7 +121,6 @@ DEPENDENCIES:
|
||||
- native_video_player (from `.symlinks/plugins/native_video_player/ios`)
|
||||
- network_info_plus (from `.symlinks/plugins/network_info_plus/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
||||
@ -135,7 +128,7 @@ DEPENDENCIES:
|
||||
- share_handler_ios_models (from `.symlinks/plugins/share_handler_ios/ios/Models`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
|
||||
@ -147,13 +140,12 @@ SPEC REPOS:
|
||||
- SAMKeychain
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- Toast
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
background_downloader:
|
||||
:path: ".symlinks/plugins/background_downloader/ios"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/darwin"
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
file_picker:
|
||||
@ -186,8 +178,6 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/network_info_plus/ios"
|
||||
package_info_plus:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
path_provider_ios:
|
||||
:path: ".symlinks/plugins/path_provider_ios/ios"
|
||||
permission_handler_apple:
|
||||
@ -202,50 +192,48 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
sqflite:
|
||||
:path: ".symlinks/plugins/sqflite/darwin"
|
||||
sqflite_darwin:
|
||||
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock_plus:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
background_downloader: 9f788ffc5de45acf87d6380e91ca0841066c18cf
|
||||
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
|
||||
background_downloader: 3ca0e156ad83a9fc1c8300f5f7c38e94e2d0bf51
|
||||
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
|
||||
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||
flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04
|
||||
flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29
|
||||
flutter_udid: b2417673f287ee62817a1de3d1643f47b9f508ab
|
||||
flutter_web_auth_2: 06d500582775790a0d4c323222fcb6d7990f9603
|
||||
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
|
||||
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450
|
||||
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
|
||||
geolocator_apple: 9bcea1918ff7f0062d98345d238ae12718acfbc1
|
||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
|
||||
isar_flutter_libs: fdf730ca925d05687f36d7f1d355e482529ed097
|
||||
MapLibre: 620fc933c1d6029b33738c905c1490d024e5d4ef
|
||||
maplibre_gl: a2efec727dd340e4c65e26d2b03b584f14881fd9
|
||||
MapLibre: 0ebfa9329d313cec8bf0a5ba5a336a1dc903785e
|
||||
maplibre_gl: be7b98f1c3ed75bf77f321eec04df359d0ff6f62
|
||||
native_video_player: d12af78a1a4a8cf09775a5177d5b392def6fd23c
|
||||
network_info_plus: 6613d9d7cdeb0e6f366ed4dbe4b3c51c52d567a9
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
|
||||
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
|
||||
share_handler_ios: 6dd3a4ac5ca0d955274aec712ba0ecdcaf583e7c
|
||||
share_handler_ios_models: fc638c9b4330dc7f082586c92aee9dfa0b87b871
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||
wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
|
||||
|
||||
PODFILE CHECKSUM: 03b7eead4ee77b9e778179eeb0f3b5513617451c
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
import Flutter
|
||||
import BackgroundTasks
|
||||
import path_provider_foundation
|
||||
import path_provider_ios
|
||||
import CryptoKit
|
||||
import Network
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
@ -40,25 +41,29 @@ extension MapMarkers on MapLibreMapController {
|
||||
|
||||
await addGeoJSONSourceForMarkers(markers);
|
||||
|
||||
await addCircleLayer(
|
||||
MapUtils.defaultSourceId,
|
||||
MapUtils.defaultHeatMapLayerId,
|
||||
const CircleLayerProperties(
|
||||
circleRadius: 10,
|
||||
circleColor: "rgba(150,86,34,0.7)",
|
||||
circleBlur: 1.0,
|
||||
circleOpacity: 0.7,
|
||||
circleStrokeWidth: 0.1,
|
||||
circleStrokeColor: "rgba(203,46,19,0.5)",
|
||||
circleStrokeOpacity: 0.7,
|
||||
),
|
||||
);
|
||||
if (Platform.isAndroid) {
|
||||
await addCircleLayer(
|
||||
MapUtils.defaultSourceId,
|
||||
MapUtils.defaultHeatMapLayerId,
|
||||
const CircleLayerProperties(
|
||||
circleRadius: 10,
|
||||
circleColor: "rgba(150,86,34,0.7)",
|
||||
circleBlur: 1.0,
|
||||
circleOpacity: 0.7,
|
||||
circleStrokeWidth: 0.1,
|
||||
circleStrokeColor: "rgba(203,46,19,0.5)",
|
||||
circleStrokeOpacity: 0.7,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// await addHeatmapLayer(
|
||||
// MapUtils.defaultSourceId,
|
||||
// MapUtils.defaultHeatMapLayerId,
|
||||
// MapUtils.defaultHeatMapLayerProperties,
|
||||
// );
|
||||
if (Platform.isIOS) {
|
||||
await addHeatmapLayer(
|
||||
MapUtils.defaultSourceId,
|
||||
MapUtils.defaultHeatMapLayerId,
|
||||
MapUtils.defaultHeatMapLayerProperties,
|
||||
);
|
||||
}
|
||||
|
||||
_completer.complete();
|
||||
}
|
||||
|
@ -10,14 +10,14 @@ extension ImmichColorSchemeExtensions on ColorScheme {
|
||||
extension ColorExtensions on Color {
|
||||
Color lighten({double amount = 0.1}) {
|
||||
return Color.alphaBlend(
|
||||
Colors.white.withOpacity(amount),
|
||||
Colors.white.withValues(alpha: amount),
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
Color darken({double amount = 0.1}) {
|
||||
return Color.alphaBlend(
|
||||
Colors.black.withOpacity(amount),
|
||||
Colors.black.withValues(alpha: amount),
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ typedef AsyncFuture<T> = Future<AsyncValue<T>>;
|
||||
mixin ErrorLoggerMixin {
|
||||
abstract final Logger logger;
|
||||
|
||||
// ignore: unintended_html_in_doc_comment
|
||||
/// Returns an AsyncValue<T> if the future is successfully executed
|
||||
/// Else, logs the error to the overridden logger and returns an AsyncError<>
|
||||
AsyncFuture<T> guardError<T>(
|
||||
|
@ -53,7 +53,7 @@ class AlbumAdditionalSharedUserSelectionPage extends HookConsumerWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Chip(
|
||||
backgroundColor: context.primaryColor.withOpacity(0.15),
|
||||
backgroundColor: context.primaryColor.withValues(alpha: 0.15),
|
||||
label: Text(
|
||||
user.name,
|
||||
style: const TextStyle(
|
||||
|
@ -72,7 +72,7 @@ class AlbumSharedUserSelectionPage extends HookConsumerWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Chip(
|
||||
backgroundColor: context.primaryColor.withOpacity(0.15),
|
||||
backgroundColor: context.primaryColor.withValues(alpha: 0.15),
|
||||
label: Text(
|
||||
user.email,
|
||||
style: const TextStyle(
|
||||
|
@ -106,9 +106,9 @@ class AlbumsPage extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
context.colorScheme.primary.withOpacity(0.075),
|
||||
context.colorScheme.primary.withOpacity(0.09),
|
||||
context.colorScheme.primary.withOpacity(0.075),
|
||||
context.colorScheme.primary.withValues(alpha: 0.075),
|
||||
context.colorScheme.primary.withValues(alpha: 0.09),
|
||||
context.colorScheme.primary.withValues(alpha: 0.075),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
|
@ -49,9 +49,9 @@ class AppLogPage extends HookConsumerWidget {
|
||||
|
||||
Color getTileColor(LogLevel level) => switch (level) {
|
||||
LogLevel.info => Colors.transparent,
|
||||
LogLevel.severe => Colors.redAccent.withOpacity(0.25),
|
||||
LogLevel.warning => Colors.orangeAccent.withOpacity(0.25),
|
||||
_ => context.primaryColor.withOpacity(0.1),
|
||||
LogLevel.severe => Colors.redAccent.withValues(alpha: 0.25),
|
||||
LogLevel.warning => Colors.orangeAccent.withValues(alpha: 0.25),
|
||||
_ => context.primaryColor.withValues(alpha: 0.1),
|
||||
};
|
||||
|
||||
return Scaffold(
|
||||
|
@ -127,7 +127,7 @@ class EditImagePage extends ConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(7),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
color: Colors.black.withValues(alpha: 0.2),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 3),
|
||||
|
@ -49,7 +49,7 @@ class PeopleCollectionPage extends HookConsumerWidget {
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(left: 24),
|
||||
filled: true,
|
||||
fillColor: context.primaryColor.withOpacity(0.1),
|
||||
fillColor: context.primaryColor.withValues(alpha: 0.1),
|
||||
hintStyle: context.textTheme.bodyLarge?.copyWith(
|
||||
color: context.themeData.colorScheme.onSurfaceSecondary,
|
||||
),
|
||||
|
@ -58,7 +58,8 @@ class SharedLinkPage extends HookConsumerWidget {
|
||||
child: Icon(
|
||||
Icons.link_off,
|
||||
size: 100,
|
||||
color: context.themeData.iconTheme.color?.withOpacity(0.5),
|
||||
color:
|
||||
context.themeData.iconTheme.color?.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -120,7 +120,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
||||
fontSize: 14,
|
||||
),
|
||||
disabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey.withOpacity(0.5)),
|
||||
borderSide: BorderSide(color: Colors.grey.withValues(alpha: 0.5)),
|
||||
),
|
||||
),
|
||||
onTapOutside: (_) => descriptionFocusNode.unfocus(),
|
||||
@ -146,7 +146,7 @@ class SharedLinkEditPage extends HookConsumerWidget {
|
||||
fontSize: 14,
|
||||
),
|
||||
disabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.grey.withOpacity(0.5)),
|
||||
borderSide: BorderSide(color: Colors.grey.withValues(alpha: 0.5)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -350,7 +350,7 @@ class MemoryPage extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
shape: const CircleBorder(),
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
color: Colors.white.withValues(alpha: 0.2),
|
||||
elevation: 0,
|
||||
child: const Icon(
|
||||
Icons.close_rounded,
|
||||
|
@ -517,8 +517,6 @@ class SearchPage extends HookConsumerWidget {
|
||||
return Icons.abc_rounded;
|
||||
case TextSearchType.description:
|
||||
return Icons.text_snippet_outlined;
|
||||
default:
|
||||
return Icons.search_rounded;
|
||||
}
|
||||
}
|
||||
|
||||
@ -634,9 +632,9 @@ class SearchPage extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
context.colorScheme.primary.withOpacity(0.075),
|
||||
context.colorScheme.primary.withOpacity(0.09),
|
||||
context.colorScheme.primary.withOpacity(0.075),
|
||||
context.colorScheme.primary.withValues(alpha: 0.075),
|
||||
context.colorScheme.primary.withValues(alpha: 0.09),
|
||||
context.colorScheme.primary.withValues(alpha: 0.075),
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
|
@ -5,6 +5,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'activity.provider.g.dart';
|
||||
|
||||
// ignore: unintended_html_in_doc_comment
|
||||
/// Maintains the current list of all activities for <share-album-id, asset>
|
||||
@riverpod
|
||||
class AlbumActivity extends _$AlbumActivity {
|
||||
|
@ -3,6 +3,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'activity_statistics.provider.g.dart';
|
||||
|
||||
// ignore: unintended_html_in_doc_comment
|
||||
/// Maintains the current number of comments by <shared-album, asset>
|
||||
@riverpod
|
||||
class ActivityStatistics extends _$ActivityStatistics {
|
||||
|
@ -24,9 +24,8 @@ ThemeData getThemeData({
|
||||
hintColor: colorScheme.onSurfaceSecondary,
|
||||
focusColor: colorScheme.primary,
|
||||
scaffoldBackgroundColor: colorScheme.surface,
|
||||
splashColor: colorScheme.primary.withOpacity(0.1),
|
||||
highlightColor: colorScheme.primary.withOpacity(0.1),
|
||||
dialogBackgroundColor: colorScheme.surfaceContainer,
|
||||
splashColor: colorScheme.primary.withValues(alpha: 0.1),
|
||||
highlightColor: colorScheme.primary.withValues(alpha: 0.1),
|
||||
bottomSheetTheme: BottomSheetThemeData(
|
||||
backgroundColor: colorScheme.surfaceContainer,
|
||||
),
|
||||
@ -163,6 +162,7 @@ ThemeData getThemeData({
|
||||
),
|
||||
),
|
||||
),
|
||||
dialogTheme: DialogThemeData(backgroundColor: colorScheme.surfaceContainer),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ class _ActivityTitle extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final textColor = context.isDarkTheme ? Colors.white : Colors.black;
|
||||
final textStyle = context.textTheme.bodyMedium
|
||||
?.copyWith(color: textColor.withOpacity(0.6));
|
||||
?.copyWith(color: textColor.withValues(alpha: 0.6));
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment:
|
||||
|
@ -202,12 +202,12 @@ class ThumbnailImage extends ConsumerWidget {
|
||||
bottom: 5,
|
||||
child: Icon(
|
||||
storageIcon(asset),
|
||||
color: Colors.white.withOpacity(.8),
|
||||
color: Colors.white.withValues(alpha: .8),
|
||||
size: 16,
|
||||
shadows: [
|
||||
Shadow(
|
||||
blurRadius: 5.0,
|
||||
color: Colors.black.withOpacity(0.6),
|
||||
color: Colors.black.withValues(alpha: 0.6),
|
||||
offset: const Offset(0.0, 0.0),
|
||||
),
|
||||
],
|
||||
|
@ -113,7 +113,7 @@ class GalleryAppBar extends ConsumerWidget {
|
||||
duration: const Duration(milliseconds: 100),
|
||||
opacity: showControls ? 1.0 : 0.0,
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.4),
|
||||
color: Colors.black.withValues(alpha: 0.4),
|
||||
child: TopControlAppBar(
|
||||
isOwner: isOwner,
|
||||
isPartner: isPartner,
|
||||
|
@ -170,7 +170,7 @@ class AppBarServerInfo extends HookConsumerWidget {
|
||||
child: Tooltip(
|
||||
verticalOffset: 0,
|
||||
decoration: BoxDecoration(
|
||||
color: context.primaryColor.withOpacity(0.9),
|
||||
color: context.primaryColor.withValues(alpha: 0.9),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
|
@ -146,7 +146,7 @@ class DropdownSearchMenu<T> extends HookWidget {
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.12)
|
||||
.withValues(alpha: 0.12)
|
||||
: null,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
|
@ -124,7 +124,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: badgeBackground,
|
||||
border: Border.all(
|
||||
color: context.colorScheme.outline.withOpacity(.3),
|
||||
color: context.colorScheme.outline.withValues(alpha: .3),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(widgetSize / 2),
|
||||
),
|
||||
|
@ -43,7 +43,7 @@ class ImmichToast {
|
||||
borderRadius: BorderRadius.circular(5.0),
|
||||
color: context.colorScheme.surfaceContainer,
|
||||
border: Border.all(
|
||||
color: context.colorScheme.outline.withOpacity(.5),
|
||||
color: context.colorScheme.outline.withValues(alpha: .5),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
|
@ -27,7 +27,8 @@ class ScaffoldErrorBody extends StatelessWidget {
|
||||
child: Icon(
|
||||
Icons.error_outline,
|
||||
size: 100,
|
||||
color: context.themeData.iconTheme.color?.withOpacity(0.5),
|
||||
color:
|
||||
context.themeData.iconTheme.color?.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -48,7 +48,7 @@ class MemoryBottomInfo extends StatelessWidget {
|
||||
.scrollToDate(memory.assets[0].fileCreatedAt);
|
||||
},
|
||||
shape: const CircleBorder(),
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
color: Colors.white.withValues(alpha: 0.2),
|
||||
elevation: 0,
|
||||
child: const Icon(
|
||||
Icons.open_in_new,
|
||||
|
@ -126,7 +126,7 @@ class _BlurredBackdrop extends HookWidget {
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
color: Colors.black.withValues(alpha: 0.2),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@ -147,7 +147,7 @@ class _BlurredBackdrop extends HookWidget {
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.2),
|
||||
color: Colors.black.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -31,7 +31,7 @@ class MemoryLane extends HookConsumerWidget {
|
||||
elevation: 2,
|
||||
backgroundColor: Colors.black,
|
||||
overlayColor: WidgetStateProperty.all(
|
||||
Colors.white.withOpacity(0.1),
|
||||
Colors.white.withValues(alpha: 0.1),
|
||||
),
|
||||
onTap: (memoryIndex) {
|
||||
ref.read(hapticFeedbackProvider.notifier).heavyImpact();
|
||||
@ -84,7 +84,7 @@ class MemoryCard extends ConsumerWidget {
|
||||
children: [
|
||||
ColorFiltered(
|
||||
colorFilter: ColorFilter.mode(
|
||||
Colors.black.withOpacity(0.2),
|
||||
Colors.black.withValues(alpha: 0.2),
|
||||
BlendMode.darken,
|
||||
),
|
||||
child: Hero(
|
||||
|
@ -37,7 +37,7 @@ class PeoplePicker extends HookConsumerWidget {
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(left: 24),
|
||||
filled: true,
|
||||
fillColor: context.primaryColor.withOpacity(0.1),
|
||||
fillColor: context.primaryColor.withValues(alpha: 0.1),
|
||||
hintStyle: context.textTheme.bodyLarge?.copyWith(
|
||||
color: context.themeData.colorScheme.onSurfaceSecondary,
|
||||
),
|
||||
|
@ -22,7 +22,7 @@ class SearchFilterChip extends StatelessWidget {
|
||||
onTap: onTap,
|
||||
child: Card(
|
||||
elevation: 0,
|
||||
color: context.primaryColor.withOpacity(.5),
|
||||
color: context.primaryColor.withValues(alpha: .5),
|
||||
shape: StadiumBorder(
|
||||
side: BorderSide(color: context.colorScheme.secondaryContainer),
|
||||
),
|
||||
|
@ -44,8 +44,8 @@ class ThumbnailWithInfoContainer extends StatelessWidget {
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
label == ''
|
||||
? Colors.black.withOpacity(0.1)
|
||||
: Colors.black.withOpacity(0.5),
|
||||
? Colors.black.withValues(alpha: 0.1)
|
||||
: Colors.black.withValues(alpha: 0.5),
|
||||
],
|
||||
stops: const [0.0, 1.0],
|
||||
),
|
||||
|
@ -72,7 +72,7 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return Material(
|
||||
color: context.colorScheme.surfaceContainerHighest,
|
||||
shadowColor: context.colorScheme.primary.withOpacity(0.2),
|
||||
shadowColor: context.colorScheme.primary.withValues(alpha: 0.2),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
@ -116,7 +116,7 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
child: Icon(
|
||||
Icons.dns_rounded,
|
||||
size: 120,
|
||||
color: context.primaryColor.withOpacity(0.05),
|
||||
color: context.primaryColor.withValues(alpha: 0.05),
|
||||
),
|
||||
),
|
||||
ListView(
|
||||
|
@ -161,7 +161,7 @@ class LocalNetworkPreference extends HookConsumerWidget {
|
||||
child: Icon(
|
||||
Icons.home_outlined,
|
||||
size: 120,
|
||||
color: context.primaryColor.withOpacity(0.05),
|
||||
color: context.primaryColor.withValues(alpha: 0.05),
|
||||
),
|
||||
),
|
||||
ListView(
|
||||
|
@ -98,7 +98,7 @@ class PrimaryColorSetting extends HookConsumerWidget {
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(100)),
|
||||
color: Colors.grey[900]?.withOpacity(.4),
|
||||
color: Colors.grey[900]?.withValues(alpha: .4),
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(3),
|
||||
|
@ -240,7 +240,7 @@ class SharedLinkItem extends ConsumerWidget {
|
||||
child: Tooltip(
|
||||
verticalOffset: 0,
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.primary.withOpacity(0.9),
|
||||
color: colorScheme.primary.withValues(alpha: 0.9),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
@ -268,7 +268,7 @@ class SharedLinkItem extends ConsumerWidget {
|
||||
child: Tooltip(
|
||||
verticalOffset: 0,
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.primary.withOpacity(0.9),
|
||||
color: colorScheme.primary.withValues(alpha: 0.9),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@ version: 1.129.0+187
|
||||
|
||||
environment:
|
||||
sdk: '>=3.3.0 <4.0.0'
|
||||
flutter: 3.24.5
|
||||
flutter: 3.29.1
|
||||
|
||||
isar_version: &isar_version 3.1.8 # define the version to be used
|
||||
|
||||
@ -14,7 +14,6 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
path_provider_ios:
|
||||
photo_manager: ^3.6.1
|
||||
photo_manager_image_provider: ^2.2.0
|
||||
flutter_hooks: ^0.21.2
|
||||
@ -39,7 +38,8 @@ dependencies:
|
||||
flutter_displaymode: ^0.6.0
|
||||
scrollable_positioned_list: ^0.3.8
|
||||
path: ^1.8.3
|
||||
path_provider: ^2.1.2
|
||||
path_provider: ^2.1.5
|
||||
path_provider_ios: ^2.0.11
|
||||
collection: ^1.18.0
|
||||
http_parser: ^4.0.2
|
||||
flutter_web_auth_2: ^5.0.0-alpha.0
|
||||
|
8
open-api/typescript-sdk/package-lock.json
generated
8
open-api/typescript-sdk/package-lock.json
generated
@ -12,7 +12,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@ -23,9 +23,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.8.tgz",
|
||||
"integrity": "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==",
|
||||
"version": "22.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
|
||||
"integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -19,7 +19,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"repository": {
|
||||
|
22
server/package-lock.json
generated
22
server/package-lock.json
generated
@ -17,7 +17,6 @@
|
||||
"@nestjs/platform-socket.io": "^11.0.4",
|
||||
"@nestjs/schedule": "^5.0.0",
|
||||
"@nestjs/swagger": "^11.0.2",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@nestjs/websockets": "^11.0.4",
|
||||
"@opentelemetry/auto-instrumentations-node": "^0.56.0",
|
||||
"@opentelemetry/context-async-hooks": "^1.24.0",
|
||||
@ -89,7 +88,7 @@
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/picomatch": "^3.0.0",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
@ -2920,19 +2919,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/typeorm": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-11.0.0.tgz",
|
||||
"integrity": "sha512-SOeUQl70Lb2OfhGkvnh4KXWlsd+zA08RuuQgT7kKbzivngxzSo1Oc7Usu5VxCxACQC9wc2l9esOHILSJeK7rJA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
||||
"reflect-metadata": "^0.1.13 || ^0.2.0",
|
||||
"rxjs": "^7.2.0",
|
||||
"typeorm": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/websockets": {
|
||||
"version": "11.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-11.0.11.tgz",
|
||||
@ -5830,9 +5816,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz",
|
||||
"integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==",
|
||||
"version": "22.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
|
||||
"integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
|
@ -43,7 +43,6 @@
|
||||
"@nestjs/platform-socket.io": "^11.0.4",
|
||||
"@nestjs/schedule": "^5.0.0",
|
||||
"@nestjs/swagger": "^11.0.2",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@nestjs/websockets": "^11.0.4",
|
||||
"@opentelemetry/auto-instrumentations-node": "^0.56.0",
|
||||
"@opentelemetry/context-async-hooks": "^1.24.0",
|
||||
@ -115,7 +114,7 @@
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/picomatch": "^3.0.0",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { EmailRenderRequest, EmailTemplate, NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { newFakeLoggingRepository } from 'test/repositories/logger.repository.mock';
|
||||
import { automock } from 'test/utils';
|
||||
|
||||
describe(NotificationRepository.name, () => {
|
||||
let sut: NotificationRepository;
|
||||
|
||||
beforeEach(() => {
|
||||
sut = new NotificationRepository(newFakeLoggingRepository());
|
||||
sut = new NotificationRepository(automock(LoggingRepository, { args: [, { getEnv: () => ({}) }], strict: false }));
|
||||
});
|
||||
|
||||
describe('renderEmail', () => {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import mockfs from 'mock-fs';
|
||||
import { CrawlOptionsDto } from 'src/dtos/library.dto';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { StorageRepository } from 'src/repositories/storage.repository';
|
||||
import { newFakeLoggingRepository } from 'test/repositories/logger.repository.mock';
|
||||
import { automock } from 'test/utils';
|
||||
|
||||
interface Test {
|
||||
test: string;
|
||||
@ -182,7 +183,7 @@ describe(StorageRepository.name, () => {
|
||||
let sut: StorageRepository;
|
||||
|
||||
beforeEach(() => {
|
||||
sut = new StorageRepository(newFakeLoggingRepository());
|
||||
sut = new StorageRepository(automock(LoggingRepository, { args: [, { getEnv: () => ({}) }], strict: false }));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -146,6 +146,7 @@ describe(ActivityService.name, () => {
|
||||
const activity = factory.activity();
|
||||
|
||||
mocks.access.activity.checkOwnerAccess.mockResolvedValue(new Set([activity.id]));
|
||||
mocks.activity.delete.mockResolvedValue();
|
||||
|
||||
await sut.delete(factory.auth(), activity.id);
|
||||
|
||||
@ -156,6 +157,7 @@ describe(ActivityService.name, () => {
|
||||
const activity = factory.activity();
|
||||
|
||||
mocks.access.activity.checkAlbumOwnerAccess.mockResolvedValue(new Set([activity.id]));
|
||||
mocks.activity.delete.mockResolvedValue();
|
||||
|
||||
await sut.delete(factory.auth(), activity.id);
|
||||
|
||||
|
@ -347,6 +347,7 @@ describe(AlbumService.name, () => {
|
||||
it('should remove a shared user from an owned album', async () => {
|
||||
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([albumStub.sharedWithUser.id]));
|
||||
mocks.album.getById.mockResolvedValue(albumStub.sharedWithUser);
|
||||
mocks.albumUser.delete.mockResolvedValue();
|
||||
|
||||
await expect(
|
||||
sut.removeUser(authStub.admin, albumStub.sharedWithUser.id, userStub.user1.id),
|
||||
@ -376,6 +377,7 @@ describe(AlbumService.name, () => {
|
||||
|
||||
it('should allow a shared user to remove themselves', async () => {
|
||||
mocks.album.getById.mockResolvedValue(albumStub.sharedWithUser);
|
||||
mocks.albumUser.delete.mockResolvedValue();
|
||||
|
||||
await sut.removeUser(authStub.user1, albumStub.sharedWithUser.id, authStub.user1.user.id);
|
||||
|
||||
@ -388,6 +390,7 @@ describe(AlbumService.name, () => {
|
||||
|
||||
it('should allow a shared user to remove themselves using "me"', async () => {
|
||||
mocks.album.getById.mockResolvedValue(albumStub.sharedWithUser);
|
||||
mocks.albumUser.delete.mockResolvedValue();
|
||||
|
||||
await sut.removeUser(authStub.user1, albumStub.sharedWithUser.id, 'me');
|
||||
|
||||
@ -422,6 +425,8 @@ describe(AlbumService.name, () => {
|
||||
describe('updateUser', () => {
|
||||
it('should update user role', async () => {
|
||||
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([albumStub.sharedWithAdmin.id]));
|
||||
mocks.albumUser.update.mockResolvedValue(null as any);
|
||||
|
||||
await sut.updateUser(authStub.user1, albumStub.sharedWithAdmin.id, userStub.admin.id, {
|
||||
role: AlbumUserRole.EDITOR,
|
||||
});
|
||||
|
@ -67,6 +67,8 @@ describe(ApiKeyService.name, () => {
|
||||
const id = newUuid();
|
||||
const auth = factory.auth();
|
||||
|
||||
mocks.apiKey.getById.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.update(auth, id, { name: 'New Name' })).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.apiKey.update).not.toHaveBeenCalledWith(id);
|
||||
@ -91,6 +93,8 @@ describe(ApiKeyService.name, () => {
|
||||
const auth = factory.auth();
|
||||
const id = newUuid();
|
||||
|
||||
mocks.apiKey.getById.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.delete(auth, id)).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.apiKey.delete).not.toHaveBeenCalledWith(id);
|
||||
@ -101,6 +105,7 @@ describe(ApiKeyService.name, () => {
|
||||
const apiKey = factory.apiKey({ userId: auth.user.id });
|
||||
|
||||
mocks.apiKey.getById.mockResolvedValue(apiKey);
|
||||
mocks.apiKey.delete.mockResolvedValue();
|
||||
|
||||
await sut.delete(auth, apiKey.id);
|
||||
|
||||
@ -113,6 +118,8 @@ describe(ApiKeyService.name, () => {
|
||||
const auth = factory.auth();
|
||||
const id = newUuid();
|
||||
|
||||
mocks.apiKey.getById.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.getById(auth, id)).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.apiKey.getById).toHaveBeenCalledWith(auth.user.id, id);
|
||||
|
@ -127,8 +127,11 @@ describe(AssetService.name, () => {
|
||||
|
||||
describe('getRandom', () => {
|
||||
it('should get own random assets', async () => {
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
mocks.asset.getRandom.mockResolvedValue([assetStub.image]);
|
||||
|
||||
await sut.getRandom(authStub.admin, 1);
|
||||
|
||||
expect(mocks.asset.getRandom).toHaveBeenCalledWith([authStub.admin.user.id], 1);
|
||||
});
|
||||
|
||||
@ -531,6 +534,7 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should update stack primary asset if deleted asset was primary asset in a stack', async () => {
|
||||
mocks.stack.update.mockResolvedValue(factory.stack() as unknown as any);
|
||||
mocks.asset.getById.mockResolvedValue(assetStub.primaryImage as AssetEntity);
|
||||
|
||||
await sut.handleAssetDeletion({ id: assetStub.primaryImage.id, deleteOnDisk: true });
|
||||
@ -542,6 +546,7 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should delete the entire stack if deleted asset was the primary asset and the stack would only contain one asset afterwards', async () => {
|
||||
mocks.stack.delete.mockResolvedValue();
|
||||
mocks.asset.getById.mockResolvedValue({
|
||||
...assetStub.primaryImage,
|
||||
stack: { ...assetStub.primaryImage.stack, assets: assetStub.primaryImage.stack!.assets.slice(0, 2) },
|
||||
|
@ -18,7 +18,10 @@ describe(AuditService.name, () => {
|
||||
|
||||
describe('handleCleanup', () => {
|
||||
it('should delete old audit entries', async () => {
|
||||
mocks.audit.removeBefore.mockResolvedValue();
|
||||
|
||||
await expect(sut.handleCleanup()).resolves.toBe(JobStatus.SUCCESS);
|
||||
|
||||
expect(mocks.audit.removeBefore).toHaveBeenCalledWith(expect.any(Date));
|
||||
});
|
||||
});
|
||||
|
@ -65,7 +65,10 @@ describe('AuthService', () => {
|
||||
|
||||
describe('onBootstrap', () => {
|
||||
it('should init the repo', () => {
|
||||
mocks.oauth.init.mockResolvedValue();
|
||||
|
||||
sut.onBootstrap();
|
||||
|
||||
expect(mocks.oauth.init).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@ -73,24 +76,30 @@ describe('AuthService', () => {
|
||||
describe('login', () => {
|
||||
it('should throw an error if password login is disabled', async () => {
|
||||
mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.disabled);
|
||||
|
||||
await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(UnauthorizedException);
|
||||
});
|
||||
|
||||
it('should check the user exists', async () => {
|
||||
mocks.user.getByEmail.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(UnauthorizedException);
|
||||
|
||||
expect(mocks.user.getByEmail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should check the user has a password', async () => {
|
||||
mocks.user.getByEmail.mockResolvedValue({} as UserEntity);
|
||||
|
||||
await expect(sut.login(fixtures.login, loginDetails)).rejects.toBeInstanceOf(UnauthorizedException);
|
||||
|
||||
expect(mocks.user.getByEmail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should successfully log the user in', async () => {
|
||||
mocks.user.getByEmail.mockResolvedValue(userStub.user1);
|
||||
mocks.session.create.mockResolvedValue(sessionStub.valid);
|
||||
|
||||
await expect(sut.login(fixtures.login, loginDetails)).resolves.toEqual({
|
||||
accessToken: 'cmFuZG9tLWJ5dGVz',
|
||||
userId: 'user-id',
|
||||
@ -100,6 +109,7 @@ describe('AuthService', () => {
|
||||
isAdmin: false,
|
||||
shouldChangePassword: false,
|
||||
});
|
||||
|
||||
expect(mocks.user.getByEmail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@ -159,8 +169,10 @@ describe('AuthService', () => {
|
||||
|
||||
describe('logout', () => {
|
||||
it('should return the end session endpoint', async () => {
|
||||
const auth = factory.auth();
|
||||
|
||||
mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.enabled);
|
||||
const auth = { user: { id: '123' } } as AuthDto;
|
||||
|
||||
await expect(sut.logout(auth, AuthType.OAUTH)).resolves.toEqual({
|
||||
successful: true,
|
||||
redirectUri: 'http://end-session-endpoint',
|
||||
@ -168,7 +180,7 @@ describe('AuthService', () => {
|
||||
});
|
||||
|
||||
it('should return the default redirect', async () => {
|
||||
const auth = { user: { id: '123' } } as AuthDto;
|
||||
const auth = factory.auth();
|
||||
|
||||
await expect(sut.logout(auth, AuthType.PASSWORD)).resolves.toEqual({
|
||||
successful: true,
|
||||
@ -178,6 +190,7 @@ describe('AuthService', () => {
|
||||
|
||||
it('should delete the access token', async () => {
|
||||
const auth = { user: { id: '123' }, session: { id: 'token123' } } as AuthDto;
|
||||
mocks.session.delete.mockResolvedValue();
|
||||
|
||||
await expect(sut.logout(auth, AuthType.PASSWORD)).resolves.toEqual({
|
||||
successful: true,
|
||||
@ -203,7 +216,9 @@ describe('AuthService', () => {
|
||||
|
||||
it('should only allow one admin', async () => {
|
||||
mocks.user.getAdmin.mockResolvedValue({} as UserEntity);
|
||||
|
||||
await expect(sut.adminSignUp(dto)).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.user.getAdmin).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -215,6 +230,7 @@ describe('AuthService', () => {
|
||||
createdAt: new Date('2021-01-01'),
|
||||
metadata: [] as UserMetadataEntity[],
|
||||
} as UserEntity);
|
||||
|
||||
await expect(sut.adminSignUp(dto)).resolves.toMatchObject({
|
||||
avatarColor: expect.any(String),
|
||||
id: 'admin',
|
||||
@ -222,6 +238,7 @@ describe('AuthService', () => {
|
||||
email: 'test@immich.com',
|
||||
name: 'immich admin',
|
||||
});
|
||||
|
||||
expect(mocks.user.getAdmin).toHaveBeenCalled();
|
||||
expect(mocks.user.create).toHaveBeenCalled();
|
||||
});
|
||||
@ -241,6 +258,7 @@ describe('AuthService', () => {
|
||||
it('should validate using authorization header', async () => {
|
||||
mocks.user.get.mockResolvedValue(userStub.user1);
|
||||
mocks.session.getByToken.mockResolvedValue(sessionStub.valid as any);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { authorization: 'Bearer auth_token' },
|
||||
@ -256,6 +274,8 @@ describe('AuthService', () => {
|
||||
|
||||
describe('validate - shared key', () => {
|
||||
it('should not accept a non-existent key', async () => {
|
||||
mocks.sharedLink.getByKey.mockResolvedValue(void 0);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-immich-share-key': 'key' },
|
||||
@ -267,6 +287,7 @@ describe('AuthService', () => {
|
||||
|
||||
it('should not accept an expired key', async () => {
|
||||
mocks.sharedLink.getByKey.mockResolvedValue(sharedLinkStub.expired);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-immich-share-key': 'key' },
|
||||
@ -278,6 +299,7 @@ describe('AuthService', () => {
|
||||
|
||||
it('should not accept a key on a non-shared route', async () => {
|
||||
mocks.sharedLink.getByKey.mockResolvedValue(sharedLinkStub.valid);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-immich-share-key': 'key' },
|
||||
@ -290,6 +312,7 @@ describe('AuthService', () => {
|
||||
it('should not accept a key without a user', async () => {
|
||||
mocks.sharedLink.getByKey.mockResolvedValue(sharedLinkStub.expired);
|
||||
mocks.user.get.mockResolvedValue(void 0);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-immich-share-key': 'key' },
|
||||
@ -302,6 +325,7 @@ describe('AuthService', () => {
|
||||
it('should accept a base64url key', async () => {
|
||||
mocks.sharedLink.getByKey.mockResolvedValue(sharedLinkStub.valid);
|
||||
mocks.user.get.mockResolvedValue(userStub.admin);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-immich-share-key': sharedLinkStub.valid.key.toString('base64url') },
|
||||
@ -318,6 +342,7 @@ describe('AuthService', () => {
|
||||
it('should accept a hex key', async () => {
|
||||
mocks.sharedLink.getByKey.mockResolvedValue(sharedLinkStub.valid);
|
||||
mocks.user.get.mockResolvedValue(userStub.admin);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-immich-share-key': sharedLinkStub.valid.key.toString('hex') },
|
||||
@ -335,6 +360,7 @@ describe('AuthService', () => {
|
||||
describe('validate - user token', () => {
|
||||
it('should throw if no token is found', async () => {
|
||||
mocks.session.getByToken.mockResolvedValue(void 0);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-immich-user-token': 'auth_token' },
|
||||
@ -346,6 +372,7 @@ describe('AuthService', () => {
|
||||
|
||||
it('should return an auth dto', async () => {
|
||||
mocks.session.getByToken.mockResolvedValue(sessionStub.valid as any);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { cookie: 'immich_access_token=auth_token' },
|
||||
@ -360,6 +387,7 @@ describe('AuthService', () => {
|
||||
|
||||
it('should throw if admin route and not an admin', async () => {
|
||||
mocks.session.getByToken.mockResolvedValue(sessionStub.valid as any);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { cookie: 'immich_access_token=auth_token' },
|
||||
@ -372,6 +400,7 @@ describe('AuthService', () => {
|
||||
it('should update when access time exceeds an hour', async () => {
|
||||
mocks.session.getByToken.mockResolvedValue(sessionStub.inactive as any);
|
||||
mocks.session.update.mockResolvedValue(sessionStub.valid);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { cookie: 'immich_access_token=auth_token' },
|
||||
@ -386,6 +415,7 @@ describe('AuthService', () => {
|
||||
describe('validate - api key', () => {
|
||||
it('should throw an error if no api key is found', async () => {
|
||||
mocks.apiKey.getKey.mockResolvedValue(void 0);
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-api-key': 'auth_token' },
|
||||
@ -401,6 +431,7 @@ describe('AuthService', () => {
|
||||
const authApiKey = factory.authApiKey({ permissions: [] });
|
||||
|
||||
mocks.apiKey.getKey.mockResolvedValue({ ...authApiKey, user: authUser });
|
||||
|
||||
await expect(
|
||||
sut.authenticate({
|
||||
headers: { 'x-api-key': 'auth_token' },
|
||||
@ -442,6 +473,7 @@ describe('AuthService', () => {
|
||||
describe('authorize', () => {
|
||||
it('should fail if oauth is disabled', async () => {
|
||||
mocks.systemMetadata.get.mockResolvedValue({ oauth: { enabled: false } });
|
||||
|
||||
await expect(sut.authorize({ redirectUri: 'https://demo.immich.app' })).rejects.toBeInstanceOf(
|
||||
BadRequestException,
|
||||
);
|
||||
@ -449,6 +481,7 @@ describe('AuthService', () => {
|
||||
|
||||
it('should authorize the user', async () => {
|
||||
mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.oauthWithMobileOverride);
|
||||
|
||||
await sut.authorize({ redirectUri: 'https://demo.immich.app' });
|
||||
});
|
||||
});
|
||||
@ -461,9 +494,11 @@ describe('AuthService', () => {
|
||||
it('should not allow auto registering', async () => {
|
||||
mocks.systemMetadata.get.mockResolvedValue(systemConfigStub.oauthEnabled);
|
||||
mocks.user.getByEmail.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).rejects.toBeInstanceOf(
|
||||
BadRequestException,
|
||||
);
|
||||
|
||||
expect(mocks.user.getByEmail).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@ -540,6 +575,7 @@ describe('AuthService', () => {
|
||||
mocks.session.create.mockResolvedValue(sessionStub.valid);
|
||||
|
||||
await sut.callback({ url }, loginDetails);
|
||||
|
||||
expect(mocks.oauth.getProfile).toHaveBeenCalledWith(expect.objectContaining({}), url, 'http://mobile-redirect');
|
||||
});
|
||||
}
|
||||
@ -549,6 +585,7 @@ describe('AuthService', () => {
|
||||
mocks.user.getByEmail.mockResolvedValue(void 0);
|
||||
mocks.user.getAdmin.mockResolvedValue(userStub.user1);
|
||||
mocks.user.create.mockResolvedValue(userStub.user1);
|
||||
mocks.session.create.mockResolvedValue(factory.session());
|
||||
|
||||
await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).resolves.toEqual(
|
||||
oauthResponse,
|
||||
@ -563,6 +600,7 @@ describe('AuthService', () => {
|
||||
mocks.user.getAdmin.mockResolvedValue(userStub.user1);
|
||||
mocks.user.create.mockResolvedValue(userStub.user1);
|
||||
mocks.oauth.getProfile.mockResolvedValue({ sub, email, immich_quota: 'abc' });
|
||||
mocks.session.create.mockResolvedValue(factory.session());
|
||||
|
||||
await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).resolves.toEqual(
|
||||
oauthResponse,
|
||||
@ -577,6 +615,7 @@ describe('AuthService', () => {
|
||||
mocks.user.getAdmin.mockResolvedValue(userStub.user1);
|
||||
mocks.user.create.mockResolvedValue(userStub.user1);
|
||||
mocks.oauth.getProfile.mockResolvedValue({ sub, email, immich_quota: -5 });
|
||||
mocks.session.create.mockResolvedValue(factory.session());
|
||||
|
||||
await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).resolves.toEqual(
|
||||
oauthResponse,
|
||||
@ -591,6 +630,7 @@ describe('AuthService', () => {
|
||||
mocks.user.getAdmin.mockResolvedValue(userStub.user1);
|
||||
mocks.user.create.mockResolvedValue(userStub.user1);
|
||||
mocks.oauth.getProfile.mockResolvedValue({ sub, email, immich_quota: 0 });
|
||||
mocks.session.create.mockResolvedValue(factory.session());
|
||||
|
||||
await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).resolves.toEqual(
|
||||
oauthResponse,
|
||||
@ -611,6 +651,7 @@ describe('AuthService', () => {
|
||||
mocks.user.getAdmin.mockResolvedValue(userStub.user1);
|
||||
mocks.user.create.mockResolvedValue(userStub.user1);
|
||||
mocks.oauth.getProfile.mockResolvedValue({ sub, email, immich_quota: 5 });
|
||||
mocks.session.create.mockResolvedValue(factory.session());
|
||||
|
||||
await expect(sut.callback({ url: 'http://immich/auth/login?code=abc123' }, loginDetails)).resolves.toEqual(
|
||||
oauthResponse,
|
||||
|
@ -22,6 +22,7 @@ describe(BackupService.name, () => {
|
||||
describe('onBootstrapEvent', () => {
|
||||
it('should init cron job and handle config changes', async () => {
|
||||
mocks.database.tryLock.mockResolvedValue(true);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.backupEnabled as SystemConfig });
|
||||
|
||||
@ -47,10 +48,14 @@ describe(BackupService.name, () => {
|
||||
describe('onConfigUpdateEvent', () => {
|
||||
beforeEach(async () => {
|
||||
mocks.database.tryLock.mockResolvedValue(true);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: defaults });
|
||||
});
|
||||
|
||||
it('should update cron job if backup is enabled', () => {
|
||||
mocks.cron.update.mockResolvedValue();
|
||||
|
||||
sut.onConfigUpdate({
|
||||
oldConfig: defaults,
|
||||
newConfig: {
|
||||
|
@ -31,6 +31,8 @@ describe(CliService.name, () => {
|
||||
|
||||
it('should default to a random password', async () => {
|
||||
mocks.user.getAdmin.mockResolvedValue(userStub.admin);
|
||||
mocks.user.update.mockResolvedValue(userStub.admin);
|
||||
|
||||
const ask = vitest.fn().mockImplementation(() => {});
|
||||
|
||||
const response = await sut.resetAdminPassword(ask);
|
||||
@ -45,6 +47,8 @@ describe(CliService.name, () => {
|
||||
|
||||
it('should use the supplied password', async () => {
|
||||
mocks.user.getAdmin.mockResolvedValue(userStub.admin);
|
||||
mocks.user.update.mockResolvedValue(userStub.admin);
|
||||
|
||||
const ask = vitest.fn().mockResolvedValue('new-password');
|
||||
|
||||
const response = await sut.resetAdminPassword(ask);
|
||||
|
@ -173,6 +173,7 @@ describe(DownloadService.name, () => {
|
||||
it('should return a list of archives (assetIds)', async () => {
|
||||
const assetIds = ['asset-1', 'asset-2'];
|
||||
|
||||
mocks.user.getMetadata.mockResolvedValue([]);
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(assetIds));
|
||||
mocks.downloadRepository.downloadAssetIds.mockReturnValue(
|
||||
makeStream([
|
||||
@ -187,6 +188,7 @@ describe(DownloadService.name, () => {
|
||||
});
|
||||
|
||||
it('should return a list of archives (albumId)', async () => {
|
||||
mocks.user.getMetadata.mockResolvedValue([]);
|
||||
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set(['album-1']));
|
||||
mocks.downloadRepository.downloadAlbumId.mockReturnValue(
|
||||
makeStream([
|
||||
@ -202,6 +204,7 @@ describe(DownloadService.name, () => {
|
||||
});
|
||||
|
||||
it('should return a list of archives (userId)', async () => {
|
||||
mocks.user.getMetadata.mockResolvedValue([]);
|
||||
mocks.downloadRepository.downloadUserId.mockReturnValue(
|
||||
makeStream([
|
||||
{ id: 'asset-1', livePhotoVideoId: null, size: 100_000 },
|
||||
@ -217,6 +220,7 @@ describe(DownloadService.name, () => {
|
||||
});
|
||||
|
||||
it('should split archives by size', async () => {
|
||||
mocks.user.getMetadata.mockResolvedValue([]);
|
||||
mocks.downloadRepository.downloadUserId.mockReturnValue(
|
||||
makeStream([
|
||||
{ id: 'asset-1', livePhotoVideoId: null, size: 5000 },
|
||||
@ -244,13 +248,13 @@ describe(DownloadService.name, () => {
|
||||
const assetIds = ['asset-1', 'asset-2'];
|
||||
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(assetIds));
|
||||
mocks.user.getMetadata.mockResolvedValue([]);
|
||||
mocks.downloadRepository.downloadAssetIds.mockReturnValue(
|
||||
makeStream([
|
||||
{ id: 'asset-1', livePhotoVideoId: 'asset-3', size: 5000 },
|
||||
{ id: 'asset-2', livePhotoVideoId: 'asset-4', size: 100_000 },
|
||||
]),
|
||||
);
|
||||
|
||||
mocks.downloadRepository.downloadMotionAssetIds.mockReturnValue(
|
||||
makeStream([
|
||||
{ id: 'asset-3', livePhotoVideoId: null, size: 23_456, originalPath: '/path/to/file.mp4' },
|
||||
@ -271,11 +275,10 @@ describe(DownloadService.name, () => {
|
||||
const assetIds = ['asset-1'];
|
||||
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(assetIds));
|
||||
|
||||
mocks.user.getMetadata.mockResolvedValue([]);
|
||||
mocks.downloadRepository.downloadAssetIds.mockReturnValue(
|
||||
makeStream([{ id: 'asset-1', livePhotoVideoId: 'asset-3', size: 5000 }]),
|
||||
);
|
||||
|
||||
mocks.downloadRepository.downloadMotionAssetIds.mockReturnValue(
|
||||
makeStream([
|
||||
{ id: 'asset-2', livePhotoVideoId: null, size: 23_456, originalPath: 'upload/encoded-video/uuid-MP.mp4' },
|
||||
|
@ -36,6 +36,9 @@ describe(LibraryService.name, () => {
|
||||
|
||||
describe('onConfigInit', () => {
|
||||
it('should init cron job and handle config changes', async () => {
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
mocks.cron.update.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: defaults });
|
||||
|
||||
expect(mocks.cron.create).toHaveBeenCalled();
|
||||
@ -65,6 +68,7 @@ describe(LibraryService.name, () => {
|
||||
mocks.library.get.mockImplementation((id) =>
|
||||
Promise.resolve([library1, library2].find((library) => library.id === id)),
|
||||
);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
|
||||
|
||||
@ -74,6 +78,8 @@ describe(LibraryService.name, () => {
|
||||
});
|
||||
|
||||
it('should not initialize watcher when watching is disabled', async () => {
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchDisabled as SystemConfig });
|
||||
|
||||
expect(mocks.storage.watch).not.toHaveBeenCalled();
|
||||
@ -99,6 +105,8 @@ describe(LibraryService.name, () => {
|
||||
describe('onConfigUpdateEvent', () => {
|
||||
beforeEach(async () => {
|
||||
mocks.database.tryLock.mockResolvedValue(true);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: defaults });
|
||||
});
|
||||
|
||||
@ -111,6 +119,9 @@ describe(LibraryService.name, () => {
|
||||
|
||||
it('should update cron job and enable watching', async () => {
|
||||
mocks.library.getAll.mockResolvedValue([]);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
mocks.cron.update.mockResolvedValue();
|
||||
|
||||
await sut.onConfigUpdate({
|
||||
newConfig: systemConfigStub.libraryScanAndWatch as SystemConfig,
|
||||
oldConfig: defaults,
|
||||
@ -125,6 +136,9 @@ describe(LibraryService.name, () => {
|
||||
|
||||
it('should update cron job and disable watching', async () => {
|
||||
mocks.library.getAll.mockResolvedValue([]);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
mocks.cron.update.mockResolvedValue();
|
||||
|
||||
await sut.onConfigUpdate({
|
||||
newConfig: systemConfigStub.libraryScanAndWatch as SystemConfig,
|
||||
oldConfig: defaults,
|
||||
@ -620,6 +634,7 @@ describe(LibraryService.name, () => {
|
||||
|
||||
const mockClose = vitest.fn();
|
||||
mocks.storage.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
|
||||
await sut.delete(library.id);
|
||||
@ -765,6 +780,7 @@ describe(LibraryService.name, () => {
|
||||
mocks.library.create.mockResolvedValue(library);
|
||||
mocks.library.get.mockResolvedValue(library);
|
||||
mocks.library.getAll.mockResolvedValue([]);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
|
||||
await sut.create({ ownerId: authStub.admin.user.id, importPaths: library.importPaths });
|
||||
@ -832,6 +848,7 @@ describe(LibraryService.name, () => {
|
||||
describe('update', () => {
|
||||
beforeEach(async () => {
|
||||
mocks.library.getAll.mockResolvedValue([]);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
|
||||
});
|
||||
@ -878,6 +895,8 @@ describe(LibraryService.name, () => {
|
||||
|
||||
describe('watching disabled', () => {
|
||||
beforeEach(async () => {
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchDisabled as SystemConfig });
|
||||
});
|
||||
|
||||
@ -895,6 +914,8 @@ describe(LibraryService.name, () => {
|
||||
describe('watching enabled', () => {
|
||||
beforeEach(async () => {
|
||||
mocks.library.getAll.mockResolvedValue([]);
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
|
||||
});
|
||||
|
||||
@ -1067,6 +1088,7 @@ describe(LibraryService.name, () => {
|
||||
|
||||
const mockClose = vitest.fn();
|
||||
mocks.storage.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
|
||||
mocks.cron.create.mockResolvedValue();
|
||||
|
||||
await sut.onConfigInit({ newConfig: systemConfigStub.libraryWatchEnabled as SystemConfig });
|
||||
await sut.onShutdown();
|
||||
|
@ -33,6 +33,8 @@ describe(MemoryService.name, () => {
|
||||
});
|
||||
|
||||
it('should map ', async () => {
|
||||
mocks.memory.search.mockResolvedValue([]);
|
||||
|
||||
await expect(sut.search(factory.auth(), {})).resolves.toEqual([]);
|
||||
});
|
||||
});
|
||||
@ -46,6 +48,7 @@ describe(MemoryService.name, () => {
|
||||
const [memoryId] = newUuids();
|
||||
|
||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memoryId]));
|
||||
mocks.memory.get.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.get(factory.auth(), memoryId)).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
@ -159,6 +162,7 @@ describe(MemoryService.name, () => {
|
||||
const memoryId = newUuid();
|
||||
|
||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memoryId]));
|
||||
mocks.memory.delete.mockResolvedValue();
|
||||
|
||||
await expect(sut.remove(factory.auth(), memoryId)).resolves.toBeUndefined();
|
||||
|
||||
@ -183,6 +187,7 @@ describe(MemoryService.name, () => {
|
||||
|
||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||
mocks.memory.get.mockResolvedValue(memory);
|
||||
mocks.memory.getAssetIds.mockResolvedValue(new Set());
|
||||
|
||||
await expect(sut.addAssets(factory.auth(), memory.id, { ids: [assetId] })).resolves.toEqual([
|
||||
{ error: 'no_permission', id: assetId, success: false },
|
||||
@ -213,6 +218,9 @@ describe(MemoryService.name, () => {
|
||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set([assetId]));
|
||||
mocks.memory.get.mockResolvedValue(memory);
|
||||
mocks.memory.update.mockResolvedValue(memory);
|
||||
mocks.memory.getAssetIds.mockResolvedValue(new Set());
|
||||
mocks.memory.addAssetIds.mockResolvedValue();
|
||||
|
||||
await expect(sut.addAssets(factory.auth(), memory.id, { ids: [assetId] })).resolves.toEqual([
|
||||
{ id: assetId, success: true },
|
||||
@ -233,6 +241,7 @@ describe(MemoryService.name, () => {
|
||||
|
||||
it('should skip assets not in the memory', async () => {
|
||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
||||
mocks.memory.getAssetIds.mockResolvedValue(new Set());
|
||||
|
||||
await expect(sut.removeAssets(factory.auth(), 'memory1', { ids: ['not-found'] })).resolves.toEqual([
|
||||
{ error: 'not_found', id: 'not-found', success: false },
|
||||
@ -242,15 +251,20 @@ describe(MemoryService.name, () => {
|
||||
});
|
||||
|
||||
it('should remove assets', async () => {
|
||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1']));
|
||||
mocks.memory.getAssetIds.mockResolvedValue(new Set(['asset1']));
|
||||
const memory = factory.memory();
|
||||
const asset = factory.asset();
|
||||
|
||||
await expect(sut.removeAssets(factory.auth(), 'memory1', { ids: ['asset1'] })).resolves.toEqual([
|
||||
{ id: 'asset1', success: true },
|
||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set([asset.id]));
|
||||
mocks.memory.getAssetIds.mockResolvedValue(new Set([asset.id]));
|
||||
mocks.memory.removeAssetIds.mockResolvedValue();
|
||||
mocks.memory.update.mockResolvedValue(memory);
|
||||
|
||||
await expect(sut.removeAssets(factory.auth(), memory.id, { ids: [asset.id] })).resolves.toEqual([
|
||||
{ id: asset.id, success: true },
|
||||
]);
|
||||
|
||||
expect(mocks.memory.removeAssetIds).toHaveBeenCalledWith('memory1', ['asset1']);
|
||||
expect(mocks.memory.removeAssetIds).toHaveBeenCalledWith(memory.id, [asset.id]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -52,6 +52,10 @@ describe(MetadataService.name, () => {
|
||||
|
||||
describe('onBootstrapEvent', () => {
|
||||
it('should pause and resume queue during init', async () => {
|
||||
mocks.job.pause.mockResolvedValue();
|
||||
mocks.map.init.mockResolvedValue();
|
||||
mocks.job.resume.mockResolvedValue();
|
||||
|
||||
await sut.onBootstrap();
|
||||
|
||||
expect(mocks.job.pause).toHaveBeenCalledTimes(1);
|
||||
|
@ -260,6 +260,7 @@ describe(NotificationService.name, () => {
|
||||
mocks.user.get.mockResolvedValue(userStub.admin);
|
||||
mocks.notification.verifySmtp.mockResolvedValue(true);
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.notification.sendEmail.mockResolvedValue({ messageId: 'message-1', response: '' });
|
||||
|
||||
await expect(sut.sendTestEmail('', configs.smtpTransport.notifications.smtp)).resolves.not.toThrow();
|
||||
expect(mocks.notification.renderEmail).toHaveBeenCalledWith({
|
||||
@ -279,6 +280,7 @@ describe(NotificationService.name, () => {
|
||||
mocks.notification.verifySmtp.mockResolvedValue(true);
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.systemMetadata.get.mockResolvedValue({ server: { externalDomain: 'https://demo.immich.app' } });
|
||||
mocks.notification.sendEmail.mockResolvedValue({ messageId: 'message-1', response: '' });
|
||||
|
||||
await expect(sut.sendTestEmail('', configs.smtpTransport.notifications.smtp)).resolves.not.toThrow();
|
||||
expect(mocks.notification.renderEmail).toHaveBeenCalledWith({
|
||||
@ -297,6 +299,7 @@ describe(NotificationService.name, () => {
|
||||
mocks.user.get.mockResolvedValue(userStub.admin);
|
||||
mocks.notification.verifySmtp.mockResolvedValue(true);
|
||||
mocks.notification.renderEmail.mockResolvedValue({ html: '', text: '' });
|
||||
mocks.notification.sendEmail.mockResolvedValue({ messageId: 'message-1', response: '' });
|
||||
|
||||
await expect(
|
||||
sut.sendTestEmail('', { ...configs.smtpTransport.notifications.smtp, replyTo: 'demo@immich.app' }),
|
||||
|
@ -324,6 +324,10 @@ describe(PersonService.name, () => {
|
||||
mocks.person.getFacesByIds.mockResolvedValue([faceStub.face1]);
|
||||
mocks.person.reassignFace.mockResolvedValue(1);
|
||||
mocks.person.getRandomFace.mockResolvedValue(faceStub.primaryFace1);
|
||||
mocks.person.refreshFaces.mockResolvedValue();
|
||||
mocks.person.reassignFace.mockResolvedValue(5);
|
||||
mocks.person.update.mockResolvedValue(personStub.noName);
|
||||
|
||||
await expect(
|
||||
sut.reassignFaces(authStub.admin, personStub.noName.id, {
|
||||
data: [{ personId: personStub.withName.id, assetId: assetStub.image.id }],
|
||||
@ -515,6 +519,7 @@ describe(PersonService.name, () => {
|
||||
hasNextPage: false,
|
||||
});
|
||||
mocks.person.getAllWithoutFaces.mockResolvedValue([personStub.randomPerson]);
|
||||
mocks.person.deleteFaces.mockResolvedValue();
|
||||
|
||||
await sut.handleQueueDetectFaces({ force: true });
|
||||
|
||||
@ -633,6 +638,7 @@ describe(PersonService.name, () => {
|
||||
mocks.person.getAll.mockReturnValue(makeStream());
|
||||
mocks.person.getAllFaces.mockReturnValue(makeStream([faceStub.face1]));
|
||||
mocks.person.getAllWithoutFaces.mockResolvedValue([]);
|
||||
mocks.person.unassignFaces.mockResolvedValue();
|
||||
|
||||
await sut.handleQueueRecognizeFaces({ force: true, nightly: true });
|
||||
|
||||
@ -679,6 +685,7 @@ describe(PersonService.name, () => {
|
||||
mocks.person.getAll.mockReturnValue(makeStream([faceStub.face1.person, personStub.randomPerson]));
|
||||
mocks.person.getAllFaces.mockReturnValue(makeStream([faceStub.face1]));
|
||||
mocks.person.getAllWithoutFaces.mockResolvedValue([personStub.randomPerson]);
|
||||
mocks.person.unassignFaces.mockResolvedValue();
|
||||
|
||||
await sut.handleQueueRecognizeFaces({ force: true });
|
||||
|
||||
@ -757,6 +764,7 @@ describe(PersonService.name, () => {
|
||||
mocks.machineLearning.detectFaces.mockResolvedValue(detectFaceMock);
|
||||
mocks.search.searchFaces.mockResolvedValue([{ ...faceStub.face1, distance: 0.7 }]);
|
||||
mocks.asset.getByIds.mockResolvedValue([assetStub.image]);
|
||||
mocks.person.refreshFaces.mockResolvedValue();
|
||||
|
||||
await sut.handleDetectFaces({ id: assetStub.image.id });
|
||||
|
||||
@ -784,6 +792,7 @@ describe(PersonService.name, () => {
|
||||
it('should add new face and delete an existing face not among the new detected faces', async () => {
|
||||
mocks.machineLearning.detectFaces.mockResolvedValue(detectFaceMock);
|
||||
mocks.asset.getByIds.mockResolvedValue([{ ...assetStub.image, faces: [faceStub.primaryFace1] }]);
|
||||
mocks.person.refreshFaces.mockResolvedValue();
|
||||
|
||||
await sut.handleDetectFaces({ id: assetStub.image.id });
|
||||
|
||||
@ -799,6 +808,7 @@ describe(PersonService.name, () => {
|
||||
it('should add embedding to matching metadata face', async () => {
|
||||
mocks.machineLearning.detectFaces.mockResolvedValue(detectFaceMock);
|
||||
mocks.asset.getByIds.mockResolvedValue([{ ...assetStub.image, faces: [faceStub.fromExif1] }]);
|
||||
mocks.person.refreshFaces.mockResolvedValue();
|
||||
|
||||
await sut.handleDetectFaces({ id: assetStub.image.id });
|
||||
|
||||
@ -1006,6 +1016,7 @@ describe(PersonService.name, () => {
|
||||
mocks.person.getById.mockResolvedValue({ ...personStub.primaryPerson, faceAssetId: faceStub.middle.assetId });
|
||||
mocks.person.getFaceByIdWithAssets.mockResolvedValue(faceStub.middle);
|
||||
mocks.asset.getById.mockResolvedValue(assetStub.primaryImage);
|
||||
mocks.media.generateThumbnail.mockResolvedValue();
|
||||
|
||||
await sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id });
|
||||
|
||||
@ -1038,6 +1049,7 @@ describe(PersonService.name, () => {
|
||||
mocks.person.getById.mockResolvedValue({ ...personStub.primaryPerson, faceAssetId: faceStub.start.assetId });
|
||||
mocks.person.getFaceByIdWithAssets.mockResolvedValue(faceStub.start);
|
||||
mocks.asset.getById.mockResolvedValue(assetStub.image);
|
||||
mocks.media.generateThumbnail.mockResolvedValue();
|
||||
|
||||
await sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id });
|
||||
|
||||
@ -1063,7 +1075,9 @@ describe(PersonService.name, () => {
|
||||
it('should generate a thumbnail without overflowing', async () => {
|
||||
mocks.person.getById.mockResolvedValue({ ...personStub.primaryPerson, faceAssetId: faceStub.end.assetId });
|
||||
mocks.person.getFaceByIdWithAssets.mockResolvedValue(faceStub.end);
|
||||
mocks.person.update.mockResolvedValue(personStub.primaryPerson);
|
||||
mocks.asset.getById.mockResolvedValue(assetStub.primaryImage);
|
||||
mocks.media.generateThumbnail.mockResolvedValue();
|
||||
|
||||
await sut.handleGeneratePersonThumbnail({ id: personStub.primaryPerson.id });
|
||||
|
||||
|
@ -57,6 +57,8 @@ describe(SearchService.name, () => {
|
||||
describe('getSearchSuggestions', () => {
|
||||
it('should return search suggestions for country', async () => {
|
||||
mocks.search.getCountries.mockResolvedValue(['USA']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: false, type: SearchSuggestionType.COUNTRY }),
|
||||
).resolves.toEqual(['USA']);
|
||||
@ -65,6 +67,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for country (including null)', async () => {
|
||||
mocks.search.getCountries.mockResolvedValue(['USA']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: true, type: SearchSuggestionType.COUNTRY }),
|
||||
).resolves.toEqual(['USA', null]);
|
||||
@ -73,6 +77,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for state', async () => {
|
||||
mocks.search.getStates.mockResolvedValue(['California']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: false, type: SearchSuggestionType.STATE }),
|
||||
).resolves.toEqual(['California']);
|
||||
@ -81,6 +87,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for state (including null)', async () => {
|
||||
mocks.search.getStates.mockResolvedValue(['California']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: true, type: SearchSuggestionType.STATE }),
|
||||
).resolves.toEqual(['California', null]);
|
||||
@ -89,6 +97,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for city', async () => {
|
||||
mocks.search.getCities.mockResolvedValue(['Denver']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: false, type: SearchSuggestionType.CITY }),
|
||||
).resolves.toEqual(['Denver']);
|
||||
@ -97,6 +107,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for city (including null)', async () => {
|
||||
mocks.search.getCities.mockResolvedValue(['Denver']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: true, type: SearchSuggestionType.CITY }),
|
||||
).resolves.toEqual(['Denver', null]);
|
||||
@ -105,6 +117,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for camera make', async () => {
|
||||
mocks.search.getCameraMakes.mockResolvedValue(['Nikon']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: false, type: SearchSuggestionType.CAMERA_MAKE }),
|
||||
).resolves.toEqual(['Nikon']);
|
||||
@ -113,6 +127,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for camera make (including null)', async () => {
|
||||
mocks.search.getCameraMakes.mockResolvedValue(['Nikon']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: true, type: SearchSuggestionType.CAMERA_MAKE }),
|
||||
).resolves.toEqual(['Nikon', null]);
|
||||
@ -121,6 +137,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for camera model', async () => {
|
||||
mocks.search.getCameraModels.mockResolvedValue(['Fujifilm X100VI']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: false, type: SearchSuggestionType.CAMERA_MODEL }),
|
||||
).resolves.toEqual(['Fujifilm X100VI']);
|
||||
@ -129,6 +147,8 @@ describe(SearchService.name, () => {
|
||||
|
||||
it('should return search suggestions for camera model (including null)', async () => {
|
||||
mocks.search.getCameraModels.mockResolvedValue(['Fujifilm X100VI']);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getSearchSuggestions(authStub.user1, { includeNull: true, type: SearchSuggestionType.CAMERA_MODEL }),
|
||||
).resolves.toEqual(['Fujifilm X100VI', null]);
|
||||
|
@ -36,6 +36,7 @@ describe('SessionService', () => {
|
||||
updateId: 'uuid-v7',
|
||||
},
|
||||
]);
|
||||
mocks.session.delete.mockResolvedValue();
|
||||
|
||||
await expect(sut.handleCleanup()).resolves.toEqual(JobStatus.SUCCESS);
|
||||
expect(mocks.session.delete).toHaveBeenCalledWith('123');
|
||||
@ -71,6 +72,7 @@ describe('SessionService', () => {
|
||||
describe('logoutDevices', () => {
|
||||
it('should logout all devices', async () => {
|
||||
mocks.session.getByUserId.mockResolvedValue([sessionStub.inactive, sessionStub.valid] as any[]);
|
||||
mocks.session.delete.mockResolvedValue();
|
||||
|
||||
await sut.deleteAll(authStub.user1);
|
||||
|
||||
@ -83,6 +85,7 @@ describe('SessionService', () => {
|
||||
describe('logoutDevice', () => {
|
||||
it('should logout the device', async () => {
|
||||
mocks.access.authDevice.checkOwnerAccess.mockResolvedValue(new Set(['token-1']));
|
||||
mocks.session.delete.mockResolvedValue();
|
||||
|
||||
await sut.delete(authStub.user1, 'token-1');
|
||||
|
||||
|
@ -71,7 +71,10 @@ describe(SharedLinkService.name, () => {
|
||||
|
||||
describe('get', () => {
|
||||
it('should throw an error for an invalid shared link', async () => {
|
||||
mocks.sharedLink.get.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.get(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.sharedLink.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id');
|
||||
expect(mocks.sharedLink.update).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -194,7 +197,10 @@ describe(SharedLinkService.name, () => {
|
||||
|
||||
describe('update', () => {
|
||||
it('should throw an error for an invalid shared link', async () => {
|
||||
mocks.sharedLink.get.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.update(authStub.user1, 'missing-id', {})).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.sharedLink.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id');
|
||||
expect(mocks.sharedLink.update).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -214,14 +220,20 @@ describe(SharedLinkService.name, () => {
|
||||
|
||||
describe('remove', () => {
|
||||
it('should throw an error for an invalid shared link', async () => {
|
||||
mocks.sharedLink.get.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.remove(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(mocks.sharedLink.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id');
|
||||
expect(mocks.sharedLink.update).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should remove a key', async () => {
|
||||
mocks.sharedLink.get.mockResolvedValue(sharedLinkStub.valid);
|
||||
mocks.sharedLink.remove.mockResolvedValue();
|
||||
|
||||
await sut.remove(authStub.user1, sharedLinkStub.valid.id);
|
||||
|
||||
expect(mocks.sharedLink.get).toHaveBeenCalledWith(authStub.user1.user.id, sharedLinkStub.valid.id);
|
||||
expect(mocks.sharedLink.remove).toHaveBeenCalledWith(sharedLinkStub.valid);
|
||||
});
|
||||
@ -238,6 +250,7 @@ describe(SharedLinkService.name, () => {
|
||||
it('should add assets to a shared link', async () => {
|
||||
mocks.sharedLink.get.mockResolvedValue(_.cloneDeep(sharedLinkStub.individual));
|
||||
mocks.sharedLink.create.mockResolvedValue(sharedLinkStub.individual);
|
||||
mocks.sharedLink.update.mockResolvedValue(sharedLinkStub.individual);
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-3']));
|
||||
|
||||
await expect(
|
||||
@ -268,6 +281,7 @@ describe(SharedLinkService.name, () => {
|
||||
it('should remove assets from a shared link', async () => {
|
||||
mocks.sharedLink.get.mockResolvedValue(_.cloneDeep(sharedLinkStub.individual));
|
||||
mocks.sharedLink.create.mockResolvedValue(sharedLinkStub.individual);
|
||||
mocks.sharedLink.update.mockResolvedValue(sharedLinkStub.individual);
|
||||
|
||||
await expect(
|
||||
sut.removeAssets(authStub.admin, 'link-1', { assetIds: [assetStub.image.id, 'asset-2'] }),
|
||||
|
@ -155,6 +155,7 @@ describe(StackService.name, () => {
|
||||
|
||||
it('should delete stack', async () => {
|
||||
mocks.access.stack.checkOwnerAccess.mockResolvedValue(new Set(['stack-id']));
|
||||
mocks.stack.delete.mockResolvedValue();
|
||||
|
||||
await sut.delete(authStub.admin, 'stack-id');
|
||||
|
||||
@ -176,6 +177,7 @@ describe(StackService.name, () => {
|
||||
|
||||
it('should delete all stacks', async () => {
|
||||
mocks.access.stack.checkOwnerAccess.mockResolvedValue(new Set(['stack-id']));
|
||||
mocks.stack.deleteAll.mockResolvedValue();
|
||||
|
||||
await sut.deleteAll(authStub.admin, { ids: ['stack-id'] });
|
||||
|
||||
|
@ -93,7 +93,9 @@ describe(StorageTemplateService.name, () => {
|
||||
describe('handleMigrationSingle', () => {
|
||||
it('should skip when storage template is disabled', async () => {
|
||||
mocks.systemMetadata.get.mockResolvedValue({ storageTemplate: { enabled: false } });
|
||||
|
||||
await expect(sut.handleMigrationSingle({ id: testAsset.id })).resolves.toBe(JobStatus.SKIPPED);
|
||||
|
||||
expect(mocks.asset.getByIds).not.toHaveBeenCalled();
|
||||
expect(mocks.storage.checkFileExists).not.toHaveBeenCalled();
|
||||
expect(mocks.storage.rename).not.toHaveBeenCalled();
|
||||
|
@ -87,9 +87,12 @@ describe(TagService.name, () => {
|
||||
|
||||
it('should create a new tag with optional color', async () => {
|
||||
mocks.tag.create.mockResolvedValue(tagStub.colorCreate);
|
||||
mocks.tag.getByValue.mockResolvedValue(void 0);
|
||||
|
||||
await expect(sut.create(authStub.admin, { name: 'tag-1', color: '#000000' })).resolves.toEqual(
|
||||
tagResponseStub.color1,
|
||||
);
|
||||
|
||||
expect(mocks.tag.create).toHaveBeenCalledWith({
|
||||
userId: authStub.admin.user.id,
|
||||
value: 'tag-1',
|
||||
@ -168,6 +171,8 @@ describe(TagService.name, () => {
|
||||
|
||||
it('should remove a tag', async () => {
|
||||
mocks.tag.get.mockResolvedValue(tagStub.tag);
|
||||
mocks.tag.delete.mockResolvedValue();
|
||||
|
||||
await sut.remove(authStub.admin, 'tag-1');
|
||||
expect(mocks.tag.delete).toHaveBeenCalledWith('tag-1');
|
||||
});
|
||||
@ -223,6 +228,7 @@ describe(TagService.name, () => {
|
||||
it('should accept accept ids that are new and reject the rest', async () => {
|
||||
mocks.tag.get.mockResolvedValue(tagStub.tag);
|
||||
mocks.tag.getAssetIds.mockResolvedValue(new Set(['asset-1']));
|
||||
mocks.tag.addAssetIds.mockResolvedValue();
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-2']));
|
||||
|
||||
await expect(
|
||||
@ -242,6 +248,8 @@ describe(TagService.name, () => {
|
||||
describe('removeAssets', () => {
|
||||
it('should throw an error for an invalid id', async () => {
|
||||
mocks.tag.getAssetIds.mockResolvedValue(new Set());
|
||||
mocks.tag.removeAssetIds.mockResolvedValue();
|
||||
|
||||
await expect(sut.removeAssets(authStub.admin, 'tag-1', { ids: ['asset-1'] })).resolves.toEqual([
|
||||
{ id: 'asset-1', success: false, error: 'not_found' },
|
||||
]);
|
||||
@ -250,6 +258,7 @@ describe(TagService.name, () => {
|
||||
it('should accept accept ids that are tagged and reject the rest', async () => {
|
||||
mocks.tag.get.mockResolvedValue(tagStub.tag);
|
||||
mocks.tag.getAssetIds.mockResolvedValue(new Set(['asset-1']));
|
||||
mocks.tag.removeAssetIds.mockResolvedValue();
|
||||
|
||||
await expect(
|
||||
sut.removeAssets(authStub.admin, 'tag-1', {
|
||||
@ -267,7 +276,10 @@ describe(TagService.name, () => {
|
||||
|
||||
describe('handleTagCleanup', () => {
|
||||
it('should delete empty tags', async () => {
|
||||
mocks.tag.deleteEmptyTags.mockResolvedValue();
|
||||
|
||||
await expect(sut.handleTagCleanup()).resolves.toBe(JobStatus.SUCCESS);
|
||||
|
||||
expect(mocks.tag.deleteEmptyTags).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -70,6 +70,7 @@ describe(TimelineService.name, () => {
|
||||
|
||||
it('should include partner shared assets', async () => {
|
||||
mocks.asset.getTimeBucket.mockResolvedValue([assetStub.image]);
|
||||
mocks.partner.getAll.mockResolvedValue([]);
|
||||
|
||||
await expect(
|
||||
sut.getTimeBucket(authStub.admin, {
|
||||
|
@ -39,6 +39,7 @@ describe(TrashService.name, () => {
|
||||
|
||||
it('should restore a batch of assets', async () => {
|
||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1', 'asset2']));
|
||||
mocks.trash.restoreAll.mockResolvedValue(0);
|
||||
|
||||
await sut.restoreAssets(authStub.user1, { ids: ['asset1', 'asset2'] });
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { serverVersion } from 'src/constants';
|
||||
import { ImmichEnvironment, JobName, JobStatus, SystemMetadataKey } from 'src/enum';
|
||||
import { VersionService } from 'src/services/version.service';
|
||||
import { mockEnvData } from 'test/repositories/config.repository.mock';
|
||||
import { factory } from 'test/small.factory';
|
||||
import { newTestService, ServiceMocks } from 'test/utils';
|
||||
|
||||
const mockRelease = (version: string) => ({
|
||||
@ -30,7 +31,12 @@ describe(VersionService.name, () => {
|
||||
|
||||
describe('onBootstrap', () => {
|
||||
it('should record a new version', async () => {
|
||||
mocks.versionHistory.getAll.mockResolvedValue([]);
|
||||
mocks.versionHistory.getLatest.mockResolvedValue(void 0);
|
||||
mocks.versionHistory.create.mockResolvedValue(factory.versionHistory());
|
||||
|
||||
await expect(sut.onBootstrap()).resolves.toBeUndefined();
|
||||
|
||||
expect(mocks.versionHistory.create).toHaveBeenCalledWith({ version: expect.any(String) });
|
||||
});
|
||||
|
||||
|
@ -34,9 +34,9 @@ import { TrashRepository } from 'src/repositories/trash.repository';
|
||||
import { UserRepository } from 'src/repositories/user.repository';
|
||||
import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
|
||||
import { ViewRepository } from 'src/repositories/view-repository';
|
||||
import { newLoggingRepositoryMock } from 'test/repositories/logger.repository.mock';
|
||||
import { newTelemetryRepositoryMock } from 'test/repositories/telemetry.repository.mock';
|
||||
import { newUuid } from 'test/small.factory';
|
||||
import { automock } from 'test/utils';
|
||||
|
||||
class CustomWritable extends Writable {
|
||||
private data = '';
|
||||
@ -213,7 +213,7 @@ export class TestContext {
|
||||
view: ViewRepository;
|
||||
|
||||
private constructor(public db: Kysely<DB>) {
|
||||
const logger = newLoggingRepositoryMock() as unknown as LoggingRepository;
|
||||
const logger = automock(LoggingRepository, { args: [, { getEnv: () => ({}) }], strict: false });
|
||||
const config = new ConfigRepository();
|
||||
|
||||
this.access = new AccessRepository(this.db);
|
||||
|
@ -3,12 +3,14 @@ import { writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { AssetEntity } from 'src/entities/asset.entity';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { MetadataRepository } from 'src/repositories/metadata.repository';
|
||||
import { MetadataService } from 'src/services/metadata.service';
|
||||
import { newFakeLoggingRepository } from 'test/repositories/logger.repository.mock';
|
||||
import { newRandomImage, newTestService, ServiceMocks } from 'test/utils';
|
||||
import { automock, newRandomImage, newTestService, ServiceMocks } from 'test/utils';
|
||||
|
||||
const metadataRepository = new MetadataRepository(newFakeLoggingRepository());
|
||||
const metadataRepository = new MetadataRepository(
|
||||
automock(LoggingRepository, { args: [, { getEnv: () => ({}) }], strict: false }),
|
||||
);
|
||||
|
||||
const createTestFile = async (exifData: Record<string, any>) => {
|
||||
const data = newRandomImage();
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newActivityRepositoryMock = (): Mocked<RepositoryInterface<ActivityRepository>> => {
|
||||
return {
|
||||
search: vitest.fn(),
|
||||
create: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
getStatistics: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newAlbumUserRepositoryMock = (): Mocked<RepositoryInterface<AlbumUserRepository>> => {
|
||||
return {
|
||||
create: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,25 +0,0 @@
|
||||
import { AlbumRepository } from 'src/repositories/album.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newAlbumRepositoryMock = (): Mocked<RepositoryInterface<AlbumRepository>> => {
|
||||
return {
|
||||
getById: vitest.fn(),
|
||||
getByAssetId: vitest.fn(),
|
||||
getMetadataForIds: vitest.fn(),
|
||||
getOwned: vitest.fn(),
|
||||
getShared: vitest.fn(),
|
||||
getNotShared: vitest.fn(),
|
||||
restoreAll: vitest.fn(),
|
||||
softDeleteAll: vitest.fn(),
|
||||
deleteAll: vitest.fn(),
|
||||
addAssetIds: vitest.fn(),
|
||||
removeAsset: vitest.fn(),
|
||||
removeAssetIds: vitest.fn(),
|
||||
getAssetIds: vitest.fn(),
|
||||
create: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
updateThumbnails: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newKeyRepositoryMock = (): Mocked<RepositoryInterface<ApiKeyRepository>> => {
|
||||
return {
|
||||
create: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
getKey: vitest.fn(),
|
||||
getById: vitest.fn(),
|
||||
getByUserId: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newAuditRepositoryMock = (): Mocked<RepositoryInterface<AuditRepository>> => {
|
||||
return {
|
||||
getAfter: vitest.fn(),
|
||||
removeBefore: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
import { CronRepository } from 'src/repositories/cron.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newCronRepositoryMock = (): Mocked<RepositoryInterface<CronRepository>> => {
|
||||
return {
|
||||
create: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
import { DownloadRepository } from 'src/repositories/download.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newDownloadRepositoryMock = (): Mocked<RepositoryInterface<DownloadRepository>> => {
|
||||
return {
|
||||
downloadAssetIds: vitest.fn(),
|
||||
downloadMotionAssetIds: vitest.fn(),
|
||||
downloadAlbumId: vitest.fn(),
|
||||
downloadUserId: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
import { EventRepository } from 'src/repositories/event.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newEventRepositoryMock = (): Mocked<RepositoryInterface<EventRepository>> => {
|
||||
return {
|
||||
setup: vitest.fn(),
|
||||
emit: vitest.fn() as any,
|
||||
clientSend: vitest.fn() as any,
|
||||
clientBroadcast: vitest.fn() as any,
|
||||
serverSend: vitest.fn(),
|
||||
afterInit: vitest.fn(),
|
||||
handleConnection: vitest.fn(),
|
||||
handleDisconnect: vitest.fn(),
|
||||
setAuthFn: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
import { LibraryRepository } from 'src/repositories/library.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newLibraryRepositoryMock = (): Mocked<RepositoryInterface<LibraryRepository>> => {
|
||||
return {
|
||||
get: vitest.fn(),
|
||||
create: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
softDelete: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
getStatistics: vitest.fn(),
|
||||
getAllDeleted: vitest.fn(),
|
||||
getAll: vitest.fn(),
|
||||
streamAssetIds: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,23 +0,0 @@
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newLoggingRepositoryMock = (): Mocked<RepositoryInterface<LoggingRepository>> => {
|
||||
return {
|
||||
setLogLevel: vitest.fn(),
|
||||
setContext: vitest.fn(),
|
||||
setAppName: vitest.fn(),
|
||||
isLevelEnabled: vitest.fn(),
|
||||
verbose: vitest.fn(),
|
||||
verboseFn: vitest.fn(),
|
||||
debug: vitest.fn(),
|
||||
debugFn: vitest.fn(),
|
||||
log: vitest.fn(),
|
||||
warn: vitest.fn(),
|
||||
error: vitest.fn(),
|
||||
fatal: vitest.fn(),
|
||||
};
|
||||
};
|
||||
|
||||
export const newFakeLoggingRepository = () =>
|
||||
newLoggingRepositoryMock() as RepositoryInterface<LoggingRepository> as LoggingRepository;
|
@ -1,11 +0,0 @@
|
||||
import { MachineLearningRepository } from 'src/repositories/machine-learning.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newMachineLearningRepositoryMock = (): Mocked<RepositoryInterface<MachineLearningRepository>> => {
|
||||
return {
|
||||
encodeImage: vitest.fn(),
|
||||
encodeText: vitest.fn(),
|
||||
detectFaces: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
import { MapRepository } from 'src/repositories/map.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newMapRepositoryMock = (): Mocked<RepositoryInterface<MapRepository>> => {
|
||||
return {
|
||||
init: vitest.fn(),
|
||||
reverseGeocode: vitest.fn(),
|
||||
getMapMarkers: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newMemoryRepositoryMock = (): Mocked<RepositoryInterface<MemoryRepository>> => {
|
||||
return {
|
||||
search: vitest.fn().mockResolvedValue([]),
|
||||
get: vitest.fn(),
|
||||
create: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
getAssetIds: vitest.fn().mockResolvedValue(new Set()),
|
||||
addAssetIds: vitest.fn(),
|
||||
removeAssetIds: vitest.fn(),
|
||||
cleanup: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
import { MoveRepository } from 'src/repositories/move.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newMoveRepositoryMock = (): Mocked<RepositoryInterface<MoveRepository>> => {
|
||||
return {
|
||||
create: vitest.fn(),
|
||||
getByEntity: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
cleanMoveHistory: vitest.fn(),
|
||||
cleanMoveHistorySingle: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
import { NotificationRepository } from 'src/repositories/notification.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newNotificationRepositoryMock = (): Mocked<RepositoryInterface<NotificationRepository>> => {
|
||||
return {
|
||||
renderEmail: vitest.fn(),
|
||||
sendEmail: vitest.fn().mockResolvedValue({ messageId: 'message-1' }),
|
||||
verifySmtp: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
import { OAuthRepository } from 'src/repositories/oauth.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
export const newOAuthRepositoryMock = (): Mocked<RepositoryInterface<OAuthRepository>> => {
|
||||
return {
|
||||
init: vitest.fn(),
|
||||
authorize: vitest.fn(),
|
||||
getLogoutEndpoint: vitest.fn(),
|
||||
getProfile: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,13 +0,0 @@
|
||||
import { PartnerRepository } from 'src/repositories/partner.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newPartnerRepositoryMock = (): Mocked<RepositoryInterface<PartnerRepository>> => {
|
||||
return {
|
||||
create: vitest.fn(),
|
||||
remove: vitest.fn(),
|
||||
getAll: vitest.fn().mockResolvedValue([]),
|
||||
get: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,41 +0,0 @@
|
||||
import { PersonRepository } from 'src/repositories/person.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newPersonRepositoryMock = (): Mocked<RepositoryInterface<PersonRepository>> => {
|
||||
return {
|
||||
getById: vitest.fn(),
|
||||
getAll: vitest.fn(),
|
||||
getAllForUser: vitest.fn(),
|
||||
getAllWithoutFaces: vitest.fn(),
|
||||
|
||||
getByName: vitest.fn(),
|
||||
getDistinctNames: vitest.fn(),
|
||||
|
||||
create: vitest.fn(),
|
||||
createAll: vitest.fn(),
|
||||
update: vitest.fn(),
|
||||
updateAll: vitest.fn(),
|
||||
delete: vitest.fn(),
|
||||
deleteFaces: vitest.fn(),
|
||||
|
||||
getStatistics: vitest.fn(),
|
||||
getAllFaces: vitest.fn(),
|
||||
getFacesByIds: vitest.fn(),
|
||||
getRandomFace: vitest.fn(),
|
||||
|
||||
reassignFaces: vitest.fn(),
|
||||
unassignFaces: vitest.fn(),
|
||||
refreshFaces: vitest.fn(),
|
||||
getFaces: vitest.fn(),
|
||||
reassignFace: vitest.fn(),
|
||||
getFaceById: vitest.fn(),
|
||||
getFaceByIdWithAssets: vitest.fn(),
|
||||
getNumberOfPeople: vitest.fn(),
|
||||
getLatestFaceDate: vitest.fn(),
|
||||
|
||||
createAssetFace: vitest.fn(),
|
||||
deleteAssetFace: vitest.fn(),
|
||||
softDeleteAssetFaces: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
import { ProcessRepository } from 'src/repositories/process.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newProcessRepositoryMock = (): Mocked<RepositoryInterface<ProcessRepository>> => {
|
||||
return {
|
||||
spawn: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import { SearchRepository } from 'src/repositories/search.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newSearchRepositoryMock = (): Mocked<RepositoryInterface<SearchRepository>> => {
|
||||
return {
|
||||
searchMetadata: vitest.fn(),
|
||||
searchSmart: vitest.fn(),
|
||||
searchDuplicates: vitest.fn(),
|
||||
searchFaces: vitest.fn(),
|
||||
searchRandom: vitest.fn(),
|
||||
upsert: vitest.fn(),
|
||||
searchPlaces: vitest.fn(),
|
||||
getAssetsByCity: vitest.fn(),
|
||||
deleteAllSearchEmbeddings: vitest.fn(),
|
||||
getDimensionSize: vitest.fn(),
|
||||
setDimensionSize: vitest.fn(),
|
||||
getCameraMakes: vitest.fn(),
|
||||
getCameraModels: vitest.fn(),
|
||||
getCities: vitest.fn(),
|
||||
getCountries: vitest.fn(),
|
||||
getStates: vitest.fn(),
|
||||
};
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
import { ServerInfoRepository } from 'src/repositories/server-info.repository';
|
||||
import { RepositoryInterface } from 'src/types';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
export const newServerInfoRepositoryMock = (): Mocked<RepositoryInterface<ServerInfoRepository>> => {
|
||||
return {
|
||||
getGitHubRelease: vitest.fn(),
|
||||
getBuildVersions: vitest.fn(),
|
||||
};
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user