mirror of
https://github.com/standardnotes/server
synced 2026-04-19 08:02:23 -04:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 503b84531b | |||
| fe8ca828fb | |||
| 03a4a3f2ab | |||
| 3a8607d146 | |||
| 93b6e65554 | |||
| 5984e4c3e7 | |||
| b4257c10ea | |||
| c164bde847 | |||
| 883df939dd | |||
| c7807d0f9e | |||
| fc90343aaa | |||
| fbcb45c3a2 | |||
| 179d8eaaa1 | |||
| 38685c1861 | |||
| cdf42fbe2d | |||
| 9be4c002b7 | |||
| a16c5307a0 | |||
| d5536f5430 | |||
| b1d88b15be | |||
| ff78285e43 | |||
| 1a26221385 | |||
| 54113abe2a | |||
| afe385aed4 | |||
| f055e52e06 | |||
| fab5d18064 | |||
| a1e654a0d0 | |||
| aa835268ea | |||
| 74b4312928 | |||
| e91a832152 | |||
| 4f95bbee3f | |||
| b9c9f74d0c | |||
| e535cd504c | |||
| db0360860a | |||
| aa2b5f3b74 | |||
| 6241661e27 | |||
| 25047bf46d | |||
| a1820ed212 | |||
| 0a1d1624e8 | |||
| 7367de6832 | |||
| f0abfe89fc | |||
| d1244d165a | |||
| 106d8f9192 | |||
| 1d86ba8fcb | |||
| f20a947f8a | |||
| 19b9de05ae | |||
| 1d751c0fbe | |||
| fa2564e164 | |||
| 330bff0124 | |||
| ca57c8e7b5 | |||
| a82b9a0c8a | |||
| ea7e9d73c4 | |||
| 117b7b4b99 | |||
| b4bf11d9da | |||
| 0306e10469 | |||
| 0ab47013f2 | |||
| 836883b82d | |||
| ed671be9c5 | |||
| 9676a2586c | |||
| e95ba61c7f | |||
| a0718aea26 | |||
| 156fa7a618 | |||
| 8d006ece30 | |||
| 037c994040 | |||
| a164ba291d | |||
| 610fba2601 | |||
| 398338c8f8 | |||
| 34be157d8e | |||
| 76372fe357 | |||
| 46879c336b | |||
| aef9e936bd | |||
| 8cb92d9678 | |||
| 52db89de81 | |||
| c5af8dfc05 | |||
| 27ad8e6959 | |||
| c4a1502f70 | |||
| d1d6c753c4 | |||
| 3bd63f7674 | |||
| 376466d9b2 | |||
| e100c52bbc | |||
| d4830dec01 | |||
| 7e11821021 | |||
| 4715e019a2 | |||
| 794cd8734a | |||
| 14d42b26bb | |||
| 6bb44afd91 | |||
| c82345aeeb | |||
| 72ab08a0d0 |
@@ -4,6 +4,7 @@ DB_USERNAME=std_notes_user
|
||||
DB_PASSWORD=changeme123
|
||||
DB_DATABASE=standard_notes_db
|
||||
DB_PORT=3306
|
||||
DB_DEBUG_LEVEL=all
|
||||
DB_SQLITE_DATABASE_PATH=standard_notes_db
|
||||
REDIS_PORT=6379
|
||||
REDIS_HOST=cache
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
e2e:
|
||||
name: (Self Hosting) E2E Test Suite
|
||||
strategy:
|
||||
fail-fast: true
|
||||
fail-fast: false
|
||||
matrix:
|
||||
secondary_db_enabled: [true, false]
|
||||
transition_mode_enabled: [true, false]
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
e2e-home-server:
|
||||
name: (Home Server) E2E Test Suite
|
||||
strategy:
|
||||
fail-fast: true
|
||||
fail-fast: false
|
||||
matrix:
|
||||
db_type: [mysql, sqlite]
|
||||
cache_type: [redis, memory]
|
||||
@@ -141,6 +141,7 @@ jobs:
|
||||
echo "DB_USERNAME=standardnotes" >> packages/home-server/.env
|
||||
echo "DB_PASSWORD=standardnotes" >> packages/home-server/.env
|
||||
echo "DB_TYPE=${{ matrix.db_type }}" >> packages/home-server/.env
|
||||
echo "DB_DEBUG_LEVEL=all" >> packages/home-server/.env
|
||||
echo "REDIS_URL=redis://localhost:6379" >> packages/home-server/.env
|
||||
echo "CACHE_TYPE=${{ matrix.cache_type }}" >> packages/home-server/.env
|
||||
echo "SECONDARY_DB_ENABLED=${{ matrix.secondary_db_enabled }}" >> packages/home-server/.env
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
name: E2E Test Suite On Self Hosted Server
|
||||
|
||||
run-name: E2E Test Suite against ${{ inputs.ref_name }} by ${{ inputs.author }}
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 */12 * * *'
|
||||
@@ -9,6 +11,14 @@ on:
|
||||
type: string
|
||||
default: latest
|
||||
description: The Docker image tag used for SNJS container
|
||||
author:
|
||||
type: string
|
||||
default: unknown
|
||||
description: The author that triggered the workflow
|
||||
ref_name:
|
||||
type: string
|
||||
default: unknown
|
||||
description: The ref name from which the workflow was triggered
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
|
||||
@@ -275,6 +275,51 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/client-apigatewaymanagementapi", [\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-client-apigatewaymanagementapi-npm-3.405.0-e4e17d811f-d7103d0b37.zip/node_modules/@aws-sdk/client-apigatewaymanagementapi/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/client-apigatewaymanagementapi", "npm:3.405.0"],\
|
||||
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
|
||||
["@aws-crypto/sha256-js", "npm:3.0.0"],\
|
||||
["@aws-sdk/client-sts", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-node", "npm:3.405.0"],\
|
||||
["@aws-sdk/middleware-host-header", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-logger", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-recursion-detection", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-signing", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-user-agent", "npm:3.398.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-endpoints", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-browser", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-node", "virtual:0b227682399940b7e75175c6ae399b938ec07d3986be60e73f8026d2677e9fe96d05ac258f3f223cf1b6bdd7fd2a24f55f0efa40a8406ba949dc1b7af3a6a968#npm:3.405.0"],\
|
||||
["@smithy/config-resolver", "npm:2.0.5"],\
|
||||
["@smithy/fetch-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/hash-node", "npm:2.0.5"],\
|
||||
["@smithy/invalid-dependency", "npm:2.0.5"],\
|
||||
["@smithy/middleware-content-length", "npm:2.0.5"],\
|
||||
["@smithy/middleware-endpoint", "npm:2.0.5"],\
|
||||
["@smithy/middleware-retry", "npm:2.0.5"],\
|
||||
["@smithy/middleware-serde", "npm:2.0.5"],\
|
||||
["@smithy/middleware-stack", "npm:2.0.0"],\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/node-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/protocol-http", "npm:2.0.5"],\
|
||||
["@smithy/smithy-client", "npm:2.0.5"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["@smithy/url-parser", "npm:2.0.5"],\
|
||||
["@smithy/util-base64", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-browser", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-node", "npm:2.1.0"],\
|
||||
["@smithy/util-defaults-mode-browser", "npm:2.0.6"],\
|
||||
["@smithy/util-defaults-mode-node", "npm:2.0.7"],\
|
||||
["@smithy/util-retry", "npm:2.0.0"],\
|
||||
["@smithy/util-utf8", "npm:2.0.0"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/client-lambda", [\
|
||||
["npm:3.398.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-client-lambda-npm-3.398.0-fa4aacfc7b-85ef0fe18d.zip/node_modules/@aws-sdk/client-lambda/",\
|
||||
@@ -563,6 +608,46 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-client-sso-npm-3.405.0-0b22768239-323f99e024.zip/node_modules/@aws-sdk/client-sso/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/client-sso", "npm:3.405.0"],\
|
||||
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
|
||||
["@aws-crypto/sha256-js", "npm:3.0.0"],\
|
||||
["@aws-sdk/middleware-host-header", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-logger", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-recursion-detection", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-user-agent", "npm:3.398.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-endpoints", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-browser", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-node", "virtual:0b227682399940b7e75175c6ae399b938ec07d3986be60e73f8026d2677e9fe96d05ac258f3f223cf1b6bdd7fd2a24f55f0efa40a8406ba949dc1b7af3a6a968#npm:3.405.0"],\
|
||||
["@smithy/config-resolver", "npm:2.0.5"],\
|
||||
["@smithy/fetch-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/hash-node", "npm:2.0.5"],\
|
||||
["@smithy/invalid-dependency", "npm:2.0.5"],\
|
||||
["@smithy/middleware-content-length", "npm:2.0.5"],\
|
||||
["@smithy/middleware-endpoint", "npm:2.0.5"],\
|
||||
["@smithy/middleware-retry", "npm:2.0.5"],\
|
||||
["@smithy/middleware-serde", "npm:2.0.5"],\
|
||||
["@smithy/middleware-stack", "npm:2.0.0"],\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/node-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/protocol-http", "npm:2.0.5"],\
|
||||
["@smithy/smithy-client", "npm:2.0.5"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["@smithy/url-parser", "npm:2.0.5"],\
|
||||
["@smithy/util-base64", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-browser", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-node", "npm:2.1.0"],\
|
||||
["@smithy/util-defaults-mode-browser", "npm:2.0.6"],\
|
||||
["@smithy/util-defaults-mode-node", "npm:2.0.7"],\
|
||||
["@smithy/util-retry", "npm:2.0.0"],\
|
||||
["@smithy/util-utf8", "npm:2.0.0"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/client-sso-oidc", [\
|
||||
@@ -695,6 +780,50 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-client-sts-npm-3.405.0-b83c3faf19-01ea2a8695.zip/node_modules/@aws-sdk/client-sts/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/client-sts", "npm:3.405.0"],\
|
||||
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
|
||||
["@aws-crypto/sha256-js", "npm:3.0.0"],\
|
||||
["@aws-sdk/credential-provider-node", "npm:3.405.0"],\
|
||||
["@aws-sdk/middleware-host-header", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-logger", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-recursion-detection", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-sdk-sts", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-signing", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-user-agent", "npm:3.398.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-endpoints", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-browser", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-node", "virtual:0b227682399940b7e75175c6ae399b938ec07d3986be60e73f8026d2677e9fe96d05ac258f3f223cf1b6bdd7fd2a24f55f0efa40a8406ba949dc1b7af3a6a968#npm:3.405.0"],\
|
||||
["@smithy/config-resolver", "npm:2.0.5"],\
|
||||
["@smithy/fetch-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/hash-node", "npm:2.0.5"],\
|
||||
["@smithy/invalid-dependency", "npm:2.0.5"],\
|
||||
["@smithy/middleware-content-length", "npm:2.0.5"],\
|
||||
["@smithy/middleware-endpoint", "npm:2.0.5"],\
|
||||
["@smithy/middleware-retry", "npm:2.0.5"],\
|
||||
["@smithy/middleware-serde", "npm:2.0.5"],\
|
||||
["@smithy/middleware-stack", "npm:2.0.0"],\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/node-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/protocol-http", "npm:2.0.5"],\
|
||||
["@smithy/smithy-client", "npm:2.0.5"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["@smithy/url-parser", "npm:2.0.5"],\
|
||||
["@smithy/util-base64", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-browser", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-node", "npm:2.1.0"],\
|
||||
["@smithy/util-defaults-mode-browser", "npm:2.0.6"],\
|
||||
["@smithy/util-defaults-mode-node", "npm:2.0.7"],\
|
||||
["@smithy/util-retry", "npm:2.0.0"],\
|
||||
["@smithy/util-utf8", "npm:2.0.0"],\
|
||||
["fast-xml-parser", "npm:4.2.5"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/config-resolver", [\
|
||||
@@ -780,6 +909,23 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-ini-npm-3.405.0-759c2d9674-0d2694b969.zip/node_modules/@aws-sdk/credential-provider-ini/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/credential-provider-ini", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-env", "npm:3.398.0"],\
|
||||
["@aws-sdk/credential-provider-process", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-sso", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-web-identity", "npm:3.398.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@smithy/credential-provider-imds", "npm:2.0.5"],\
|
||||
["@smithy/property-provider", "npm:2.0.5"],\
|
||||
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/credential-provider-node", [\
|
||||
@@ -817,6 +963,24 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-node-npm-3.405.0-33a4e3c01f-58cf90600d.zip/node_modules/@aws-sdk/credential-provider-node/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/credential-provider-node", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-env", "npm:3.398.0"],\
|
||||
["@aws-sdk/credential-provider-ini", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-process", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-sso", "npm:3.405.0"],\
|
||||
["@aws-sdk/credential-provider-web-identity", "npm:3.398.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@smithy/credential-provider-imds", "npm:2.0.5"],\
|
||||
["@smithy/property-provider", "npm:2.0.5"],\
|
||||
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/credential-provider-process", [\
|
||||
@@ -842,6 +1006,18 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-process-npm-3.405.0-ed6dc867ed-bd23e267bd.zip/node_modules/@aws-sdk/credential-provider-process/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/credential-provider-process", "npm:3.405.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@smithy/property-provider", "npm:2.0.5"],\
|
||||
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/credential-provider-sso", [\
|
||||
@@ -871,6 +1047,20 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-credential-provider-sso-npm-3.405.0-24b76ee82f-754f796b2a.zip/node_modules/@aws-sdk/credential-provider-sso/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/credential-provider-sso", "npm:3.405.0"],\
|
||||
["@aws-sdk/client-sso", "npm:3.405.0"],\
|
||||
["@aws-sdk/token-providers", "npm:3.405.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@smithy/property-provider", "npm:2.0.5"],\
|
||||
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/credential-provider-web-identity", [\
|
||||
@@ -1538,6 +1728,48 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-token-providers-npm-3.405.0-29e68d4065-08e30dbc7b.zip/node_modules/@aws-sdk/token-providers/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/token-providers", "npm:3.405.0"],\
|
||||
["@aws-crypto/sha256-browser", "npm:3.0.0"],\
|
||||
["@aws-crypto/sha256-js", "npm:3.0.0"],\
|
||||
["@aws-sdk/middleware-host-header", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-logger", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-recursion-detection", "npm:3.398.0"],\
|
||||
["@aws-sdk/middleware-user-agent", "npm:3.398.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-endpoints", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-browser", "npm:3.398.0"],\
|
||||
["@aws-sdk/util-user-agent-node", "virtual:0b227682399940b7e75175c6ae399b938ec07d3986be60e73f8026d2677e9fe96d05ac258f3f223cf1b6bdd7fd2a24f55f0efa40a8406ba949dc1b7af3a6a968#npm:3.405.0"],\
|
||||
["@smithy/config-resolver", "npm:2.0.5"],\
|
||||
["@smithy/fetch-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/hash-node", "npm:2.0.5"],\
|
||||
["@smithy/invalid-dependency", "npm:2.0.5"],\
|
||||
["@smithy/middleware-content-length", "npm:2.0.5"],\
|
||||
["@smithy/middleware-endpoint", "npm:2.0.5"],\
|
||||
["@smithy/middleware-retry", "npm:2.0.5"],\
|
||||
["@smithy/middleware-serde", "npm:2.0.5"],\
|
||||
["@smithy/middleware-stack", "npm:2.0.0"],\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/node-http-handler", "npm:2.0.5"],\
|
||||
["@smithy/property-provider", "npm:2.0.5"],\
|
||||
["@smithy/protocol-http", "npm:2.0.5"],\
|
||||
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
|
||||
["@smithy/smithy-client", "npm:2.0.5"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["@smithy/url-parser", "npm:2.0.5"],\
|
||||
["@smithy/util-base64", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-browser", "npm:2.0.0"],\
|
||||
["@smithy/util-body-length-node", "npm:2.1.0"],\
|
||||
["@smithy/util-defaults-mode-browser", "npm:2.0.6"],\
|
||||
["@smithy/util-defaults-mode-node", "npm:2.0.7"],\
|
||||
["@smithy/util-retry", "npm:2.0.0"],\
|
||||
["@smithy/util-utf8", "npm:2.0.0"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@aws-sdk/types", [\
|
||||
@@ -1798,6 +2030,30 @@ const RAW_RUNTIME_STATE =
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/cache/@aws-sdk-util-user-agent-node-npm-3.405.0-160b854f92-6422874d9e.zip/node_modules/@aws-sdk/util-user-agent-node/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/util-user-agent-node", "npm:3.405.0"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:0b227682399940b7e75175c6ae399b938ec07d3986be60e73f8026d2677e9fe96d05ac258f3f223cf1b6bdd7fd2a24f55f0efa40a8406ba949dc1b7af3a6a968#npm:3.405.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@aws-sdk-util-user-agent-node-virtual-f09536a53a/0/cache/@aws-sdk-util-user-agent-node-npm-3.405.0-160b854f92-6422874d9e.zip/node_modules/@aws-sdk/util-user-agent-node/",\
|
||||
"packageDependencies": [\
|
||||
["@aws-sdk/util-user-agent-node", "virtual:0b227682399940b7e75175c6ae399b938ec07d3986be60e73f8026d2677e9fe96d05ac258f3f223cf1b6bdd7fd2a24f55f0efa40a8406ba949dc1b7af3a6a968#npm:3.405.0"],\
|
||||
["@aws-sdk/types", "npm:3.398.0"],\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["@types/aws-crt", null],\
|
||||
["aws-crt", null],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/aws-crt",\
|
||||
"aws-crt"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:bc215baaece010534480a5bbeef12e01b493e2e880132aa6bad8e946a74eb78bacf426e63b2a17a031e79d1b4089081937de686f0c09183e86cf908c3bd861cc#npm:3.398.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/@aws-sdk-util-user-agent-node-virtual-cb6c764817/0/cache/@aws-sdk-util-user-agent-node-npm-3.398.0-e1c632b733-6d5dae585a.zip/node_modules/@aws-sdk/util-user-agent-node/",\
|
||||
"packageDependencies": [\
|
||||
@@ -4927,6 +5183,18 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.0.7", {\
|
||||
"packageLocation": "./.yarn/cache/@smithy-credential-provider-imds-npm-2.0.7-46bd1e8858-61c59aea7e.zip/node_modules/@smithy/credential-provider-imds/",\
|
||||
"packageDependencies": [\
|
||||
["@smithy/credential-provider-imds", "npm:2.0.7"],\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/property-provider", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["@smithy/url-parser", "npm:2.0.5"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@smithy/eventstream-codec", [\
|
||||
@@ -5111,6 +5379,17 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.0.7", {\
|
||||
"packageLocation": "./.yarn/cache/@smithy-node-config-provider-npm-2.0.7-806b68f393-d4b58ee69f.zip/node_modules/@smithy/node-config-provider/",\
|
||||
"packageDependencies": [\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/property-provider", "npm:2.0.6"],\
|
||||
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@smithy/node-http-handler", [\
|
||||
@@ -5136,6 +5415,15 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.0.6", {\
|
||||
"packageLocation": "./.yarn/cache/@smithy-property-provider-npm-2.0.6-4f294049d1-b9a4aff1f0.zip/node_modules/@smithy/property-provider/",\
|
||||
"packageDependencies": [\
|
||||
["@smithy/property-provider", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@smithy/protocol-http", [\
|
||||
@@ -5199,6 +5487,15 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.0.6", {\
|
||||
"packageLocation": "./.yarn/cache/@smithy-shared-ini-file-loader-npm-2.0.6-ebbee54019-4b538ef59a.zip/node_modules/@smithy/shared-ini-file-loader/",\
|
||||
"packageDependencies": [\
|
||||
["@smithy/shared-ini-file-loader", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@smithy/signature-v4", [\
|
||||
@@ -5324,6 +5621,17 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.0.6", {\
|
||||
"packageLocation": "./.yarn/cache/@smithy-util-defaults-mode-browser-npm-2.0.6-d40f165a01-286295e6e9.zip/node_modules/@smithy/util-defaults-mode-browser/",\
|
||||
"packageDependencies": [\
|
||||
["@smithy/util-defaults-mode-browser", "npm:2.0.6"],\
|
||||
["@smithy/property-provider", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["bowser", "npm:2.11.0"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@smithy/util-defaults-mode-node", [\
|
||||
@@ -5339,6 +5647,19 @@ const RAW_RUNTIME_STATE =
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.0.7", {\
|
||||
"packageLocation": "./.yarn/cache/@smithy-util-defaults-mode-node-npm-2.0.7-8a9d03e11c-b1c74a3b41.zip/node_modules/@smithy/util-defaults-mode-node/",\
|
||||
"packageDependencies": [\
|
||||
["@smithy/util-defaults-mode-node", "npm:2.0.7"],\
|
||||
["@smithy/config-resolver", "npm:2.0.5"],\
|
||||
["@smithy/credential-provider-imds", "npm:2.0.7"],\
|
||||
["@smithy/node-config-provider", "npm:2.0.7"],\
|
||||
["@smithy/property-provider", "npm:2.0.6"],\
|
||||
["@smithy/types", "npm:2.2.2"],\
|
||||
["tslib", "npm:2.5.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@smithy/util-hex-encoding", [\
|
||||
@@ -6161,6 +6482,7 @@ const RAW_RUNTIME_STATE =
|
||||
"packageLocation": "./packages/websockets/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/websockets-server", "workspace:packages/websockets"],\
|
||||
["@aws-sdk/client-apigatewaymanagementapi", "npm:3.405.0"],\
|
||||
["@aws-sdk/client-sqs", "npm:3.342.0"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.1"],\
|
||||
["@standardnotes/api", "npm:1.26.26"],\
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -53,7 +53,7 @@ services:
|
||||
image: mysql:8
|
||||
container_name: db-ci
|
||||
env_file: .github/ci.env
|
||||
expose:
|
||||
ports:
|
||||
- 3306
|
||||
restart: unless-stopped
|
||||
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
|
||||
@@ -66,7 +66,7 @@ services:
|
||||
secondary_db:
|
||||
image: mongo:5.0
|
||||
container_name: secondary_db-ci
|
||||
expose:
|
||||
ports:
|
||||
- 27017
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
@@ -83,7 +83,7 @@ services:
|
||||
container_name: cache-ci
|
||||
volumes:
|
||||
- ./data/redis/:/data
|
||||
expose:
|
||||
ports:
|
||||
- 6379
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
|
||||
@@ -3,6 +3,42 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.26.12](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.11...@standardnotes/analytics@2.26.12) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.11](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.10...@standardnotes/analytics@2.26.11) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.10](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.9...@standardnotes/analytics@2.26.10) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.9](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.8...@standardnotes/analytics@2.26.9) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.8](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.7...@standardnotes/analytics@2.26.8) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.7](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.6...@standardnotes/analytics@2.26.7) (2023-09-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.5...@standardnotes/analytics@2.26.6) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.4...@standardnotes/analytics@2.26.5) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.3...@standardnotes/analytics@2.26.4) (2023-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.2...@standardnotes/analytics@2.26.3) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "2.26.3",
|
||||
"version": "2.26.12",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,56 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.74.10](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.9...@standardnotes/api-gateway@1.74.10) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adjust transition timestamps to be universal ([c7807d0](https://github.com/standardnotes/api-gateway/commit/c7807d0f9e69ce572c4c03ff606375d706f24d9f))
|
||||
|
||||
## [1.74.9](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.8...@standardnotes/api-gateway@1.74.9) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.8](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.7...@standardnotes/api-gateway@1.74.8) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.6...@standardnotes/api-gateway@1.74.7) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.5...@standardnotes/api-gateway@1.74.6) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.4...@standardnotes/api-gateway@1.74.5) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.3...@standardnotes/api-gateway@1.74.4) (2023-09-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** awaiting for other services to start ([0ab4701](https://github.com/standardnotes/api-gateway/commit/0ab47013f210dca7aa404966798011947fb5c362))
|
||||
|
||||
## [1.74.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.2...@standardnotes/api-gateway@1.74.3) (2023-09-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.1...@standardnotes/api-gateway@1.74.2) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.0...@standardnotes/api-gateway@1.74.1) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.74.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.73.7...@standardnotes/api-gateway@1.74.0) (2023-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/api-gateway/issues/807)) ([794cd87](https://github.com/standardnotes/api-gateway/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
|
||||
|
||||
## [1.73.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.73.6...@standardnotes/api-gateway@1.73.7) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.73.7",
|
||||
"version": "1.74.10",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -72,6 +72,7 @@ export abstract class AuthMiddleware extends BaseMiddleware {
|
||||
response.locals.session = decodedToken.session
|
||||
response.locals.roles = decodedToken.roles
|
||||
response.locals.sharedVaultOwnerContext = decodedToken.shared_vault_owner_context
|
||||
response.locals.belongsToSharedVaults = decodedToken.belongs_to_shared_vaults ?? []
|
||||
} catch (error) {
|
||||
const errorMessage = (error as AxiosError).isAxiosError
|
||||
? JSON.stringify((error as AxiosError).response?.data)
|
||||
|
||||
@@ -80,15 +80,6 @@ export class UsersController extends BaseHttpController {
|
||||
)
|
||||
}
|
||||
|
||||
@httpGet('/transition-status', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
async getTransitionStatus(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
request,
|
||||
response,
|
||||
this.endpointResolver.resolveEndpointOrMethodIdentifier('GET', 'users/transition-status'),
|
||||
)
|
||||
}
|
||||
|
||||
@httpGet('/:userId/params', TYPES.ApiGateway_RequiredCrossServiceTokenMiddleware)
|
||||
async getKeyParams(request: Request, response: Response): Promise<void> {
|
||||
await this.httpService.callAuthServer(
|
||||
|
||||
@@ -43,7 +43,6 @@ export class EndpointResolver implements EndpointResolverInterface {
|
||||
['[PATCH]:users/:userId', 'auth.users.update'],
|
||||
['[PUT]:users/:userUuid/attributes/credentials', 'auth.users.updateCredentials'],
|
||||
['[GET]:users/params', 'auth.users.getKeyParams'],
|
||||
['[GET]:users/transition-status', 'auth.users.transition-status'],
|
||||
['[DELETE]:users/:userUuid', 'auth.users.delete'],
|
||||
['[POST]:listed', 'auth.users.createListedAccount'],
|
||||
['[POST]:auth', 'auth.users.register'],
|
||||
@@ -59,13 +58,11 @@ export class EndpointResolver implements EndpointResolverInterface {
|
||||
// Syncing Server
|
||||
['[POST]:items/sync', 'sync.items.sync'],
|
||||
['[POST]:items/check-integrity', 'sync.items.check_integrity'],
|
||||
['[POST]:items/transition', 'sync.items.transition'],
|
||||
['[GET]:items/:uuid', 'sync.items.get_item'],
|
||||
// Revisions Controller V2
|
||||
['[GET]:items/:itemUuid/revisions', 'revisions.revisions.getRevisions'],
|
||||
['[GET]:items/:itemUuid/revisions/:id', 'revisions.revisions.getRevision'],
|
||||
['[DELETE]:items/:itemUuid/revisions/:id', 'revisions.revisions.deleteRevision'],
|
||||
['[POST]:revisions/transition', 'revisions.revisions.transition'],
|
||||
// Messages Controller
|
||||
['[GET]:messages/', 'sync.messages.get-received'],
|
||||
['[GET]:messages/outbound', 'sync.messages.get-sent'],
|
||||
|
||||
@@ -2,5 +2,8 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
sh supervisor/wait-for.sh localhost $AUTH_SERVER_PORT
|
||||
sh supervisor/wait-for.sh localhost $FILES_SERVER_PORT
|
||||
sh supervisor/wait-for.sh localhost $REVISIONS_SERVER_PORT
|
||||
sh supervisor/wait-for.sh localhost $SYNCING_SERVER_PORT
|
||||
node docker/entrypoint-server.js
|
||||
|
||||
@@ -3,6 +3,121 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.141.13](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.12...@standardnotes/auth-server@1.141.13) (2023-09-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** set ttl for started and not picked up transitions to 10h ([fe8ca82](https://github.com/standardnotes/server/commit/fe8ca828fb37306e0e5056627e67366885e86861))
|
||||
|
||||
## [1.141.12](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.11...@standardnotes/auth-server@1.141.12) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** remove re-triggering revisions transition ([5984e4c](https://github.com/standardnotes/server/commit/5984e4c3e7e550e5ed53805bde1e6dabcbe54da8))
|
||||
|
||||
## [1.141.11](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.10...@standardnotes/auth-server@1.141.11) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** passing transition timestamp ([c164bde](https://github.com/standardnotes/server/commit/c164bde847b5974e74fd439f0d439526ad439443))
|
||||
|
||||
## [1.141.10](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.9...@standardnotes/auth-server@1.141.10) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adjust transition timestamps to be universal ([c7807d0](https://github.com/standardnotes/server/commit/c7807d0f9e69ce572c4c03ff606375d706f24d9f))
|
||||
|
||||
## [1.141.9](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.8...@standardnotes/auth-server@1.141.9) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* display transition progress in logs ([38685c1](https://github.com/standardnotes/server/commit/38685c1861b13e398dd96aa39f2cf1aece2090fb))
|
||||
|
||||
## [1.141.8](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.7...@standardnotes/auth-server@1.141.8) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** add transition role only if the items transition has completed ([f055e52](https://github.com/standardnotes/server/commit/f055e52e06b6e93501abd340dfce214d5363bc30))
|
||||
* **auth:** remove the transition role constraint ([afe385a](https://github.com/standardnotes/server/commit/afe385aed4ba5ca53d8ef429ae4154f4ccf81419))
|
||||
* imports ([54113ab](https://github.com/standardnotes/server/commit/54113abe2a961720a3561e5ff3a0069046ea8d25))
|
||||
|
||||
## [1.141.7](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.6...@standardnotes/auth-server@1.141.7) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* retry failed revision transitions ([e535cd5](https://github.com/standardnotes/server/commit/e535cd504cf1929539ff7faf13e9c1fdd2b7bfd1))
|
||||
|
||||
## [1.141.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.5...@standardnotes/auth-server@1.141.6) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.141.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.4...@standardnotes/auth-server@1.141.5) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* domain event values ([f0abfe8](https://github.com/standardnotes/server/commit/f0abfe89fca0049c47131389683efe2f5aff23f8))
|
||||
|
||||
## [1.141.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.3...@standardnotes/auth-server@1.141.4) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adjust transitions to not create revisions during ongoing revisions transition ([106d8f9](https://github.com/standardnotes/server/commit/106d8f9192f630794ca4ddc2c4503f2c6cd196e7))
|
||||
|
||||
## [1.141.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.2...@standardnotes/auth-server@1.141.3) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* transition adjustments ([f20a947](https://github.com/standardnotes/server/commit/f20a947f8a555c074d8dc1543c7a8bf61d1d887e))
|
||||
|
||||
## [1.141.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.1...@standardnotes/auth-server@1.141.2) (2023-09-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** remove transitioning upon sign out ([#819](https://github.com/standardnotes/server/issues/819)) ([330bff0](https://github.com/standardnotes/server/commit/330bff0124f5f49c3441304d166ea43c21fea7bc))
|
||||
|
||||
## [1.141.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.0...@standardnotes/auth-server@1.141.1) (2023-09-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* disable running migrations in worker mode of a given service ([a82b9a0](https://github.com/standardnotes/server/commit/a82b9a0c8a023ba8a450ff9e34bcd62f928fcab3))
|
||||
|
||||
# [1.141.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.140.0...@standardnotes/auth-server@1.141.0) (2023-09-11)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add procedure to transition users created between dates ([#816](https://github.com/standardnotes/server/issues/816)) ([e95ba61](https://github.com/standardnotes/server/commit/e95ba61c7f769736698ebbc38179d6dc05a8cc5e))
|
||||
|
||||
# [1.140.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.139.0...@standardnotes/auth-server@1.140.0) (2023-09-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** specs ([a164ba2](https://github.com/standardnotes/server/commit/a164ba291d4893b5a0bb4b39a8795d654212a1a6))
|
||||
* **auth:** transition users only when transition mode enabled ([610fba2](https://github.com/standardnotes/server/commit/610fba260150d0757020e01ac0c8967feeadd4d6))
|
||||
|
||||
### Features
|
||||
|
||||
* transition users after sign out ([398338c](https://github.com/standardnotes/server/commit/398338c8f81b12406c7ab3bf1654e60b94d7cfd0))
|
||||
|
||||
# [1.139.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.138.2...@standardnotes/auth-server@1.139.0) (2023-09-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add vaults user role into database ([aef9e93](https://github.com/standardnotes/server/commit/aef9e936bdbd1f4ccc32658d3d892e7675ec0e0e))
|
||||
|
||||
## [1.138.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.138.1...@standardnotes/auth-server@1.138.2) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.138.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.138.0...@standardnotes/auth-server@1.138.1) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.138.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.137.6...@standardnotes/auth-server@1.138.0) (2023-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/server/issues/807)) ([794cd87](https://github.com/standardnotes/server/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
|
||||
|
||||
## [1.137.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.137.5...@standardnotes/auth-server@1.137.6) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
@@ -75,7 +75,7 @@ const requestBackups = async (
|
||||
})
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
dayjs.extend(utc)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const cleanup = async (
|
||||
await cleanupExpiredSessions.execute({ date })
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
@@ -8,7 +8,7 @@ import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { PersistStatistics } from '../src/Domain/UseCase/PersistStatistics/PersistStatistics'
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { Logger } from 'winston'
|
||||
import * as dayjs from 'dayjs'
|
||||
import * as utc from 'dayjs/plugin/utc'
|
||||
|
||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
||||
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
const inputArgs = process.argv.slice(2)
|
||||
const startDateString = inputArgs[0]
|
||||
const endDateString = inputArgs[1]
|
||||
|
||||
const requestTransition = async (
|
||||
userRepository: UserRepositoryInterface,
|
||||
logger: Logger,
|
||||
domainEventFactory: DomainEventFactoryInterface,
|
||||
domainEventPublisher: DomainEventPublisherInterface,
|
||||
timer: TimerInterface,
|
||||
): Promise<void> => {
|
||||
const startDate = new Date(startDateString)
|
||||
const endDate = new Date(endDateString)
|
||||
|
||||
const users = await userRepository.findAllCreatedBetween(startDate, endDate)
|
||||
|
||||
const timestamp = timer.getTimestampInMicroseconds()
|
||||
|
||||
logger.info(
|
||||
`[TRANSITION ${timestamp}] Found ${users.length} users created between ${startDateString} and ${endDateString}`,
|
||||
)
|
||||
|
||||
let usersTriggered = 0
|
||||
for (const user of users) {
|
||||
const transitionRequestedEvent = domainEventFactory.createTransitionRequestedEvent({
|
||||
userUuid: user.uuid,
|
||||
type: 'items',
|
||||
timestamp,
|
||||
})
|
||||
|
||||
usersTriggered += 1
|
||||
|
||||
await domainEventPublisher.publish(transitionRequestedEvent)
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`[TRANSITION ${timestamp}] Triggered transition for ${usersTriggered} users created between ${startDateString} and ${endDateString}`,
|
||||
)
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
dayjs.extend(utc)
|
||||
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const logger: Logger = container.get(TYPES.Auth_Logger)
|
||||
|
||||
logger.info(`Starting transition request for users created between ${startDateString} and ${endDateString}`)
|
||||
|
||||
const userRepository: UserRepositoryInterface = container.get(TYPES.Auth_UserRepository)
|
||||
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.Auth_DomainEventFactory)
|
||||
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.Auth_DomainEventPublisher)
|
||||
const timer = container.get<TimerInterface>(TYPES.Auth_Timer)
|
||||
|
||||
Promise.resolve(requestTransition(userRepository, logger, domainEventFactory, domainEventPublisher, timer))
|
||||
.then(() => {
|
||||
logger.info(`Finished transition request for users created between ${startDateString} and ${endDateString}`)
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(
|
||||
`Error while requesting transition for users created between ${startDateString} and ${endDateString}: ${error}`,
|
||||
)
|
||||
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
@@ -63,7 +63,7 @@ const requestBackups = async (
|
||||
return
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
dayjs.extend(utc)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { DomainEventSubscriberFactoryInterface } from '@standardnotes/domain-eve
|
||||
import * as dayjs from 'dayjs'
|
||||
import * as utc from 'dayjs/plugin/utc'
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
dayjs.extend(utc)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
|
||||
|
||||
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/transition.js')))
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
|
||||
exports.default = index
|
||||
@@ -55,6 +55,13 @@ case "$COMMAND" in
|
||||
node docker/entrypoint-backup.js one_drive daily
|
||||
;;
|
||||
|
||||
'transition' )
|
||||
START_DATE=$1 && shift 1
|
||||
END_DATE=$1 && shift 1
|
||||
echo "[Docker] Starting Transition..."
|
||||
node docker/entrypoint-transition.js $START_DATE $END_DATE
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "[Docker] Unknown command"
|
||||
;;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultUsers1694000575425 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE `auth_shared_vault_users` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `permission` varchar(24) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_auth_shared_vault_users` (`shared_vault_uuid`), INDEX `user_uuid_on_auth_shared_vault_users` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `user_uuid_on_auth_shared_vault_users` ON `auth_shared_vault_users`')
|
||||
await queryRunner.query('DROP INDEX `shared_vault_uuid_on_auth_shared_vault_users` ON `auth_shared_vault_users`')
|
||||
await queryRunner.query('DROP TABLE `auth_shared_vault_users`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddVaultsUser1694157482134 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'INSERT INTO `roles` (uuid, name, version) VALUES ("35669f45-a2d8-4172-bdab-b7b3d42044ce", "VAULTS_USER", 1)',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultUsers1694000640645 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE "auth_shared_vault_users" ("uuid" varchar PRIMARY KEY NOT NULL, "shared_vault_uuid" varchar(36) NOT NULL, "user_uuid" varchar(36) NOT NULL, "permission" varchar(24) NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL)',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX "shared_vault_uuid_on_auth_shared_vault_users" ON "auth_shared_vault_users" ("shared_vault_uuid") ',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'CREATE INDEX "user_uuid_on_auth_shared_vault_users" ON "auth_shared_vault_users" ("user_uuid") ',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX "user_uuid_on_auth_shared_vault_users"')
|
||||
await queryRunner.query('DROP INDEX "shared_vault_uuid_on_auth_shared_vault_users"')
|
||||
await queryRunner.query('DROP TABLE "auth_shared_vault_users"')
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.137.6",
|
||||
"version": "1.141.13",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -189,6 +189,7 @@ import {
|
||||
ControllerContainer,
|
||||
ControllerContainerInterface,
|
||||
MapperInterface,
|
||||
SharedVaultUser,
|
||||
} from '@standardnotes/domain-core'
|
||||
import { SessionTracePersistenceMapper } from '../Mapping/SessionTracePersistenceMapper'
|
||||
import { SessionTrace } from '../Domain/Session/SessionTrace'
|
||||
@@ -263,8 +264,18 @@ import { InMemoryTransitionStatusRepository } from '../Infra/InMemory/InMemoryTr
|
||||
import { TransitionStatusUpdatedEventHandler } from '../Domain/Handler/TransitionStatusUpdatedEventHandler'
|
||||
import { UpdateTransitionStatus } from '../Domain/UseCase/UpdateTransitionStatus/UpdateTransitionStatus'
|
||||
import { GetTransitionStatus } from '../Domain/UseCase/GetTransitionStatus/GetTransitionStatus'
|
||||
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
|
||||
import { SharedVaultUserPersistenceMapper } from '../Mapping/SharedVaultUserPersistenceMapper'
|
||||
import { SharedVaultUserRepositoryInterface } from '../Domain/SharedVault/SharedVaultUserRepositoryInterface'
|
||||
import { TypeORMSharedVaultUserRepository } from '../Infra/TypeORM/TypeORMSharedVaultUserRepository'
|
||||
import { AddSharedVaultUser } from '../Domain/UseCase/AddSharedVaultUser/AddSharedVaultUser'
|
||||
import { RemoveSharedVaultUser } from '../Domain/UseCase/RemoveSharedVaultUser/RemoveSharedVaultUser'
|
||||
import { UserAddedToSharedVaultEventHandler } from '../Domain/Handler/UserAddedToSharedVaultEventHandler'
|
||||
import { UserRemovedFromSharedVaultEventHandler } from '../Domain/Handler/UserRemovedFromSharedVaultEventHandler'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
constructor(private mode: 'server' | 'worker' = 'server') {}
|
||||
|
||||
async load(configuration?: {
|
||||
controllerConatiner?: ControllerContainerInterface
|
||||
directCallDomainEventPublisher?: DirectCallDomainEventPublisher
|
||||
@@ -301,7 +312,7 @@ export class ContainerConfigLoader {
|
||||
}
|
||||
container.bind<winston.Logger>(TYPES.Auth_Logger).toConstantValue(logger)
|
||||
|
||||
const appDataSource = new AppDataSource(env)
|
||||
const appDataSource = new AppDataSource({ env, runMigrations: this.mode === 'server' })
|
||||
await appDataSource.initialize()
|
||||
|
||||
logger.debug('Database initialized')
|
||||
@@ -372,6 +383,9 @@ export class ContainerConfigLoader {
|
||||
container
|
||||
.bind<MapperInterface<CacheEntry, TypeORMCacheEntry>>(TYPES.Auth_CacheEntryPersistenceMapper)
|
||||
.toConstantValue(new CacheEntryPersistenceMapper())
|
||||
container
|
||||
.bind<MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>>(TYPES.Auth_SharedVaultUserPersistenceMapper)
|
||||
.toConstantValue(new SharedVaultUserPersistenceMapper())
|
||||
|
||||
// ORM
|
||||
container
|
||||
@@ -412,6 +426,9 @@ export class ContainerConfigLoader {
|
||||
container
|
||||
.bind<Repository<TypeORMCacheEntry>>(TYPES.Auth_ORMCacheEntryRepository)
|
||||
.toConstantValue(appDataSource.getRepository(TypeORMCacheEntry))
|
||||
container
|
||||
.bind<Repository<TypeORMSharedVaultUser>>(TYPES.Auth_ORMSharedVaultUserRepository)
|
||||
.toConstantValue(appDataSource.getRepository(TypeORMSharedVaultUser))
|
||||
|
||||
// Repositories
|
||||
container.bind<SessionRepositoryInterface>(TYPES.Auth_SessionRepository).to(TypeORMSessionRepository)
|
||||
@@ -468,6 +485,16 @@ export class ContainerConfigLoader {
|
||||
container.get(TYPES.Auth_CacheEntryPersistenceMapper),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository)
|
||||
.toConstantValue(
|
||||
new TypeORMSharedVaultUserRepository(
|
||||
container.get<Repository<TypeORMSharedVaultUser>>(TYPES.Auth_ORMSharedVaultUserRepository),
|
||||
container.get<MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>>(
|
||||
TYPES.Auth_SharedVaultUserPersistenceMapper,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// Middleware
|
||||
container.bind<SessionMiddleware>(TYPES.Auth_SessionMiddleware).to(SessionMiddleware)
|
||||
@@ -916,6 +943,7 @@ export class ContainerConfigLoader {
|
||||
new UpdateTransitionStatus(
|
||||
container.get<TransitionStatusRepositoryInterface>(TYPES.Auth_TransitionStatusRepository),
|
||||
container.get<RoleServiceInterface>(TYPES.Auth_RoleService),
|
||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
@@ -926,6 +954,18 @@ export class ContainerConfigLoader {
|
||||
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<AddSharedVaultUser>(TYPES.Auth_AddSharedVaultUser)
|
||||
.toConstantValue(
|
||||
new AddSharedVaultUser(container.get<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository)),
|
||||
)
|
||||
container
|
||||
.bind<RemoveSharedVaultUser>(TYPES.Auth_RemoveSharedVaultUser)
|
||||
.toConstantValue(
|
||||
new RemoveSharedVaultUser(
|
||||
container.get<SharedVaultUserRepositoryInterface>(TYPES.Auth_SharedVaultUserRepository),
|
||||
),
|
||||
)
|
||||
|
||||
// Controller
|
||||
container
|
||||
@@ -1075,6 +1115,22 @@ export class ContainerConfigLoader {
|
||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<UserAddedToSharedVaultEventHandler>(TYPES.Auth_UserAddedToSharedVaultEventHandler)
|
||||
.toConstantValue(
|
||||
new UserAddedToSharedVaultEventHandler(
|
||||
container.get<AddSharedVaultUser>(TYPES.Auth_AddSharedVaultUser),
|
||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<UserRemovedFromSharedVaultEventHandler>(TYPES.Auth_UserRemovedFromSharedVaultEventHandler)
|
||||
.toConstantValue(
|
||||
new UserRemovedFromSharedVaultEventHandler(
|
||||
container.get<RemoveSharedVaultUser>(TYPES.Auth_RemoveSharedVaultUser),
|
||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||
),
|
||||
)
|
||||
|
||||
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
||||
['USER_REGISTERED', container.get(TYPES.Auth_UserRegisteredEventHandler)],
|
||||
@@ -1107,6 +1163,8 @@ export class ContainerConfigLoader {
|
||||
['EMAIL_SUBSCRIPTION_UNSUBSCRIBED', container.get(TYPES.Auth_EmailSubscriptionUnsubscribedEventHandler)],
|
||||
['PAYMENTS_ACCOUNT_DELETED', container.get(TYPES.Auth_PaymentsAccountDeletedEventHandler)],
|
||||
['TRANSITION_STATUS_UPDATED', container.get(TYPES.Auth_TransitionStatusUpdatedEventHandler)],
|
||||
['USER_ADDED_TO_SHARED_VAULT', container.get(TYPES.Auth_UserAddedToSharedVaultEventHandler)],
|
||||
['USER_REMOVED_FROM_SHARED_VAULT', container.get(TYPES.Auth_UserRemovedFromSharedVaultEventHandler)],
|
||||
])
|
||||
|
||||
if (isConfiguredForHomeServer) {
|
||||
@@ -1218,7 +1276,6 @@ export class ContainerConfigLoader {
|
||||
container.get<ClearLoginAttempts>(TYPES.Auth_ClearLoginAttempts),
|
||||
container.get<IncreaseLoginAttempts>(TYPES.Auth_IncreaseLoginAttempts),
|
||||
container.get<ChangeCredentials>(TYPES.Auth_ChangeCredentials),
|
||||
container.get<GetTransitionStatus>(TYPES.Auth_GetTransitionStatus),
|
||||
container.get<ControllerContainerInterface>(TYPES.Auth_ControllerContainer),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -18,11 +18,17 @@ import { TypeORMEmergencyAccessInvitation } from '../Infra/TypeORM/TypeORMEmerge
|
||||
import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace'
|
||||
import { Env } from './Env'
|
||||
import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
|
||||
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
|
||||
|
||||
export class AppDataSource {
|
||||
private _dataSource: DataSource | undefined
|
||||
|
||||
constructor(private env: Env) {}
|
||||
constructor(
|
||||
private configuration: {
|
||||
env: Env
|
||||
runMigrations: boolean
|
||||
},
|
||||
) {}
|
||||
|
||||
getRepository<Entity extends ObjectLiteral>(target: EntityTarget<Entity>): Repository<Entity> {
|
||||
if (!this._dataSource) {
|
||||
@@ -37,12 +43,12 @@ export class AppDataSource {
|
||||
}
|
||||
|
||||
get dataSource(): DataSource {
|
||||
this.env.load()
|
||||
this.configuration.env.load()
|
||||
|
||||
const isConfiguredForMySQL = this.env.get('DB_TYPE') === 'mysql'
|
||||
const isConfiguredForMySQL = this.configuration.env.get('DB_TYPE') === 'mysql'
|
||||
|
||||
const maxQueryExecutionTime = this.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
? +this.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
const maxQueryExecutionTime = this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
? +this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
: 45_000
|
||||
|
||||
const commonDataSourceOptions = {
|
||||
@@ -64,30 +70,31 @@ export class AppDataSource {
|
||||
TypeORMAuthenticatorChallenge,
|
||||
TypeORMEmergencyAccessInvitation,
|
||||
TypeORMCacheEntry,
|
||||
TypeORMSharedVaultUser,
|
||||
],
|
||||
migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
|
||||
migrationsRun: true,
|
||||
logging: <LoggerOptions>this.env.get('DB_DEBUG_LEVEL', true) ?? 'info',
|
||||
migrationsRun: this.configuration.runMigrations,
|
||||
logging: <LoggerOptions>this.configuration.env.get('DB_DEBUG_LEVEL', true) ?? 'info',
|
||||
}
|
||||
|
||||
if (isConfiguredForMySQL) {
|
||||
const inReplicaMode = this.env.get('DB_REPLICA_HOST', true) ? true : false
|
||||
const inReplicaMode = this.configuration.env.get('DB_REPLICA_HOST', true) ? true : false
|
||||
|
||||
const replicationConfig = {
|
||||
master: {
|
||||
host: this.env.get('DB_HOST'),
|
||||
port: parseInt(this.env.get('DB_PORT')),
|
||||
username: this.env.get('DB_USERNAME'),
|
||||
password: this.env.get('DB_PASSWORD'),
|
||||
database: this.env.get('DB_DATABASE'),
|
||||
host: this.configuration.env.get('DB_HOST'),
|
||||
port: parseInt(this.configuration.env.get('DB_PORT')),
|
||||
username: this.configuration.env.get('DB_USERNAME'),
|
||||
password: this.configuration.env.get('DB_PASSWORD'),
|
||||
database: this.configuration.env.get('DB_DATABASE'),
|
||||
},
|
||||
slaves: [
|
||||
{
|
||||
host: this.env.get('DB_REPLICA_HOST', true),
|
||||
port: parseInt(this.env.get('DB_PORT')),
|
||||
username: this.env.get('DB_USERNAME'),
|
||||
password: this.env.get('DB_PASSWORD'),
|
||||
database: this.env.get('DB_DATABASE'),
|
||||
host: this.configuration.env.get('DB_REPLICA_HOST', true),
|
||||
port: parseInt(this.configuration.env.get('DB_PORT')),
|
||||
username: this.configuration.env.get('DB_USERNAME'),
|
||||
password: this.configuration.env.get('DB_PASSWORD'),
|
||||
database: this.configuration.env.get('DB_DATABASE'),
|
||||
},
|
||||
],
|
||||
removeNodeErrorCount: 10,
|
||||
@@ -101,11 +108,11 @@ export class AppDataSource {
|
||||
supportBigNumbers: true,
|
||||
bigNumberStrings: false,
|
||||
replication: inReplicaMode ? replicationConfig : undefined,
|
||||
host: inReplicaMode ? undefined : this.env.get('DB_HOST'),
|
||||
port: inReplicaMode ? undefined : parseInt(this.env.get('DB_PORT')),
|
||||
username: inReplicaMode ? undefined : this.env.get('DB_USERNAME'),
|
||||
password: inReplicaMode ? undefined : this.env.get('DB_PASSWORD'),
|
||||
database: inReplicaMode ? undefined : this.env.get('DB_DATABASE'),
|
||||
host: inReplicaMode ? undefined : this.configuration.env.get('DB_HOST'),
|
||||
port: inReplicaMode ? undefined : parseInt(this.configuration.env.get('DB_PORT')),
|
||||
username: inReplicaMode ? undefined : this.configuration.env.get('DB_USERNAME'),
|
||||
password: inReplicaMode ? undefined : this.configuration.env.get('DB_PASSWORD'),
|
||||
database: inReplicaMode ? undefined : this.configuration.env.get('DB_DATABASE'),
|
||||
}
|
||||
|
||||
this._dataSource = new DataSource(mySQLDataSourceOptions)
|
||||
@@ -113,7 +120,7 @@ export class AppDataSource {
|
||||
const sqliteDataSourceOptions: SqliteConnectionOptions = {
|
||||
...commonDataSourceOptions,
|
||||
type: 'sqlite',
|
||||
database: this.env.get('DB_SQLITE_DATABASE_PATH'),
|
||||
database: this.configuration.env.get('DB_SQLITE_DATABASE_PATH'),
|
||||
enableWAL: true,
|
||||
busyErrorRetry: 2000,
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ import { Env } from './Env'
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
export const MigrationsDataSource = new AppDataSource(env).dataSource
|
||||
export const MigrationsDataSource = new AppDataSource({ env, runMigrations: true }).dataSource
|
||||
|
||||
@@ -9,6 +9,7 @@ const TYPES = {
|
||||
Auth_AuthenticatorPersistenceMapper: Symbol.for('Auth_AuthenticatorPersistenceMapper'),
|
||||
Auth_AuthenticatorHttpMapper: Symbol.for('Auth_AuthenticatorHttpMapper'),
|
||||
Auth_CacheEntryPersistenceMapper: Symbol.for('Auth_CacheEntryPersistenceMapper'),
|
||||
Auth_SharedVaultUserPersistenceMapper: Symbol.for('Auth_SharedVaultUserPersistenceMapper'),
|
||||
// Controller
|
||||
Auth_ControllerContainer: Symbol.for('Auth_ControllerContainer'),
|
||||
Auth_AuthController: Symbol.for('Auth_AuthController'),
|
||||
@@ -36,6 +37,7 @@ const TYPES = {
|
||||
Auth_AuthenticatorChallengeRepository: Symbol.for('Auth_AuthenticatorChallengeRepository'),
|
||||
Auth_CacheEntryRepository: Symbol.for('Auth_CacheEntryRepository'),
|
||||
Auth_TransitionStatusRepository: Symbol.for('Auth_TransitionStatusRepository'),
|
||||
Auth_SharedVaultUserRepository: Symbol.for('Auth_SharedVaultUserRepository'),
|
||||
// ORM
|
||||
Auth_ORMOfflineSettingRepository: Symbol.for('Auth_ORMOfflineSettingRepository'),
|
||||
Auth_ORMOfflineUserSubscriptionRepository: Symbol.for('Auth_ORMOfflineUserSubscriptionRepository'),
|
||||
@@ -51,6 +53,7 @@ const TYPES = {
|
||||
Auth_ORMAuthenticatorRepository: Symbol.for('Auth_ORMAuthenticatorRepository'),
|
||||
Auth_ORMAuthenticatorChallengeRepository: Symbol.for('Auth_ORMAuthenticatorChallengeRepository'),
|
||||
Auth_ORMCacheEntryRepository: Symbol.for('Auth_ORMCacheEntryRepository'),
|
||||
Auth_ORMSharedVaultUserRepository: Symbol.for('Auth_ORMSharedVaultUserRepository'),
|
||||
// Middleware
|
||||
Auth_RequiredCrossServiceTokenMiddleware: Symbol.for('Auth_RequiredCrossServiceTokenMiddleware'),
|
||||
Auth_OptionalCrossServiceTokenMiddleware: Symbol.for('Auth_OptionalCrossServiceTokenMiddleware'),
|
||||
@@ -157,6 +160,8 @@ const TYPES = {
|
||||
Auth_UpdateStorageQuotaUsedForUser: Symbol.for('Auth_UpdateStorageQuotaUsedForUser'),
|
||||
Auth_UpdateTransitionStatus: Symbol.for('Auth_UpdateTransitionStatus'),
|
||||
Auth_GetTransitionStatus: Symbol.for('Auth_GetTransitionStatus'),
|
||||
Auth_AddSharedVaultUser: Symbol.for('Auth_AddSharedVaultUser'),
|
||||
Auth_RemoveSharedVaultUser: Symbol.for('Auth_RemoveSharedVaultUser'),
|
||||
// Handlers
|
||||
Auth_UserRegisteredEventHandler: Symbol.for('Auth_UserRegisteredEventHandler'),
|
||||
Auth_AccountDeletionRequestedEventHandler: Symbol.for('Auth_AccountDeletionRequestedEventHandler'),
|
||||
@@ -186,6 +191,8 @@ const TYPES = {
|
||||
Auth_EmailSubscriptionUnsubscribedEventHandler: Symbol.for('Auth_EmailSubscriptionUnsubscribedEventHandler'),
|
||||
Auth_PaymentsAccountDeletedEventHandler: Symbol.for('Auth_PaymentsAccountDeletedEventHandler'),
|
||||
Auth_TransitionStatusUpdatedEventHandler: Symbol.for('Auth_TransitionStatusUpdatedEventHandler'),
|
||||
Auth_UserAddedToSharedVaultEventHandler: Symbol.for('Auth_UserAddedToSharedVaultEventHandler'),
|
||||
Auth_UserRemovedFromSharedVaultEventHandler: Symbol.for('Auth_UserRemovedFromSharedVaultEventHandler'),
|
||||
// Services
|
||||
Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
|
||||
Auth_SessionService: Symbol.for('Auth_SessionService'),
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
StatisticPersistenceRequestedEvent,
|
||||
SessionCreatedEvent,
|
||||
SessionRefreshedEvent,
|
||||
TransitionRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
@@ -32,6 +33,25 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
|
||||
export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
constructor(@inject(TYPES.Auth_Timer) private timer: TimerInterface) {}
|
||||
|
||||
createTransitionRequestedEvent(dto: {
|
||||
userUuid: string
|
||||
type: 'items' | 'revisions'
|
||||
timestamp: number
|
||||
}): TransitionRequestedEvent {
|
||||
return {
|
||||
type: 'TRANSITION_REQUESTED',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: dto.userUuid,
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: DomainEventService.Auth,
|
||||
},
|
||||
payload: dto,
|
||||
}
|
||||
}
|
||||
|
||||
createSessionCreatedEvent(dto: { userUuid: string }): SessionCreatedEvent {
|
||||
return {
|
||||
type: 'SESSION_CREATED',
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
StatisticPersistenceRequestedEvent,
|
||||
SessionCreatedEvent,
|
||||
SessionRefreshedEvent,
|
||||
TransitionRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
|
||||
|
||||
@@ -89,4 +90,9 @@ export interface DomainEventFactoryInterface {
|
||||
}): StatisticPersistenceRequestedEvent
|
||||
createSessionCreatedEvent(dto: { userUuid: string }): SessionCreatedEvent
|
||||
createSessionRefreshedEvent(dto: { userUuid: string }): SessionRefreshedEvent
|
||||
createTransitionRequestedEvent(dto: {
|
||||
userUuid: string
|
||||
type: 'items' | 'revisions'
|
||||
timestamp: number
|
||||
}): TransitionRequestedEvent
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerIn
|
||||
status: event.payload.status,
|
||||
userUuid: event.payload.userUuid,
|
||||
transitionType: event.payload.transitionType,
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { DomainEventHandlerInterface, UserAddedToSharedVaultEvent } from '@standardnotes/domain-events'
|
||||
import { Logger } from 'winston'
|
||||
import { AddSharedVaultUser } from '../UseCase/AddSharedVaultUser/AddSharedVaultUser'
|
||||
|
||||
export class UserAddedToSharedVaultEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private addSharedVaultUser: AddSharedVaultUser,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async handle(event: UserAddedToSharedVaultEvent): Promise<void> {
|
||||
const result = await this.addSharedVaultUser.execute({
|
||||
userUuid: event.payload.userUuid,
|
||||
sharedVaultUuid: event.payload.sharedVaultUuid,
|
||||
permission: event.payload.permission,
|
||||
createdAt: event.payload.createdAt,
|
||||
updatedAt: event.payload.updatedAt,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to add user to shared vault: ${result.getError()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { DomainEventHandlerInterface, UserRemovedFromSharedVaultEvent } from '@standardnotes/domain-events'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { RemoveSharedVaultUser } from '../UseCase/RemoveSharedVaultUser/RemoveSharedVaultUser'
|
||||
|
||||
export class UserRemovedFromSharedVaultEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private removeSharedVaultUser: RemoveSharedVaultUser,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async handle(event: UserRemovedFromSharedVaultEvent): Promise<void> {
|
||||
const result = await this.removeSharedVaultUser.execute({
|
||||
userUuid: event.payload.userUuid,
|
||||
sharedVaultUuid: event.payload.sharedVaultUuid,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to remove user from shared vault: ${result.getError()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { SharedVaultUser, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export interface SharedVaultUserRepositoryInterface {
|
||||
findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultUser | null>
|
||||
findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]>
|
||||
save(sharedVaultUser: SharedVaultUser): Promise<void>
|
||||
remove(sharedVault: SharedVaultUser): Promise<void>
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
export interface TransitionStatusRepositoryInterface {
|
||||
updateStatus(userUuid: string, transitionType: 'items' | 'revisions', status: 'STARTED' | 'FAILED'): Promise<void>
|
||||
updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED',
|
||||
): Promise<void>
|
||||
removeStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void>
|
||||
getStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<'STARTED' | 'FAILED' | null>
|
||||
getStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<'STARTED' | 'IN_PROGRESS' | 'FAILED' | null>
|
||||
getStatuses(
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<Array<{ userUuid: string; status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' }>>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import { Result, SharedVaultUser } from '@standardnotes/domain-core'
|
||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||
import { AddSharedVaultUser } from './AddSharedVaultUser'
|
||||
|
||||
describe('AddSharedVaultUser', () => {
|
||||
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
||||
|
||||
const createUseCase = () => new AddSharedVaultUser(sharedVaultUserRepository)
|
||||
|
||||
beforeEach(() => {
|
||||
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
|
||||
sharedVaultUserRepository.save = jest.fn()
|
||||
})
|
||||
|
||||
it('should save shared vault user', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
createdAt: 1,
|
||||
updatedAt: 2,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(sharedVaultUserRepository.save).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when user uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: 'invalid',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
createdAt: 1,
|
||||
updatedAt: 2,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when shared vault uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: 'invalid',
|
||||
permission: 'read',
|
||||
createdAt: 1,
|
||||
updatedAt: 2,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when permission is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'invalid',
|
||||
createdAt: 1,
|
||||
updatedAt: 2,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when timestamps are invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
createdAt: 'invalid' as unknown as number,
|
||||
updatedAt: 1,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(sharedVaultUserRepository.save).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when shared vault user is invalid', async () => {
|
||||
const mock = jest.spyOn(SharedVaultUser, 'create')
|
||||
mock.mockReturnValue(Result.fail('Oops'))
|
||||
|
||||
const result = await createUseCase().execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
createdAt: 2,
|
||||
updatedAt: 1,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
|
||||
mock.mockRestore()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,56 @@
|
||||
import {
|
||||
Result,
|
||||
SharedVaultUser,
|
||||
SharedVaultUserPermission,
|
||||
Timestamps,
|
||||
UseCaseInterface,
|
||||
Uuid,
|
||||
} from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||
import { AddSharedVaultUserDTO } from './AddSharedVaultUserDTO'
|
||||
|
||||
export class AddSharedVaultUser implements UseCaseInterface<void> {
|
||||
constructor(private sharedVaultUserRepository: SharedVaultUserRepositoryInterface) {}
|
||||
|
||||
async execute(dto: AddSharedVaultUserDTO): Promise<Result<void>> {
|
||||
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return Result.fail(userUuidOrError.getError())
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultUuidOrError.getError())
|
||||
}
|
||||
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||
|
||||
const permissionOrError = SharedVaultUserPermission.create(dto.permission)
|
||||
if (permissionOrError.isFailed()) {
|
||||
return Result.fail(permissionOrError.getError())
|
||||
}
|
||||
const permission = permissionOrError.getValue()
|
||||
|
||||
const timestampsOrError = Timestamps.create(dto.createdAt, dto.updatedAt)
|
||||
if (timestampsOrError.isFailed()) {
|
||||
return Result.fail(timestampsOrError.getError())
|
||||
}
|
||||
const timestamps = timestampsOrError.getValue()
|
||||
|
||||
const sharedVaultUserOrError = SharedVaultUser.create({
|
||||
userUuid,
|
||||
sharedVaultUuid,
|
||||
permission,
|
||||
timestamps,
|
||||
})
|
||||
if (sharedVaultUserOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultUserOrError.getError())
|
||||
}
|
||||
const sharedVaultUser = sharedVaultUserOrError.getValue()
|
||||
|
||||
await this.sharedVaultUserRepository.save(sharedVaultUser)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface AddSharedVaultUserDTO {
|
||||
sharedVaultUuid: string
|
||||
userUuid: string
|
||||
permission: string
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
+50
-2
@@ -9,8 +9,9 @@ import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
|
||||
import { CreateCrossServiceToken } from './CreateCrossServiceToken'
|
||||
import { GetSetting } from '../GetSetting/GetSetting'
|
||||
import { Result } from '@standardnotes/domain-core'
|
||||
import { Result, SharedVaultUser, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||
|
||||
describe('CreateCrossServiceToken', () => {
|
||||
let userProjector: ProjectorInterface<User>
|
||||
@@ -20,6 +21,7 @@ describe('CreateCrossServiceToken', () => {
|
||||
let userRepository: UserRepositoryInterface
|
||||
let getSettingUseCase: GetSetting
|
||||
let transitionStatusRepository: TransitionStatusRepositoryInterface
|
||||
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
||||
const jwtTTL = 60
|
||||
|
||||
let session: Session
|
||||
@@ -36,6 +38,7 @@ describe('CreateCrossServiceToken', () => {
|
||||
jwtTTL,
|
||||
getSettingUseCase,
|
||||
transitionStatusRepository,
|
||||
sharedVaultUserRepository,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -70,6 +73,16 @@ describe('CreateCrossServiceToken', () => {
|
||||
|
||||
transitionStatusRepository = {} as jest.Mocked<TransitionStatusRepositoryInterface>
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('TO-DO')
|
||||
|
||||
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
|
||||
sharedVaultUserRepository.findByUserUuid = jest.fn().mockReturnValue([
|
||||
SharedVaultUser.create({
|
||||
permission: SharedVaultUserPermission.create('read').getValue(),
|
||||
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
timestamps: Timestamps.create(123456789, 123456789).getValue(),
|
||||
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
}).getValue(),
|
||||
])
|
||||
})
|
||||
|
||||
it('should create a cross service token for user', async () => {
|
||||
@@ -86,6 +99,12 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '1-3-4',
|
||||
},
|
||||
],
|
||||
belongs_to_shared_vaults: [
|
||||
{
|
||||
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
},
|
||||
],
|
||||
session: {
|
||||
test: 'test',
|
||||
},
|
||||
@@ -94,13 +113,14 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
},
|
||||
ongoing_transition: false,
|
||||
ongoing_revisions_transition: false,
|
||||
},
|
||||
60,
|
||||
)
|
||||
})
|
||||
|
||||
it('should create a cross service token for user that has an ongoing transaction', async () => {
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('STARTED')
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('IN_PROGRESS')
|
||||
|
||||
await createUseCase().execute({
|
||||
user,
|
||||
@@ -115,6 +135,12 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '1-3-4',
|
||||
},
|
||||
],
|
||||
belongs_to_shared_vaults: [
|
||||
{
|
||||
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
},
|
||||
],
|
||||
session: {
|
||||
test: 'test',
|
||||
},
|
||||
@@ -123,6 +149,7 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
},
|
||||
ongoing_transition: true,
|
||||
ongoing_revisions_transition: true,
|
||||
},
|
||||
60,
|
||||
)
|
||||
@@ -141,11 +168,18 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '1-3-4',
|
||||
},
|
||||
],
|
||||
belongs_to_shared_vaults: [
|
||||
{
|
||||
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
},
|
||||
],
|
||||
user: {
|
||||
email: 'test@test.te',
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
},
|
||||
ongoing_transition: false,
|
||||
ongoing_revisions_transition: false,
|
||||
},
|
||||
60,
|
||||
)
|
||||
@@ -164,11 +198,18 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '1-3-4',
|
||||
},
|
||||
],
|
||||
belongs_to_shared_vaults: [
|
||||
{
|
||||
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
},
|
||||
],
|
||||
user: {
|
||||
email: 'test@test.te',
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
},
|
||||
ongoing_transition: false,
|
||||
ongoing_revisions_transition: false,
|
||||
},
|
||||
60,
|
||||
)
|
||||
@@ -208,6 +249,12 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '1-3-4',
|
||||
},
|
||||
],
|
||||
belongs_to_shared_vaults: [
|
||||
{
|
||||
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
},
|
||||
],
|
||||
session: {
|
||||
test: 'test',
|
||||
},
|
||||
@@ -218,6 +265,7 @@ describe('CreateCrossServiceToken', () => {
|
||||
email: 'test@test.te',
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
},
|
||||
ongoing_revisions_transition: false,
|
||||
ongoing_transition: false,
|
||||
},
|
||||
60,
|
||||
|
||||
+14
-1
@@ -13,6 +13,7 @@ import { CreateCrossServiceTokenDTO } from './CreateCrossServiceTokenDTO'
|
||||
import { GetSetting } from '../GetSetting/GetSetting'
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||
|
||||
@injectable()
|
||||
export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
||||
@@ -27,6 +28,7 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
||||
private getSettingUseCase: GetSetting,
|
||||
@inject(TYPES.Auth_TransitionStatusRepository)
|
||||
private transitionStatusRepository: TransitionStatusRepositoryInterface,
|
||||
@inject(TYPES.Auth_SharedVaultUserRepository) private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: CreateCrossServiceTokenDTO): Promise<Result<string>> {
|
||||
@@ -46,14 +48,25 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
||||
}
|
||||
|
||||
const transitionStatus = await this.transitionStatusRepository.getStatus(user.uuid, 'items')
|
||||
const revisionsTransitionStatus = await this.transitionStatusRepository.getStatus(user.uuid, 'revisions')
|
||||
|
||||
const roles = await user.roles
|
||||
|
||||
const sharedVaultAssociations = await this.sharedVaultUserRepository.findByUserUuid(
|
||||
Uuid.create(user.uuid).getValue(),
|
||||
)
|
||||
|
||||
const authTokenData: CrossServiceTokenData = {
|
||||
user: this.projectUser(user),
|
||||
roles: this.projectRoles(roles),
|
||||
shared_vault_owner_context: undefined,
|
||||
ongoing_transition: transitionStatus === 'STARTED',
|
||||
ongoing_transition: transitionStatus === 'IN_PROGRESS',
|
||||
ongoing_revisions_transition:
|
||||
revisionsTransitionStatus === 'STARTED' || revisionsTransitionStatus === 'IN_PROGRESS',
|
||||
belongs_to_shared_vaults: sharedVaultAssociations.map((association) => ({
|
||||
shared_vault_uuid: association.props.sharedVaultUuid.value,
|
||||
permission: association.props.permission.value,
|
||||
})),
|
||||
}
|
||||
|
||||
if (dto.sharedVaultOwnerContext !== undefined) {
|
||||
|
||||
@@ -4,13 +4,17 @@ import { GetTransitionStatusDTO } from './GetTransitionStatusDTO'
|
||||
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
|
||||
export class GetTransitionStatus implements UseCaseInterface<'TO-DO' | 'STARTED' | 'FINISHED' | 'FAILED'> {
|
||||
export class GetTransitionStatus
|
||||
implements UseCaseInterface<'TO-DO' | 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'>
|
||||
{
|
||||
constructor(
|
||||
private transitionStatusRepository: TransitionStatusRepositoryInterface,
|
||||
private userRepository: UserRepositoryInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: GetTransitionStatusDTO): Promise<Result<'TO-DO' | 'STARTED' | 'FINISHED' | 'FAILED'>> {
|
||||
async execute(
|
||||
dto: GetTransitionStatusDTO,
|
||||
): Promise<Result<'TO-DO' | 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'>> {
|
||||
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return Result.fail(userUuidOrError.getError())
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { SharedVaultUser } from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||
import { RemoveSharedVaultUser } from './RemoveSharedVaultUser'
|
||||
|
||||
describe('RemoveSharedVaultUser', () => {
|
||||
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
||||
|
||||
const createUseCase = () => new RemoveSharedVaultUser(sharedVaultUserRepository)
|
||||
|
||||
beforeEach(() => {
|
||||
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
|
||||
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<SharedVaultUser>)
|
||||
sharedVaultUserRepository.remove = jest.fn()
|
||||
})
|
||||
|
||||
it('should remove shared vault user', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(sharedVaultUserRepository.remove).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when user uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: 'invalid',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(sharedVaultUserRepository.remove).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when shared vault uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: 'invalid',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(sharedVaultUserRepository.remove).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fail when shared vault user is not found', async () => {
|
||||
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockReturnValue(null)
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(sharedVaultUserRepository.remove).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||
import { RemoveSharedVaultUserDTO } from './RemoveSharedVaultUserDTO'
|
||||
|
||||
export class RemoveSharedVaultUser implements UseCaseInterface<void> {
|
||||
constructor(private sharedVaultUserRepository: SharedVaultUserRepositoryInterface) {}
|
||||
|
||||
async execute(dto: RemoveSharedVaultUserDTO): Promise<Result<void>> {
|
||||
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return Result.fail(userUuidOrError.getError())
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultUuidOrError.getError())
|
||||
}
|
||||
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||
|
||||
const sharedVaultUser = await this.sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid({
|
||||
userUuid,
|
||||
sharedVaultUuid,
|
||||
})
|
||||
if (!sharedVaultUser) {
|
||||
return Result.fail('Shared vault user not found')
|
||||
}
|
||||
|
||||
await this.sharedVaultUserRepository.remove(sharedVaultUser)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface RemoveSharedVaultUserDTO {
|
||||
sharedVaultUuid: string
|
||||
userUuid: string
|
||||
}
|
||||
+41
-1
@@ -3,17 +3,36 @@ import { RoleName, Uuid } from '@standardnotes/domain-core'
|
||||
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { UpdateTransitionStatus } from './UpdateTransitionStatus'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
describe('UpdateTransitionStatus', () => {
|
||||
let transitionStatusRepository: TransitionStatusRepositoryInterface
|
||||
let roleService: RoleServiceInterface
|
||||
let logger: Logger
|
||||
|
||||
const createUseCase = () => new UpdateTransitionStatus(transitionStatusRepository, roleService)
|
||||
const createUseCase = () => new UpdateTransitionStatus(transitionStatusRepository, roleService, logger)
|
||||
|
||||
beforeEach(() => {
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.info = jest.fn()
|
||||
|
||||
transitionStatusRepository = {} as jest.Mocked<TransitionStatusRepositoryInterface>
|
||||
transitionStatusRepository.removeStatus = jest.fn()
|
||||
transitionStatusRepository.updateStatus = jest.fn()
|
||||
transitionStatusRepository.getStatuses = jest.fn().mockResolvedValue([
|
||||
{
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'STARTED',
|
||||
},
|
||||
{
|
||||
userUuid: '00000000-0000-0000-0000-000000000001',
|
||||
status: 'IN_PROGRESS',
|
||||
},
|
||||
{
|
||||
userUuid: '00000000-0000-0000-0000-000000000002',
|
||||
status: 'FAILED',
|
||||
},
|
||||
])
|
||||
|
||||
roleService = {} as jest.Mocked<RoleServiceInterface>
|
||||
roleService.addRoleToUser = jest.fn()
|
||||
@@ -26,6 +45,7 @@ describe('UpdateTransitionStatus', () => {
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'FINISHED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
@@ -39,6 +59,24 @@ describe('UpdateTransitionStatus', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('should remove transition status', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'FINISHED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(transitionStatusRepository.removeStatus).toHaveBeenCalledWith(
|
||||
'00000000-0000-0000-0000-000000000000',
|
||||
'revisions',
|
||||
)
|
||||
expect(roleService.addRoleToUser).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should update transition status', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
@@ -46,6 +84,7 @@ describe('UpdateTransitionStatus', () => {
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'STARTED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
@@ -63,6 +102,7 @@ describe('UpdateTransitionStatus', () => {
|
||||
userUuid: 'invalid',
|
||||
status: 'STARTED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
|
||||
@@ -2,11 +2,13 @@ import { Result, RoleName, UseCaseInterface, Uuid } from '@standardnotes/domain-
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { UpdateTransitionStatusDTO } from './UpdateTransitionStatusDTO'
|
||||
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
export class UpdateTransitionStatus implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private transitionStatusRepository: TransitionStatusRepositoryInterface,
|
||||
private roleService: RoleServiceInterface,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async execute(dto: UpdateTransitionStatusDTO): Promise<Result<void>> {
|
||||
@@ -16,15 +18,41 @@ export class UpdateTransitionStatus implements UseCaseInterface<void> {
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
if (dto.status === 'FINISHED') {
|
||||
await this.transitionStatusRepository.removeStatus(dto.userUuid, dto.transitionType)
|
||||
|
||||
await this.roleService.addRoleToUser(userUuid, RoleName.create(RoleName.NAMES.TransitionUser).getValue())
|
||||
if (dto.status !== 'FINISHED') {
|
||||
await this.transitionStatusRepository.updateStatus(dto.userUuid, dto.transitionType, dto.status)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
await this.transitionStatusRepository.updateStatus(dto.userUuid, dto.transitionType, dto.status)
|
||||
await this.transitionStatusRepository.removeStatus(dto.userUuid, dto.transitionType)
|
||||
|
||||
if (dto.transitionType === 'items') {
|
||||
await this.roleService.addRoleToUser(userUuid, RoleName.create(RoleName.NAMES.TransitionUser).getValue())
|
||||
}
|
||||
|
||||
if (dto.transitionType === 'items') {
|
||||
const itemStatuses = await this.transitionStatusRepository.getStatuses('items')
|
||||
const itemsStartedStatusesCount = itemStatuses.filter((status) => status.status === 'STARTED').length
|
||||
const itemsInProgressStatusesCount = itemStatuses.filter((status) => status.status === 'IN_PROGRESS').length
|
||||
const itemsFailedStatusesCount = itemStatuses.filter((status) => status.status === 'FAILED').length
|
||||
|
||||
this.logger.info(
|
||||
`[TRANSITION ${dto.transitionTimestamp}] Items transition statuses: ${itemsStartedStatusesCount} started, ${itemsInProgressStatusesCount} in progress, ${itemsFailedStatusesCount} failed`,
|
||||
)
|
||||
}
|
||||
|
||||
if (dto.transitionType === 'revisions') {
|
||||
const revisionStatuses = await this.transitionStatusRepository.getStatuses('revisions')
|
||||
const revisionsStartedStatusesCount = revisionStatuses.filter((status) => status.status === 'STARTED').length
|
||||
const revisionsInProgressStatusesCount = revisionStatuses.filter(
|
||||
(status) => status.status === 'IN_PROGRESS',
|
||||
).length
|
||||
const revisionsFailedStatusesCount = revisionStatuses.filter((status) => status.status === 'FAILED').length
|
||||
|
||||
this.logger.info(
|
||||
`[TRANSITION ${dto.transitionTimestamp}] Revisions transition statuses: ${revisionsStartedStatusesCount} started, ${revisionsInProgressStatusesCount} in progress, ${revisionsFailedStatusesCount} failed`,
|
||||
)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
export interface UpdateTransitionStatusDTO {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
status: 'STARTED' | 'FINISHED' | 'FAILED'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export interface UserRepositoryInterface {
|
||||
streamTeam(memberEmail?: Email): Promise<ReadStream>
|
||||
findOneByUuid(uuid: Uuid): Promise<User | null>
|
||||
findOneByUsernameOrEmail(usernameOrEmail: Email | Username): Promise<User | null>
|
||||
findAllCreatedBetween(start: Date, end: Date): Promise<User[]>
|
||||
save(user: User): Promise<User>
|
||||
remove(user: User): Promise<User>
|
||||
}
|
||||
|
||||
@@ -4,6 +4,24 @@ export class InMemoryTransitionStatusRepository implements TransitionStatusRepos
|
||||
private itemStatuses: Map<string, 'STARTED' | 'FAILED'> = new Map()
|
||||
private revisionStatuses: Map<string, 'STARTED' | 'FAILED'> = new Map()
|
||||
|
||||
async getStatuses(
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<{ userUuid: string; status: 'STARTED' | 'FAILED' | 'IN_PROGRESS' }[]> {
|
||||
const statuses: { userUuid: string; status: 'STARTED' | 'FAILED' | 'IN_PROGRESS' }[] = []
|
||||
|
||||
if (transitionType === 'items') {
|
||||
for (const [userUuid, status] of this.itemStatuses) {
|
||||
statuses.push({ userUuid, status })
|
||||
}
|
||||
} else {
|
||||
for (const [userUuid, status] of this.revisionStatuses) {
|
||||
statuses.push({ userUuid, status })
|
||||
}
|
||||
}
|
||||
|
||||
return statuses
|
||||
}
|
||||
|
||||
async updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
|
||||
@@ -14,7 +14,6 @@ import { IncreaseLoginAttempts } from '../../Domain/UseCase/IncreaseLoginAttempt
|
||||
import { InviteToSharedSubscription } from '../../Domain/UseCase/InviteToSharedSubscription/InviteToSharedSubscription'
|
||||
import { UpdateUser } from '../../Domain/UseCase/UpdateUser'
|
||||
import { User } from '../../Domain/User/User'
|
||||
import { GetTransitionStatus } from '../../Domain/UseCase/GetTransitionStatus/GetTransitionStatus'
|
||||
|
||||
describe('AnnotatedUsersController', () => {
|
||||
let updateUser: UpdateUser
|
||||
@@ -25,7 +24,6 @@ describe('AnnotatedUsersController', () => {
|
||||
let increaseLoginAttempts: IncreaseLoginAttempts
|
||||
let changeCredentials: ChangeCredentials
|
||||
let inviteToSharedSubscription: InviteToSharedSubscription
|
||||
let getTransitionStatus: GetTransitionStatus
|
||||
|
||||
let request: express.Request
|
||||
let response: express.Response
|
||||
@@ -40,7 +38,6 @@ describe('AnnotatedUsersController', () => {
|
||||
clearLoginAttempts,
|
||||
increaseLoginAttempts,
|
||||
changeCredentials,
|
||||
getTransitionStatus,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -72,9 +69,6 @@ describe('AnnotatedUsersController', () => {
|
||||
inviteToSharedSubscription = {} as jest.Mocked<InviteToSharedSubscription>
|
||||
inviteToSharedSubscription.execute = jest.fn()
|
||||
|
||||
getTransitionStatus = {} as jest.Mocked<GetTransitionStatus>
|
||||
getTransitionStatus.execute = jest.fn()
|
||||
|
||||
request = {
|
||||
headers: {},
|
||||
body: {},
|
||||
|
||||
@@ -18,7 +18,6 @@ import { ClearLoginAttempts } from '../../Domain/UseCase/ClearLoginAttempts'
|
||||
import { IncreaseLoginAttempts } from '../../Domain/UseCase/IncreaseLoginAttempts'
|
||||
import { ChangeCredentials } from '../../Domain/UseCase/ChangeCredentials/ChangeCredentials'
|
||||
import { BaseUsersController } from './Base/BaseUsersController'
|
||||
import { GetTransitionStatus } from '../../Domain/UseCase/GetTransitionStatus/GetTransitionStatus'
|
||||
|
||||
@controller('/users')
|
||||
export class AnnotatedUsersController extends BaseUsersController {
|
||||
@@ -30,7 +29,6 @@ export class AnnotatedUsersController extends BaseUsersController {
|
||||
@inject(TYPES.Auth_ClearLoginAttempts) override clearLoginAttempts: ClearLoginAttempts,
|
||||
@inject(TYPES.Auth_IncreaseLoginAttempts) override increaseLoginAttempts: IncreaseLoginAttempts,
|
||||
@inject(TYPES.Auth_ChangeCredentials) override changeCredentialsUseCase: ChangeCredentials,
|
||||
@inject(TYPES.Auth_GetTransitionStatus) override getTransitionStatusUseCase: GetTransitionStatus,
|
||||
) {
|
||||
super(
|
||||
updateUser,
|
||||
@@ -40,7 +38,6 @@ export class AnnotatedUsersController extends BaseUsersController {
|
||||
clearLoginAttempts,
|
||||
increaseLoginAttempts,
|
||||
changeCredentialsUseCase,
|
||||
getTransitionStatusUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -54,11 +51,6 @@ export class AnnotatedUsersController extends BaseUsersController {
|
||||
return super.keyParams(request)
|
||||
}
|
||||
|
||||
@httpGet('/transition-status', TYPES.Auth_RequiredCrossServiceTokenMiddleware)
|
||||
override async transitionStatus(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
return super.transitionStatus(request, response)
|
||||
}
|
||||
|
||||
@httpDelete('/:userUuid', TYPES.Auth_RequiredCrossServiceTokenMiddleware)
|
||||
override async deleteAccount(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
return super.deleteAccount(request, response)
|
||||
|
||||
@@ -10,7 +10,6 @@ import { GetUserSubscription } from '../../../Domain/UseCase/GetUserSubscription
|
||||
import { IncreaseLoginAttempts } from '../../../Domain/UseCase/IncreaseLoginAttempts'
|
||||
import { UpdateUser } from '../../../Domain/UseCase/UpdateUser'
|
||||
import { ErrorTag } from '@standardnotes/responses'
|
||||
import { GetTransitionStatus } from '../../../Domain/UseCase/GetTransitionStatus/GetTransitionStatus'
|
||||
|
||||
export class BaseUsersController extends BaseHttpController {
|
||||
constructor(
|
||||
@@ -21,7 +20,6 @@ export class BaseUsersController extends BaseHttpController {
|
||||
protected clearLoginAttempts: ClearLoginAttempts,
|
||||
protected increaseLoginAttempts: IncreaseLoginAttempts,
|
||||
protected changeCredentialsUseCase: ChangeCredentials,
|
||||
protected getTransitionStatusUseCase: GetTransitionStatus,
|
||||
private controllerContainer?: ControllerContainerInterface,
|
||||
) {
|
||||
super()
|
||||
@@ -32,7 +30,6 @@ export class BaseUsersController extends BaseHttpController {
|
||||
this.controllerContainer.register('auth.users.getSubscription', this.getSubscription.bind(this))
|
||||
this.controllerContainer.register('auth.users.updateCredentials', this.changeCredentials.bind(this))
|
||||
this.controllerContainer.register('auth.users.delete', this.deleteAccount.bind(this))
|
||||
this.controllerContainer.register('auth.users.transition-status', this.transitionStatus.bind(this))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,30 +103,6 @@ export class BaseUsersController extends BaseHttpController {
|
||||
return this.json(result.keyParams)
|
||||
}
|
||||
|
||||
async transitionStatus(_request: Request, response: Response): Promise<results.JsonResult> {
|
||||
const result = await this.getTransitionStatusUseCase.execute({
|
||||
userUuid: response.locals.user.uuid,
|
||||
transitionType: 'items',
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
return this.json(
|
||||
{
|
||||
error: {
|
||||
message: result.getError(),
|
||||
},
|
||||
},
|
||||
400,
|
||||
)
|
||||
}
|
||||
|
||||
response.setHeader('x-invalidate-cache', response.locals.user.uuid)
|
||||
|
||||
return this.json({
|
||||
status: result.getValue(),
|
||||
})
|
||||
}
|
||||
|
||||
async deleteAccount(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
if (request.params.userUuid !== response.locals.user.uuid) {
|
||||
return this.json(
|
||||
|
||||
@@ -7,21 +7,46 @@ export class RedisTransitionStatusRepository implements TransitionStatusReposito
|
||||
|
||||
constructor(private redisClient: IORedis.Redis) {}
|
||||
|
||||
async getStatuses(
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<{ userUuid: string; status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' }[]> {
|
||||
const keys = await this.redisClient.keys(`${this.PREFIX}:${transitionType}:*`)
|
||||
const statuses = await Promise.all(
|
||||
keys.map(async (key) => {
|
||||
const userUuid = key.split(':')[2]
|
||||
const status = (await this.redisClient.get(key)) as 'STARTED' | 'IN_PROGRESS' | 'FAILED'
|
||||
return { userUuid, status }
|
||||
}),
|
||||
)
|
||||
|
||||
return statuses
|
||||
}
|
||||
|
||||
async updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
status: 'STARTED' | 'FAILED',
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED',
|
||||
): Promise<void> {
|
||||
await this.redisClient.set(`${this.PREFIX}:${transitionType}:${userUuid}`, status)
|
||||
if (status === 'IN_PROGRESS') {
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, 7_200, status)
|
||||
} else if (status === 'STARTED') {
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, 36_000, status)
|
||||
} else {
|
||||
await this.redisClient.set(`${this.PREFIX}:${transitionType}:${userUuid}`, status)
|
||||
}
|
||||
}
|
||||
|
||||
async removeStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void> {
|
||||
await this.redisClient.del(`${this.PREFIX}:${transitionType}:${userUuid}`)
|
||||
}
|
||||
|
||||
async getStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<'STARTED' | 'FAILED' | null> {
|
||||
async getStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<'STARTED' | 'IN_PROGRESS' | 'FAILED' | null> {
|
||||
const status = (await this.redisClient.get(`${this.PREFIX}:${transitionType}:${userUuid}`)) as
|
||||
| 'STARTED'
|
||||
| 'IN_PROGRESS'
|
||||
| 'FAILED'
|
||||
| null
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
|
||||
|
||||
@Entity({ name: 'auth_shared_vault_users' })
|
||||
export class TypeORMSharedVaultUser {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
declare uuid: string
|
||||
|
||||
@Column({
|
||||
name: 'shared_vault_uuid',
|
||||
length: 36,
|
||||
})
|
||||
@Index('shared_vault_uuid_on_auth_shared_vault_users')
|
||||
declare sharedVaultUuid: string
|
||||
|
||||
@Column({
|
||||
name: 'user_uuid',
|
||||
length: 36,
|
||||
})
|
||||
@Index('user_uuid_on_auth_shared_vault_users')
|
||||
declare userUuid: string
|
||||
|
||||
@Column({
|
||||
name: 'permission',
|
||||
type: 'varchar',
|
||||
length: 24,
|
||||
})
|
||||
declare permission: string
|
||||
|
||||
@Column({
|
||||
name: 'created_at_timestamp',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare createdAtTimestamp: number
|
||||
|
||||
@Column({
|
||||
name: 'updated_at_timestamp',
|
||||
type: 'bigint',
|
||||
})
|
||||
declare updatedAtTimestamp: number
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Repository } from 'typeorm'
|
||||
import { MapperInterface, SharedVaultUser, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultUserRepositoryInterface } from '../../Domain/SharedVault/SharedVaultUserRepositoryInterface'
|
||||
import { TypeORMSharedVaultUser } from './TypeORMSharedVaultUser'
|
||||
|
||||
export class TypeORMSharedVaultUserRepository implements SharedVaultUserRepositoryInterface {
|
||||
constructor(
|
||||
private ormRepository: Repository<TypeORMSharedVaultUser>,
|
||||
private mapper: MapperInterface<SharedVaultUser, TypeORMSharedVaultUser>,
|
||||
) {}
|
||||
|
||||
async findByUserUuid(userUuid: Uuid): Promise<SharedVaultUser[]> {
|
||||
const persistence = await this.ormRepository
|
||||
.createQueryBuilder('shared_vault_user')
|
||||
.where('shared_vault_user.user_uuid = :userUuid', {
|
||||
userUuid: userUuid.value,
|
||||
})
|
||||
.getMany()
|
||||
|
||||
return persistence.map((p) => this.mapper.toDomain(p))
|
||||
}
|
||||
|
||||
async findByUserUuidAndSharedVaultUuid(dto: {
|
||||
userUuid: Uuid
|
||||
sharedVaultUuid: Uuid
|
||||
}): Promise<SharedVaultUser | null> {
|
||||
const persistence = await this.ormRepository
|
||||
.createQueryBuilder('shared_vault_user')
|
||||
.where('shared_vault_user.user_uuid = :userUuid', {
|
||||
userUuid: dto.userUuid.value,
|
||||
})
|
||||
.andWhere('shared_vault_user.shared_vault_uuid = :sharedVaultUuid', {
|
||||
sharedVaultUuid: dto.sharedVaultUuid.value,
|
||||
})
|
||||
.getOne()
|
||||
|
||||
if (persistence === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return this.mapper.toDomain(persistence)
|
||||
}
|
||||
|
||||
async save(sharedVaultUser: SharedVaultUser): Promise<void> {
|
||||
const persistence = this.mapper.toProjection(sharedVaultUser)
|
||||
|
||||
await this.ormRepository.save(persistence)
|
||||
}
|
||||
|
||||
async remove(sharedVaultUser: SharedVaultUser): Promise<void> {
|
||||
await this.ormRepository.remove(this.mapper.toProjection(sharedVaultUser))
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,13 @@ export class TypeORMUserRepository implements UserRepositoryInterface {
|
||||
private ormRepository: Repository<User>,
|
||||
) {}
|
||||
|
||||
async findAllCreatedBetween(start: Date, end: Date): Promise<User[]> {
|
||||
return this.ormRepository
|
||||
.createQueryBuilder('user')
|
||||
.where('user.created_at BETWEEN :start AND :end', { start, end })
|
||||
.getMany()
|
||||
}
|
||||
|
||||
async save(user: User): Promise<User> {
|
||||
return this.ormRepository.save(user)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
Timestamps,
|
||||
MapperInterface,
|
||||
UniqueEntityId,
|
||||
Uuid,
|
||||
SharedVaultUserPermission,
|
||||
SharedVaultUser,
|
||||
} from '@standardnotes/domain-core'
|
||||
|
||||
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
|
||||
|
||||
export class SharedVaultUserPersistenceMapper implements MapperInterface<SharedVaultUser, TypeORMSharedVaultUser> {
|
||||
toDomain(projection: TypeORMSharedVaultUser): SharedVaultUser {
|
||||
const userUuidOrError = Uuid.create(projection.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
throw new Error(`Failed to create shared vault user from projection: ${userUuidOrError.getError()}`)
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const sharedVaultUuidOrError = Uuid.create(projection.sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
throw new Error(`Failed to create shared vault user from projection: ${sharedVaultUuidOrError.getError()}`)
|
||||
}
|
||||
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||
|
||||
const timestampsOrError = Timestamps.create(projection.createdAtTimestamp, projection.updatedAtTimestamp)
|
||||
if (timestampsOrError.isFailed()) {
|
||||
throw new Error(`Failed to create shared vault user from projection: ${timestampsOrError.getError()}`)
|
||||
}
|
||||
const timestamps = timestampsOrError.getValue()
|
||||
|
||||
const permissionOrError = SharedVaultUserPermission.create(projection.permission)
|
||||
if (permissionOrError.isFailed()) {
|
||||
throw new Error(`Failed to create shared vault user from projection: ${permissionOrError.getError()}`)
|
||||
}
|
||||
const permission = permissionOrError.getValue()
|
||||
|
||||
const sharedVaultUserOrError = SharedVaultUser.create(
|
||||
{
|
||||
userUuid,
|
||||
sharedVaultUuid,
|
||||
permission,
|
||||
timestamps,
|
||||
},
|
||||
new UniqueEntityId(projection.uuid),
|
||||
)
|
||||
if (sharedVaultUserOrError.isFailed()) {
|
||||
throw new Error(`Failed to create shared vault user from projection: ${sharedVaultUserOrError.getError()}`)
|
||||
}
|
||||
const sharedVaultUser = sharedVaultUserOrError.getValue()
|
||||
|
||||
return sharedVaultUser
|
||||
}
|
||||
|
||||
toProjection(domain: SharedVaultUser): TypeORMSharedVaultUser {
|
||||
const typeorm = new TypeORMSharedVaultUser()
|
||||
|
||||
typeorm.uuid = domain.id.toString()
|
||||
typeorm.sharedVaultUuid = domain.props.sharedVaultUuid.value
|
||||
typeorm.userUuid = domain.props.userUuid.value
|
||||
typeorm.permission = domain.props.permission.value
|
||||
typeorm.createdAtTimestamp = domain.props.timestamps.createdAt
|
||||
typeorm.updatedAtTimestamp = domain.props.timestamps.updatedAt
|
||||
|
||||
return typeorm
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.28.0...@standardnotes/domain-core@1.28.1) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* comparing uuids ([0a1d162](https://github.com/standardnotes/server/commit/0a1d1624e818000f2e951f29323a88e6e233c755))
|
||||
|
||||
# [1.28.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.27.0...@standardnotes/domain-core@1.28.0) (2023-09-07)
|
||||
|
||||
### Features
|
||||
|
||||
* add VaultsUser role name ([#809](https://github.com/standardnotes/server/issues/809)) ([d4830de](https://github.com/standardnotes/server/commit/d4830dec018139ffaf93d0e91d6655c5dcc6be9c))
|
||||
|
||||
# [1.27.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.26.3...@standardnotes/domain-core@1.27.0) (2023-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/server/issues/807)) ([794cd87](https://github.com/standardnotes/server/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
|
||||
|
||||
## [1.26.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.26.2...@standardnotes/domain-core@1.26.3) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-core
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-core",
|
||||
"version": "1.26.3",
|
||||
"version": "1.28.1",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ export class RoleName extends ValueObject<RoleNameProps> {
|
||||
ProUser: 'PRO_USER',
|
||||
InternalTeamUser: 'INTERNAL_TEAM_USER',
|
||||
TransitionUser: 'TRANSITION_USER',
|
||||
VaultsUser: 'VAULTS_USER',
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
@@ -32,6 +33,7 @@ export class RoleName extends ValueObject<RoleNameProps> {
|
||||
)
|
||||
case RoleName.NAMES.CoreUser:
|
||||
case RoleName.NAMES.TransitionUser:
|
||||
case RoleName.NAMES.VaultsUser:
|
||||
return [RoleName.NAMES.CoreUser, RoleName.NAMES.TransitionUser].includes(roleName.value)
|
||||
/*istanbul ignore next*/
|
||||
default:
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('RoleNameCollection', () => {
|
||||
})
|
||||
|
||||
it('should tell if collection has a role with more or equal power to', () => {
|
||||
let roles = [RoleName.NAMES.CoreUser]
|
||||
let roles = [RoleName.NAMES.VaultsUser]
|
||||
let valueOrError = RoleNameCollection.create(roles)
|
||||
let roleNames = valueOrError.getValue()
|
||||
|
||||
@@ -63,6 +63,18 @@ describe('RoleNameCollection', () => {
|
||||
roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.CoreUser).getValue()),
|
||||
).toBeTruthy()
|
||||
|
||||
roles = [RoleName.NAMES.CoreUser]
|
||||
valueOrError = RoleNameCollection.create(roles)
|
||||
roleNames = valueOrError.getValue()
|
||||
|
||||
expect(
|
||||
roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.PlusUser).getValue()),
|
||||
).toBeFalsy()
|
||||
expect(roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.ProUser).getValue())).toBeFalsy()
|
||||
expect(
|
||||
roleNames.hasARoleNameWithMoreOrEqualPowerTo(RoleName.create(RoleName.NAMES.CoreUser).getValue()),
|
||||
).toBeTruthy()
|
||||
|
||||
roles = [RoleName.NAMES.CoreUser, RoleName.NAMES.PlusUser]
|
||||
valueOrError = RoleNameCollection.create(roles)
|
||||
roleNames = valueOrError.getValue()
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Timestamps } from './Timestamps'
|
||||
|
||||
describe('Timestamps', () => {
|
||||
it('should create a value object', () => {
|
||||
const valueOrError = Timestamps.create(123, 234)
|
||||
|
||||
expect(valueOrError.isFailed()).toBeFalsy()
|
||||
expect(valueOrError.getValue().createdAt).toEqual(123)
|
||||
expect(valueOrError.getValue().updatedAt).toEqual(234)
|
||||
})
|
||||
|
||||
it('should not create an invalid value object', () => {
|
||||
const valueOrError = Timestamps.create('' as unknown as number, 123)
|
||||
|
||||
expect(valueOrError.isFailed()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should not create an invalid value object', () => {
|
||||
const valueOrError = Timestamps.create(123, '' as unknown as number)
|
||||
|
||||
expect(valueOrError.isFailed()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
@@ -16,12 +16,12 @@ export class Timestamps extends ValueObject<TimestampsProps> {
|
||||
}
|
||||
|
||||
static create(createdAt: number, updatedAt: number): Result<Timestamps> {
|
||||
if (isNaN(createdAt)) {
|
||||
if (isNaN(createdAt) || typeof createdAt !== 'number') {
|
||||
return Result.fail<Timestamps>(
|
||||
`Could not create Timestamps. Creation date should be a number, given: ${createdAt}`,
|
||||
)
|
||||
}
|
||||
if (isNaN(updatedAt)) {
|
||||
if (isNaN(updatedAt) || typeof updatedAt !== 'number') {
|
||||
return Result.fail<Timestamps>(`Could not create Timestamps. Update date should be a number, given: ${updatedAt}`)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,13 @@ describe('Uuid', () => {
|
||||
expect(valueOrError.getValue().value).toEqual('84c0f8e8-544a-4c7e-9adf-26209303bc1d')
|
||||
})
|
||||
|
||||
it('should create a value object on upper case', () => {
|
||||
const valueOrError = Uuid.create('00B57455-B563-4B50-A2AA-B19762102219')
|
||||
|
||||
expect(valueOrError.isFailed()).toBeFalsy()
|
||||
expect(valueOrError.getValue().value).toEqual('00B57455-B563-4B50-A2AA-B19762102219')
|
||||
})
|
||||
|
||||
it('should not create an invalid value object', () => {
|
||||
const valueOrError = Uuid.create('1-2-3')
|
||||
|
||||
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
|
||||
import { SharedVaultUser } from './SharedVaultUser'
|
||||
import { Uuid } from '../Common/Uuid'
|
||||
import { Timestamps } from '../Common/Timestamps'
|
||||
|
||||
describe('SharedVaultUser', () => {
|
||||
it('should create an entity', () => {
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
|
||||
|
||||
import { Entity } from '../Core/Entity'
|
||||
import { Result } from '../Core/Result'
|
||||
import { UniqueEntityId } from '../Core/UniqueEntityId'
|
||||
import { SharedVaultUserProps } from './SharedVaultUserProps'
|
||||
|
||||
export class SharedVaultUser extends Entity<SharedVaultUserProps> {
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Timestamps } from '../Common/Timestamps'
|
||||
import { Uuid } from '../Common/Uuid'
|
||||
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
|
||||
|
||||
export interface SharedVaultUserProps {
|
||||
sharedVaultUuid: Uuid
|
||||
userUuid: Uuid
|
||||
permission: SharedVaultUserPermission
|
||||
timestamps: Timestamps
|
||||
}
|
||||
@@ -59,8 +59,10 @@ export * from './Service/ServiceIdentifier'
|
||||
export * from './Service/ServiceIdentifierProps'
|
||||
export * from './Service/ServiceInterface'
|
||||
|
||||
export * from './SharedVault/SharedVaultUser'
|
||||
export * from './SharedVault/SharedVaultUserPermission'
|
||||
export * from './SharedVault/SharedVaultUserPermissionProps'
|
||||
export * from './SharedVault/SharedVaultUserProps'
|
||||
|
||||
export * from './Subscription/SubscriptionPlanName'
|
||||
export * from './Subscription/SubscriptionPlanNameProps'
|
||||
|
||||
@@ -3,6 +3,34 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.12.28](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.27...@standardnotes/domain-events-infra@1.12.28) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.27](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.26...@standardnotes/domain-events-infra@1.12.27) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.26](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.25...@standardnotes/domain-events-infra@1.12.26) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.25](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.24...@standardnotes/domain-events-infra@1.12.25) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.24](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.23...@standardnotes/domain-events-infra@1.12.24) (2023-09-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.23](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.22...@standardnotes/domain-events-infra@1.12.23) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.22](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.21...@standardnotes/domain-events-infra@1.12.22) (2023-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.21](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.20...@standardnotes/domain-events-infra@1.12.21) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.12.21",
|
||||
"version": "1.12.28",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,46 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.125.4](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.125.3...@standardnotes/domain-events@2.125.4) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* display transition progress in logs ([38685c1](https://github.com/standardnotes/server/commit/38685c1861b13e398dd96aa39f2cf1aece2090fb))
|
||||
|
||||
## [2.125.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.125.2...@standardnotes/domain-events@2.125.3) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* retry failed revision transitions ([e535cd5](https://github.com/standardnotes/server/commit/e535cd504cf1929539ff7faf13e9c1fdd2b7bfd1))
|
||||
|
||||
## [2.125.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.125.1...@standardnotes/domain-events@2.125.2) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* domain event values ([f0abfe8](https://github.com/standardnotes/server/commit/f0abfe89fca0049c47131389683efe2f5aff23f8))
|
||||
|
||||
## [2.125.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.125.0...@standardnotes/domain-events@2.125.1) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
# [2.125.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.124.0...@standardnotes/domain-events@2.125.0) (2023-09-08)
|
||||
|
||||
### Features
|
||||
|
||||
* transition users after sign out ([398338c](https://github.com/standardnotes/server/commit/398338c8f81b12406c7ab3bf1654e60b94d7cfd0))
|
||||
|
||||
# [2.124.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.123.0...@standardnotes/domain-events@2.124.0) (2023-09-07)
|
||||
|
||||
### Features
|
||||
|
||||
* add removing revisions from shared vaults ([#811](https://github.com/standardnotes/server/issues/811)) ([3bd63f7](https://github.com/standardnotes/server/commit/3bd63f767464baf9b9f1ffa52eea9eed4a4e11b5))
|
||||
|
||||
# [2.123.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.122.2...@standardnotes/domain-events@2.123.0) (2023-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* should be able to access shared item revisions as third party user ([#807](https://github.com/standardnotes/server/issues/807)) ([794cd87](https://github.com/standardnotes/server/commit/794cd8734acf89fb29f09dfb169a3f08f252bb6a))
|
||||
|
||||
## [2.122.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.122.1...@standardnotes/domain-events@2.122.2) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.122.2",
|
||||
"version": "2.125.4",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { ItemRemovedFromSharedVaultEventPayload } from './ItemRemovedFromSharedVaultEventPayload'
|
||||
|
||||
export interface ItemRemovedFromSharedVaultEvent extends DomainEventInterface {
|
||||
type: 'ITEM_REMOVED_FROM_SHARED_VAULT'
|
||||
payload: ItemRemovedFromSharedVaultEventPayload
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface ItemRemovedFromSharedVaultEventPayload {
|
||||
userUuid: string
|
||||
itemUuid: string
|
||||
sharedVaultUuid: string
|
||||
roleNames: string[]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
|
||||
import { TransitionRequestedEventPayload } from './TransitionRequestedEventPayload'
|
||||
|
||||
export interface TransitionRequestedEvent extends DomainEventInterface {
|
||||
type: 'TRANSITION_REQUESTED'
|
||||
payload: TransitionRequestedEventPayload
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface TransitionRequestedEventPayload {
|
||||
userUuid: string
|
||||
type: 'items' | 'revisions'
|
||||
timestamp: number
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
export interface TransitionStatusUpdatedEventPayload {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
status: 'STARTED' | 'FINISHED' | 'FAILED'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { UserAddedToSharedVaultEventPayload } from './UserAddedToSharedVaultEventPayload'
|
||||
|
||||
export interface UserAddedToSharedVaultEvent extends DomainEventInterface {
|
||||
type: 'USER_ADDED_TO_SHARED_VAULT'
|
||||
payload: UserAddedToSharedVaultEventPayload
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface UserAddedToSharedVaultEventPayload {
|
||||
sharedVaultUuid: string
|
||||
userUuid: string
|
||||
permission: string
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { UserRemovedFromSharedVaultEventPayload } from './UserRemovedFromSharedVaultEventPayload'
|
||||
|
||||
export interface UserRemovedFromSharedVaultEvent extends DomainEventInterface {
|
||||
type: 'USER_REMOVED_FROM_SHARED_VAULT'
|
||||
payload: UserRemovedFromSharedVaultEventPayload
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface UserRemovedFromSharedVaultEventPayload {
|
||||
sharedVaultUuid: string
|
||||
userUuid: string
|
||||
}
|
||||
@@ -32,6 +32,8 @@ export * from './Event/FileUploadedEvent'
|
||||
export * from './Event/FileUploadedEventPayload'
|
||||
export * from './Event/ItemDumpedEvent'
|
||||
export * from './Event/ItemDumpedEventPayload'
|
||||
export * from './Event/ItemRemovedFromSharedVaultEvent'
|
||||
export * from './Event/ItemRemovedFromSharedVaultEventPayload'
|
||||
export * from './Event/ItemRevisionCreationRequestedEvent'
|
||||
export * from './Event/ItemRevisionCreationRequestedEventPayload'
|
||||
export * from './Event/ListedAccountCreatedEvent'
|
||||
@@ -94,8 +96,12 @@ export * from './Event/SubscriptionRevertRequestedEvent'
|
||||
export * from './Event/SubscriptionRevertRequestedEventPayload'
|
||||
export * from './Event/SubscriptionSyncRequestedEvent'
|
||||
export * from './Event/SubscriptionSyncRequestedEventPayload'
|
||||
export * from './Event/TransitionRequestedEvent'
|
||||
export * from './Event/TransitionRequestedEventPayload'
|
||||
export * from './Event/TransitionStatusUpdatedEvent'
|
||||
export * from './Event/TransitionStatusUpdatedEventPayload'
|
||||
export * from './Event/UserAddedToSharedVaultEvent'
|
||||
export * from './Event/UserAddedToSharedVaultEventPayload'
|
||||
export * from './Event/UserDisabledSessionUserAgentLoggingEvent'
|
||||
export * from './Event/UserDisabledSessionUserAgentLoggingEventPayload'
|
||||
export * from './Event/UserEmailChangedEvent'
|
||||
@@ -104,6 +110,8 @@ export * from './Event/UserInvitedToSharedVaultEvent'
|
||||
export * from './Event/UserInvitedToSharedVaultEventPayload'
|
||||
export * from './Event/UserRegisteredEvent'
|
||||
export * from './Event/UserRegisteredEventPayload'
|
||||
export * from './Event/UserRemovedFromSharedVaultEvent'
|
||||
export * from './Event/UserRemovedFromSharedVaultEventPayload'
|
||||
export * from './Event/UserRolesChangedEvent'
|
||||
export * from './Event/UserRolesChangedEventPayload'
|
||||
export * from './Event/WebSocketMessageRequestedEvent'
|
||||
|
||||
@@ -3,6 +3,42 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.11.40](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.39...@standardnotes/event-store@1.11.40) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.39](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.38...@standardnotes/event-store@1.11.39) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.38](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.37...@standardnotes/event-store@1.11.38) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.37](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.36...@standardnotes/event-store@1.11.37) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.36](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.35...@standardnotes/event-store@1.11.36) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.35](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.34...@standardnotes/event-store@1.11.35) (2023-09-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.34](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.33...@standardnotes/event-store@1.11.34) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.33](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.32...@standardnotes/event-store@1.11.33) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.32](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.31...@standardnotes/event-store@1.11.32) (2023-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.31](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.30...@standardnotes/event-store@1.11.31) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user