Compare commits

..

1 Commits

Author SHA1 Message Date
Jonathan Jogenfors 43d66c7a36 ignore perm errors 2025-02-07 00:30:28 +01:00
124 changed files with 1696 additions and 3277 deletions
+3 -3
View File
@@ -1,12 +1,12 @@
{ {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.50", "version": "2.2.48",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.50", "version": "2.2.48",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
@@ -52,7 +52,7 @@
}, },
"../open-api/typescript-sdk": { "../open-api/typescript-sdk": {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.126.1", "version": "1.125.7",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.50", "version": "2.2.48",
"description": "Command Line Interface (CLI) for Immich", "description": "Command Line Interface (CLI) for Immich",
"type": "module", "type": "module",
"exports": "./dist/index.js", "exports": "./dist/index.js",
+30 -30
View File
@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates. # Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" { provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.0" version = "4.50.0"
constraints = "4.52.0" constraints = "4.50.0"
hashes = [ hashes = [
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=", "h1:0qvD5ZKn2tMZ8cOjQrUSITIC9tKCZbrSaSswV9lOyiU=",
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=", "h1:4N0gplrZ0zOsJv3Kx1VfIx2FwrZHbYU0Un2yfiLZIGQ=",
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=", "h1:81AMQq4kNKU/35U8ElQegUxG4E6xB0erIjG5xVmjIyo=",
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=", "h1:EEQNADUmV3IL6x00yzy04i7OCSLeOMgM9XQkV3w71gA=",
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=", "h1:HD0KI7td6oiSSAnJNn8UPSGf+hKiTo4JVQYfAiU1SqM=",
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=", "h1:Hl+o5LtcvZg2f3l1hh9vaG/DFK6k+dTIZSeM0lXyfpo=",
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=", "h1:ZUO2oIJ6jtZdvl816h0cEIiIeZ/fFCF64+abGEVxZZM=",
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=", "h1:Zio80fnEeUKdlSOhTVskMEFSLUQ6TMsMKnXc+Dy2P2A=",
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=", "h1:aLLvg36evTyqjtXGV2MjAV8imktXFmry7p/xCu9GQC4=",
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=", "h1:azL05eWyy2V8SWkbZZImPWvv8ynG4eqmrbZhjXBDFug=",
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=", "h1:ckMysHY4fJmr7o58XMi+DdgOTB/U/Mf1u1JA9ly3g/I=",
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=", "h1:jxOwjDNjt5WCb4YjjiMsman91O8Y+MAPz6UwJ4a6F+0=",
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=", "h1:u4OfnjSLa4Wk1IUFAzrvMnGgr8MvRHEWVDHEScPK2E8=",
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=", "h1:wQkR1oeSkzlHn3rnVuLJRJLBHlg4EHt7Y64DeTjfkjQ=",
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0", "zh:0ef99ed39472a94e6a0d6fa733cf0a46bce3bf66eba2873efae8846efdddc237",
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8", "zh:2929cbbffcead171d45c88e4a7a59e9c013ea775dafa68b10da8db7cd04b6140",
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238", "zh:462601c87118088e1a718842e367af7d8e7620598d426980a6d6b33de759865e",
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f", "zh:56766eb62a74a9d88d9efb8486dd3a0c5c9db873d0a980ae9ef1e8af27d74231",
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f", "zh:6b4e8810d99498a5a20a5872982a0f1354e79cfc4a7dfe7cc656f1c7eaae47d8",
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8", "zh:6d65bdb4ec94b6eecc8abe26d94e2ca09262dc1e7a9934db829f418be0119920",
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9", "zh:71adeaf31e41a358ec6095004062e43f56ee7d4b2504e5613ab351d511695641",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6", "zh:89761c15908ccc2cf9c50bb5cb3be45d3ad0c45fc7c608c6b95f48c0288b7160",
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb", "zh:8cc5d7c5939da89cfd01f3e51c84f3576564783acea9db86bd9e32049805ed96",
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b", "zh:987cff8225b1dd436cdcb4fc6228689ae7e4281de6896412a2a9a3325c49f05e",
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380", "zh:991e83ebb89867d71e01a1c215ed159efb425683b0a44707be8579eb0a337f06",
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7", "zh:ab8177ae2d8f5cfa90043a6f867435012cae115f6061b832a7e2462e0ae87a67",
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672", "zh:d1ca34df1398f201274a6a18102975148c10ca15aa43cfc56cc9897620929509",
"zh:d34946f70201baf6dda03e3b294c6bbe40d95d0278e97b9f636ded94822b24ac",
] ]
} }
@@ -5,7 +5,7 @@ terraform {
required_providers { required_providers {
cloudflare = { cloudflare = {
source = "cloudflare/cloudflare" source = "cloudflare/cloudflare"
version = "4.52.0" version = "4.50.0"
} }
} }
} }
+30 -30
View File
@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates. # Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" { provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.0" version = "4.50.0"
constraints = "4.52.0" constraints = "4.50.0"
hashes = [ hashes = [
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=", "h1:0qvD5ZKn2tMZ8cOjQrUSITIC9tKCZbrSaSswV9lOyiU=",
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=", "h1:4N0gplrZ0zOsJv3Kx1VfIx2FwrZHbYU0Un2yfiLZIGQ=",
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=", "h1:81AMQq4kNKU/35U8ElQegUxG4E6xB0erIjG5xVmjIyo=",
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=", "h1:EEQNADUmV3IL6x00yzy04i7OCSLeOMgM9XQkV3w71gA=",
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=", "h1:HD0KI7td6oiSSAnJNn8UPSGf+hKiTo4JVQYfAiU1SqM=",
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=", "h1:Hl+o5LtcvZg2f3l1hh9vaG/DFK6k+dTIZSeM0lXyfpo=",
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=", "h1:ZUO2oIJ6jtZdvl816h0cEIiIeZ/fFCF64+abGEVxZZM=",
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=", "h1:Zio80fnEeUKdlSOhTVskMEFSLUQ6TMsMKnXc+Dy2P2A=",
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=", "h1:aLLvg36evTyqjtXGV2MjAV8imktXFmry7p/xCu9GQC4=",
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=", "h1:azL05eWyy2V8SWkbZZImPWvv8ynG4eqmrbZhjXBDFug=",
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=", "h1:ckMysHY4fJmr7o58XMi+DdgOTB/U/Mf1u1JA9ly3g/I=",
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=", "h1:jxOwjDNjt5WCb4YjjiMsman91O8Y+MAPz6UwJ4a6F+0=",
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=", "h1:u4OfnjSLa4Wk1IUFAzrvMnGgr8MvRHEWVDHEScPK2E8=",
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=", "h1:wQkR1oeSkzlHn3rnVuLJRJLBHlg4EHt7Y64DeTjfkjQ=",
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0", "zh:0ef99ed39472a94e6a0d6fa733cf0a46bce3bf66eba2873efae8846efdddc237",
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8", "zh:2929cbbffcead171d45c88e4a7a59e9c013ea775dafa68b10da8db7cd04b6140",
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238", "zh:462601c87118088e1a718842e367af7d8e7620598d426980a6d6b33de759865e",
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f", "zh:56766eb62a74a9d88d9efb8486dd3a0c5c9db873d0a980ae9ef1e8af27d74231",
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f", "zh:6b4e8810d99498a5a20a5872982a0f1354e79cfc4a7dfe7cc656f1c7eaae47d8",
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8", "zh:6d65bdb4ec94b6eecc8abe26d94e2ca09262dc1e7a9934db829f418be0119920",
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9", "zh:71adeaf31e41a358ec6095004062e43f56ee7d4b2504e5613ab351d511695641",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6", "zh:89761c15908ccc2cf9c50bb5cb3be45d3ad0c45fc7c608c6b95f48c0288b7160",
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb", "zh:8cc5d7c5939da89cfd01f3e51c84f3576564783acea9db86bd9e32049805ed96",
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b", "zh:987cff8225b1dd436cdcb4fc6228689ae7e4281de6896412a2a9a3325c49f05e",
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380", "zh:991e83ebb89867d71e01a1c215ed159efb425683b0a44707be8579eb0a337f06",
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7", "zh:ab8177ae2d8f5cfa90043a6f867435012cae115f6061b832a7e2462e0ae87a67",
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672", "zh:d1ca34df1398f201274a6a18102975148c10ca15aa43cfc56cc9897620929509",
"zh:d34946f70201baf6dda03e3b294c6bbe40d95d0278e97b9f636ded94822b24ac",
] ]
} }
+1 -1
View File
@@ -5,7 +5,7 @@ terraform {
required_providers { required_providers {
cloudflare = { cloudflare = {
source = "cloudflare/cloudflare" source = "cloudflare/cloudflare"
version = "4.52.0" version = "4.50.0"
} }
} }
} }
+1 -1
View File
@@ -103,7 +103,7 @@ services:
command: ['./run.sh', '-disable-reporting'] command: ['./run.sh', '-disable-reporting']
ports: ports:
- 3000:3000 - 3000:3000
image: grafana/grafana:11.5.1-ubuntu@sha256:9a4ab78cec1a2ec7d1ca5dfd5aacec6412706a1bc9e971fc7184e2f6696a63f5 image: grafana/grafana:11.4.0-ubuntu@sha256:afccec22ba0e4815cca1d2bf3836e414322390dc78d77f1851976ffa8d61051c
volumes: volumes:
- grafana-data:/var/lib/grafana - grafana-data:/var/lib/grafana
+1 -1
View File
@@ -76,7 +76,7 @@ To see local changes to `@immich/ui` in Immich, do the following:
### Mobile app ### Mobile app
The mobile app `(/mobile)` will required Flutter toolchain 3.13.x and FVM to be installed on your system. The mobile app `(/mobile)` will required Flutter toolchain 3.13.x to be installed on your system.
Please refer to the [Flutter's official documentation](https://flutter.dev/docs/get-started/install) for more information on setting up the toolchain on your machine. Please refer to the [Flutter's official documentation](https://flutter.dev/docs/get-started/install) for more information on setting up the toolchain on your machine.
@@ -11,7 +11,7 @@ You do not need to redo any machine learning jobs after enabling hardware accele
- ARM NN (Mali) - ARM NN (Mali)
- CUDA (NVIDIA GPUs with [compute capability](https://developer.nvidia.com/cuda-gpus) 5.2 or higher) - CUDA (NVIDIA GPUs with [compute capability](https://developer.nvidia.com/cuda-gpus) 5.2 or higher)
- OpenVINO (Intel GPUs such as Iris Xe and Arc) - OpenVINO (Intel discrete GPUs such as Iris Xe and Arc)
## Limitations ## Limitations
@@ -43,9 +43,8 @@ You do not need to redo any machine learning jobs after enabling hardware accele
#### OpenVINO #### OpenVINO
- Integrated GPUs are more likely to experience issues than discrete GPUs, especially for older processors or servers with low RAM. - The server must have a discrete GPU, i.e. Iris Xe or Arc. Expect issues when attempting to use integrated graphics.
- Ensure the server's kernel version is new enough to use the device for hardware accceleration. - Ensure the server's kernel version is new enough to use the device for hardware accceleration.
- Expect higher RAM usage when using OpenVINO compared to CPU processing.
## Setup ## Setup
+2 -2
View File
@@ -44,12 +44,12 @@ export default function VersionSwitcher(): JSX.Element {
return ( return (
versions.length > 0 && ( versions.length > 0 && (
<DropdownNavbarItem <DropdownNavbarItem
className="version-switcher-34ab39" className="navbar__item"
label={label} label={label}
mobile={windowSize === 'mobile'} mobile={windowSize === 'mobile'}
items={versions.map(({ label, url }) => ({ items={versions.map(({ label, url }) => ({
label, label,
to: url + location.pathname + location.hash, to: url + location.pathname,
target: '_self', target: '_self',
}))} }))}
/> />
-5
View File
@@ -75,11 +75,6 @@ div[class^='announcementBar_'] {
font-weight: 500; font-weight: 500;
} }
/* workaround for version switcher PR 15894 */
div[class*='navbar__items'] > li:has(a[class*='version-switcher-34ab39']) {
display: none;
}
code { code {
font-weight: 600; font-weight: 600;
} }
+1 -1
View File
@@ -53,7 +53,7 @@ function HomepageHeader() {
<Link <Link
className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary/10 dark:bg-gray-300 rounded-xl hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase" className="flex place-items-center place-content-center py-3 px-8 border bg-immich-primary/10 dark:bg-gray-300 rounded-xl hover:no-underline text-immich-primary dark:text-immich-dark-bg font-bold uppercase"
to="https://immich.store" to="https://demo.immich.app/"
> >
Buy Merch Buy Merch
</Link> </Link>
-8
View File
@@ -1,12 +1,4 @@
[ [
{
"label": "v1.126.1",
"url": "https://v1.126.1.archive.immich.app"
},
{
"label": "v1.126.0",
"url": "https://v1.126.0.archive.immich.app"
},
{ {
"label": "v1.125.7", "label": "v1.125.7",
"url": "https://v1.125.7.archive.immich.app" "url": "https://v1.125.7.archive.immich.app"
+3
View File
@@ -32,6 +32,9 @@ services:
- database - database
ports: ports:
- 2285:2285 - 2285:2285
cap_drop:
# We need this to perform testing on permission errors
- DAC_OVERRIDE
redis: redis:
image: redis:6.2-alpine@sha256:905c4ee67b8e0aa955331960d2aa745781e6bd89afc44a8584bfd13bc890f0ae image: redis:6.2-alpine@sha256:905c4ee67b8e0aa955331960d2aa745781e6bd89afc44a8584bfd13bc890f0ae
+4 -4
View File
@@ -1,12 +1,12 @@
{ {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.126.1", "version": "1.125.7",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.126.1", "version": "1.125.7",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0", "@eslint/eslintrc": "^3.1.0",
@@ -45,7 +45,7 @@
}, },
"../cli": { "../cli": {
"name": "@immich/cli", "name": "@immich/cli",
"version": "2.2.50", "version": "2.2.48",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
@@ -92,7 +92,7 @@
}, },
"../open-api/typescript-sdk": { "../open-api/typescript-sdk": {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.126.1", "version": "1.125.7",
"dev": true, "dev": true,
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "immich-e2e", "name": "immich-e2e",
"version": "1.126.1", "version": "1.125.7",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",
+29 -1
View File
@@ -1,5 +1,5 @@
import { LibraryResponseDto, LoginResponseDto, getAllLibraries, scanLibrary } from '@immich/sdk'; import { LibraryResponseDto, LoginResponseDto, getAllLibraries, scanLibrary } from '@immich/sdk';
import { cpSync, existsSync, rmSync, unlinkSync } from 'node:fs'; import { chmodSync, cpSync, existsSync, promises, rmSync, unlinkSync } from 'node:fs';
import { Socket } from 'socket.io-client'; import { Socket } from 'socket.io-client';
import { userDto, uuidDto } from 'src/fixtures'; import { userDto, uuidDto } from 'src/fixtures';
import { errorDto } from 'src/responses'; import { errorDto } from 'src/responses';
@@ -492,6 +492,34 @@ describe('/libraries', () => {
utils.removeImageFile(`${testAssetDir}/temp/folder${char}2/asset2.png`); utils.removeImageFile(`${testAssetDir}/temp/folder${char}2/asset2.png`);
}); });
it('should handle permission errors on import paths without error', async () => {
const library = await utils.createLibrary(admin.accessToken, {
ownerId: admin.userId,
importPaths: [`${testAssetDirInternal}/temp/`],
});
const stat = await promises.stat(`${testAssetDir}/temp/directoryA`);
const mode = stat.mode;
chmodSync(`${testAssetDir}/temp/directoryB`, 0o000);
const { status } = await request(app)
.post(`/libraries/${library.id}/scan`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send();
expect(status).toBe(204);
await utils.waitForQueueFinish(admin.accessToken, 'library');
chmodSync(`${testAssetDir}/temp/directoryB`, mode);
const { assets } = await utils.searchAssets(admin.accessToken, { libraryId: library.id });
expect(assets.count).toBe(1);
expect(assets.items.find((asset) => asset.originalPath.includes('directoryA'))).toBeDefined();
expect(assets.items.find((asset) => asset.originalPath.includes('directoryB'))).not.toBeDefined();
});
it('should reimport a modified file', async () => { it('should reimport a modified file', async () => {
const library = await utils.createLibrary(admin.accessToken, { const library = await utils.createLibrary(admin.accessToken, {
ownerId: admin.userId, ownerId: admin.userId,
-19
View File
@@ -195,7 +195,6 @@ describe('/people', () => {
.send({ .send({
name: 'New Person', name: 'New Person',
birthDate: '1990-01-01', birthDate: '1990-01-01',
color: '#333',
}); });
expect(status).toBe(201); expect(status).toBe(201);
expect(body).toMatchObject({ expect(body).toMatchObject({
@@ -274,24 +273,6 @@ describe('/people', () => {
expect(body).toMatchObject({ birthDate: null }); expect(body).toMatchObject({ birthDate: null });
}); });
it('should set a color', async () => {
const { status, body } = await request(app)
.put(`/people/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ color: '#555' });
expect(status).toBe(200);
expect(body).toMatchObject({ color: '#555' });
});
it('should clear a color', async () => {
const { status, body } = await request(app)
.put(`/people/${visiblePerson.id}`)
.set('Authorization', `Bearer ${admin.accessToken}`)
.send({ color: null });
expect(status).toBe(200);
expect(body.color).toBeUndefined();
});
it('should mark a person as favorite', async () => { it('should mark a person as favorite', async () => {
const person = await utils.createPerson(admin.accessToken, { const person = await utils.createPerson(admin.accessToken, {
name: 'visible_person', name: 'visible_person',
-24
View File
@@ -150,30 +150,6 @@ describe('/shared-links', () => {
); );
}); });
it('should filter on albumId', async () => {
const { status, body } = await request(app)
.get(`/shared-links?albumId=${album.id}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(2);
expect(body).toEqual(
expect.arrayContaining([
expect.objectContaining({ id: linkWithAlbum.id }),
expect.objectContaining({ id: linkWithPassword.id }),
]),
);
});
it('should find 0 albums', async () => {
const { status, body } = await request(app)
.get(`/shared-links?albumId=${uuidDto.notFound}`)
.set('Authorization', `Bearer ${user1.accessToken}`);
expect(status).toBe(200);
expect(body).toHaveLength(0);
});
it('should not get shared links created by other users', async () => { it('should not get shared links created by other users', async () => {
const { status, body } = await request(app) const { status, body } = await request(app)
.get('/shared-links') .get('/shared-links')
-7
View File
@@ -436,7 +436,6 @@
"back_close_deselect": "Back, close, or deselect", "back_close_deselect": "Back, close, or deselect",
"backward": "Backward", "backward": "Backward",
"birthdate_saved": "Date of birth saved successfully", "birthdate_saved": "Date of birth saved successfully",
"show_shared_links": "Show shared links",
"birthdate_set_description": "Date of birth is used to calculate the age of this person at the time of a photo.", "birthdate_set_description": "Date of birth is used to calculate the age of this person at the time of a photo.",
"blurred_background": "Blurred background", "blurred_background": "Blurred background",
"bugs_and_feature_requests": "Bugs & Feature Requests", "bugs_and_feature_requests": "Bugs & Feature Requests",
@@ -769,10 +768,8 @@
"go_to_search": "Go to search", "go_to_search": "Go to search",
"go_to_folder": "Go to folder", "go_to_folder": "Go to folder",
"group_albums_by": "Group albums by...", "group_albums_by": "Group albums by...",
"group_country": "Group by country",
"group_no": "No grouping", "group_no": "No grouping",
"group_owner": "Group by owner", "group_owner": "Group by owner",
"group_places_by": "Group places by...",
"group_year": "Group by year", "group_year": "Group by year",
"has_quota": "Has quota", "has_quota": "Has quota",
"hi_user": "Hi {name} ({email})", "hi_user": "Hi {name} ({email})",
@@ -805,7 +802,6 @@
"include_shared_albums": "Include shared albums", "include_shared_albums": "Include shared albums",
"include_shared_partner_assets": "Include shared partner assets", "include_shared_partner_assets": "Include shared partner assets",
"individual_share": "Individual share", "individual_share": "Individual share",
"individual_shares": "Individual shares",
"info": "Info", "info": "Info",
"interval": { "interval": {
"day_at_onepm": "Every day at 1pm", "day_at_onepm": "Every day at 1pm",
@@ -991,7 +987,6 @@
"pick_a_location": "Pick a location", "pick_a_location": "Pick a location",
"place": "Place", "place": "Place",
"places": "Places", "places": "Places",
"places_count": "{count, plural, one {{count, number} Place} other {{count, number} Places}}",
"play": "Play", "play": "Play",
"play_memories": "Play memories", "play_memories": "Play memories",
"play_motion_photo": "Play Motion Photo", "play_motion_photo": "Play Motion Photo",
@@ -1174,7 +1169,6 @@
"shared_from_partner": "Photos from {partner}", "shared_from_partner": "Photos from {partner}",
"shared_link_options": "Shared link options", "shared_link_options": "Shared link options",
"shared_links": "Shared links", "shared_links": "Shared links",
"shared_links_description": "Share photos and videos with a link",
"shared_photos_and_videos_count": "{assetCount, plural, other {# shared photos & videos.}}", "shared_photos_and_videos_count": "{assetCount, plural, other {# shared photos & videos.}}",
"shared_with_partner": "Shared with {partner}", "shared_with_partner": "Shared with {partner}",
"sharing": "Sharing", "sharing": "Sharing",
@@ -1284,7 +1278,6 @@
"unfavorite": "Unfavorite", "unfavorite": "Unfavorite",
"unhide_person": "Unhide person", "unhide_person": "Unhide person",
"unknown": "Unknown", "unknown": "Unknown",
"unknown_country": "Unknown Country",
"unknown_year": "Unknown Year", "unknown_year": "Unknown Year",
"unlimited": "Unlimited", "unlimited": "Unlimited",
"unlink_motion_video": "Unlink motion video", "unlink_motion_video": "Unlink motion video",
+437 -437
View File
@@ -312,157 +312,157 @@
"admin_password": "رمز عبور مدیر", "admin_password": "رمز عبور مدیر",
"administration": "مدیریت", "administration": "مدیریت",
"advanced": "پیشرفته", "advanced": "پیشرفته",
"album_added": "آلبوم اضافه شد", "album_added": "",
"album_added_notification_setting_description": "", "album_added_notification_setting_description": "",
"album_cover_updated": "جلد آلبوم به‌روزرسانی شد", "album_cover_updated": "",
"album_info_updated": "اطلاعات آلبوم به‌روزرسانی شد", "album_info_updated": "",
"album_name": "نام آلبوم", "album_name": "",
"album_options": "گزینه‌های آلبوم", "album_options": "",
"album_updated": "آلبوم به‌روزرسانی شد", "album_updated": "",
"album_updated_setting_description": "", "album_updated_setting_description": "",
"albums": "آلبوم‌ها", "albums": "",
"albums_count": "", "albums_count": "",
"all": "همه", "all": "",
"all_people": "همه افراد", "all_people": "",
"allow_dark_mode": "اجازه دادن به حالت تاریک", "allow_dark_mode": "",
"allow_edits": "اجازه ویرایش", "allow_edits": "",
"api_key": "کلید API", "api_key": "",
"api_keys": "کلیدهای API", "api_keys": "",
"app_settings": "تنظیمات برنامه", "app_settings": "",
"appears_in": "ظاهر می‌شود در", "appears_in": "",
"archive": "بایگانی", "archive": "",
"archive_or_unarchive_photo": "", "archive_or_unarchive_photo": "",
"archive_size": "اندازه بایگانی", "archive_size": "",
"archive_size_description": "", "archive_size_description": "",
"asset_offline": "محتوا آفلاین", "asset_offline": "",
"assets": "محتواها", "assets": "",
"authorized_devices": "دستگاه‌های مجاز", "authorized_devices": "",
"back": "بازگشت", "back": "",
"backward": "عقب", "backward": "",
"blurred_background": "پس‌زمینه محو", "blurred_background": "",
"bulk_delete_duplicates_confirmation": "", "bulk_delete_duplicates_confirmation": "",
"bulk_keep_duplicates_confirmation": "", "bulk_keep_duplicates_confirmation": "",
"bulk_trash_duplicates_confirmation": "", "bulk_trash_duplicates_confirmation": "",
"camera": "دوربین", "camera": "",
"camera_brand": "برند دوربین", "camera_brand": "",
"camera_model": "مدل دوربین", "camera_model": "",
"cancel": "لغو", "cancel": "",
"cancel_search": "لغو جستجو", "cancel_search": "",
"cannot_merge_people": "نمی‌توان افراد را ادغام کرد", "cannot_merge_people": "",
"cannot_update_the_description": "نمی‌توان توضیحات را به‌روزرسانی کرد", "cannot_update_the_description": "",
"change_date": "تغییر تاریخ", "change_date": "",
"change_expiration_time": "تغییر زمان انقضا", "change_expiration_time": "",
"change_location": "تغییر مکان", "change_location": "",
"change_name": "تغییر نام", "change_name": "",
"change_name_successfully": "نام با موفقیت تغییر یافت", "change_name_successfully": "",
"change_password": "تغییر رمز عبور", "change_password": "",
"change_your_password": "رمز عبور خود را تغییر دهید", "change_your_password": "",
"changed_visibility_successfully": "", "changed_visibility_successfully": "",
"check_all": "انتخاب همه", "check_all": "",
"check_logs": "بررسی لاگ‌ها", "check_logs": "",
"choose_matching_people_to_merge": "", "choose_matching_people_to_merge": "",
"city": "شهر", "city": "",
"clear": "پاک کردن", "clear": "",
"clear_all": "پاک کردن همه", "clear_all": "",
"clear_message": "پاک کردن پیام", "clear_message": "",
"clear_value": "پاک کردن مقدار", "clear_value": "",
"close": "بستن", "close": "",
"collapse_all": "جمع کردن همه", "collapse_all": "",
"color_theme": "تم رنگ", "color_theme": "",
"comment_options": "گزینه‌های نظر", "comment_options": "",
"comments_are_disabled": "نظرات غیرفعال هستند", "comments_are_disabled": "",
"confirm": "تأیید", "confirm": "",
"confirm_admin_password": "تأیید رمز عبور مدیر", "confirm_admin_password": "",
"confirm_delete_shared_link": "", "confirm_delete_shared_link": "",
"confirm_password": "تأیید رمز عبور", "confirm_password": "",
"contain": "شامل", "contain": "",
"context": "زمینه", "context": "",
"continue": "ادامه", "continue": "",
"copied_image_to_clipboard": "تصویر به کلیپ‌بورد کپی شد.", "copied_image_to_clipboard": "",
"copied_to_clipboard": "به کلیپ‌بورد کپی شد!", "copied_to_clipboard": "",
"copy_error": "خطا در کپی", "copy_error": "",
"copy_file_path": "کپی مسیر فایل", "copy_file_path": "",
"copy_image": "کپی تصویر", "copy_image": "",
"copy_link": "کپی لینک", "copy_link": "",
"copy_link_to_clipboard": "کپی لینک به کلیپ‌بورد", "copy_link_to_clipboard": "",
"copy_password": "کپی رمز عبور", "copy_password": "",
"copy_to_clipboard": "کپی به کلیپ‌بورد", "copy_to_clipboard": "",
"country": "کشور", "country": "",
"cover": "جلد", "cover": "",
"covers": "جلدها", "covers": "",
"create": "ایجاد", "create": "",
"create_album": "ایجاد آلبوم", "create_album": "",
"create_library": "ایجاد کتابخانه", "create_library": "",
"create_link": "ایجاد لینک", "create_link": "",
"create_link_to_share": "ایجاد لینک برای اشتراک‌گذاری", "create_link_to_share": "",
"create_new_person": "ایجاد فرد جدید", "create_new_person": "",
"create_new_user": "ایجاد کاربر جدید", "create_new_user": "",
"create_user": "ایجاد کاربر", "create_user": "",
"created": "ایجاد شد", "created": "",
"current_device": "دستگاه فعلی", "current_device": "",
"custom_locale": "", "custom_locale": "",
"custom_locale_description": "", "custom_locale_description": "",
"dark": "تاریک", "dark": "",
"date_after": "تاریخ پس از", "date_after": "",
"date_and_time": "تاریخ و زمان", "date_and_time": "",
"date_before": "تاریخ قبل از", "date_before": "",
"date_range": "بازه زمانی", "date_range": "",
"day": "روز", "day": "",
"deduplicate_all": "حذف تکراری‌ها به صورت کامل", "deduplicate_all": "",
"default_locale": "", "default_locale": "",
"default_locale_description": "", "default_locale_description": "",
"delete": "حذف", "delete": "",
"delete_album": "حذف آلبوم", "delete_album": "",
"delete_api_key_prompt": "", "delete_api_key_prompt": "",
"delete_duplicates_confirmation": "", "delete_duplicates_confirmation": "",
"delete_key": "حذف کلید", "delete_key": "",
"delete_library": "حذف کتابخانه", "delete_library": "",
"delete_link": "حذف لینک", "delete_link": "",
"delete_shared_link": "حذف لینک اشتراکی", "delete_shared_link": "",
"delete_user": "حذف کاربر", "delete_user": "",
"deleted_shared_link": "لینک اشتراکی حذف شد", "deleted_shared_link": "",
"description": "توضیحات", "description": "",
"details": "جزئیات", "details": "",
"direction": "جهت", "direction": "",
"disabled": "غیرفعال", "disabled": "",
"disallow_edits": "عدم اجازه ویرایش", "disallow_edits": "",
"discover": "کشف کردن", "discover": "",
"dismiss_all_errors": "رد تمام خطاها", "dismiss_all_errors": "",
"dismiss_error": "رد خطا", "dismiss_error": "",
"display_options": "گزینه‌های نمایش", "display_options": "",
"display_order": "ترتیب نمایش", "display_order": "",
"display_original_photos": "نمایش عکس‌های اصلی", "display_original_photos": "",
"display_original_photos_setting_description": "", "display_original_photos_setting_description": "",
"done": "انجام شد", "done": "",
"download": "دانلود", "download": "",
"download_settings": "تنظیمات دانلود", "download_settings": "",
"download_settings_description": "مدیریت تنظیمات مرتبط با دانلود محتوا", "download_settings_description": "",
"downloading": "در حال دانلود", "downloading": "",
"duplicates": "تکراری‌ها", "duplicates": "",
"duplicates_description": "", "duplicates_description": "",
"duration": "مدت زمان", "duration": "",
"edit_album": "ویرایش آلبوم", "edit_album": "",
"edit_avatar": "ویرایش آواتار", "edit_avatar": "",
"edit_date": "ویرایش تاریخ", "edit_date": "",
"edit_date_and_time": "ویرایش تاریخ و زمان", "edit_date_and_time": "",
"edit_exclusion_pattern": "ویرایش الگوی استثناء", "edit_exclusion_pattern": "",
"edit_faces": "ویرایش چهره‌ها", "edit_faces": "",
"edit_import_path": "", "edit_import_path": "",
"edit_import_paths": "", "edit_import_paths": "",
"edit_key": "ویرایش کلید", "edit_key": "",
"edit_link": "ویرایش لینک", "edit_link": "",
"edit_location": "ویرایش مکان", "edit_location": "",
"edit_name": "ویرایش نام", "edit_name": "",
"edit_people": "ویرایش افراد", "edit_people": "",
"edit_title": "ویرایش عنوان", "edit_title": "",
"edit_user": "ویرایش کاربر", "edit_user": "",
"edited": "ویرایش شد", "edited": "",
"editor": "ویرایشگر", "editor": "",
"email": "ایمیل", "email": "",
"empty_trash": "خالی کردن سطل زباله", "empty_trash": "",
"end_date": "تاریخ پایان", "end_date": "",
"error": "خطا", "error": "",
"error_loading_image": "خطا در بارگذاری تصویر", "error_loading_image": "",
"errors": { "errors": {
"exclusion_pattern_already_exists": "", "exclusion_pattern_already_exists": "",
"import_path_already_exists": "", "import_path_already_exists": "",
@@ -530,400 +530,400 @@
"unable_to_update_timeline_display_status": "", "unable_to_update_timeline_display_status": "",
"unable_to_update_user": "" "unable_to_update_user": ""
}, },
"exit_slideshow": "خروج از نمایش اسلاید", "exit_slideshow": "",
"expand_all": "باز کردن همه", "expand_all": "",
"expire_after": "منقضی شدن بعد از", "expire_after": "",
"expired": "منقضی شده", "expired": "",
"explore": "کاوش کردن", "explore": "",
"export": "صادر کردن", "export": "",
"export_as_json": "صادر کردن به‌صورت JSON", "export_as_json": "",
"extension": "پسوند", "extension": "",
"external": "خارجی", "external": "",
"external_libraries": "کتابخانه‌های خارجی", "external_libraries": "",
"favorite": "علاقه‌مندی", "favorite": "",
"favorite_or_unfavorite_photo": "", "favorite_or_unfavorite_photo": "",
"favorites": "علاقه‌مندی‌ها", "favorites": "",
"feature_photo_updated": "", "feature_photo_updated": "",
"file_name": "نام فایل", "file_name": "",
"file_name_or_extension": "نام فایل یا پسوند", "file_name_or_extension": "",
"filename": "نام فایل", "filename": "",
"filetype": "نوع فایل", "filetype": "",
"filter_people": "فیلتر افراد", "filter_people": "",
"find_them_fast": "", "find_them_fast": "",
"fix_incorrect_match": "رفع تطابق نادرست", "fix_incorrect_match": "",
"forward": "جلو", "forward": "",
"general": "عمومی", "general": "",
"get_help": "دریافت کمک", "get_help": "",
"getting_started": "شروع به کار", "getting_started": "",
"go_back": "بازگشت", "go_back": "",
"go_to_search": "رفتن به جستجو", "go_to_search": "",
"group_albums_by": "گروه‌بندی آلبوم‌ها براساس...", "group_albums_by": "",
"has_quota": "دارای سهمیه", "has_quota": "",
"hide_gallery": "پنهان کردن گالری", "hide_gallery": "",
"hide_password": "پنهان کردن رمز عبور", "hide_password": "",
"hide_person": "پنهان کردن فرد", "hide_person": "",
"host": "میزبان", "host": "",
"hour": "ساعت", "hour": "",
"image": "تصویر", "image": "",
"immich_logo": "لوگوی Immich", "immich_logo": "",
"immich_web_interface": "رابط وب Immich", "immich_web_interface": "",
"import_from_json": "وارد کردن از JSON", "import_from_json": "",
"import_path": "مسیر وارد کردن", "import_path": "",
"in_albums": "", "in_albums": "",
"in_archive": "در بایگانی", "in_archive": "",
"include_archived": "شامل بایگانی شده‌ها", "include_archived": "",
"include_shared_albums": "شامل آلبوم‌های اشتراکی", "include_shared_albums": "",
"include_shared_partner_assets": "", "include_shared_partner_assets": "",
"individual_share": "اشتراک فردی", "individual_share": "",
"info": "اطلاعات", "info": "",
"interval": { "interval": {
"day_at_onepm": "", "day_at_onepm": "",
"hours": "", "hours": "",
"night_at_midnight": "", "night_at_midnight": "",
"night_at_twoam": "" "night_at_twoam": ""
}, },
"invite_people": "دعوت افراد", "invite_people": "",
"invite_to_album": "دعوت به آلبوم", "invite_to_album": "",
"jobs": "وظایف", "jobs": "",
"keep": "نگه داشتن", "keep": "",
"keep_all": "نگه داشتن همه", "keep_all": "",
"keyboard_shortcuts": "میانبرهای صفحه‌کلید", "keyboard_shortcuts": "",
"language": "زبان", "language": "",
"language_setting_description": "انتخاب زبان دلخواه شما", "language_setting_description": "",
"last_seen": "آخرین مشاهده", "last_seen": "",
"leave": "ترک کردن", "leave": "",
"let_others_respond": "اجازه به دیگران برای پاسخ‌گویی", "let_others_respond": "",
"level": "سطح", "level": "",
"library": "کتابخانه", "library": "",
"library_options": "گزینه‌های کتابخانه", "library_options": "",
"light": "روشن", "light": "",
"link_options": "گزینه‌های لینک", "link_options": "",
"link_to_oauth": "اتصال به OAuth", "link_to_oauth": "",
"linked_oauth_account": "حساب OAuth متصل شده", "linked_oauth_account": "",
"list": "لیست", "list": "",
"loading": "در حال بارگذاری", "loading": "",
"loading_search_results_failed": "بارگذاری نتایج جستجو ناموفق بود", "loading_search_results_failed": "",
"log_out": "خروج از سیستم", "log_out": "",
"log_out_all_devices": "خروج از همه دستگاه‌ها", "log_out_all_devices": "",
"login_has_been_disabled": "ورود غیرفعال شده است.", "login_has_been_disabled": "",
"look": "نگاه کردن", "look": "",
"loop_videos": "پخش مداوم ویدئوها", "loop_videos": "",
"loop_videos_description": "", "loop_videos_description": "",
"make": "ساختن", "make": "",
"manage_shared_links": "مدیریت لینک‌های اشتراکی", "manage_shared_links": "",
"manage_sharing_with_partners": "", "manage_sharing_with_partners": "",
"manage_the_app_settings": "مدیریت تنظیمات برنامه", "manage_the_app_settings": "",
"manage_your_account": "مدیریت حساب کاربری شما", "manage_your_account": "",
"manage_your_api_keys": "مدیریت کلیدهای API شما", "manage_your_api_keys": "",
"manage_your_devices": "مدیریت دستگاه‌های متصل", "manage_your_devices": "",
"manage_your_oauth_connection": "مدیریت اتصال OAuth شما", "manage_your_oauth_connection": "",
"map": "نقشه", "map": "",
"map_marker_with_image": "", "map_marker_with_image": "",
"map_settings": "تنظیمات نقشه", "map_settings": "",
"matches": "تطابق‌ها", "matches": "",
"media_type": "نوع رسانه", "media_type": "",
"memories": "خاطرات", "memories": "",
"memories_setting_description": "", "memories_setting_description": "",
"memory": "خاطره", "memory": "",
"menu": "منو", "menu": "",
"merge": "ادغام", "merge": "",
"merge_people": "ادغام افراد", "merge_people": "",
"merge_people_limit": "", "merge_people_limit": "",
"merge_people_prompt": "", "merge_people_prompt": "",
"merge_people_successfully": "ادغام افراد با موفقیت انجام شد", "merge_people_successfully": "",
"minimize": "کوچک کردن", "minimize": "",
"minute": "دقیقه", "minute": "",
"missing": "گمشده", "missing": "",
"model": "مدل", "model": "",
"month": "ماه", "month": "",
"more": "بیشتر", "more": "",
"moved_to_trash": "به سطل زباله منتقل شد", "moved_to_trash": "",
"my_albums": "آلبوم‌های من", "my_albums": "",
"name": "نام", "name": "",
"name_or_nickname": "نام یا لقب", "name_or_nickname": "",
"never": "هرگز", "never": "",
"new_api_key": "کلید API جدید", "new_api_key": "",
"new_password": "رمز عبور جدید", "new_password": "",
"new_person": "فرد جدید", "new_person": "",
"new_user_created": "کاربر جدید ایجاد شد", "new_user_created": "",
"newest_first": "جدیدترین ابتدا", "newest_first": "",
"next": "بعدی", "next": "",
"next_memory": "خاطره بعدی", "next_memory": "",
"no": "خیر", "no": "",
"no_albums_message": "", "no_albums_message": "",
"no_archived_assets_message": "", "no_archived_assets_message": "",
"no_assets_message": "", "no_assets_message": "",
"no_duplicates_found": "هیچ تکراری یافت نشد.", "no_duplicates_found": "",
"no_exif_info_available": "اطلاعات EXIF موجود نیست", "no_exif_info_available": "",
"no_explore_results_message": "", "no_explore_results_message": "",
"no_favorites_message": "", "no_favorites_message": "",
"no_libraries_message": "", "no_libraries_message": "",
"no_name": "بدون نام", "no_name": "",
"no_places": "مکانی یافت نشد", "no_places": "",
"no_results": "نتیجه‌ای یافت نشد", "no_results": "",
"no_shared_albums_message": "", "no_shared_albums_message": "",
"not_in_any_album": "در هیچ آلبومی نیست", "not_in_any_album": "",
"note_apply_storage_label_to_previously_uploaded assets": "", "note_apply_storage_label_to_previously_uploaded assets": "",
"note_unlimited_quota": "", "note_unlimited_quota": "",
"notes": "یادداشت‌ها", "notes": "",
"notification_toggle_setting_description": "اعلان‌های ایمیلی را فعال کنید", "notification_toggle_setting_description": "",
"notifications": "اعلان‌ها", "notifications": "",
"notifications_setting_description": "مدیریت اعلان‌ها", "notifications_setting_description": "",
"oauth": "OAuth", "oauth": "",
"offline": "آفلاین", "offline": "",
"offline_paths": "مسیرهای آفلاین", "offline_paths": "",
"offline_paths_description": "", "offline_paths_description": "",
"ok": "تأیید", "ok": "",
"oldest_first": "قدیمی‌ترین ابتدا", "oldest_first": "",
"online": "آنلاین", "online": "",
"only_favorites": "فقط علاقه‌مندی‌ها", "only_favorites": "",
"open_the_search_filters": "باز کردن فیلترهای جستجو", "open_the_search_filters": "",
"options": "گزینه‌ها", "options": "",
"organize_your_library": "کتابخانه خود را سازماندهی کنید", "organize_your_library": "",
"other": "دیگر", "other": "",
"other_devices": "دستگاه‌های دیگر", "other_devices": "",
"other_variables": "متغیرهای دیگر", "other_variables": "",
"owned": "مالکیت", "owned": "",
"owner": "مالک", "owner": "",
"partner": "شریک", "partner": "",
"partner_can_access": "{partner} می‌تواند دسترسی داشته باشد", "partner_can_access": "",
"partner_can_access_assets": "", "partner_can_access_assets": "",
"partner_can_access_location": "مکان‌هایی که عکس‌های شما گرفته شده‌اند", "partner_can_access_location": "",
"partner_sharing": "اشتراک‌گذاری با شریک", "partner_sharing": "",
"partners": "شرکا", "partners": "",
"password": "رمز عبور", "password": "",
"password_does_not_match": "رمز عبور مطابقت ندارد", "password_does_not_match": "",
"password_required": "رمز عبور مورد نیاز است", "password_required": "",
"password_reset_success": "بازنشانی رمز عبور موفقیت‌آمیز بود", "password_reset_success": "",
"past_durations": { "past_durations": {
"days": "", "days": "",
"hours": "", "hours": "",
"years": "" "years": ""
}, },
"path": "مسیر", "path": "",
"pattern": "الگو", "pattern": "",
"pause": "توقف", "pause": "",
"pause_memories": "توقف خاطرات", "pause_memories": "",
"paused": "متوقف شده", "paused": "",
"pending": "در انتظار", "pending": "",
"people": "افراد", "people": "",
"people_sidebar_description": "", "people_sidebar_description": "",
"permanent_deletion_warning": "هشدار حذف دائمی", "permanent_deletion_warning": "",
"permanent_deletion_warning_setting_description": "نمایش هشدار هنگام حذف دائمی محتواها", "permanent_deletion_warning_setting_description": "",
"permanently_delete": "حذف دائمی", "permanently_delete": "",
"permanently_deleted_asset": "محتوای حذف شده دائمی", "permanently_deleted_asset": "",
"person": "فرد", "person": "",
"photos": "عکس‌ها", "photos": "",
"photos_count": "", "photos_count": "",
"photos_from_previous_years": "عکس‌های سال‌های گذشته", "photos_from_previous_years": "",
"pick_a_location": "یک مکان انتخاب کنید", "pick_a_location": "",
"place": "مکان", "place": "",
"places": "مکان‌ها", "places": "",
"play": "پخش", "play": "",
"play_memories": "پخش خاطرات", "play_memories": "",
"play_motion_photo": "پخش عکس متحرک", "play_motion_photo": "",
"play_or_pause_video": "پخش یا توقف ویدیو", "play_or_pause_video": "",
"port": "پورت", "port": "",
"preset": "پیش‌فرض", "preset": "",
"preview": "پیش‌نمایش", "preview": "",
"previous": "قبلی", "previous": "",
"previous_memory": "خاطره قبلی", "previous_memory": "",
"previous_or_next_photo": "عکس قبلی یا بعدی", "previous_or_next_photo": "",
"primary": "اصلی", "primary": "",
"profile_picture_set": "تصویر پروفایل تنظیم شد.", "profile_picture_set": "",
"public_share": "اشتراک عمومی", "public_share": "",
"reaction_options": "گزینه‌های واکنش", "reaction_options": "",
"read_changelog": "مطالعه تغییرات نسخه", "read_changelog": "",
"recent": "اخیر", "recent": "",
"recent_searches": "جستجوهای اخیر", "recent_searches": "",
"refresh": "تازه سازی", "refresh": "",
"refreshed": "تازه سازی شد", "refreshed": "",
"refreshes_every_file": "", "refreshes_every_file": "",
"remove": "حذف", "remove": "",
"remove_deleted_assets": "حذف محتواهای حذف‌شده", "remove_deleted_assets": "",
"remove_from_album": "حذف از آلبوم", "remove_from_album": "",
"remove_from_favorites": "حذف از علاقه‌مندی‌ها", "remove_from_favorites": "",
"remove_from_shared_link": "", "remove_from_shared_link": "",
"removed_api_key": "", "removed_api_key": "",
"rename": "تغییر نام", "rename": "",
"repair": "تعمیر", "repair": "",
"repair_no_results_message": "", "repair_no_results_message": "",
"replace_with_upload": "جایگزینی با آپلود", "replace_with_upload": "",
"require_password": "", "require_password": "",
"require_user_to_change_password_on_first_login": "", "require_user_to_change_password_on_first_login": "",
"reset": "بازنشانی", "reset": "",
"reset_password": "بازنشانی رمز عبور", "reset_password": "",
"reset_people_visibility": "", "reset_people_visibility": "",
"resolved_all_duplicates": "", "resolved_all_duplicates": "",
"restore": "بازیابی", "restore": "",
"restore_all": "بازیابی همه", "restore_all": "",
"restore_user": "بازیابی کاربر", "restore_user": "",
"resume": "ادامه", "resume": "",
"retry_upload": "", "retry_upload": "",
"review_duplicates": "بررسی تکراری‌ها", "review_duplicates": "",
"role": "نقش", "role": "",
"save": "ذخیره", "save": "",
"saved_api_key": "", "saved_api_key": "",
"saved_profile": "پروفایل ذخیره شد", "saved_profile": "",
"saved_settings": "تنظیمات ذخیره شد", "saved_settings": "",
"say_something": "چیزی بگویید", "say_something": "",
"scan_all_libraries": "اسکن همه کتابخانه‌ها", "scan_all_libraries": "",
"scan_settings": "تنظیمات اسکن", "scan_settings": "",
"scanning_for_album": "", "scanning_for_album": "",
"search": "جستجو", "search": "",
"search_albums": "جستجوی آلبوم‌ها", "search_albums": "",
"search_by_context": "جستجو براساس زمینه", "search_by_context": "",
"search_camera_make": "جستجوی برند دوربین...", "search_camera_make": "",
"search_camera_model": "جستجوی مدل دوربین...", "search_camera_model": "",
"search_city": "جستجوی شهر...", "search_city": "",
"search_country": "جستجوی کشور...", "search_country": "",
"search_for_existing_person": "جستجوی فرد موجود", "search_for_existing_person": "",
"search_people": "جستجوی افراد", "search_people": "",
"search_places": "جستجوی مکان‌ها", "search_places": "",
"search_state": "جستجوی ایالت...", "search_state": "",
"search_timezone": "جستجوی منطقه زمانی...", "search_timezone": "",
"search_type": "نوع جستجو", "search_type": "",
"search_your_photos": "", "search_your_photos": "",
"searching_locales": "", "searching_locales": "",
"second": "ثانیه", "second": "",
"select_album_cover": "انتخاب جلد آلبوم", "select_album_cover": "",
"select_all": "انتخاب همه", "select_all": "",
"select_avatar_color": "انتخاب رنگ آواتار", "select_avatar_color": "",
"select_face": "انتخاب چهره", "select_face": "",
"select_featured_photo": "انتخاب عکس ویژه", "select_featured_photo": "",
"select_keep_all": "انتخاب نگهداری همه", "select_keep_all": "",
"select_library_owner": "انتخاب مالک کتابخانه", "select_library_owner": "",
"select_new_face": "انتخاب چهره جدید", "select_new_face": "",
"select_photos": "انتخاب عکس‌ها", "select_photos": "",
"select_trash_all": "", "select_trash_all": "",
"selected": "انتخاب شده", "selected": "",
"send_message": "ارسال پیام", "send_message": "",
"send_welcome_email": "ارسال ایمیل خوش‌آمدگویی", "send_welcome_email": "",
"server_stats": "آمار سرور", "server_stats": "",
"set": "تنظیم", "set": "",
"set_as_album_cover": "", "set_as_album_cover": "",
"set_as_profile_picture": "", "set_as_profile_picture": "",
"set_date_of_birth": "تنظیم تاریخ تولد", "set_date_of_birth": "",
"set_profile_picture": "تنظیم تصویر پروفایل", "set_profile_picture": "",
"set_slideshow_to_fullscreen": "", "set_slideshow_to_fullscreen": "",
"settings": "تنظیمات", "settings": "",
"settings_saved": "تنظیمات ذخیره شد", "settings_saved": "",
"share": "اشتراک‌گذاری", "share": "",
"shared": "مشترک", "shared": "",
"shared_by": "مشترک توسط", "shared_by": "",
"shared_by_you": "", "shared_by_you": "",
"shared_from_partner": "عکس‌ها از {partner}", "shared_from_partner": "",
"shared_links": "لینک‌های اشتراکی", "shared_links": "",
"shared_photos_and_videos_count": "", "shared_photos_and_videos_count": "",
"shared_with_partner": "مشترک با {partner}", "shared_with_partner": "",
"sharing": "اشتراک‌گذاری", "sharing": "",
"sharing_sidebar_description": "", "sharing_sidebar_description": "",
"show_album_options": "نمایش گزینه‌های آلبوم", "show_album_options": "",
"show_and_hide_people": "", "show_and_hide_people": "",
"show_file_location": "نمایش مسیر فایل", "show_file_location": "",
"show_gallery": "نمایش گالری", "show_gallery": "",
"show_hidden_people": "نمایش افراد پنهان", "show_hidden_people": "",
"show_in_timeline": "", "show_in_timeline": "",
"show_in_timeline_setting_description": "", "show_in_timeline_setting_description": "",
"show_keyboard_shortcuts": "", "show_keyboard_shortcuts": "",
"show_metadata": "نمایش اطلاعات متا", "show_metadata": "",
"show_or_hide_info": "", "show_or_hide_info": "",
"show_password": "نمایش رمز عبور", "show_password": "",
"show_person_options": "", "show_person_options": "",
"show_progress_bar": "نمایش نوار پیشرفت", "show_progress_bar": "",
"show_search_options": "نمایش گزینه‌های جستجو", "show_search_options": "",
"shuffle": "تصادفی", "shuffle": "",
"sign_out": "خروج", "sign_out": "",
"sign_up": "ثبت‌نام", "sign_up": "",
"size": "اندازه", "size": "",
"skip_to_content": "رفتن به محتوا", "skip_to_content": "",
"slideshow": "نمایش اسلاید", "slideshow": "",
"slideshow_settings": "تنظیمات نمایش اسلاید", "slideshow_settings": "",
"sort_albums_by": "", "sort_albums_by": "",
"stack": "پشته", "stack": "",
"stack_selected_photos": "", "stack_selected_photos": "",
"stacktrace": "", "stacktrace": "",
"start": "شروع", "start": "",
"start_date": "تاریخ شروع", "start_date": "",
"state": "ایالت", "state": "",
"status": "وضعیت", "status": "",
"stop_motion_photo": "توقف عکس متحرک", "stop_motion_photo": "",
"stop_photo_sharing": "", "stop_photo_sharing": "",
"stop_photo_sharing_description": "", "stop_photo_sharing_description": "",
"stop_sharing_photos_with_user": "", "stop_sharing_photos_with_user": "",
"storage": "فضای ذخیره‌سازی", "storage": "",
"storage_label": "برچسب فضای ذخیره‌سازی", "storage_label": "",
"storage_usage": "", "storage_usage": "",
"submit": "ارسال", "submit": "",
"suggestions": "پیشنهادات", "suggestions": "",
"sunrise_on_the_beach": "", "sunrise_on_the_beach": "",
"swap_merge_direction": "تغییر جهت ادغام", "swap_merge_direction": "",
"sync": "همگام‌سازی", "sync": "",
"template": "الگو", "template": "",
"theme": "تم", "theme": "",
"theme_selection": "انتخاب تم", "theme_selection": "",
"theme_selection_description": "", "theme_selection_description": "",
"time_based_memories": "", "time_based_memories": "",
"timezone": "منطقه زمانی", "timezone": "",
"to_archive": "بایگانی", "to_archive": "",
"to_favorite": "به علاقه‌مندی‌ها", "to_favorite": "",
"to_trash": "", "to_trash": "",
"toggle_settings": "تغییر تنظیمات", "toggle_settings": "",
"toggle_theme": "تغییر تم تاریک", "toggle_theme": "",
"total_usage": "استفاده کلی", "total_usage": "",
"trash": "سطل زباله", "trash": "",
"trash_all": "", "trash_all": "",
"trash_count": "", "trash_count": "",
"trash_no_results_message": "", "trash_no_results_message": "",
"trashed_items_will_be_permanently_deleted_after": "", "trashed_items_will_be_permanently_deleted_after": "",
"type": "نوع", "type": "",
"unarchive": "", "unarchive": "",
"unfavorite": "حذف از علاقه‌مندی‌ها", "unfavorite": "",
"unhide_person": "آشکار کردن فرد", "unhide_person": "",
"unknown": "ناشناخته", "unknown": "",
"unknown_year": "سال نامشخص", "unknown_year": "",
"unlimited": "نامحدود", "unlimited": "",
"unlink_oauth": "لغو اتصال OAuth", "unlink_oauth": "",
"unlinked_oauth_account": "", "unlinked_oauth_account": "",
"unnamed_album": "آلبوم بدون نام", "unnamed_album": "",
"unnamed_share": "اشتراک بدون نام", "unnamed_share": "",
"unselect_all": "لغو انتخاب همه", "unselect_all": "",
"unstack": "", "unstack": "",
"untracked_files": "", "untracked_files": "",
"untracked_files_decription": "", "untracked_files_decription": "",
"up_next": "مورد بعدی", "up_next": "",
"updated_password": "", "updated_password": "",
"upload": "آپلود", "upload": "",
"upload_concurrency": "تعداد آپلود همزمان", "upload_concurrency": "",
"url": "آدرس", "url": "",
"usage": "استفاده", "usage": "",
"user": "کاربر", "user": "",
"user_id": "شناسه کاربر", "user_id": "",
"user_usage_detail": "جزئیات استفاده کاربر", "user_usage_detail": "",
"username": "نام کاربری", "username": "",
"users": "کاربران", "users": "",
"utilities": "ابزارها", "utilities": "",
"validate": "اعتبارسنجی", "validate": "",
"variables": "متغیرها", "variables": "",
"version": "نسخه", "version": "",
"version_announcement_message": "", "version_announcement_message": "",
"video": "ویدیو", "video": "",
"video_hover_setting": "", "video_hover_setting": "",
"video_hover_setting_description": "", "video_hover_setting_description": "",
"videos": "ویدیوها", "videos": "",
"videos_count": "", "videos_count": "",
"view": "مشاهده", "view": "",
"view_all": "مشاهده همه", "view_all": "",
"view_all_users": "مشاهده همه کاربران", "view_all_users": "",
"view_links": "مشاهده لینک‌ها", "view_links": "",
"view_next_asset": "مشاهده محتوای بعدی", "view_next_asset": "",
"view_previous_asset": "مشاهده محتوای قبلی", "view_previous_asset": "",
"waiting": "در انتظار", "waiting": "",
"week": "هفته", "week": "",
"welcome": "خوش آمدید", "welcome": "",
"welcome_to_immich": "", "welcome_to_immich": "",
"year": "سال", "year": "",
"yes": "بله", "yes": "",
"you_dont_have_any_shared_links": "", "you_dont_have_any_shared_links": "",
"zoom_image": "بزرگنمایی تصویر" "zoom_image": "بزرگنمایی تصویر"
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "machine-learning" name = "machine-learning"
version = "1.126.1" version = "1.125.7"
description = "" description = ""
authors = ["Hau Tran <alex.tran1502@gmail.com>"] authors = ["Hau Tran <alex.tran1502@gmail.com>"]
readme = "README.md" readme = "README.md"
+2 -2
View File
@@ -35,8 +35,8 @@ platform :android do
task: 'bundle', task: 'bundle',
build_type: 'Release', build_type: 'Release',
properties: { properties: {
"android.injected.version.code" => 184, "android.injected.version.code" => 182,
"android.injected.version.name" => "1.126.1", "android.injected.version.name" => "1.125.7",
} }
) )
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab') upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
+6 -6
View File
@@ -541,7 +541,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 193; CURRENT_PROJECT_VERSION = 190;
CUSTOM_GROUP_ID = group.app.immich.share; CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79; DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
@@ -685,7 +685,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 193; CURRENT_PROJECT_VERSION = 190;
CUSTOM_GROUP_ID = group.app.immich.share; CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79; DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
@@ -715,7 +715,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 193; CURRENT_PROJECT_VERSION = 190;
CUSTOM_GROUP_ID = group.app.immich.share; CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79; DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
@@ -748,7 +748,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 193; CURRENT_PROJECT_VERSION = 190;
CUSTOM_GROUP_ID = group.app.immich.share; CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79; DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -791,7 +791,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 193; CURRENT_PROJECT_VERSION = 190;
CUSTOM_GROUP_ID = group.app.immich.share; CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79; DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -831,7 +831,7 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements; CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 193; CURRENT_PROJECT_VERSION = 190;
CUSTOM_GROUP_ID = group.app.immich.share; CUSTOM_GROUP_ID = group.app.immich.share;
DEVELOPMENT_TEAM = 2F67MQ8R79; DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES;
+2 -2
View File
@@ -78,7 +78,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.126.0</string> <string>1.125.2</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
@@ -93,7 +93,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>193</string> <string>190</string>
<key>FLTEnableImpeller</key> <key>FLTEnableImpeller</key>
<true/> <true/>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
+1 -1
View File
@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Release" desc "iOS Release"
lane :release do lane :release do
increment_version_number( increment_version_number(
version_number: "1.126.1" version_number: "1.125.7"
) )
increment_build_number( increment_build_number(
build_number: latest_testflight_build_number + 1, build_number: latest_testflight_build_number + 1,
-1
View File
@@ -10,7 +10,6 @@ dynamic upgradeDto(dynamic value, String targetType) {
addDefault(value, 'ratings', RatingsResponse().toJson()); addDefault(value, 'ratings', RatingsResponse().toJson());
addDefault(value, 'people', PeopleResponse().toJson()); addDefault(value, 'people', PeopleResponse().toJson());
addDefault(value, 'tags', TagsResponse().toJson()); addDefault(value, 'tags', TagsResponse().toJson());
addDefault(value, 'sharedLinks', SharedLinksResponse().toJson());
} }
break; break;
case 'ServerConfigDto': case 'ServerConfigDto':
+1 -3
View File
@@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project: This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 1.126.1 - API version: 1.125.7
- Generator version: 7.8.0 - Generator version: 7.8.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen - Build package: org.openapitools.codegen.languages.DartClientCodegen
@@ -408,8 +408,6 @@ Class | Method | HTTP request | Description
- [SharedLinkEditDto](doc//SharedLinkEditDto.md) - [SharedLinkEditDto](doc//SharedLinkEditDto.md)
- [SharedLinkResponseDto](doc//SharedLinkResponseDto.md) - [SharedLinkResponseDto](doc//SharedLinkResponseDto.md)
- [SharedLinkType](doc//SharedLinkType.md) - [SharedLinkType](doc//SharedLinkType.md)
- [SharedLinksResponse](doc//SharedLinksResponse.md)
- [SharedLinksUpdate](doc//SharedLinksUpdate.md)
- [SignUpDto](doc//SignUpDto.md) - [SignUpDto](doc//SignUpDto.md)
- [SmartSearchDto](doc//SmartSearchDto.md) - [SmartSearchDto](doc//SmartSearchDto.md)
- [SourceType](doc//SourceType.md) - [SourceType](doc//SourceType.md)
-2
View File
@@ -221,8 +221,6 @@ part 'model/shared_link_create_dto.dart';
part 'model/shared_link_edit_dto.dart'; part 'model/shared_link_edit_dto.dart';
part 'model/shared_link_response_dto.dart'; part 'model/shared_link_response_dto.dart';
part 'model/shared_link_type.dart'; part 'model/shared_link_type.dart';
part 'model/shared_links_response.dart';
part 'model/shared_links_update.dart';
part 'model/sign_up_dto.dart'; part 'model/sign_up_dto.dart';
part 'model/smart_search_dto.dart'; part 'model/smart_search_dto.dart';
part 'model/source_type.dart'; part 'model/source_type.dart';
+3 -13
View File
@@ -127,10 +127,7 @@ class SharedLinksApi {
} }
/// Performs an HTTP 'GET /shared-links' operation and returns the [Response]. /// Performs an HTTP 'GET /shared-links' operation and returns the [Response].
/// Parameters: Future<Response> getAllSharedLinksWithHttpInfo() async {
///
/// * [String] albumId:
Future<Response> getAllSharedLinksWithHttpInfo({ String? albumId, }) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/shared-links'; final path = r'/shared-links';
@@ -141,10 +138,6 @@ class SharedLinksApi {
final headerParams = <String, String>{}; final headerParams = <String, String>{};
final formParams = <String, String>{}; final formParams = <String, String>{};
if (albumId != null) {
queryParams.addAll(_queryParams('', 'albumId', albumId));
}
const contentTypes = <String>[]; const contentTypes = <String>[];
@@ -159,11 +152,8 @@ class SharedLinksApi {
); );
} }
/// Parameters: Future<List<SharedLinkResponseDto>?> getAllSharedLinks() async {
/// final response = await getAllSharedLinksWithHttpInfo();
/// * [String] albumId:
Future<List<SharedLinkResponseDto>?> getAllSharedLinks({ String? albumId, }) async {
final response = await getAllSharedLinksWithHttpInfo( albumId: albumId, );
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }
-4
View File
@@ -496,10 +496,6 @@ class ApiClient {
return SharedLinkResponseDto.fromJson(value); return SharedLinkResponseDto.fromJson(value);
case 'SharedLinkType': case 'SharedLinkType':
return SharedLinkTypeTypeTransformer().decode(value); return SharedLinkTypeTypeTransformer().decode(value);
case 'SharedLinksResponse':
return SharedLinksResponse.fromJson(value);
case 'SharedLinksUpdate':
return SharedLinksUpdate.fromJson(value);
case 'SignUpDto': case 'SignUpDto':
return SignUpDto.fromJson(value); return SignUpDto.fromJson(value);
case 'SmartSearchDto': case 'SmartSearchDto':
+1 -12
View File
@@ -14,7 +14,6 @@ class PeopleUpdateItem {
/// Returns a new [PeopleUpdateItem] instance. /// Returns a new [PeopleUpdateItem] instance.
PeopleUpdateItem({ PeopleUpdateItem({
this.birthDate, this.birthDate,
this.color,
this.featureFaceAssetId, this.featureFaceAssetId,
required this.id, required this.id,
this.isFavorite, this.isFavorite,
@@ -25,8 +24,6 @@ class PeopleUpdateItem {
/// Person date of birth. Note: the mobile app cannot currently set the birth date to null. /// Person date of birth. Note: the mobile app cannot currently set the birth date to null.
DateTime? birthDate; DateTime? birthDate;
String? color;
/// Asset is used to get the feature face thumbnail. /// Asset is used to get the feature face thumbnail.
/// ///
/// Please note: This property should have been non-nullable! Since the specification file /// Please note: This property should have been non-nullable! Since the specification file
@@ -68,7 +65,6 @@ class PeopleUpdateItem {
@override @override
bool operator ==(Object other) => identical(this, other) || other is PeopleUpdateItem && bool operator ==(Object other) => identical(this, other) || other is PeopleUpdateItem &&
other.birthDate == birthDate && other.birthDate == birthDate &&
other.color == color &&
other.featureFaceAssetId == featureFaceAssetId && other.featureFaceAssetId == featureFaceAssetId &&
other.id == id && other.id == id &&
other.isFavorite == isFavorite && other.isFavorite == isFavorite &&
@@ -79,7 +75,6 @@ class PeopleUpdateItem {
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(birthDate == null ? 0 : birthDate!.hashCode) + (birthDate == null ? 0 : birthDate!.hashCode) +
(color == null ? 0 : color!.hashCode) +
(featureFaceAssetId == null ? 0 : featureFaceAssetId!.hashCode) + (featureFaceAssetId == null ? 0 : featureFaceAssetId!.hashCode) +
(id.hashCode) + (id.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode) + (isFavorite == null ? 0 : isFavorite!.hashCode) +
@@ -87,7 +82,7 @@ class PeopleUpdateItem {
(name == null ? 0 : name!.hashCode); (name == null ? 0 : name!.hashCode);
@override @override
String toString() => 'PeopleUpdateItem[birthDate=$birthDate, color=$color, featureFaceAssetId=$featureFaceAssetId, id=$id, isFavorite=$isFavorite, isHidden=$isHidden, name=$name]'; String toString() => 'PeopleUpdateItem[birthDate=$birthDate, featureFaceAssetId=$featureFaceAssetId, id=$id, isFavorite=$isFavorite, isHidden=$isHidden, name=$name]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -96,11 +91,6 @@ class PeopleUpdateItem {
} else { } else {
// json[r'birthDate'] = null; // json[r'birthDate'] = null;
} }
if (this.color != null) {
json[r'color'] = this.color;
} else {
// json[r'color'] = null;
}
if (this.featureFaceAssetId != null) { if (this.featureFaceAssetId != null) {
json[r'featureFaceAssetId'] = this.featureFaceAssetId; json[r'featureFaceAssetId'] = this.featureFaceAssetId;
} else { } else {
@@ -135,7 +125,6 @@ class PeopleUpdateItem {
return PeopleUpdateItem( return PeopleUpdateItem(
birthDate: mapDateTime(json, r'birthDate', r''), birthDate: mapDateTime(json, r'birthDate', r''),
color: mapValueOfType<String>(json, r'color'),
featureFaceAssetId: mapValueOfType<String>(json, r'featureFaceAssetId'), featureFaceAssetId: mapValueOfType<String>(json, r'featureFaceAssetId'),
id: mapValueOfType<String>(json, r'id')!, id: mapValueOfType<String>(json, r'id')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite'), isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
+1 -12
View File
@@ -14,7 +14,6 @@ class PersonCreateDto {
/// Returns a new [PersonCreateDto] instance. /// Returns a new [PersonCreateDto] instance.
PersonCreateDto({ PersonCreateDto({
this.birthDate, this.birthDate,
this.color,
this.isFavorite, this.isFavorite,
this.isHidden, this.isHidden,
this.name, this.name,
@@ -23,8 +22,6 @@ class PersonCreateDto {
/// Person date of birth. Note: the mobile app cannot currently set the birth date to null. /// Person date of birth. Note: the mobile app cannot currently set the birth date to null.
DateTime? birthDate; DateTime? birthDate;
String? color;
/// ///
/// Please note: This property should have been non-nullable! Since the specification file /// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated /// does not include a default value (using the "default:" property), however, the generated
@@ -54,7 +51,6 @@ class PersonCreateDto {
@override @override
bool operator ==(Object other) => identical(this, other) || other is PersonCreateDto && bool operator ==(Object other) => identical(this, other) || other is PersonCreateDto &&
other.birthDate == birthDate && other.birthDate == birthDate &&
other.color == color &&
other.isFavorite == isFavorite && other.isFavorite == isFavorite &&
other.isHidden == isHidden && other.isHidden == isHidden &&
other.name == name; other.name == name;
@@ -63,13 +59,12 @@ class PersonCreateDto {
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(birthDate == null ? 0 : birthDate!.hashCode) + (birthDate == null ? 0 : birthDate!.hashCode) +
(color == null ? 0 : color!.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode) + (isFavorite == null ? 0 : isFavorite!.hashCode) +
(isHidden == null ? 0 : isHidden!.hashCode) + (isHidden == null ? 0 : isHidden!.hashCode) +
(name == null ? 0 : name!.hashCode); (name == null ? 0 : name!.hashCode);
@override @override
String toString() => 'PersonCreateDto[birthDate=$birthDate, color=$color, isFavorite=$isFavorite, isHidden=$isHidden, name=$name]'; String toString() => 'PersonCreateDto[birthDate=$birthDate, isFavorite=$isFavorite, isHidden=$isHidden, name=$name]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -78,11 +73,6 @@ class PersonCreateDto {
} else { } else {
// json[r'birthDate'] = null; // json[r'birthDate'] = null;
} }
if (this.color != null) {
json[r'color'] = this.color;
} else {
// json[r'color'] = null;
}
if (this.isFavorite != null) { if (this.isFavorite != null) {
json[r'isFavorite'] = this.isFavorite; json[r'isFavorite'] = this.isFavorite;
} else { } else {
@@ -111,7 +101,6 @@ class PersonCreateDto {
return PersonCreateDto( return PersonCreateDto(
birthDate: mapDateTime(json, r'birthDate', r''), birthDate: mapDateTime(json, r'birthDate', r''),
color: mapValueOfType<String>(json, r'color'),
isFavorite: mapValueOfType<bool>(json, r'isFavorite'), isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
isHidden: mapValueOfType<bool>(json, r'isHidden'), isHidden: mapValueOfType<bool>(json, r'isHidden'),
name: mapValueOfType<String>(json, r'name'), name: mapValueOfType<String>(json, r'name'),
+1 -19
View File
@@ -14,7 +14,6 @@ class PersonResponseDto {
/// Returns a new [PersonResponseDto] instance. /// Returns a new [PersonResponseDto] instance.
PersonResponseDto({ PersonResponseDto({
required this.birthDate, required this.birthDate,
this.color,
required this.id, required this.id,
this.isFavorite, this.isFavorite,
required this.isHidden, required this.isHidden,
@@ -25,15 +24,6 @@ class PersonResponseDto {
DateTime? birthDate; DateTime? birthDate;
/// This property was added in v1.126.0
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? color;
String id; String id;
/// This property was added in v1.126.0 /// This property was added in v1.126.0
@@ -63,7 +53,6 @@ class PersonResponseDto {
@override @override
bool operator ==(Object other) => identical(this, other) || other is PersonResponseDto && bool operator ==(Object other) => identical(this, other) || other is PersonResponseDto &&
other.birthDate == birthDate && other.birthDate == birthDate &&
other.color == color &&
other.id == id && other.id == id &&
other.isFavorite == isFavorite && other.isFavorite == isFavorite &&
other.isHidden == isHidden && other.isHidden == isHidden &&
@@ -75,7 +64,6 @@ class PersonResponseDto {
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(birthDate == null ? 0 : birthDate!.hashCode) + (birthDate == null ? 0 : birthDate!.hashCode) +
(color == null ? 0 : color!.hashCode) +
(id.hashCode) + (id.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode) + (isFavorite == null ? 0 : isFavorite!.hashCode) +
(isHidden.hashCode) + (isHidden.hashCode) +
@@ -84,7 +72,7 @@ class PersonResponseDto {
(updatedAt == null ? 0 : updatedAt!.hashCode); (updatedAt == null ? 0 : updatedAt!.hashCode);
@override @override
String toString() => 'PersonResponseDto[birthDate=$birthDate, color=$color, id=$id, isFavorite=$isFavorite, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath, updatedAt=$updatedAt]'; String toString() => 'PersonResponseDto[birthDate=$birthDate, id=$id, isFavorite=$isFavorite, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -92,11 +80,6 @@ class PersonResponseDto {
json[r'birthDate'] = _dateFormatter.format(this.birthDate!.toUtc()); json[r'birthDate'] = _dateFormatter.format(this.birthDate!.toUtc());
} else { } else {
// json[r'birthDate'] = null; // json[r'birthDate'] = null;
}
if (this.color != null) {
json[r'color'] = this.color;
} else {
// json[r'color'] = null;
} }
json[r'id'] = this.id; json[r'id'] = this.id;
if (this.isFavorite != null) { if (this.isFavorite != null) {
@@ -125,7 +108,6 @@ class PersonResponseDto {
return PersonResponseDto( return PersonResponseDto(
birthDate: mapDateTime(json, r'birthDate', r''), birthDate: mapDateTime(json, r'birthDate', r''),
color: mapValueOfType<String>(json, r'color'),
id: mapValueOfType<String>(json, r'id')!, id: mapValueOfType<String>(json, r'id')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite'), isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
isHidden: mapValueOfType<bool>(json, r'isHidden')!, isHidden: mapValueOfType<bool>(json, r'isHidden')!,
+1 -12
View File
@@ -14,7 +14,6 @@ class PersonUpdateDto {
/// Returns a new [PersonUpdateDto] instance. /// Returns a new [PersonUpdateDto] instance.
PersonUpdateDto({ PersonUpdateDto({
this.birthDate, this.birthDate,
this.color,
this.featureFaceAssetId, this.featureFaceAssetId,
this.isFavorite, this.isFavorite,
this.isHidden, this.isHidden,
@@ -24,8 +23,6 @@ class PersonUpdateDto {
/// Person date of birth. Note: the mobile app cannot currently set the birth date to null. /// Person date of birth. Note: the mobile app cannot currently set the birth date to null.
DateTime? birthDate; DateTime? birthDate;
String? color;
/// Asset is used to get the feature face thumbnail. /// Asset is used to get the feature face thumbnail.
/// ///
/// Please note: This property should have been non-nullable! Since the specification file /// Please note: This property should have been non-nullable! Since the specification file
@@ -64,7 +61,6 @@ class PersonUpdateDto {
@override @override
bool operator ==(Object other) => identical(this, other) || other is PersonUpdateDto && bool operator ==(Object other) => identical(this, other) || other is PersonUpdateDto &&
other.birthDate == birthDate && other.birthDate == birthDate &&
other.color == color &&
other.featureFaceAssetId == featureFaceAssetId && other.featureFaceAssetId == featureFaceAssetId &&
other.isFavorite == isFavorite && other.isFavorite == isFavorite &&
other.isHidden == isHidden && other.isHidden == isHidden &&
@@ -74,14 +70,13 @@ class PersonUpdateDto {
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(birthDate == null ? 0 : birthDate!.hashCode) + (birthDate == null ? 0 : birthDate!.hashCode) +
(color == null ? 0 : color!.hashCode) +
(featureFaceAssetId == null ? 0 : featureFaceAssetId!.hashCode) + (featureFaceAssetId == null ? 0 : featureFaceAssetId!.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode) + (isFavorite == null ? 0 : isFavorite!.hashCode) +
(isHidden == null ? 0 : isHidden!.hashCode) + (isHidden == null ? 0 : isHidden!.hashCode) +
(name == null ? 0 : name!.hashCode); (name == null ? 0 : name!.hashCode);
@override @override
String toString() => 'PersonUpdateDto[birthDate=$birthDate, color=$color, featureFaceAssetId=$featureFaceAssetId, isFavorite=$isFavorite, isHidden=$isHidden, name=$name]'; String toString() => 'PersonUpdateDto[birthDate=$birthDate, featureFaceAssetId=$featureFaceAssetId, isFavorite=$isFavorite, isHidden=$isHidden, name=$name]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -90,11 +85,6 @@ class PersonUpdateDto {
} else { } else {
// json[r'birthDate'] = null; // json[r'birthDate'] = null;
} }
if (this.color != null) {
json[r'color'] = this.color;
} else {
// json[r'color'] = null;
}
if (this.featureFaceAssetId != null) { if (this.featureFaceAssetId != null) {
json[r'featureFaceAssetId'] = this.featureFaceAssetId; json[r'featureFaceAssetId'] = this.featureFaceAssetId;
} else { } else {
@@ -128,7 +118,6 @@ class PersonUpdateDto {
return PersonUpdateDto( return PersonUpdateDto(
birthDate: mapDateTime(json, r'birthDate', r''), birthDate: mapDateTime(json, r'birthDate', r''),
color: mapValueOfType<String>(json, r'color'),
featureFaceAssetId: mapValueOfType<String>(json, r'featureFaceAssetId'), featureFaceAssetId: mapValueOfType<String>(json, r'featureFaceAssetId'),
isFavorite: mapValueOfType<bool>(json, r'isFavorite'), isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
isHidden: mapValueOfType<bool>(json, r'isHidden'), isHidden: mapValueOfType<bool>(json, r'isHidden'),
+1 -19
View File
@@ -14,7 +14,6 @@ class PersonWithFacesResponseDto {
/// Returns a new [PersonWithFacesResponseDto] instance. /// Returns a new [PersonWithFacesResponseDto] instance.
PersonWithFacesResponseDto({ PersonWithFacesResponseDto({
required this.birthDate, required this.birthDate,
this.color,
this.faces = const [], this.faces = const [],
required this.id, required this.id,
this.isFavorite, this.isFavorite,
@@ -26,15 +25,6 @@ class PersonWithFacesResponseDto {
DateTime? birthDate; DateTime? birthDate;
/// This property was added in v1.126.0
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
String? color;
List<AssetFaceWithoutPersonResponseDto> faces; List<AssetFaceWithoutPersonResponseDto> faces;
String id; String id;
@@ -66,7 +56,6 @@ class PersonWithFacesResponseDto {
@override @override
bool operator ==(Object other) => identical(this, other) || other is PersonWithFacesResponseDto && bool operator ==(Object other) => identical(this, other) || other is PersonWithFacesResponseDto &&
other.birthDate == birthDate && other.birthDate == birthDate &&
other.color == color &&
_deepEquality.equals(other.faces, faces) && _deepEquality.equals(other.faces, faces) &&
other.id == id && other.id == id &&
other.isFavorite == isFavorite && other.isFavorite == isFavorite &&
@@ -79,7 +68,6 @@ class PersonWithFacesResponseDto {
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(birthDate == null ? 0 : birthDate!.hashCode) + (birthDate == null ? 0 : birthDate!.hashCode) +
(color == null ? 0 : color!.hashCode) +
(faces.hashCode) + (faces.hashCode) +
(id.hashCode) + (id.hashCode) +
(isFavorite == null ? 0 : isFavorite!.hashCode) + (isFavorite == null ? 0 : isFavorite!.hashCode) +
@@ -89,7 +77,7 @@ class PersonWithFacesResponseDto {
(updatedAt == null ? 0 : updatedAt!.hashCode); (updatedAt == null ? 0 : updatedAt!.hashCode);
@override @override
String toString() => 'PersonWithFacesResponseDto[birthDate=$birthDate, color=$color, faces=$faces, id=$id, isFavorite=$isFavorite, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath, updatedAt=$updatedAt]'; String toString() => 'PersonWithFacesResponseDto[birthDate=$birthDate, faces=$faces, id=$id, isFavorite=$isFavorite, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath, updatedAt=$updatedAt]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -97,11 +85,6 @@ class PersonWithFacesResponseDto {
json[r'birthDate'] = _dateFormatter.format(this.birthDate!.toUtc()); json[r'birthDate'] = _dateFormatter.format(this.birthDate!.toUtc());
} else { } else {
// json[r'birthDate'] = null; // json[r'birthDate'] = null;
}
if (this.color != null) {
json[r'color'] = this.color;
} else {
// json[r'color'] = null;
} }
json[r'faces'] = this.faces; json[r'faces'] = this.faces;
json[r'id'] = this.id; json[r'id'] = this.id;
@@ -131,7 +114,6 @@ class PersonWithFacesResponseDto {
return PersonWithFacesResponseDto( return PersonWithFacesResponseDto(
birthDate: mapDateTime(json, r'birthDate', r''), birthDate: mapDateTime(json, r'birthDate', r''),
color: mapValueOfType<String>(json, r'color'),
faces: AssetFaceWithoutPersonResponseDto.listFromJson(json[r'faces']), faces: AssetFaceWithoutPersonResponseDto.listFromJson(json[r'faces']),
id: mapValueOfType<String>(json, r'id')!, id: mapValueOfType<String>(json, r'id')!,
isFavorite: mapValueOfType<bool>(json, r'isFavorite'), isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
-107
View File
@@ -1,107 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class SharedLinksResponse {
/// Returns a new [SharedLinksResponse] instance.
SharedLinksResponse({
this.enabled = true,
this.sidebarWeb = false,
});
bool enabled;
bool sidebarWeb;
@override
bool operator ==(Object other) => identical(this, other) || other is SharedLinksResponse &&
other.enabled == enabled &&
other.sidebarWeb == sidebarWeb;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(enabled.hashCode) +
(sidebarWeb.hashCode);
@override
String toString() => 'SharedLinksResponse[enabled=$enabled, sidebarWeb=$sidebarWeb]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'enabled'] = this.enabled;
json[r'sidebarWeb'] = this.sidebarWeb;
return json;
}
/// Returns a new [SharedLinksResponse] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SharedLinksResponse? fromJson(dynamic value) {
upgradeDto(value, "SharedLinksResponse");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SharedLinksResponse(
enabled: mapValueOfType<bool>(json, r'enabled')!,
sidebarWeb: mapValueOfType<bool>(json, r'sidebarWeb')!,
);
}
return null;
}
static List<SharedLinksResponse> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SharedLinksResponse>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SharedLinksResponse.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SharedLinksResponse> mapFromJson(dynamic json) {
final map = <String, SharedLinksResponse>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SharedLinksResponse.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SharedLinksResponse-objects as value to a dart map
static Map<String, List<SharedLinksResponse>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SharedLinksResponse>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SharedLinksResponse.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'enabled',
'sidebarWeb',
};
}
-125
View File
@@ -1,125 +0,0 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class SharedLinksUpdate {
/// Returns a new [SharedLinksUpdate] instance.
SharedLinksUpdate({
this.enabled,
this.sidebarWeb,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? enabled;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? sidebarWeb;
@override
bool operator ==(Object other) => identical(this, other) || other is SharedLinksUpdate &&
other.enabled == enabled &&
other.sidebarWeb == sidebarWeb;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(enabled == null ? 0 : enabled!.hashCode) +
(sidebarWeb == null ? 0 : sidebarWeb!.hashCode);
@override
String toString() => 'SharedLinksUpdate[enabled=$enabled, sidebarWeb=$sidebarWeb]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (this.enabled != null) {
json[r'enabled'] = this.enabled;
} else {
// json[r'enabled'] = null;
}
if (this.sidebarWeb != null) {
json[r'sidebarWeb'] = this.sidebarWeb;
} else {
// json[r'sidebarWeb'] = null;
}
return json;
}
/// Returns a new [SharedLinksUpdate] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static SharedLinksUpdate? fromJson(dynamic value) {
upgradeDto(value, "SharedLinksUpdate");
if (value is Map) {
final json = value.cast<String, dynamic>();
return SharedLinksUpdate(
enabled: mapValueOfType<bool>(json, r'enabled'),
sidebarWeb: mapValueOfType<bool>(json, r'sidebarWeb'),
);
}
return null;
}
static List<SharedLinksUpdate> listFromJson(dynamic json, {bool growable = false,}) {
final result = <SharedLinksUpdate>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = SharedLinksUpdate.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, SharedLinksUpdate> mapFromJson(dynamic json) {
final map = <String, SharedLinksUpdate>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = SharedLinksUpdate.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of SharedLinksUpdate-objects as value to a dart map
static Map<String, List<SharedLinksUpdate>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<SharedLinksUpdate>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = SharedLinksUpdate.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
};
}
+1 -9
View File
@@ -21,7 +21,6 @@ class UserPreferencesResponseDto {
required this.people, required this.people,
required this.purchase, required this.purchase,
required this.ratings, required this.ratings,
required this.sharedLinks,
required this.tags, required this.tags,
}); });
@@ -41,8 +40,6 @@ class UserPreferencesResponseDto {
RatingsResponse ratings; RatingsResponse ratings;
SharedLinksResponse sharedLinks;
TagsResponse tags; TagsResponse tags;
@override @override
@@ -55,7 +52,6 @@ class UserPreferencesResponseDto {
other.people == people && other.people == people &&
other.purchase == purchase && other.purchase == purchase &&
other.ratings == ratings && other.ratings == ratings &&
other.sharedLinks == sharedLinks &&
other.tags == tags; other.tags == tags;
@override @override
@@ -69,11 +65,10 @@ class UserPreferencesResponseDto {
(people.hashCode) + (people.hashCode) +
(purchase.hashCode) + (purchase.hashCode) +
(ratings.hashCode) + (ratings.hashCode) +
(sharedLinks.hashCode) +
(tags.hashCode); (tags.hashCode);
@override @override
String toString() => 'UserPreferencesResponseDto[avatar=$avatar, download=$download, emailNotifications=$emailNotifications, folders=$folders, memories=$memories, people=$people, purchase=$purchase, ratings=$ratings, sharedLinks=$sharedLinks, tags=$tags]'; String toString() => 'UserPreferencesResponseDto[avatar=$avatar, download=$download, emailNotifications=$emailNotifications, folders=$folders, memories=$memories, people=$people, purchase=$purchase, ratings=$ratings, tags=$tags]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -85,7 +80,6 @@ class UserPreferencesResponseDto {
json[r'people'] = this.people; json[r'people'] = this.people;
json[r'purchase'] = this.purchase; json[r'purchase'] = this.purchase;
json[r'ratings'] = this.ratings; json[r'ratings'] = this.ratings;
json[r'sharedLinks'] = this.sharedLinks;
json[r'tags'] = this.tags; json[r'tags'] = this.tags;
return json; return json;
} }
@@ -107,7 +101,6 @@ class UserPreferencesResponseDto {
people: PeopleResponse.fromJson(json[r'people'])!, people: PeopleResponse.fromJson(json[r'people'])!,
purchase: PurchaseResponse.fromJson(json[r'purchase'])!, purchase: PurchaseResponse.fromJson(json[r'purchase'])!,
ratings: RatingsResponse.fromJson(json[r'ratings'])!, ratings: RatingsResponse.fromJson(json[r'ratings'])!,
sharedLinks: SharedLinksResponse.fromJson(json[r'sharedLinks'])!,
tags: TagsResponse.fromJson(json[r'tags'])!, tags: TagsResponse.fromJson(json[r'tags'])!,
); );
} }
@@ -164,7 +157,6 @@ class UserPreferencesResponseDto {
'people', 'people',
'purchase', 'purchase',
'ratings', 'ratings',
'sharedLinks',
'tags', 'tags',
}; };
} }
+1 -18
View File
@@ -21,7 +21,6 @@ class UserPreferencesUpdateDto {
this.people, this.people,
this.purchase, this.purchase,
this.ratings, this.ratings,
this.sharedLinks,
this.tags, this.tags,
}); });
@@ -89,14 +88,6 @@ class UserPreferencesUpdateDto {
/// ///
RatingsUpdate? ratings; RatingsUpdate? ratings;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
SharedLinksUpdate? sharedLinks;
/// ///
/// Please note: This property should have been non-nullable! Since the specification file /// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated /// does not include a default value (using the "default:" property), however, the generated
@@ -115,7 +106,6 @@ class UserPreferencesUpdateDto {
other.people == people && other.people == people &&
other.purchase == purchase && other.purchase == purchase &&
other.ratings == ratings && other.ratings == ratings &&
other.sharedLinks == sharedLinks &&
other.tags == tags; other.tags == tags;
@override @override
@@ -129,11 +119,10 @@ class UserPreferencesUpdateDto {
(people == null ? 0 : people!.hashCode) + (people == null ? 0 : people!.hashCode) +
(purchase == null ? 0 : purchase!.hashCode) + (purchase == null ? 0 : purchase!.hashCode) +
(ratings == null ? 0 : ratings!.hashCode) + (ratings == null ? 0 : ratings!.hashCode) +
(sharedLinks == null ? 0 : sharedLinks!.hashCode) +
(tags == null ? 0 : tags!.hashCode); (tags == null ? 0 : tags!.hashCode);
@override @override
String toString() => 'UserPreferencesUpdateDto[avatar=$avatar, download=$download, emailNotifications=$emailNotifications, folders=$folders, memories=$memories, people=$people, purchase=$purchase, ratings=$ratings, sharedLinks=$sharedLinks, tags=$tags]'; String toString() => 'UserPreferencesUpdateDto[avatar=$avatar, download=$download, emailNotifications=$emailNotifications, folders=$folders, memories=$memories, people=$people, purchase=$purchase, ratings=$ratings, tags=$tags]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@@ -177,11 +166,6 @@ class UserPreferencesUpdateDto {
} else { } else {
// json[r'ratings'] = null; // json[r'ratings'] = null;
} }
if (this.sharedLinks != null) {
json[r'sharedLinks'] = this.sharedLinks;
} else {
// json[r'sharedLinks'] = null;
}
if (this.tags != null) { if (this.tags != null) {
json[r'tags'] = this.tags; json[r'tags'] = this.tags;
} else { } else {
@@ -207,7 +191,6 @@ class UserPreferencesUpdateDto {
people: PeopleUpdate.fromJson(json[r'people']), people: PeopleUpdate.fromJson(json[r'people']),
purchase: PurchaseUpdate.fromJson(json[r'purchase']), purchase: PurchaseUpdate.fromJson(json[r'purchase']),
ratings: RatingsUpdate.fromJson(json[r'ratings']), ratings: RatingsUpdate.fromJson(json[r'ratings']),
sharedLinks: SharedLinksUpdate.fromJson(json[r'sharedLinks']),
tags: TagsUpdate.fromJson(json[r'tags']), tags: TagsUpdate.fromJson(json[r'tags']),
); );
} }
+1 -1
View File
@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone description: Immich - selfhosted backup media file on mobile phone
publish_to: 'none' publish_to: 'none'
version: 1.126.1+184 version: 1.125.7+182
environment: environment:
sdk: '>=3.3.0 <4.0.0' sdk: '>=3.3.0 <4.0.0'
+3 -67
View File
@@ -5230,17 +5230,7 @@
"/shared-links": { "/shared-links": {
"get": { "get": {
"operationId": "getAllSharedLinks", "operationId": "getAllSharedLinks",
"parameters": [ "parameters": [],
{
"name": "albumId",
"required": false,
"in": "query",
"schema": {
"format": "uuid",
"type": "string"
}
}
],
"responses": { "responses": {
"200": { "200": {
"content": { "content": {
@@ -7468,7 +7458,7 @@
"info": { "info": {
"title": "Immich", "title": "Immich",
"description": "Immich API", "description": "Immich API",
"version": "1.126.1", "version": "1.125.7",
"contact": {} "contact": {}
}, },
"tags": [], "tags": [],
@@ -10296,10 +10286,6 @@
"nullable": true, "nullable": true,
"type": "string" "type": "string"
}, },
"color": {
"nullable": true,
"type": "string"
},
"featureFaceAssetId": { "featureFaceAssetId": {
"description": "Asset is used to get the feature face thumbnail.", "description": "Asset is used to get the feature face thumbnail.",
"type": "string" "type": "string"
@@ -10416,10 +10402,6 @@
"nullable": true, "nullable": true,
"type": "string" "type": "string"
}, },
"color": {
"nullable": true,
"type": "string"
},
"isFavorite": { "isFavorite": {
"type": "boolean" "type": "boolean"
}, },
@@ -10441,10 +10423,6 @@
"nullable": true, "nullable": true,
"type": "string" "type": "string"
}, },
"color": {
"description": "This property was added in v1.126.0",
"type": "string"
},
"id": { "id": {
"type": "string" "type": "string"
}, },
@@ -10495,10 +10473,6 @@
"nullable": true, "nullable": true,
"type": "string" "type": "string"
}, },
"color": {
"nullable": true,
"type": "string"
},
"featureFaceAssetId": { "featureFaceAssetId": {
"description": "Asset is used to get the feature face thumbnail.", "description": "Asset is used to get the feature face thumbnail.",
"type": "string" "type": "string"
@@ -10524,10 +10498,6 @@
"nullable": true, "nullable": true,
"type": "string" "type": "string"
}, },
"color": {
"description": "This property was added in v1.126.0",
"type": "string"
},
"faces": { "faces": {
"items": { "items": {
"$ref": "#/components/schemas/AssetFaceWithoutPersonResponseDto" "$ref": "#/components/schemas/AssetFaceWithoutPersonResponseDto"
@@ -11524,34 +11494,6 @@
], ],
"type": "string" "type": "string"
}, },
"SharedLinksResponse": {
"properties": {
"enabled": {
"default": true,
"type": "boolean"
},
"sidebarWeb": {
"default": false,
"type": "boolean"
}
},
"required": [
"enabled",
"sidebarWeb"
],
"type": "object"
},
"SharedLinksUpdate": {
"properties": {
"enabled": {
"type": "boolean"
},
"sidebarWeb": {
"type": "boolean"
}
},
"type": "object"
},
"SignUpDto": { "SignUpDto": {
"properties": { "properties": {
"email": { "email": {
@@ -12669,6 +12611,7 @@
"properties": { "properties": {
"color": { "color": {
"nullable": true, "nullable": true,
"pattern": "^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$",
"type": "string" "type": "string"
} }
}, },
@@ -13198,9 +13141,6 @@
"ratings": { "ratings": {
"$ref": "#/components/schemas/RatingsResponse" "$ref": "#/components/schemas/RatingsResponse"
}, },
"sharedLinks": {
"$ref": "#/components/schemas/SharedLinksResponse"
},
"tags": { "tags": {
"$ref": "#/components/schemas/TagsResponse" "$ref": "#/components/schemas/TagsResponse"
} }
@@ -13214,7 +13154,6 @@
"people", "people",
"purchase", "purchase",
"ratings", "ratings",
"sharedLinks",
"tags" "tags"
], ],
"type": "object" "type": "object"
@@ -13245,9 +13184,6 @@
"ratings": { "ratings": {
"$ref": "#/components/schemas/RatingsUpdate" "$ref": "#/components/schemas/RatingsUpdate"
}, },
"sharedLinks": {
"$ref": "#/components/schemas/SharedLinksUpdate"
},
"tags": { "tags": {
"$ref": "#/components/schemas/TagsUpdate" "$ref": "#/components/schemas/TagsUpdate"
} }
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.126.1", "version": "1.125.7",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.126.1", "version": "1.125.7",
"license": "GNU Affero General Public License version 3", "license": "GNU Affero General Public License version 3",
"dependencies": { "dependencies": {
"@oazapfts/runtime": "^1.0.2" "@oazapfts/runtime": "^1.0.2"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@immich/sdk", "name": "@immich/sdk",
"version": "1.126.1", "version": "1.125.7",
"description": "Auto-generated TypeScript SDK for the Immich API", "description": "Auto-generated TypeScript SDK for the Immich API",
"type": "module", "type": "module",
"main": "./build/index.js", "main": "./build/index.js",
+3 -24
View File
@@ -1,6 +1,6 @@
/** /**
* Immich * Immich
* 1.126.1 * 1.125.7
* DO NOT MODIFY - This file has been generated using oazapfts. * DO NOT MODIFY - This file has been generated using oazapfts.
* See https://www.npmjs.com/package/oazapfts * See https://www.npmjs.com/package/oazapfts
*/ */
@@ -113,10 +113,6 @@ export type PurchaseResponse = {
export type RatingsResponse = { export type RatingsResponse = {
enabled: boolean; enabled: boolean;
}; };
export type SharedLinksResponse = {
enabled: boolean;
sidebarWeb: boolean;
};
export type TagsResponse = { export type TagsResponse = {
enabled: boolean; enabled: boolean;
sidebarWeb: boolean; sidebarWeb: boolean;
@@ -130,7 +126,6 @@ export type UserPreferencesResponseDto = {
people: PeopleResponse; people: PeopleResponse;
purchase: PurchaseResponse; purchase: PurchaseResponse;
ratings: RatingsResponse; ratings: RatingsResponse;
sharedLinks: SharedLinksResponse;
tags: TagsResponse; tags: TagsResponse;
}; };
export type AvatarUpdate = { export type AvatarUpdate = {
@@ -163,10 +158,6 @@ export type PurchaseUpdate = {
export type RatingsUpdate = { export type RatingsUpdate = {
enabled?: boolean; enabled?: boolean;
}; };
export type SharedLinksUpdate = {
enabled?: boolean;
sidebarWeb?: boolean;
};
export type TagsUpdate = { export type TagsUpdate = {
enabled?: boolean; enabled?: boolean;
sidebarWeb?: boolean; sidebarWeb?: boolean;
@@ -180,7 +171,6 @@ export type UserPreferencesUpdateDto = {
people?: PeopleUpdate; people?: PeopleUpdate;
purchase?: PurchaseUpdate; purchase?: PurchaseUpdate;
ratings?: RatingsUpdate; ratings?: RatingsUpdate;
sharedLinks?: SharedLinksUpdate;
tags?: TagsUpdate; tags?: TagsUpdate;
}; };
export type AlbumUserResponseDto = { export type AlbumUserResponseDto = {
@@ -223,8 +213,6 @@ export type AssetFaceWithoutPersonResponseDto = {
}; };
export type PersonWithFacesResponseDto = { export type PersonWithFacesResponseDto = {
birthDate: string | null; birthDate: string | null;
/** This property was added in v1.126.0 */
color?: string;
faces: AssetFaceWithoutPersonResponseDto[]; faces: AssetFaceWithoutPersonResponseDto[];
id: string; id: string;
/** This property was added in v1.126.0 */ /** This property was added in v1.126.0 */
@@ -505,8 +493,6 @@ export type DuplicateResponseDto = {
}; };
export type PersonResponseDto = { export type PersonResponseDto = {
birthDate: string | null; birthDate: string | null;
/** This property was added in v1.126.0 */
color?: string;
id: string; id: string;
/** This property was added in v1.126.0 */ /** This property was added in v1.126.0 */
isFavorite?: boolean; isFavorite?: boolean;
@@ -707,7 +693,6 @@ export type PersonCreateDto = {
/** Person date of birth. /** Person date of birth.
Note: the mobile app cannot currently set the birth date to null. */ Note: the mobile app cannot currently set the birth date to null. */
birthDate?: string | null; birthDate?: string | null;
color?: string | null;
isFavorite?: boolean; isFavorite?: boolean;
/** Person visibility */ /** Person visibility */
isHidden?: boolean; isHidden?: boolean;
@@ -718,7 +703,6 @@ export type PeopleUpdateItem = {
/** Person date of birth. /** Person date of birth.
Note: the mobile app cannot currently set the birth date to null. */ Note: the mobile app cannot currently set the birth date to null. */
birthDate?: string | null; birthDate?: string | null;
color?: string | null;
/** Asset is used to get the feature face thumbnail. */ /** Asset is used to get the feature face thumbnail. */
featureFaceAssetId?: string; featureFaceAssetId?: string;
/** Person id. */ /** Person id. */
@@ -736,7 +720,6 @@ export type PersonUpdateDto = {
/** Person date of birth. /** Person date of birth.
Note: the mobile app cannot currently set the birth date to null. */ Note: the mobile app cannot currently set the birth date to null. */
birthDate?: string | null; birthDate?: string | null;
color?: string | null;
/** Asset is used to get the feature face thumbnail. */ /** Asset is used to get the feature face thumbnail. */
featureFaceAssetId?: string; featureFaceAssetId?: string;
isFavorite?: boolean; isFavorite?: boolean;
@@ -2762,15 +2745,11 @@ export function deleteSession({ id }: {
method: "DELETE" method: "DELETE"
})); }));
} }
export function getAllSharedLinks({ albumId }: { export function getAllSharedLinks(opts?: Oazapfts.RequestOpts) {
albumId?: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{ return oazapfts.ok(oazapfts.fetchJson<{
status: 200; status: 200;
data: SharedLinkResponseDto[]; data: SharedLinkResponseDto[];
}>(`/shared-links${QS.query(QS.explode({ }>("/shared-links", {
albumId
}))}`, {
...opts ...opts
})); }));
} }
+2 -2
View File
@@ -1,5 +1,5 @@
# dev build # dev build
FROM ghcr.io/immich-app/base-server-dev:20250204@sha256:8b203f19f4d5cf4619b60ee5f50d6d4b5ea3745747f5e5170d1b7404ebeb0792 AS dev FROM ghcr.io/immich-app/base-server-dev:20250123@sha256:04eba5cd87d61bc3d20a3915b2302f04d08fbc329c55ee0cde103c502f59f412 AS dev
RUN apt-get install --no-install-recommends -yqq tini RUN apt-get install --no-install-recommends -yqq tini
WORKDIR /usr/src/app WORKDIR /usr/src/app
@@ -42,7 +42,7 @@ RUN npm run build
# prod build # prod build
FROM ghcr.io/immich-app/base-server-prod:20250204@sha256:2af3da713d5ab3ccca23b216b747557ea6016117e72deac101e35069ccaf9b5e FROM ghcr.io/immich-app/base-server-prod:20250123@sha256:591739983913f82672d8191258f3a1a24c123db0d619ff91fca8fef431ee1338
WORKDIR /usr/src/app WORKDIR /usr/src/app
ENV NODE_ENV=production \ ENV NODE_ENV=production \
+726 -1316
View File
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -1,6 +1,6 @@
{ {
"name": "immich", "name": "immich",
"version": "1.126.1", "version": "1.125.7",
"description": "", "description": "",
"author": "", "author": "",
"private": true, "private": true,
@@ -35,16 +35,16 @@
"email:dev": "email dev -p 3050 --dir src/emails" "email:dev": "email dev -p 3050 --dir src/emails"
}, },
"dependencies": { "dependencies": {
"@nestjs/bullmq": "^11.0.1", "@nestjs/bullmq": "^11.0.0",
"@nestjs/common": "^11.0.4", "@nestjs/common": "^10.2.2",
"@nestjs/core": "^11.0.4", "@nestjs/core": "^10.2.2",
"@nestjs/event-emitter": "^3.0.0", "@nestjs/event-emitter": "^3.0.0",
"@nestjs/platform-express": "^11.0.4", "@nestjs/platform-express": "^10.2.2",
"@nestjs/platform-socket.io": "^11.0.4", "@nestjs/platform-socket.io": "^10.2.2",
"@nestjs/schedule": "^5.0.0", "@nestjs/schedule": "^5.0.0",
"@nestjs/swagger": "^11.0.2", "@nestjs/swagger": "^8.0.0",
"@nestjs/typeorm": "^11.0.0", "@nestjs/typeorm": "^10.0.0",
"@nestjs/websockets": "^11.0.4", "@nestjs/websockets": "^10.2.2",
"@opentelemetry/auto-instrumentations-node": "^0.55.0", "@opentelemetry/auto-instrumentations-node": "^0.55.0",
"@opentelemetry/context-async-hooks": "^1.24.0", "@opentelemetry/context-async-hooks": "^1.24.0",
"@opentelemetry/exporter-prometheus": "^0.57.0", "@opentelemetry/exporter-prometheus": "^0.57.0",
@@ -60,7 +60,7 @@
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"exiftool-vendored": "^28.3.1", "exiftool-vendored": "^28.3.1",
"fast-glob": "^3.3.2", "fast-glob": "github:etnoy/fast-glob#built",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.2",
"geo-tz": "^8.0.0", "geo-tz": "^8.0.0",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
@@ -72,9 +72,9 @@
"kysely-postgres-js": "^2.0.0", "kysely-postgres-js": "^2.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"luxon": "^3.4.2", "luxon": "^3.4.2",
"nest-commander": "^3.16.0", "nest-commander": "^3.11.1",
"nestjs-cls": "^5.0.0", "nestjs-cls": "^4.3.0",
"nestjs-kysely": "^1.1.0", "nestjs-kysely": "^1.0.0",
"nestjs-otel": "^6.0.0", "nestjs-otel": "^6.0.0",
"nodemailer": "^6.9.13", "nodemailer": "^6.9.13",
"openid-client": "^5.4.3", "openid-client": "^5.4.3",
@@ -97,9 +97,9 @@
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.1.0", "@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0", "@eslint/js": "^9.8.0",
"@nestjs/cli": "^11.0.2", "@nestjs/cli": "^10.1.16",
"@nestjs/schematics": "^11.0.0", "@nestjs/schematics": "^10.0.2",
"@nestjs/testing": "^11.0.4", "@nestjs/testing": "^10.2.2",
"@swc/core": "^1.4.14", "@swc/core": "^1.4.14",
"@testcontainers/postgresql": "^10.2.1", "@testcontainers/postgresql": "^10.2.1",
"@types/archiver": "^6.0.0", "@types/archiver": "^6.0.0",
@@ -9,7 +9,6 @@ import {
SharedLinkEditDto, SharedLinkEditDto,
SharedLinkPasswordDto, SharedLinkPasswordDto,
SharedLinkResponseDto, SharedLinkResponseDto,
SharedLinkSearchDto,
} from 'src/dtos/shared-link.dto'; } from 'src/dtos/shared-link.dto';
import { ImmichCookie, Permission } from 'src/enum'; import { ImmichCookie, Permission } from 'src/enum';
import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard'; import { Auth, Authenticated, GetLoginDetails } from 'src/middleware/auth.guard';
@@ -25,8 +24,8 @@ export class SharedLinkController {
@Get() @Get()
@Authenticated({ permission: Permission.SHARED_LINK_READ }) @Authenticated({ permission: Permission.SHARED_LINK_READ })
getAllSharedLinks(@Auth() auth: AuthDto, @Query() dto: SharedLinkSearchDto): Promise<SharedLinkResponseDto[]> { getAllSharedLinks(@Auth() auth: AuthDto): Promise<SharedLinkResponseDto[]> {
return this.service.getAll(auth, dto); return this.service.getAll(auth);
} }
@Get('me') @Get('me')
+2 -1
View File
@@ -9,7 +9,8 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IMoveRepository } from 'src/interfaces/move.interface'; import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { IConfigRepository, ILoggingRepository, ISystemMetadataRepository } from 'src/types'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IConfigRepository, ILoggingRepository } from 'src/types';
import { getAssetFiles } from 'src/utils/asset.util'; import { getAssetFiles } from 'src/utils/asset.util';
import { getConfig } from 'src/utils/config'; import { getConfig } from 'src/utils/config';
-1
View File
@@ -276,7 +276,6 @@ export interface Partners {
export interface Person { export interface Person {
birthDate: Timestamp | null; birthDate: Timestamp | null;
color: string | null;
createdAt: Generated<Timestamp>; createdAt: Generated<Timestamp>;
faceAssetId: string | null; faceAssetId: string | null;
id: Generated<string>; id: Generated<string>;
+1 -15
View File
@@ -7,14 +7,7 @@ import { AuthDto } from 'src/dtos/auth.dto';
import { AssetFaceEntity } from 'src/entities/asset-face.entity'; import { AssetFaceEntity } from 'src/entities/asset-face.entity';
import { PersonEntity } from 'src/entities/person.entity'; import { PersonEntity } from 'src/entities/person.entity';
import { SourceType } from 'src/enum'; import { SourceType } from 'src/enum';
import { import { IsDateStringFormat, MaxDateString, Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
IsDateStringFormat,
MaxDateString,
Optional,
ValidateBoolean,
ValidateHexColor,
ValidateUUID,
} from 'src/validation';
export class PersonCreateDto { export class PersonCreateDto {
/** /**
@@ -42,10 +35,6 @@ export class PersonCreateDto {
@ValidateBoolean({ optional: true }) @ValidateBoolean({ optional: true })
isFavorite?: boolean; isFavorite?: boolean;
@Optional({ emptyToNull: true, nullable: true })
@ValidateHexColor()
color?: string | null;
} }
export class PersonUpdateDto extends PersonCreateDto { export class PersonUpdateDto extends PersonCreateDto {
@@ -113,8 +102,6 @@ export class PersonResponseDto {
updatedAt?: Date; updatedAt?: Date;
@PropertyLifecycle({ addedAt: 'v1.126.0' }) @PropertyLifecycle({ addedAt: 'v1.126.0' })
isFavorite?: boolean; isFavorite?: boolean;
@PropertyLifecycle({ addedAt: 'v1.126.0' })
color?: string;
} }
export class PersonWithFacesResponseDto extends PersonResponseDto { export class PersonWithFacesResponseDto extends PersonResponseDto {
@@ -189,7 +176,6 @@ export function mapPerson(person: PersonEntity): PersonResponseDto {
thumbnailPath: person.thumbnailPath, thumbnailPath: person.thumbnailPath,
isHidden: person.isHidden, isHidden: person.isHidden,
isFavorite: person.isFavorite, isFavorite: person.isFavorite,
color: person.color ?? undefined,
updatedAt: person.updatedAt, updatedAt: person.updatedAt,
}; };
} }
+2 -2
View File
@@ -1,4 +1,4 @@
import { SessionItem } from 'src/types'; import { SessionEntity } from 'src/entities/session.entity';
export class SessionResponseDto { export class SessionResponseDto {
id!: string; id!: string;
@@ -9,7 +9,7 @@ export class SessionResponseDto {
deviceOS!: string; deviceOS!: string;
} }
export const mapSession = (entity: SessionItem, currentId?: string): SessionResponseDto => ({ export const mapSession = (entity: SessionEntity, currentId?: string): SessionResponseDto => ({
id: entity.id, id: entity.id,
createdAt: entity.createdAt.toISOString(), createdAt: entity.createdAt.toISOString(),
updatedAt: entity.updatedAt.toISOString(), updatedAt: entity.updatedAt.toISOString(),
-5
View File
@@ -7,11 +7,6 @@ import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { SharedLinkType } from 'src/enum'; import { SharedLinkType } from 'src/enum';
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation'; import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/validation';
export class SharedLinkSearchDto {
@ValidateUUID({ optional: true })
albumId?: string;
}
export class SharedLinkCreateDto { export class SharedLinkCreateDto {
@IsEnum(SharedLinkType) @IsEnum(SharedLinkType)
@ApiProperty({ enum: SharedLinkType, enumName: 'SharedLinkType' }) @ApiProperty({ enum: SharedLinkType, enumName: 'SharedLinkType' })
+5 -3
View File
@@ -1,7 +1,8 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsHexColor, IsNotEmpty, IsString } from 'class-validator'; import { IsHexColor, IsNotEmpty, IsString } from 'class-validator';
import { TagEntity } from 'src/entities/tag.entity'; import { TagEntity } from 'src/entities/tag.entity';
import { Optional, ValidateHexColor, ValidateUUID } from 'src/validation'; import { Optional, ValidateUUID } from 'src/validation';
export class TagCreateDto { export class TagCreateDto {
@IsString() @IsString()
@@ -17,8 +18,9 @@ export class TagCreateDto {
} }
export class TagUpdateDto { export class TagUpdateDto {
@Optional({ emptyToNull: true, nullable: true }) @Optional({ nullable: true, emptyToNull: true })
@ValidateHexColor() @IsHexColor()
@Transform(({ value }) => (typeof value === 'string' && value[0] !== '#' ? `#${value}` : value))
color?: string | null; color?: string | null;
} }
-19
View File
@@ -38,14 +38,6 @@ class PeopleUpdate {
sidebarWeb?: boolean; sidebarWeb?: boolean;
} }
class SharedLinksUpdate {
@ValidateBoolean({ optional: true })
enabled?: boolean;
@ValidateBoolean({ optional: true })
sidebarWeb?: boolean;
}
class TagsUpdate { class TagsUpdate {
@ValidateBoolean({ optional: true }) @ValidateBoolean({ optional: true })
enabled?: boolean; enabled?: boolean;
@@ -106,11 +98,6 @@ export class UserPreferencesUpdateDto {
@Type(() => RatingsUpdate) @Type(() => RatingsUpdate)
ratings?: RatingsUpdate; ratings?: RatingsUpdate;
@Optional()
@ValidateNested()
@Type(() => SharedLinksUpdate)
sharedLinks?: SharedLinksUpdate;
@Optional() @Optional()
@ValidateNested() @ValidateNested()
@Type(() => TagsUpdate) @Type(() => TagsUpdate)
@@ -165,11 +152,6 @@ class TagsResponse {
sidebarWeb: boolean = true; sidebarWeb: boolean = true;
} }
class SharedLinksResponse {
enabled: boolean = true;
sidebarWeb: boolean = false;
}
class EmailNotificationsResponse { class EmailNotificationsResponse {
enabled!: boolean; enabled!: boolean;
albumInvite!: boolean; albumInvite!: boolean;
@@ -193,7 +175,6 @@ export class UserPreferencesResponseDto implements UserPreferences {
memories!: MemoriesResponse; memories!: MemoriesResponse;
people!: PeopleResponse; people!: PeopleResponse;
ratings!: RatingsResponse; ratings!: RatingsResponse;
sharedLinks!: SharedLinksResponse;
tags!: TagsResponse; tags!: TagsResponse;
avatar!: AvatarResponse; avatar!: AvatarResponse;
emailNotifications!: EmailNotificationsResponse; emailNotifications!: EmailNotificationsResponse;
-3
View File
@@ -52,7 +52,4 @@ export class PersonEntity {
@Column({ default: false }) @Column({ default: false })
isFavorite!: boolean; isFavorite!: boolean;
@Column({ type: 'varchar', nullable: true, default: null })
color?: string | null;
} }
@@ -34,10 +34,6 @@ export interface UserPreferences {
ratings: { ratings: {
enabled: boolean; enabled: boolean;
}; };
sharedLinks: {
enabled: boolean;
sidebarWeb: boolean;
};
tags: { tags: {
enabled: boolean; enabled: boolean;
sidebarWeb: boolean; sidebarWeb: boolean;
@@ -78,10 +74,6 @@ export const getDefaultPreferences = (user: { email: string }): UserPreferences
enabled: true, enabled: true,
sidebarWeb: false, sidebarWeb: false,
}, },
sharedLinks: {
enabled: true,
sidebarWeb: false,
},
ratings: { ratings: {
enabled: false, enabled: false,
}, },
@@ -0,0 +1,25 @@
import { ChildProcessWithoutNullStreams, SpawnOptionsWithoutStdio } from 'node:child_process';
import { Readable } from 'node:stream';
export interface ImmichReadStream {
stream: Readable;
type?: string;
length?: number;
}
export interface ImmichZipStream extends ImmichReadStream {
addFile: (inputPath: string, filename: string) => void;
finalize: () => Promise<void>;
}
export interface DiskUsage {
available: number;
free: number;
total: number;
}
export const IProcessRepository = 'IProcessRepository';
export interface IProcessRepository {
spawn(command: string, args?: readonly string[], options?: SpawnOptionsWithoutStdio): ChildProcessWithoutNullStreams;
}
@@ -0,0 +1,17 @@
import { Insertable, Updateable } from 'kysely';
import { Sessions } from 'src/db';
import { SessionEntity } from 'src/entities/session.entity';
export const ISessionRepository = 'ISessionRepository';
type E = SessionEntity;
export type SessionSearchOptions = { updatedBefore: Date };
export interface ISessionRepository {
search(options: SessionSearchOptions): Promise<SessionEntity[]>;
create(dto: Insertable<Sessions>): Promise<SessionEntity>;
update(id: string, dto: Updateable<Sessions>): Promise<SessionEntity>;
delete(id: string): Promise<void>;
getByToken(token: string): Promise<E | undefined>;
getByUserId(userId: string): Promise<E[]>;
}
@@ -4,13 +4,8 @@ import { SharedLinkEntity } from 'src/entities/shared-link.entity';
export const ISharedLinkRepository = 'ISharedLinkRepository'; export const ISharedLinkRepository = 'ISharedLinkRepository';
export type SharedLinkSearchOptions = {
userId: string;
albumId?: string;
};
export interface ISharedLinkRepository { export interface ISharedLinkRepository {
getAll(options: SharedLinkSearchOptions): Promise<SharedLinkEntity[]>; getAll(userId: string): Promise<SharedLinkEntity[]>;
get(userId: string, id: string): Promise<SharedLinkEntity | undefined>; get(userId: string, id: string): Promise<SharedLinkEntity | undefined>;
getByKey(key: Buffer): Promise<SharedLinkEntity | undefined>; getByKey(key: Buffer): Promise<SharedLinkEntity | undefined>;
create(entity: Insertable<SharedLinks> & { assetIds?: string[] }): Promise<SharedLinkEntity>; create(entity: Insertable<SharedLinks> & { assetIds?: string[] }): Promise<SharedLinkEntity>;
@@ -0,0 +1,10 @@
import { SystemMetadata } from 'src/entities/system-metadata.entity';
export const ISystemMetadataRepository = 'ISystemMetadataRepository';
export interface ISystemMetadataRepository {
get<T extends keyof SystemMetadata>(key: T): Promise<SystemMetadata[T] | null>;
set<T extends keyof SystemMetadata>(key: T, value: SystemMetadata[T]): Promise<void>;
delete<T extends keyof SystemMetadata>(key: T): Promise<void>;
readFile(filename: string): Promise<string>;
}
@@ -1,14 +0,0 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddPersonColor1738889177573 implements MigrationInterface {
name = 'AddPersonColor1738889177573'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "person" ADD "color" character varying`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "person" DROP COLUMN "color"`);
}
}
+6 -3
View File
@@ -9,10 +9,13 @@ import { IMachineLearningRepository } from 'src/interfaces/machine-learning.inte
import { IMoveRepository } from 'src/interfaces/move.interface'; import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface';
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { IProcessRepository } from 'src/interfaces/process.interface';
import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISessionRepository } from 'src/interfaces/session.interface';
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
import { IStackRepository } from 'src/interfaces/stack.interface'; import { IStackRepository } from 'src/interfaces/stack.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ITagRepository } from 'src/interfaces/tag.interface'; import { ITagRepository } from 'src/interfaces/tag.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { AccessRepository } from 'src/repositories/access.repository'; import { AccessRepository } from 'src/repositories/access.repository';
@@ -70,10 +73,7 @@ export const repositories = [
MetadataRepository, MetadataRepository,
NotificationRepository, NotificationRepository,
OAuthRepository, OAuthRepository,
ProcessRepository,
SessionRepository,
ServerInfoRepository, ServerInfoRepository,
SystemMetadataRepository,
TelemetryRepository, TelemetryRepository,
TrashRepository, TrashRepository,
ViewRepository, ViewRepository,
@@ -92,10 +92,13 @@ export const providers = [
{ provide: IMoveRepository, useClass: MoveRepository }, { provide: IMoveRepository, useClass: MoveRepository },
{ provide: IPartnerRepository, useClass: PartnerRepository }, { provide: IPartnerRepository, useClass: PartnerRepository },
{ provide: IPersonRepository, useClass: PersonRepository }, { provide: IPersonRepository, useClass: PersonRepository },
{ provide: IProcessRepository, useClass: ProcessRepository },
{ provide: ISearchRepository, useClass: SearchRepository }, { provide: ISearchRepository, useClass: SearchRepository },
{ provide: ISessionRepository, useClass: SessionRepository },
{ provide: ISharedLinkRepository, useClass: SharedLinkRepository }, { provide: ISharedLinkRepository, useClass: SharedLinkRepository },
{ provide: IStackRepository, useClass: StackRepository }, { provide: IStackRepository, useClass: StackRepository },
{ provide: IStorageRepository, useClass: StorageRepository }, { provide: IStorageRepository, useClass: StorageRepository },
{ provide: ISystemMetadataRepository, useClass: SystemMetadataRepository },
{ provide: ITagRepository, useClass: TagRepository }, { provide: ITagRepository, useClass: TagRepository },
{ provide: IUserRepository, useClass: UserRepository }, { provide: IUserRepository, useClass: UserRepository },
]; ];
+3 -3
View File
@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { getName } from 'i18n-iso-countries'; import { getName } from 'i18n-iso-countries';
import { Expression, Kysely, sql, SqlBool } from 'kysely'; import { Expression, Kysely, sql, SqlBool } from 'kysely';
import { InjectKysely } from 'nestjs-kysely'; import { InjectKysely } from 'nestjs-kysely';
@@ -11,9 +11,9 @@ import { DB, GeodataPlaces, NaturalearthCountries } from 'src/db';
import { DummyValue, GenerateSql } from 'src/decorators'; import { DummyValue, GenerateSql } from 'src/decorators';
import { NaturalEarthCountriesTempEntity } from 'src/entities/natural-earth-countries.entity'; import { NaturalEarthCountriesTempEntity } from 'src/entities/natural-earth-countries.entity';
import { LogLevel, SystemMetadataKey } from 'src/enum'; import { LogLevel, SystemMetadataKey } from 'src/enum';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
export interface MapMarkerSearchOptions { export interface MapMarkerSearchOptions {
isArchived?: boolean; isArchived?: boolean;
@@ -48,7 +48,7 @@ interface MapDB extends DB {
export class MapRepository { export class MapRepository {
constructor( constructor(
private configRepository: ConfigRepository, private configRepository: ConfigRepository,
private metadataRepository: SystemMetadataRepository, @Inject(ISystemMetadataRepository) private metadataRepository: ISystemMetadataRepository,
private logger: LoggingRepository, private logger: LoggingRepository,
@InjectKysely() private db: Kysely<MapDB>, @InjectKysely() private db: Kysely<MapDB>,
) { ) {
+1 -6
View File
@@ -43,12 +43,7 @@ export class OAuthRepository {
const params = client.callbackParams(url); const params = client.callbackParams(url);
try { try {
const tokens = await client.callback(redirectUrl, params, { state: params.state }); const tokens = await client.callback(redirectUrl, params, { state: params.state });
const profile = await client.userinfo<OAuthProfile>(tokens.access_token || ''); return await client.userinfo<OAuthProfile>(tokens.access_token || '');
if (!profile.sub) {
throw new Error('Unexpected profile response, no `sub`');
}
return profile;
} catch (error: Error | any) { } catch (error: Error | any) {
if (error.message.includes('unexpected JWT alg received')) { if (error.message.includes('unexpected JWT alg received')) {
this.logger.warn( this.logger.warn(
@@ -1,11 +1,13 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { ChildProcessWithoutNullStreams, spawn, SpawnOptionsWithoutStdio } from 'node:child_process'; import { ChildProcessWithoutNullStreams, spawn, SpawnOptionsWithoutStdio } from 'node:child_process';
import { IProcessRepository } from 'src/interfaces/process.interface';
import { LoggingRepository } from 'src/repositories/logging.repository'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { StorageRepository } from 'src/repositories/storage.repository';
@Injectable() @Injectable()
export class ProcessRepository { export class ProcessRepository implements IProcessRepository {
constructor(private logger: LoggingRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(ProcessRepository.name); this.logger.setContext(StorageRepository.name);
} }
spawn(command: string, args: readonly string[], options?: SpawnOptionsWithoutStdio): ChildProcessWithoutNullStreams { spawn(command: string, args: readonly string[], options?: SpawnOptionsWithoutStdio): ChildProcessWithoutNullStreams {
+20 -15
View File
@@ -3,37 +3,36 @@ import { Insertable, Kysely, Updateable } from 'kysely';
import { InjectKysely } from 'nestjs-kysely'; import { InjectKysely } from 'nestjs-kysely';
import { DB, Sessions } from 'src/db'; import { DB, Sessions } from 'src/db';
import { DummyValue, GenerateSql } from 'src/decorators'; import { DummyValue, GenerateSql } from 'src/decorators';
import { withUser } from 'src/entities/session.entity'; import { SessionEntity, withUser } from 'src/entities/session.entity';
import { ISessionRepository, SessionSearchOptions } from 'src/interfaces/session.interface';
import { asUuid } from 'src/utils/database'; import { asUuid } from 'src/utils/database';
export type SessionSearchOptions = { updatedBefore: Date };
@Injectable() @Injectable()
export class SessionRepository { export class SessionRepository implements ISessionRepository {
constructor(@InjectKysely() private db: Kysely<DB>) {} constructor(@InjectKysely() private db: Kysely<DB>) {}
@GenerateSql({ params: [{ updatedBefore: DummyValue.DATE }] }) @GenerateSql({ params: [{ updatedBefore: DummyValue.DATE }] })
search(options: SessionSearchOptions) { search(options: SessionSearchOptions): Promise<SessionEntity[]> {
return this.db return this.db
.selectFrom('sessions') .selectFrom('sessions')
.selectAll() .selectAll()
.where('sessions.updatedAt', '<=', options.updatedBefore) .where('sessions.updatedAt', '<=', options.updatedBefore)
.execute(); .execute() as Promise<SessionEntity[]>;
} }
@GenerateSql({ params: [DummyValue.STRING] }) @GenerateSql({ params: [DummyValue.STRING] })
getByToken(token: string) { getByToken(token: string): Promise<SessionEntity | undefined> {
return this.db return this.db
.selectFrom('sessions') .selectFrom('sessions')
.innerJoinLateral(withUser, (join) => join.onTrue()) .innerJoinLateral(withUser, (join) => join.onTrue())
.selectAll('sessions') .selectAll('sessions')
.select((eb) => eb.fn.toJson('user').as('user')) .select((eb) => eb.fn.toJson('user').as('user'))
.where('sessions.token', '=', token) .where('sessions.token', '=', token)
.executeTakeFirst(); .executeTakeFirst() as Promise<SessionEntity | undefined>;
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getByUserId(userId: string) { getByUserId(userId: string): Promise<SessionEntity[]> {
return this.db return this.db
.selectFrom('sessions') .selectFrom('sessions')
.innerJoinLateral(withUser, (join) => join.onTrue()) .innerJoinLateral(withUser, (join) => join.onTrue())
@@ -42,24 +41,30 @@ export class SessionRepository {
.where('sessions.userId', '=', userId) .where('sessions.userId', '=', userId)
.orderBy('sessions.updatedAt', 'desc') .orderBy('sessions.updatedAt', 'desc')
.orderBy('sessions.createdAt', 'desc') .orderBy('sessions.createdAt', 'desc')
.execute(); .execute() as unknown as Promise<SessionEntity[]>;
} }
create(dto: Insertable<Sessions>) { async create(dto: Insertable<Sessions>): Promise<SessionEntity> {
return this.db.insertInto('sessions').values(dto).returningAll().executeTakeFirstOrThrow(); const { id, token, userId, createdAt, updatedAt, deviceType, deviceOS } = await this.db
.insertInto('sessions')
.values(dto)
.returningAll()
.executeTakeFirstOrThrow();
return { id, token, userId, createdAt, updatedAt, deviceType, deviceOS } as SessionEntity;
} }
update(id: string, dto: Updateable<Sessions>) { update(id: string, dto: Updateable<Sessions>): Promise<SessionEntity> {
return this.db return this.db
.updateTable('sessions') .updateTable('sessions')
.set(dto) .set(dto)
.where('sessions.id', '=', asUuid(id)) .where('sessions.id', '=', asUuid(id))
.returningAll() .returningAll()
.executeTakeFirstOrThrow(); .executeTakeFirstOrThrow() as Promise<SessionEntity>;
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
async delete(id: string) { async delete(id: string): Promise<void> {
await this.db.deleteFrom('sessions').where('id', '=', asUuid(id)).execute(); await this.db.deleteFrom('sessions').where('id', '=', asUuid(id)).execute();
} }
} }
@@ -7,7 +7,7 @@ import { DB, SharedLinks } from 'src/db';
import { DummyValue, GenerateSql } from 'src/decorators'; import { DummyValue, GenerateSql } from 'src/decorators';
import { SharedLinkEntity } from 'src/entities/shared-link.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { SharedLinkType } from 'src/enum'; import { SharedLinkType } from 'src/enum';
import { ISharedLinkRepository, SharedLinkSearchOptions } from 'src/interfaces/shared-link.interface'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
@Injectable() @Injectable()
export class SharedLinkRepository implements ISharedLinkRepository { export class SharedLinkRepository implements ISharedLinkRepository {
@@ -93,7 +93,7 @@ export class SharedLinkRepository implements ISharedLinkRepository {
} }
@GenerateSql({ params: [DummyValue.UUID] }) @GenerateSql({ params: [DummyValue.UUID] })
getAll({ userId, albumId }: SharedLinkSearchOptions): Promise<SharedLinkEntity[]> { getAll(userId: string): Promise<SharedLinkEntity[]> {
return this.db return this.db
.selectFrom('shared_links') .selectFrom('shared_links')
.selectAll('shared_links') .selectAll('shared_links')
@@ -149,7 +149,6 @@ export class SharedLinkRepository implements ISharedLinkRepository {
) )
.select((eb) => eb.fn.toJson('album').as('album')) .select((eb) => eb.fn.toJson('album').as('album'))
.where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)])) .where((eb) => eb.or([eb('shared_links.type', '=', SharedLinkType.INDIVIDUAL), eb('album.id', 'is not', null)]))
.$if(!!albumId, (eb) => eb.where('shared_links.albumId', '=', albumId!))
.orderBy('shared_links.createdAt', 'desc') .orderBy('shared_links.createdAt', 'desc')
.distinctOn(['shared_links.createdAt']) .distinctOn(['shared_links.createdAt'])
.execute() as unknown as Promise<SharedLinkEntity[]>; .execute() as unknown as Promise<SharedLinkEntity[]>;
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import archiver from 'archiver'; import archiver from 'archiver';
import chokidar, { WatchOptions } from 'chokidar'; import chokidar, { WatchOptions } from 'chokidar';
import { escapePath, glob, globStream } from 'fast-glob'; import { escapePath, glob, globStream } from 'fast-glob';
import { ErrnoException } from 'fast-glob/out/types';
import { constants, createReadStream, createWriteStream, existsSync, mkdirSync } from 'node:fs'; import { constants, createReadStream, createWriteStream, existsSync, mkdirSync } from 'node:fs';
import fs from 'node:fs/promises'; import fs from 'node:fs/promises';
import path from 'node:path'; import path from 'node:path';
@@ -170,6 +171,19 @@ export class StorageRepository implements IStorageRepository {
}); });
} }
private errorHandler = (error: ErrnoException) => {
if (error.code === 'ENOENT') {
this.logger.warn(`Path ${error.path} does not exist, ignoring.`);
return true;
} else if (error.code === 'EACCES') {
this.logger.warn(`Permission denied for path ${error.path}, ignoring.`);
return true;
}
this.logger.error(`Error while walking path ${error.path}: ${error.message}`);
return false;
};
async *walk(walkOptions: WalkOptionsDto): AsyncGenerator<string[]> { async *walk(walkOptions: WalkOptionsDto): AsyncGenerator<string[]> {
const { pathsToCrawl, exclusionPatterns, includeHidden } = walkOptions; const { pathsToCrawl, exclusionPatterns, includeHidden } = walkOptions;
if (pathsToCrawl.length === 0) { if (pathsToCrawl.length === 0) {
@@ -185,6 +199,7 @@ export class StorageRepository implements IStorageRepository {
onlyFiles: true, onlyFiles: true,
dot: includeHidden, dot: includeHidden,
ignore: exclusionPatterns, ignore: exclusionPatterns,
errorHandler: this.errorHandler,
}); });
let batch: string[] = []; let batch: string[] = [];
@@ -5,11 +5,12 @@ import { readFile } from 'node:fs/promises';
import { DB, SystemMetadata as DbSystemMetadata } from 'src/db'; import { DB, SystemMetadata as DbSystemMetadata } from 'src/db';
import { GenerateSql } from 'src/decorators'; import { GenerateSql } from 'src/decorators';
import { SystemMetadata } from 'src/entities/system-metadata.entity'; import { SystemMetadata } from 'src/entities/system-metadata.entity';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
type Upsert = Insertable<DbSystemMetadata>; type Upsert = Insertable<DbSystemMetadata>;
@Injectable() @Injectable()
export class SystemMetadataRepository { export class SystemMetadataRepository implements ISystemMetadataRepository {
constructor(@InjectKysely() private db: Kysely<DB>) {} constructor(@InjectKysely() private db: Kysely<DB>) {}
@GenerateSql({ params: ['metadata_key'] }) @GenerateSql({ params: ['metadata_key'] })
+1 -1
View File
@@ -9,9 +9,9 @@ import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface';
import { IStackRepository } from 'src/interfaces/stack.interface'; import { IStackRepository } from 'src/interfaces/stack.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { AssetService } from 'src/services/asset.service'; import { AssetService } from 'src/services/asset.service';
import { ISystemMetadataRepository } from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
import { faceStub } from 'test/fixtures/face.stub'; import { faceStub } from 'test/fixtures/face.stub';
+7 -5
View File
@@ -5,10 +5,12 @@ import { UserEntity } from 'src/entities/user.entity';
import { AuthType, Permission } from 'src/enum'; import { AuthType, Permission } from 'src/enum';
import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { ISessionRepository } from 'src/interfaces/session.interface';
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { AuthService } from 'src/services/auth.service'; import { AuthService } from 'src/services/auth.service';
import { IApiKeyRepository, IOAuthRepository, ISessionRepository, ISystemMetadataRepository } from 'src/types'; import { IApiKeyRepository, IOAuthRepository } from 'src/types';
import { keyStub } from 'test/fixtures/api-key.stub'; import { keyStub } from 'test/fixtures/api-key.stub';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
import { sessionStub } from 'test/fixtures/session.stub'; import { sessionStub } from 'test/fixtures/session.stub';
@@ -256,7 +258,7 @@ describe('AuthService', () => {
it('should validate using authorization header', async () => { it('should validate using authorization header', async () => {
userMock.get.mockResolvedValue(userStub.user1); userMock.get.mockResolvedValue(userStub.user1);
sessionMock.getByToken.mockResolvedValue(sessionStub.valid as any); sessionMock.getByToken.mockResolvedValue(sessionStub.valid);
await expect( await expect(
sut.authenticate({ sut.authenticate({
headers: { authorization: 'Bearer auth_token' }, headers: { authorization: 'Bearer auth_token' },
@@ -361,7 +363,7 @@ describe('AuthService', () => {
}); });
it('should return an auth dto', async () => { it('should return an auth dto', async () => {
sessionMock.getByToken.mockResolvedValue(sessionStub.valid as any); sessionMock.getByToken.mockResolvedValue(sessionStub.valid);
await expect( await expect(
sut.authenticate({ sut.authenticate({
headers: { cookie: 'immich_access_token=auth_token' }, headers: { cookie: 'immich_access_token=auth_token' },
@@ -375,7 +377,7 @@ describe('AuthService', () => {
}); });
it('should throw if admin route and not an admin', async () => { it('should throw if admin route and not an admin', async () => {
sessionMock.getByToken.mockResolvedValue(sessionStub.valid as any); sessionMock.getByToken.mockResolvedValue(sessionStub.valid);
await expect( await expect(
sut.authenticate({ sut.authenticate({
headers: { cookie: 'immich_access_token=auth_token' }, headers: { cookie: 'immich_access_token=auth_token' },
@@ -386,7 +388,7 @@ describe('AuthService', () => {
}); });
it('should update when access time exceeds an hour', async () => { it('should update when access time exceeds an hour', async () => {
sessionMock.getByToken.mockResolvedValue(sessionStub.inactive as any); sessionMock.getByToken.mockResolvedValue(sessionStub.inactive);
sessionMock.update.mockResolvedValue(sessionStub.valid); sessionMock.update.mockResolvedValue(sessionStub.valid);
await expect( await expect(
sut.authenticate({ sut.authenticate({
+1 -2
View File
@@ -17,7 +17,6 @@ import {
mapLoginResponse, mapLoginResponse,
} from 'src/dtos/auth.dto'; } from 'src/dtos/auth.dto';
import { UserAdminResponseDto, mapUserAdmin } from 'src/dtos/user.dto'; import { UserAdminResponseDto, mapUserAdmin } from 'src/dtos/user.dto';
import { SessionEntity } from 'src/entities/session.entity';
import { UserEntity } from 'src/entities/user.entity'; import { UserEntity } from 'src/entities/user.entity';
import { AuthType, ImmichCookie, ImmichHeader, ImmichQuery, Permission } from 'src/enum'; import { AuthType, ImmichCookie, ImmichHeader, ImmichQuery, Permission } from 'src/enum';
import { OAuthProfile } from 'src/repositories/oauth.repository'; import { OAuthProfile } from 'src/repositories/oauth.repository';
@@ -339,7 +338,7 @@ export class AuthService extends BaseService {
await this.sessionRepository.update(session.id, { id: session.id, updatedAt: new Date() }); await this.sessionRepository.update(session.id, { id: session.id, updatedAt: new Date() });
} }
return { user: session.user as unknown as UserEntity, session: session as unknown as SessionEntity }; return { user: session.user, session };
} }
throw new UnauthorizedException('Invalid user token'); throw new UnauthorizedException('Invalid user token');
+3 -1
View File
@@ -4,9 +4,11 @@ import { StorageCore } from 'src/cores/storage.core';
import { ImmichWorker, StorageFolder } from 'src/enum'; import { ImmichWorker, StorageFolder } from 'src/enum';
import { IDatabaseRepository } from 'src/interfaces/database.interface'; import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { JobStatus } from 'src/interfaces/job.interface'; import { JobStatus } from 'src/interfaces/job.interface';
import { IProcessRepository } from 'src/interfaces/process.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { BackupService } from 'src/services/backup.service'; import { BackupService } from 'src/services/backup.service';
import { IConfigRepository, ICronRepository, IProcessRepository, ISystemMetadataRepository } from 'src/types'; import { IConfigRepository, ICronRepository } from 'src/types';
import { systemConfigStub } from 'test/fixtures/system-config.stub'; import { systemConfigStub } from 'test/fixtures/system-config.stub';
import { mockSpawn, newTestService } from 'test/utils'; import { mockSpawn, newTestService } from 'test/utils';
import { describe, Mocked } from 'vitest'; import { describe, Mocked } from 'vitest';
+6 -6
View File
@@ -17,10 +17,13 @@ import { IMachineLearningRepository } from 'src/interfaces/machine-learning.inte
import { IMoveRepository } from 'src/interfaces/move.interface'; import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface';
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { IProcessRepository } from 'src/interfaces/process.interface';
import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISessionRepository } from 'src/interfaces/session.interface';
import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface'; import { ISharedLinkRepository } from 'src/interfaces/shared-link.interface';
import { IStackRepository } from 'src/interfaces/stack.interface'; import { IStackRepository } from 'src/interfaces/stack.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ITagRepository } from 'src/interfaces/tag.interface'; import { ITagRepository } from 'src/interfaces/tag.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { AccessRepository } from 'src/repositories/access.repository'; import { AccessRepository } from 'src/repositories/access.repository';
@@ -37,10 +40,7 @@ import { MemoryRepository } from 'src/repositories/memory.repository';
import { MetadataRepository } from 'src/repositories/metadata.repository'; import { MetadataRepository } from 'src/repositories/metadata.repository';
import { NotificationRepository } from 'src/repositories/notification.repository'; import { NotificationRepository } from 'src/repositories/notification.repository';
import { OAuthRepository } from 'src/repositories/oauth.repository'; import { OAuthRepository } from 'src/repositories/oauth.repository';
import { ProcessRepository } from 'src/repositories/process.repository';
import { ServerInfoRepository } from 'src/repositories/server-info.repository'; import { ServerInfoRepository } from 'src/repositories/server-info.repository';
import { SessionRepository } from 'src/repositories/session.repository';
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
import { TelemetryRepository } from 'src/repositories/telemetry.repository'; import { TelemetryRepository } from 'src/repositories/telemetry.repository';
import { TrashRepository } from 'src/repositories/trash.repository'; import { TrashRepository } from 'src/repositories/trash.repository';
import { VersionHistoryRepository } from 'src/repositories/version-history.repository'; import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
@@ -77,14 +77,14 @@ export class BaseService {
protected oauthRepository: OAuthRepository, protected oauthRepository: OAuthRepository,
@Inject(IPartnerRepository) protected partnerRepository: IPartnerRepository, @Inject(IPartnerRepository) protected partnerRepository: IPartnerRepository,
@Inject(IPersonRepository) protected personRepository: IPersonRepository, @Inject(IPersonRepository) protected personRepository: IPersonRepository,
protected processRepository: ProcessRepository, @Inject(IProcessRepository) protected processRepository: IProcessRepository,
@Inject(ISearchRepository) protected searchRepository: ISearchRepository, @Inject(ISearchRepository) protected searchRepository: ISearchRepository,
protected serverInfoRepository: ServerInfoRepository, protected serverInfoRepository: ServerInfoRepository,
protected sessionRepository: SessionRepository, @Inject(ISessionRepository) protected sessionRepository: ISessionRepository,
@Inject(ISharedLinkRepository) protected sharedLinkRepository: ISharedLinkRepository, @Inject(ISharedLinkRepository) protected sharedLinkRepository: ISharedLinkRepository,
@Inject(IStackRepository) protected stackRepository: IStackRepository, @Inject(IStackRepository) protected stackRepository: IStackRepository,
@Inject(IStorageRepository) protected storageRepository: IStorageRepository, @Inject(IStorageRepository) protected storageRepository: IStorageRepository,
protected systemMetadataRepository: SystemMetadataRepository, @Inject(ISystemMetadataRepository) protected systemMetadataRepository: ISystemMetadataRepository,
@Inject(ITagRepository) protected tagRepository: ITagRepository, @Inject(ITagRepository) protected tagRepository: ITagRepository,
protected telemetryRepository: TelemetryRepository, protected telemetryRepository: TelemetryRepository,
protected trashRepository: TrashRepository, protected trashRepository: TrashRepository,
+1 -1
View File
@@ -1,6 +1,6 @@
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { CliService } from 'src/services/cli.service'; import { CliService } from 'src/services/cli.service';
import { ISystemMetadataRepository } from 'src/types';
import { userStub } from 'test/fixtures/user.stub'; import { userStub } from 'test/fixtures/user.stub';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked, describe, it } from 'vitest'; import { Mocked, describe, it } from 'vitest';
@@ -1,9 +1,10 @@
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { DuplicateService } from 'src/services/duplicate.service'; import { DuplicateService } from 'src/services/duplicate.service';
import { SearchService } from 'src/services/search.service'; import { SearchService } from 'src/services/search.service';
import { ILoggingRepository, ISystemMetadataRepository } from 'src/types'; import { ILoggingRepository } from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
+2 -1
View File
@@ -18,8 +18,9 @@ import { IJobRepository, JobCounts, JobName, JobStatus } from 'src/interfaces/jo
import { IMoveRepository } from 'src/interfaces/move.interface'; import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { MediaService } from 'src/services/media.service'; import { MediaService } from 'src/services/media.service';
import { ILoggingRepository, IMediaRepository, ISystemMetadataRepository, RawImageInfo } from 'src/types'; import { ILoggingRepository, IMediaRepository, RawImageInfo } from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { faceStub } from 'test/fixtures/face.stub'; import { faceStub } from 'test/fixtures/face.stub';
import { probeStub } from 'test/fixtures/media.stub'; import { probeStub } from 'test/fixtures/media.stub';
+2 -7
View File
@@ -12,17 +12,12 @@ import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ITagRepository } from 'src/interfaces/tag.interface'; import { ITagRepository } from 'src/interfaces/tag.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { ImmichTags } from 'src/repositories/metadata.repository'; import { ImmichTags } from 'src/repositories/metadata.repository';
import { MetadataService } from 'src/services/metadata.service'; import { MetadataService } from 'src/services/metadata.service';
import { import { IConfigRepository, IMapRepository, IMediaRepository, IMetadataRepository } from 'src/types';
IConfigRepository,
IMapRepository,
IMediaRepository,
IMetadataRepository,
ISystemMetadataRepository,
} from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { fileStub } from 'test/fixtures/file.stub'; import { fileStub } from 'test/fixtures/file.stub';
import { probeStub } from 'test/fixtures/media.stub'; import { probeStub } from 'test/fixtures/media.stub';
@@ -8,10 +8,11 @@ import { IAlbumRepository } from 'src/interfaces/album.interface';
import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository, INotifyAlbumUpdateJob, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, INotifyAlbumUpdateJob, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { EmailTemplate } from 'src/repositories/notification.repository'; import { EmailTemplate } from 'src/repositories/notification.repository';
import { NotificationService } from 'src/services/notification.service'; import { NotificationService } from 'src/services/notification.service';
import { INotificationRepository, ISystemMetadataRepository } from 'src/types'; import { INotificationRepository } from 'src/types';
import { albumStub } from 'test/fixtures/album.stub'; import { albumStub } from 'test/fixtures/album.stub';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { userStub } from 'test/fixtures/user.stub'; import { userStub } from 'test/fixtures/user.stub';
+4 -3
View File
@@ -10,8 +10,9 @@ import { DetectedFaces, IMachineLearningRepository } from 'src/interfaces/machin
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { FaceSearchResult, ISearchRepository } from 'src/interfaces/search.interface'; import { FaceSearchResult, ISearchRepository } from 'src/interfaces/search.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { PersonService } from 'src/services/person.service'; import { PersonService } from 'src/services/person.service';
import { IMediaRepository, ISystemMetadataRepository } from 'src/types'; import { IMediaRepository } from 'src/types';
import { ImmichFileResponse } from 'src/utils/file'; import { ImmichFileResponse } from 'src/utils/file';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
@@ -354,7 +355,7 @@ describe(PersonService.name, () => {
sut.reassignFaces(authStub.admin, personStub.noName.id, { sut.reassignFaces(authStub.admin, personStub.noName.id, {
data: [{ personId: personStub.withName.id, assetId: assetStub.image.id }], data: [{ personId: personStub.withName.id, assetId: assetStub.image.id }],
}), }),
).resolves.toBeDefined(); ).resolves.toEqual([personStub.noName]);
expect(jobMock.queueAll).toHaveBeenCalledWith([ expect(jobMock.queueAll).toHaveBeenCalledWith([
{ {
@@ -447,7 +448,7 @@ describe(PersonService.name, () => {
it('should create a new person', async () => { it('should create a new person', async () => {
personMock.create.mockResolvedValue(personStub.primaryPerson); personMock.create.mockResolvedValue(personStub.primaryPerson);
await expect(sut.create(authStub.admin, {})).resolves.toBeDefined(); await expect(sut.create(authStub.admin, {})).resolves.toBe(personStub.primaryPerson);
expect(personMock.create).toHaveBeenCalledWith({ ownerId: authStub.admin.user.id }); expect(personMock.create).toHaveBeenCalledWith({ ownerId: authStub.admin.user.id });
}); });
+4 -8
View File
@@ -104,7 +104,7 @@ export class PersonService extends BaseService {
await this.personRepository.reassignFace(face.id, personId); await this.personRepository.reassignFace(face.id, personId);
} }
result.push(mapPerson(person)); result.push(person);
} }
if (changeFeaturePhoto.length > 0) { if (changeFeaturePhoto.length > 0) {
// Remove duplicates // Remove duplicates
@@ -178,23 +178,20 @@ export class PersonService extends BaseService {
}); });
} }
async create(auth: AuthDto, dto: PersonCreateDto): Promise<PersonResponseDto> { create(auth: AuthDto, dto: PersonCreateDto): Promise<PersonResponseDto> {
const person = await this.personRepository.create({ return this.personRepository.create({
ownerId: auth.user.id, ownerId: auth.user.id,
name: dto.name, name: dto.name,
birthDate: dto.birthDate, birthDate: dto.birthDate,
isHidden: dto.isHidden, isHidden: dto.isHidden,
isFavorite: dto.isFavorite, isFavorite: dto.isFavorite,
color: dto.color,
}); });
return mapPerson(person);
} }
async update(auth: AuthDto, id: string, dto: PersonUpdateDto): Promise<PersonResponseDto> { async update(auth: AuthDto, id: string, dto: PersonUpdateDto): Promise<PersonResponseDto> {
await this.requireAccess({ auth, permission: Permission.PERSON_UPDATE, ids: [id] }); await this.requireAccess({ auth, permission: Permission.PERSON_UPDATE, ids: [id] });
const { name, birthDate, isHidden, featureFaceAssetId: assetId, isFavorite, color } = dto; const { name, birthDate, isHidden, featureFaceAssetId: assetId, isFavorite } = dto;
// TODO: set by faceId directly // TODO: set by faceId directly
let faceId: string | undefined = undefined; let faceId: string | undefined = undefined;
if (assetId) { if (assetId) {
@@ -214,7 +211,6 @@ export class PersonService extends BaseService {
birthDate, birthDate,
isHidden, isHidden,
isFavorite, isFavorite,
color,
}); });
if (assetId) { if (assetId) {
@@ -31,8 +31,6 @@ describe(SearchService.name, () => {
it('should pass options to search', async () => { it('should pass options to search', async () => {
const { name } = personStub.withName; const { name } = personStub.withName;
personMock.getByName.mockResolvedValue([]);
await sut.searchPerson(authStub.user1, { name, withHidden: false }); await sut.searchPerson(authStub.user1, { name, withHidden: false });
expect(personMock.getByName).toHaveBeenCalledWith(authStub.user1.user.id, name, { withHidden: false }); expect(personMock.getByName).toHaveBeenCalledWith(authStub.user1.user.id, name, { withHidden: false });
+3 -4
View File
@@ -1,9 +1,8 @@
import { BadRequestException, Injectable } from '@nestjs/common'; import { BadRequestException, Injectable } from '@nestjs/common';
import { AssetMapOptions, AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AssetMapOptions, AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto';
import { AuthDto } from 'src/dtos/auth.dto'; import { AuthDto } from 'src/dtos/auth.dto';
import { mapPerson, PersonResponseDto } from 'src/dtos/person.dto'; import { PersonResponseDto } from 'src/dtos/person.dto';
import { import {
mapPlaces,
MetadataSearchDto, MetadataSearchDto,
PlacesResponseDto, PlacesResponseDto,
RandomSearchDto, RandomSearchDto,
@@ -13,6 +12,7 @@ import {
SearchSuggestionRequestDto, SearchSuggestionRequestDto,
SearchSuggestionType, SearchSuggestionType,
SmartSearchDto, SmartSearchDto,
mapPlaces,
} from 'src/dtos/search.dto'; } from 'src/dtos/search.dto';
import { AssetEntity } from 'src/entities/asset.entity'; import { AssetEntity } from 'src/entities/asset.entity';
import { AssetOrder } from 'src/enum'; import { AssetOrder } from 'src/enum';
@@ -24,8 +24,7 @@ import { isSmartSearchEnabled } from 'src/utils/misc';
@Injectable() @Injectable()
export class SearchService extends BaseService { export class SearchService extends BaseService {
async searchPerson(auth: AuthDto, dto: SearchPeopleDto): Promise<PersonResponseDto[]> { async searchPerson(auth: AuthDto, dto: SearchPeopleDto): Promise<PersonResponseDto[]> {
const people = await this.personRepository.getByName(auth.user.id, dto.name, { withHidden: dto.withHidden }); return this.personRepository.getByName(auth.user.id, dto.name, { withHidden: dto.withHidden });
return people.map((person) => mapPerson(person));
} }
async searchPlaces(dto: SearchPlacesDto): Promise<PlacesResponseDto[]> { async searchPlaces(dto: SearchPlacesDto): Promise<PlacesResponseDto[]> {
+1 -1
View File
@@ -1,8 +1,8 @@
import { SystemMetadataKey } from 'src/enum'; import { SystemMetadataKey } from 'src/enum';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { ServerService } from 'src/services/server.service'; import { ServerService } from 'src/services/server.service';
import { ISystemMetadataRepository } from 'src/types';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
+5 -3
View File
@@ -1,6 +1,7 @@
import { UserEntity } from 'src/entities/user.entity';
import { JobStatus } from 'src/interfaces/job.interface'; import { JobStatus } from 'src/interfaces/job.interface';
import { ISessionRepository } from 'src/interfaces/session.interface';
import { SessionService } from 'src/services/session.service'; import { SessionService } from 'src/services/session.service';
import { ISessionRepository } from 'src/types';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
import { sessionStub } from 'test/fixtures/session.stub'; import { sessionStub } from 'test/fixtures/session.stub';
import { IAccessRepositoryMock } from 'test/repositories/access.repository.mock'; import { IAccessRepositoryMock } from 'test/repositories/access.repository.mock';
@@ -37,6 +38,7 @@ describe('SessionService', () => {
deviceType: '', deviceType: '',
id: '123', id: '123',
token: '420', token: '420',
user: {} as UserEntity,
userId: '42', userId: '42',
}, },
]); ]);
@@ -48,7 +50,7 @@ describe('SessionService', () => {
describe('getAll', () => { describe('getAll', () => {
it('should get the devices', async () => { it('should get the devices', async () => {
sessionMock.getByUserId.mockResolvedValue([sessionStub.valid as any, sessionStub.inactive]); sessionMock.getByUserId.mockResolvedValue([sessionStub.valid, sessionStub.inactive]);
await expect(sut.getAll(authStub.user1)).resolves.toEqual([ await expect(sut.getAll(authStub.user1)).resolves.toEqual([
{ {
createdAt: '2021-01-01T00:00:00.000Z', createdAt: '2021-01-01T00:00:00.000Z',
@@ -74,7 +76,7 @@ describe('SessionService', () => {
describe('logoutDevices', () => { describe('logoutDevices', () => {
it('should logout all devices', async () => { it('should logout all devices', async () => {
sessionMock.getByUserId.mockResolvedValue([sessionStub.inactive, sessionStub.valid] as any[]); sessionMock.getByUserId.mockResolvedValue([sessionStub.inactive, sessionStub.valid]);
await sut.deleteAll(authStub.user1); await sut.deleteAll(authStub.user1);
@@ -29,11 +29,11 @@ describe(SharedLinkService.name, () => {
describe('getAll', () => { describe('getAll', () => {
it('should return all shared links for a user', async () => { it('should return all shared links for a user', async () => {
sharedLinkMock.getAll.mockResolvedValue([sharedLinkStub.expired, sharedLinkStub.valid]); sharedLinkMock.getAll.mockResolvedValue([sharedLinkStub.expired, sharedLinkStub.valid]);
await expect(sut.getAll(authStub.user1, {})).resolves.toEqual([ await expect(sut.getAll(authStub.user1)).resolves.toEqual([
sharedLinkResponseStub.expired, sharedLinkResponseStub.expired,
sharedLinkResponseStub.valid, sharedLinkResponseStub.valid,
]); ]);
expect(sharedLinkMock.getAll).toHaveBeenCalledWith({ userId: authStub.user1.user.id }); expect(sharedLinkMock.getAll).toHaveBeenCalledWith(authStub.user1.user.id);
}); });
}); });
+2 -5
View File
@@ -9,7 +9,6 @@ import {
SharedLinkEditDto, SharedLinkEditDto,
SharedLinkPasswordDto, SharedLinkPasswordDto,
SharedLinkResponseDto, SharedLinkResponseDto,
SharedLinkSearchDto,
} from 'src/dtos/shared-link.dto'; } from 'src/dtos/shared-link.dto';
import { SharedLinkEntity } from 'src/entities/shared-link.entity'; import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { Permission, SharedLinkType } from 'src/enum'; import { Permission, SharedLinkType } from 'src/enum';
@@ -18,10 +17,8 @@ import { getExternalDomain, OpenGraphTags } from 'src/utils/misc';
@Injectable() @Injectable()
export class SharedLinkService extends BaseService { export class SharedLinkService extends BaseService {
async getAll(auth: AuthDto, { albumId }: SharedLinkSearchDto): Promise<SharedLinkResponseDto[]> { async getAll(auth: AuthDto): Promise<SharedLinkResponseDto[]> {
return this.sharedLinkRepository return this.sharedLinkRepository.getAll(auth.user.id).then((links) => links.map((link) => mapSharedLink(link)));
.getAll({ userId: auth.user.id, albumId })
.then((links) => links.map((link) => mapSharedLink(link)));
} }
async getMine(auth: AuthDto, dto: SharedLinkPasswordDto): Promise<SharedLinkResponseDto> { async getMine(auth: AuthDto, dto: SharedLinkPasswordDto): Promise<SharedLinkResponseDto> {
@@ -5,8 +5,9 @@ import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { SmartInfoService } from 'src/services/smart-info.service'; import { SmartInfoService } from 'src/services/smart-info.service';
import { IConfigRepository, ISystemMetadataRepository } from 'src/types'; import { IConfigRepository } from 'src/types';
import { getCLIPModelInfo } from 'src/utils/misc'; import { getCLIPModelInfo } from 'src/utils/misc';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { systemConfigStub } from 'test/fixtures/system-config.stub'; import { systemConfigStub } from 'test/fixtures/system-config.stub';
@@ -8,9 +8,9 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { JobStatus } from 'src/interfaces/job.interface'; import { JobStatus } from 'src/interfaces/job.interface';
import { IMoveRepository } from 'src/interfaces/move.interface'; import { IMoveRepository } from 'src/interfaces/move.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { StorageTemplateService } from 'src/services/storage-template.service'; import { StorageTemplateService } from 'src/services/storage-template.service';
import { ISystemMetadataRepository } from 'src/types';
import { albumStub } from 'test/fixtures/album.stub'; import { albumStub } from 'test/fixtures/album.stub';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { userStub } from 'test/fixtures/user.stub'; import { userStub } from 'test/fixtures/user.stub';
+2 -1
View File
@@ -1,7 +1,8 @@
import { SystemMetadataKey } from 'src/enum'; import { SystemMetadataKey } from 'src/enum';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { StorageService } from 'src/services/storage.service'; import { StorageService } from 'src/services/storage.service';
import { IConfigRepository, ILoggingRepository, ISystemMetadataRepository } from 'src/types'; import { IConfigRepository, ILoggingRepository } from 'src/types';
import { ImmichStartupError } from 'src/utils/misc'; import { ImmichStartupError } from 'src/utils/misc';
import { mockEnvData } from 'test/repositories/config.repository.mock'; import { mockEnvData } from 'test/repositories/config.repository.mock';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
@@ -14,8 +14,9 @@ import {
} from 'src/enum'; } from 'src/enum';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { QueueName } from 'src/interfaces/job.interface'; import { QueueName } from 'src/interfaces/job.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { SystemConfigService } from 'src/services/system-config.service'; import { SystemConfigService } from 'src/services/system-config.service';
import { DeepPartial, IConfigRepository, ILoggingRepository, ISystemMetadataRepository } from 'src/types'; import { DeepPartial, IConfigRepository, ILoggingRepository } from 'src/types';
import { mockEnvData } from 'test/repositories/config.repository.mock'; import { mockEnvData } from 'test/repositories/config.repository.mock';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
@@ -1,6 +1,6 @@
import { SystemMetadataKey } from 'src/enum'; import { SystemMetadataKey } from 'src/enum';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { SystemMetadataService } from 'src/services/system-metadata.service'; import { SystemMetadataService } from 'src/services/system-metadata.service';
import { ISystemMetadataRepository } from 'src/types';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
+1 -1
View File
@@ -4,9 +4,9 @@ import { CacheControl, UserMetadataKey } from 'src/enum';
import { IAlbumRepository } from 'src/interfaces/album.interface'; import { IAlbumRepository } from 'src/interfaces/album.interface';
import { IJobRepository, JobName } from 'src/interfaces/job.interface'; import { IJobRepository, JobName } from 'src/interfaces/job.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository } from 'src/interfaces/user.interface'; import { IUserRepository } from 'src/interfaces/user.interface';
import { UserService } from 'src/services/user.service'; import { UserService } from 'src/services/user.service';
import { ISystemMetadataRepository } from 'src/types';
import { ImmichFileResponse } from 'src/utils/file'; import { ImmichFileResponse } from 'src/utils/file';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
import { systemConfigStub } from 'test/fixtures/system-config.stub'; import { systemConfigStub } from 'test/fixtures/system-config.stub';
+2 -7
View File
@@ -4,14 +4,9 @@ import { serverVersion } from 'src/constants';
import { ImmichEnvironment, SystemMetadataKey } from 'src/enum'; import { ImmichEnvironment, SystemMetadataKey } from 'src/enum';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { VersionService } from 'src/services/version.service'; import { VersionService } from 'src/services/version.service';
import { import { IConfigRepository, ILoggingRepository, IServerInfoRepository, IVersionHistoryRepository } from 'src/types';
IConfigRepository,
ILoggingRepository,
IServerInfoRepository,
ISystemMetadataRepository,
IVersionHistoryRepository,
} from 'src/types';
import { mockEnvData } from 'test/repositories/config.repository.mock'; import { mockEnvData } from 'test/repositories/config.repository.mock';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
-8
View File
@@ -14,10 +14,7 @@ import { MemoryRepository } from 'src/repositories/memory.repository';
import { MetadataRepository } from 'src/repositories/metadata.repository'; import { MetadataRepository } from 'src/repositories/metadata.repository';
import { NotificationRepository } from 'src/repositories/notification.repository'; import { NotificationRepository } from 'src/repositories/notification.repository';
import { OAuthRepository } from 'src/repositories/oauth.repository'; import { OAuthRepository } from 'src/repositories/oauth.repository';
import { ProcessRepository } from 'src/repositories/process.repository';
import { ServerInfoRepository } from 'src/repositories/server-info.repository'; import { ServerInfoRepository } from 'src/repositories/server-info.repository';
import { SessionRepository } from 'src/repositories/session.repository';
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
import { MetricGroupRepository, TelemetryRepository } from 'src/repositories/telemetry.repository'; import { MetricGroupRepository, TelemetryRepository } from 'src/repositories/telemetry.repository';
import { TrashRepository } from 'src/repositories/trash.repository'; import { TrashRepository } from 'src/repositories/trash.repository';
import { VersionHistoryRepository } from 'src/repositories/version-history.repository'; import { VersionHistoryRepository } from 'src/repositories/version-history.repository';
@@ -61,10 +58,7 @@ export type IMetadataRepository = RepositoryInterface<MetadataRepository>;
export type IMetricGroupRepository = RepositoryInterface<MetricGroupRepository>; export type IMetricGroupRepository = RepositoryInterface<MetricGroupRepository>;
export type INotificationRepository = RepositoryInterface<NotificationRepository>; export type INotificationRepository = RepositoryInterface<NotificationRepository>;
export type IOAuthRepository = RepositoryInterface<OAuthRepository>; export type IOAuthRepository = RepositoryInterface<OAuthRepository>;
export type IProcessRepository = RepositoryInterface<ProcessRepository>;
export type ISessionRepository = RepositoryInterface<SessionRepository>;
export type IServerInfoRepository = RepositoryInterface<ServerInfoRepository>; export type IServerInfoRepository = RepositoryInterface<ServerInfoRepository>;
export type ISystemMetadataRepository = RepositoryInterface<SystemMetadataRepository>;
export type ITelemetryRepository = RepositoryInterface<TelemetryRepository>; export type ITelemetryRepository = RepositoryInterface<TelemetryRepository>;
export type ITrashRepository = RepositoryInterface<TrashRepository>; export type ITrashRepository = RepositoryInterface<TrashRepository>;
export type IViewRepository = RepositoryInterface<ViewRepository>; export type IViewRepository = RepositoryInterface<ViewRepository>;
@@ -83,8 +77,6 @@ export type MemoryItem =
| Awaited<ReturnType<IMemoryRepository['create']>> | Awaited<ReturnType<IMemoryRepository['create']>>
| Awaited<ReturnType<IMemoryRepository['search']>>[0]; | Awaited<ReturnType<IMemoryRepository['search']>>[0];
export type SessionItem = Awaited<ReturnType<ISessionRepository['getByUserId']>>[0];
export interface CropOptions { export interface CropOptions {
top: number; top: number;
left: number; left: number;
+2 -1
View File
@@ -7,7 +7,8 @@ import { SystemConfig, defaults } from 'src/config';
import { SystemConfigDto } from 'src/dtos/system-config.dto'; import { SystemConfigDto } from 'src/dtos/system-config.dto';
import { SystemMetadataKey } from 'src/enum'; import { SystemMetadataKey } from 'src/enum';
import { DatabaseLock } from 'src/interfaces/database.interface'; import { DatabaseLock } from 'src/interfaces/database.interface';
import { DeepPartial, IConfigRepository, ILoggingRepository, ISystemMetadataRepository } from 'src/types'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { DeepPartial, IConfigRepository, ILoggingRepository } from 'src/types';
import { getKeysDeep, unsetDeep } from 'src/utils/misc'; import { getKeysDeep, unsetDeep } from 'src/utils/misc';
export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise<void>; export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise<void>;
-10
View File
@@ -12,7 +12,6 @@ import {
IsArray, IsArray,
IsBoolean, IsBoolean,
IsDate, IsDate,
IsHexColor,
IsNotEmpty, IsNotEmpty,
IsOptional, IsOptional,
IsString, IsString,
@@ -98,15 +97,6 @@ export function Optional({ nullable, emptyToNull, ...validationOptions }: Option
return applyDecorators(...decorators); return applyDecorators(...decorators);
} }
export const ValidateHexColor = () => {
const decorators = [
IsHexColor(),
Transform(({ value }) => (typeof value === 'string' && value[0] !== '#' ? `#${value}` : value)),
];
return applyDecorators(...decorators);
};
type UUIDOptions = { optional?: boolean; each?: boolean; nullable?: boolean }; type UUIDOptions = { optional?: boolean; each?: boolean; nullable?: boolean };
export const ValidateUUID = (options?: UUIDOptions) => { export const ValidateUUID = (options?: UUIDOptions) => {
const { optional, each, nullable } = { optional: false, each: false, nullable: false, ...options }; const { optional, each, nullable } = { optional: false, each: false, nullable: false, ...options };
@@ -1,4 +1,4 @@
import { IProcessRepository } from 'src/types'; import { IProcessRepository } from 'src/interfaces/process.interface';
import { Mocked, vitest } from 'vitest'; import { Mocked, vitest } from 'vitest';
export const newProcessRepositoryMock = (): Mocked<IProcessRepository> => { export const newProcessRepositoryMock = (): Mocked<IProcessRepository> => {

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