mirror of
https://github.com/standardnotes/server
synced 2026-04-20 20:02:34 -04:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d1d6c753c4 | |||
| 3bd63f7674 | |||
| 376466d9b2 | |||
| e100c52bbc | |||
| d4830dec01 | |||
| 7e11821021 | |||
| 4715e019a2 | |||
| 794cd8734a | |||
| 14d42b26bb | |||
| 6bb44afd91 | |||
| c82345aeeb | |||
| 72ab08a0d0 | |||
| f2d1b47e40 | |||
| d9ee2c5be2 |
@@ -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.
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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.6",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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.2",
|
||||
"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)
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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
|
||||
|
||||
@@ -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,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.138.2",
|
||||
"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,6 +264,14 @@ 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 {
|
||||
async load(configuration?: {
|
||||
@@ -372,6 +381,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 +424,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 +483,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)
|
||||
@@ -926,6 +951,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 +1112,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 +1160,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) {
|
||||
|
||||
@@ -18,6 +18,7 @@ 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
|
||||
@@ -64,6 +65,7 @@ export class AppDataSource {
|
||||
TypeORMAuthenticatorChallenge,
|
||||
TypeORMEmergencyAccessInvitation,
|
||||
TypeORMCacheEntry,
|
||||
TypeORMSharedVaultUser,
|
||||
],
|
||||
migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
|
||||
migrationsRun: true,
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
+44
-1
@@ -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',
|
||||
},
|
||||
@@ -115,6 +134,12 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '1-3-4',
|
||||
},
|
||||
],
|
||||
belongs_to_shared_vaults: [
|
||||
{
|
||||
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
},
|
||||
],
|
||||
session: {
|
||||
test: 'test',
|
||||
},
|
||||
@@ -141,6 +166,12 @@ 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',
|
||||
@@ -164,6 +195,12 @@ 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',
|
||||
@@ -208,6 +245,12 @@ describe('CreateCrossServiceToken', () => {
|
||||
uuid: '1-3-4',
|
||||
},
|
||||
],
|
||||
belongs_to_shared_vaults: [
|
||||
{
|
||||
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||
permission: 'read',
|
||||
},
|
||||
],
|
||||
session: {
|
||||
test: 'test',
|
||||
},
|
||||
|
||||
@@ -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>> {
|
||||
@@ -49,11 +51,19 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
||||
|
||||
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',
|
||||
belongs_to_shared_vaults: sharedVaultAssociations.map((association) => ({
|
||||
shared_vault_uuid: association.props.sharedVaultUuid.value,
|
||||
permission: association.props.permission.value,
|
||||
})),
|
||||
}
|
||||
|
||||
if (dto.sharedVaultOwnerContext !== undefined) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [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.0",
|
||||
"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}`)
|
||||
}
|
||||
|
||||
|
||||
+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,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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.23",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [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.124.0",
|
||||
"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,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'
|
||||
@@ -96,6 +98,8 @@ export * from './Event/SubscriptionSyncRequestedEvent'
|
||||
export * from './Event/SubscriptionSyncRequestedEventPayload'
|
||||
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 +108,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,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.11.31",
|
||||
"version": "1.11.34",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.22.13](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.12...@standardnotes/files-server@1.22.13) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.22.12](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.11...@standardnotes/files-server@1.22.12) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.22.11](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.10...@standardnotes/files-server@1.22.11) (2023-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.22.10](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.9...@standardnotes/files-server@1.22.10) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.22.10",
|
||||
"version": "1.22.13",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.15.27](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.26...@standardnotes/home-server@1.15.27) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.26](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.25...@standardnotes/home-server@1.15.26) (2023-09-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.25](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.24...@standardnotes/home-server@1.15.25) (2023-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.24](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.23...@standardnotes/home-server@1.15.24) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.23](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.22...@standardnotes/home-server@1.15.23) (2023-09-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/home-server",
|
||||
"version": "1.15.23",
|
||||
"version": "1.15.27",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -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.33.0](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.32.0...@standardnotes/revisions-server@1.33.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))
|
||||
|
||||
# [1.32.0](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.31.0...@standardnotes/revisions-server@1.32.0) (2023-09-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **revisions:** query for shared vault revisions ([7e11821](https://github.com/standardnotes/server/commit/7e11821021a663fcf452ad8bb03eda33c03fe221))
|
||||
|
||||
### Features
|
||||
|
||||
* **revisions:** fetching single revision in shared vault ([#810](https://github.com/standardnotes/server/issues/810)) ([e100c52](https://github.com/standardnotes/server/commit/e100c52bbc07447188af3b9a04f3744401dac0ab))
|
||||
|
||||
# [1.31.0](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.30.14...@standardnotes/revisions-server@1.31.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.30.14](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.30.13...@standardnotes/revisions-server@1.30.14) (2023-09-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent doubling transitions ([d9ee2c5](https://github.com/standardnotes/server/commit/d9ee2c5be2d81c729c829e6078846df624d500bd))
|
||||
|
||||
## [1.30.13](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.30.12...@standardnotes/revisions-server@1.30.13) (2023-09-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class init1669113322388 implements MigrationInterface {
|
||||
name = 'init1669113322388'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await this.syncSchemaBetweenLegacyRevisions(queryRunner)
|
||||
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE IF NOT EXISTS `revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `content` mediumtext NULL, `content_type` varchar(255) NULL, `items_key_id` varchar(255) NULL, `enc_item_key` text NULL, `auth_hash` varchar(255) NULL, `creation_date` date NULL, `created_at` datetime(6) NULL, `updated_at` datetime(6) NULL, INDEX `item_uuid` (`item_uuid`), INDEX `user_uuid` (`user_uuid`), INDEX `creation_date` (`creation_date`), INDEX `created_at` (`created_at`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `created_at` ON `revisions`')
|
||||
await queryRunner.query('DROP INDEX `creation_date` ON `revisions`')
|
||||
await queryRunner.query('DROP INDEX `user_uuid` ON `revisions`')
|
||||
await queryRunner.query('DROP INDEX `item_uuid` ON `revisions`')
|
||||
await queryRunner.query('DROP TABLE `revisions`')
|
||||
}
|
||||
|
||||
private async syncSchemaBetweenLegacyRevisions(queryRunner: QueryRunner): Promise<void> {
|
||||
const revisionsTableExistsQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "revisions"',
|
||||
)
|
||||
const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
|
||||
if (!revisionsTableExists) {
|
||||
return
|
||||
}
|
||||
|
||||
const revisionsTableHasUserUuidColumnQueryResult = await queryRunner.manager.query(
|
||||
'SELECT COUNT(*) as count FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = "revisions" AND column_name = "user_uuid"',
|
||||
)
|
||||
const revisionsTableHasUserUuidColumn = revisionsTableHasUserUuidColumnQueryResult[0].count === 1
|
||||
if (revisionsTableHasUserUuidColumn) {
|
||||
return
|
||||
}
|
||||
|
||||
await queryRunner.query('ALTER TABLE `revisions` ADD COLUMN `user_uuid` varchar(36) NULL')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class removeDateIndexes1669636497932 implements MigrationInterface {
|
||||
name = 'removeDateIndexes1669636497932'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
const indexRevisionsOnCreatedAt = await queryRunner.manager.query(
|
||||
'SHOW INDEX FROM `revisions` where `key_name` = "created_at"',
|
||||
)
|
||||
const indexRevisionsOnCreatedAtExist = indexRevisionsOnCreatedAt && indexRevisionsOnCreatedAt.length > 0
|
||||
if (indexRevisionsOnCreatedAtExist) {
|
||||
await queryRunner.query('DROP INDEX `created_at` ON `revisions`')
|
||||
}
|
||||
|
||||
const indexRevisionsOnCreationDate = await queryRunner.manager.query(
|
||||
'SHOW INDEX FROM `revisions` where `key_name` = "creation_date"',
|
||||
)
|
||||
const indexRevisionsOnCreationDateAtExist = indexRevisionsOnCreationDate && indexRevisionsOnCreationDate.length > 0
|
||||
if (indexRevisionsOnCreationDateAtExist) {
|
||||
await queryRunner.query('DROP INDEX `creation_date` ON `revisions`')
|
||||
}
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('CREATE INDEX `creation_date` ON `revisions` (`creation_date`)')
|
||||
await queryRunner.query('CREATE INDEX `created_at` ON `revisions` (`created_at`)')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class makeUserUuidNullable1669735585016 implements MigrationInterface {
|
||||
name = 'makeUserUuidNullable1669735585016'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `revisions` CHANGE `user_uuid` `user_uuid` varchar(36) NULL')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `revisions` CHANGE `user_uuid` `user_uuid` varchar(36) NOT NULL')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultInformation1693915383950 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `revisions` ADD `edited_by` varchar(36) NULL')
|
||||
await queryRunner.query('ALTER TABLE `revisions` ADD `shared_vault_uuid` varchar(36) NULL')
|
||||
await queryRunner.query('ALTER TABLE `revisions` ADD `key_system_identifier` varchar(36) NULL')
|
||||
await queryRunner.query('CREATE INDEX `index_revisions_on_shared_vault_uuid` ON `revisions` (`shared_vault_uuid`)')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX `index_revisions_on_shared_vault_uuid` ON `revisions`')
|
||||
await queryRunner.query('ALTER TABLE `revisions` DROP COLUMN `key_system_identifier`')
|
||||
await queryRunner.query('ALTER TABLE `revisions` DROP COLUMN `shared_vault_uuid`')
|
||||
await queryRunner.query('ALTER TABLE `revisions` DROP COLUMN `last_edited_by`')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class AddSharedVaultInformation1693915775491 implements MigrationInterface {
|
||||
name = 'AddSharedVaultInformation1693915775491'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX "user_uuid"')
|
||||
await queryRunner.query('DROP INDEX "item_uuid"')
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE "temporary_revisions" ("uuid" varchar PRIMARY KEY NOT NULL, "item_uuid" varchar(36) NOT NULL, "user_uuid" varchar(36), "content" text, "content_type" varchar(255), "items_key_id" varchar(255), "enc_item_key" text, "auth_hash" varchar(255), "creation_date" date, "created_at" datetime(6), "updated_at" datetime(6), "edited_by" varchar(36), "shared_vault_uuid" varchar(36), "key_system_identifier" varchar(36))',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'INSERT INTO "temporary_revisions"("uuid", "item_uuid", "user_uuid", "content", "content_type", "items_key_id", "enc_item_key", "auth_hash", "creation_date", "created_at", "updated_at") SELECT "uuid", "item_uuid", "user_uuid", "content", "content_type", "items_key_id", "enc_item_key", "auth_hash", "creation_date", "created_at", "updated_at" FROM "revisions"',
|
||||
)
|
||||
await queryRunner.query('DROP TABLE "revisions"')
|
||||
await queryRunner.query('ALTER TABLE "temporary_revisions" RENAME TO "revisions"')
|
||||
await queryRunner.query('CREATE INDEX "user_uuid" ON "revisions" ("user_uuid") ')
|
||||
await queryRunner.query('CREATE INDEX "item_uuid" ON "revisions" ("item_uuid") ')
|
||||
await queryRunner.query('CREATE INDEX "index_revisions_on_shared_vault_uuid" ON "revisions" ("shared_vault_uuid") ')
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DROP INDEX "index_revisions_on_shared_vault_uuid"')
|
||||
await queryRunner.query('DROP INDEX "item_uuid"')
|
||||
await queryRunner.query('DROP INDEX "user_uuid"')
|
||||
await queryRunner.query('ALTER TABLE "revisions" RENAME TO "temporary_revisions"')
|
||||
await queryRunner.query(
|
||||
'CREATE TABLE "revisions" ("uuid" varchar PRIMARY KEY NOT NULL, "item_uuid" varchar(36) NOT NULL, "user_uuid" varchar(36), "content" text, "content_type" varchar(255), "items_key_id" varchar(255), "enc_item_key" text, "auth_hash" varchar(255), "creation_date" date, "created_at" datetime(6), "updated_at" datetime(6))',
|
||||
)
|
||||
await queryRunner.query(
|
||||
'INSERT INTO "revisions"("uuid", "item_uuid", "user_uuid", "content", "content_type", "items_key_id", "enc_item_key", "auth_hash", "creation_date", "created_at", "updated_at") SELECT "uuid", "item_uuid", "user_uuid", "content", "content_type", "items_key_id", "enc_item_key", "auth_hash", "creation_date", "created_at", "updated_at" FROM "temporary_revisions"',
|
||||
)
|
||||
await queryRunner.query('DROP TABLE "temporary_revisions"')
|
||||
await queryRunner.query('CREATE INDEX "item_uuid" ON "revisions" ("item_uuid") ')
|
||||
await queryRunner.query('CREATE INDEX "user_uuid" ON "revisions" ("user_uuid") ')
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/revisions-server",
|
||||
"version": "1.30.13",
|
||||
"version": "1.33.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -7,8 +7,8 @@ import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
|
||||
import { Revision } from '../Domain/Revision/Revision'
|
||||
import { RevisionMetadata } from '../Domain/Revision/RevisionMetadata'
|
||||
import { RevisionRepositoryInterface } from '../Domain/Revision/RevisionRepositoryInterface'
|
||||
import { SQLRevisionRepository } from '../Infra/TypeORM/SQL/SQLRevisionRepository'
|
||||
import { SQLRevision } from '../Infra/TypeORM/SQL/SQLRevision'
|
||||
import { SQLLegacyRevisionRepository } from '../Infra/TypeORM/SQL/SQLLegacyRevisionRepository'
|
||||
import { SQLLegacyRevision } from '../Infra/TypeORM/SQL/SQLLegacyRevision'
|
||||
import { AppDataSource } from './DataSource'
|
||||
import { Env } from './Env'
|
||||
import TYPES from './Types'
|
||||
@@ -48,8 +48,8 @@ import { BaseRevisionsController } from '../Infra/InversifyExpress/Base/BaseRevi
|
||||
import { Transform } from 'stream'
|
||||
import { MongoDBRevision } from '../Infra/TypeORM/MongoDB/MongoDBRevision'
|
||||
import { MongoDBRevisionRepository } from '../Infra/TypeORM/MongoDB/MongoDBRevisionRepository'
|
||||
import { SQLRevisionMetadataPersistenceMapper } from '../Mapping/Persistence/SQL/SQLRevisionMetadataPersistenceMapper'
|
||||
import { SQLRevisionPersistenceMapper } from '../Mapping/Persistence/SQL/SQLRevisionPersistenceMapper'
|
||||
import { SQLLegacyRevisionMetadataPersistenceMapper } from '../Mapping/Persistence/SQL/SQLLegacyRevisionMetadataPersistenceMapper'
|
||||
import { SQLLegacyRevisionPersistenceMapper } from '../Mapping/Persistence/SQL/SQLLegacyRevisionPersistenceMapper'
|
||||
import { MongoDBRevisionMetadataPersistenceMapper } from '../Mapping/Persistence/MongoDB/MongoDBRevisionMetadataPersistenceMapper'
|
||||
import { MongoDBRevisionPersistenceMapper } from '../Mapping/Persistence/MongoDB/MongoDBRevisionPersistenceMapper'
|
||||
import { RevisionHttpMapper } from '../Mapping/Http/RevisionHttpMapper'
|
||||
@@ -62,6 +62,12 @@ import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryI
|
||||
import { DomainEventFactory } from '../Domain/Event/DomainEventFactory'
|
||||
import { TransitionStatusUpdatedEventHandler } from '../Domain/Handler/TransitionStatusUpdatedEventHandler'
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from '../Domain/UseCase/Transition/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { SQLRevision } from '../Infra/TypeORM/SQL/SQLRevision'
|
||||
import { SQLRevisionRepository } from '../Infra/TypeORM/SQL/SQLRevisionRepository'
|
||||
import { SQLRevisionMetadataPersistenceMapper } from '../Mapping/Persistence/SQL/SQLRevisionMetadataPersistenceMapper'
|
||||
import { SQLRevisionPersistenceMapper } from '../Mapping/Persistence/SQL/SQLRevisionPersistenceMapper'
|
||||
import { RemoveRevisionsFromSharedVault } from '../Domain/UseCase/RemoveRevisionsFromSharedVault/RemoveRevisionsFromSharedVault'
|
||||
import { ItemRemovedFromSharedVaultEventHandler } from '../Domain/Handler/ItemRemovedFromSharedVaultEventHandler'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
async load(configuration?: {
|
||||
@@ -77,6 +83,8 @@ export class ContainerConfigLoader {
|
||||
env.load()
|
||||
|
||||
const isConfiguredForHomeServer = env.get('MODE', true) === 'home-server'
|
||||
const isConfiguredForSelfHosting = env.get('MODE', true) === 'self-hosted'
|
||||
const isConfiguredForHomeServerOrSelfHosting = isConfiguredForHomeServer || isConfiguredForSelfHosting
|
||||
const isSecondaryDatabaseEnabled = env.get('SECONDARY_DB_ENABLED', true) === 'true'
|
||||
|
||||
const container = new Container({
|
||||
@@ -197,9 +205,17 @@ export class ContainerConfigLoader {
|
||||
.toConstantValue(new DomainEventFactory(container.get(TYPES.Revisions_Timer)))
|
||||
|
||||
// Map
|
||||
container
|
||||
.bind<MapperInterface<RevisionMetadata, SQLLegacyRevision>>(
|
||||
TYPES.Revisions_SQLLegacyRevisionMetadataPersistenceMapper,
|
||||
)
|
||||
.toConstantValue(new SQLLegacyRevisionMetadataPersistenceMapper())
|
||||
container
|
||||
.bind<MapperInterface<RevisionMetadata, SQLRevision>>(TYPES.Revisions_SQLRevisionMetadataPersistenceMapper)
|
||||
.toConstantValue(new SQLRevisionMetadataPersistenceMapper())
|
||||
container
|
||||
.bind<MapperInterface<Revision, SQLLegacyRevision>>(TYPES.Revisions_SQLLegacyRevisionPersistenceMapper)
|
||||
.toConstantValue(new SQLLegacyRevisionPersistenceMapper())
|
||||
container
|
||||
.bind<MapperInterface<Revision, SQLRevision>>(TYPES.Revisions_SQLRevisionPersistenceMapper)
|
||||
.toConstantValue(new SQLRevisionPersistenceMapper())
|
||||
@@ -213,22 +229,36 @@ export class ContainerConfigLoader {
|
||||
.toConstantValue(new MongoDBRevisionPersistenceMapper())
|
||||
|
||||
// ORM
|
||||
container
|
||||
.bind<Repository<SQLLegacyRevision>>(TYPES.Revisions_ORMLegacyRevisionRepository)
|
||||
.toDynamicValue(() => appDataSource.getRepository(SQLLegacyRevision))
|
||||
container
|
||||
.bind<Repository<SQLRevision>>(TYPES.Revisions_ORMRevisionRepository)
|
||||
.toDynamicValue(() => appDataSource.getRepository(SQLRevision))
|
||||
.toConstantValue(appDataSource.getRepository(SQLRevision))
|
||||
|
||||
// Repositories
|
||||
container
|
||||
.bind<RevisionRepositoryInterface>(TYPES.Revisions_SQLRevisionRepository)
|
||||
.toConstantValue(
|
||||
new SQLRevisionRepository(
|
||||
container.get<Repository<SQLRevision>>(TYPES.Revisions_ORMRevisionRepository),
|
||||
container.get<MapperInterface<RevisionMetadata, SQLRevision>>(
|
||||
TYPES.Revisions_SQLRevisionMetadataPersistenceMapper,
|
||||
),
|
||||
container.get<MapperInterface<Revision, SQLRevision>>(TYPES.Revisions_SQLRevisionPersistenceMapper),
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
isConfiguredForHomeServerOrSelfHosting
|
||||
? new SQLRevisionRepository(
|
||||
container.get<Repository<SQLRevision>>(TYPES.Revisions_ORMRevisionRepository),
|
||||
container.get<MapperInterface<RevisionMetadata, SQLRevision>>(
|
||||
TYPES.Revisions_SQLRevisionMetadataPersistenceMapper,
|
||||
),
|
||||
container.get<MapperInterface<Revision, SQLRevision>>(TYPES.Revisions_SQLRevisionPersistenceMapper),
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
)
|
||||
: new SQLLegacyRevisionRepository(
|
||||
container.get<Repository<SQLLegacyRevision>>(TYPES.Revisions_ORMLegacyRevisionRepository),
|
||||
container.get<MapperInterface<RevisionMetadata, SQLLegacyRevision>>(
|
||||
TYPES.Revisions_SQLLegacyRevisionMetadataPersistenceMapper,
|
||||
),
|
||||
container.get<MapperInterface<Revision, SQLLegacyRevision>>(
|
||||
TYPES.Revisions_SQLLegacyRevisionPersistenceMapper,
|
||||
),
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
|
||||
if (isSecondaryDatabaseEnabled) {
|
||||
@@ -330,6 +360,13 @@ export class ContainerConfigLoader {
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Revisions_DomainEventFactory),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<RemoveRevisionsFromSharedVault>(TYPES.Revisions_RemoveRevisionsFromSharedVault)
|
||||
.toConstantValue(
|
||||
new RemoveRevisionsFromSharedVault(
|
||||
container.get<RevisionRepositoryResolverInterface>(TYPES.Revisions_RevisionRepositoryResolver),
|
||||
),
|
||||
)
|
||||
|
||||
// env vars
|
||||
container.bind(TYPES.Revisions_AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
|
||||
@@ -409,12 +446,21 @@ export class ContainerConfigLoader {
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<ItemRemovedFromSharedVaultEventHandler>(TYPES.Revisions_ItemRemovedFromSharedVaultEventHandler)
|
||||
.toConstantValue(
|
||||
new ItemRemovedFromSharedVaultEventHandler(
|
||||
container.get<RemoveRevisionsFromSharedVault>(TYPES.Revisions_RemoveRevisionsFromSharedVault),
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
|
||||
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
||||
['ITEM_DUMPED', container.get(TYPES.Revisions_ItemDumpedEventHandler)],
|
||||
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Revisions_AccountDeletionRequestedEventHandler)],
|
||||
['REVISIONS_COPY_REQUESTED', container.get(TYPES.Revisions_RevisionsCopyRequestedEventHandler)],
|
||||
['TRANSITION_STATUS_UPDATED', container.get(TYPES.Revisions_TransitionStatusUpdatedEventHandler)],
|
||||
['ITEM_REMOVED_FROM_SHARED_VAULT', container.get(TYPES.Revisions_ItemRemovedFromSharedVaultEventHandler)],
|
||||
])
|
||||
|
||||
if (isConfiguredForHomeServer) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { DataSource, EntityTarget, LoggerOptions, MongoRepository, ObjectLiteral, Repository } from 'typeorm'
|
||||
import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'
|
||||
|
||||
import { SQLRevision } from '../Infra/TypeORM/SQL/SQLRevision'
|
||||
import { SQLLegacyRevision } from '../Infra/TypeORM/SQL/SQLLegacyRevision'
|
||||
|
||||
import { Env } from './Env'
|
||||
import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
|
||||
import { MongoDBRevision } from '../Infra/TypeORM/MongoDB/MongoDBRevision'
|
||||
import { SQLRevision } from '../Infra/TypeORM/SQL/SQLRevision'
|
||||
|
||||
export class AppDataSource {
|
||||
private _dataSource: DataSource | undefined
|
||||
@@ -65,14 +66,23 @@ export class AppDataSource {
|
||||
|
||||
const isConfiguredForMySQL = this.env.get('DB_TYPE') === 'mysql'
|
||||
|
||||
const isConfiguredForHomeServerOrSelfHosting =
|
||||
this.env.get('MODE', true) === 'home-server' || this.env.get('MODE', true) === 'self-hosted'
|
||||
|
||||
const maxQueryExecutionTime = this.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
? +this.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
|
||||
: 45_000
|
||||
|
||||
const migrationsSourceDirectoryName = isConfiguredForMySQL
|
||||
? isConfiguredForHomeServerOrSelfHosting
|
||||
? 'mysql'
|
||||
: 'mysql-legacy'
|
||||
: 'sqlite'
|
||||
|
||||
const commonDataSourceOptions = {
|
||||
maxQueryExecutionTime,
|
||||
entities: [SQLRevision],
|
||||
migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
|
||||
entities: [isConfiguredForHomeServerOrSelfHosting ? SQLRevision : SQLLegacyRevision],
|
||||
migrations: [`${__dirname}/../../migrations/${migrationsSourceDirectoryName}/*.js`],
|
||||
migrationsRun: true,
|
||||
logging: <LoggerOptions>this.env.get('DB_DEBUG_LEVEL', true) ?? 'info',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import { AppDataSource } from './DataSource'
|
||||
import { Env } from './Env'
|
||||
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
export const MigrationsDataSource = new AppDataSource(env).dataSource
|
||||
@@ -6,7 +6,11 @@ const TYPES = {
|
||||
Revisions_S3: Symbol.for('Revisions_S3'),
|
||||
Revisions_Env: Symbol.for('Revisions_Env'),
|
||||
// Map
|
||||
Revisions_SQLLegacyRevisionMetadataPersistenceMapper: Symbol.for(
|
||||
'Revisions_SQLLegacyRevisionMetadataPersistenceMapper',
|
||||
),
|
||||
Revisions_SQLRevisionMetadataPersistenceMapper: Symbol.for('Revisions_SQLRevisionMetadataPersistenceMapper'),
|
||||
Revisions_SQLLegacyRevisionPersistenceMapper: Symbol.for('Revisions_SQLLegacyRevisionPersistenceMapper'),
|
||||
Revisions_SQLRevisionPersistenceMapper: Symbol.for('Revisions_SQLRevisionPersistenceMapper'),
|
||||
Revisions_MongoDBRevisionMetadataPersistenceMapper: Symbol.for('Revisions_MongoDBRevisionMetadataPersistenceMapper'),
|
||||
Revisions_MongoDBRevisionPersistenceMapper: Symbol.for('Revisions_MongoDBRevisionPersistenceMapper'),
|
||||
@@ -15,6 +19,7 @@ const TYPES = {
|
||||
Revisions_RevisionMetadataHttpMapper: Symbol.for('Revisions_RevisionMetadataHttpMapper'),
|
||||
// ORM
|
||||
Revisions_ORMRevisionRepository: Symbol.for('Revisions_ORMRevisionRepository'),
|
||||
Revisions_ORMLegacyRevisionRepository: Symbol.for('Revisions_ORMLegacyRevisionRepository'),
|
||||
// Mongo
|
||||
Revisions_ORMMongoRevisionRepository: Symbol.for('Revisions_ORMMongoRevisionRepository'),
|
||||
// Repositories
|
||||
@@ -44,6 +49,7 @@ const TYPES = {
|
||||
Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser: Symbol.for(
|
||||
'Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser',
|
||||
),
|
||||
Revisions_RemoveRevisionsFromSharedVault: Symbol.for('Revisions_RemoveRevisionsFromSharedVault'),
|
||||
// Controller
|
||||
Revisions_ControllerContainer: Symbol.for('Revisions_ControllerContainer'),
|
||||
Revisions_RevisionsController: Symbol.for('Revisions_RevisionsController'),
|
||||
@@ -53,6 +59,7 @@ const TYPES = {
|
||||
Revisions_AccountDeletionRequestedEventHandler: Symbol.for('Revisions_AccountDeletionRequestedEventHandler'),
|
||||
Revisions_RevisionsCopyRequestedEventHandler: Symbol.for('Revisions_RevisionsCopyRequestedEventHandler'),
|
||||
Revisions_TransitionStatusUpdatedEventHandler: Symbol.for('Revisions_TransitionStatusUpdatedEventHandler'),
|
||||
Revisions_ItemRemovedFromSharedVaultEventHandler: Symbol.for('Revisions_ItemRemovedFromSharedVaultEventHandler'),
|
||||
// Services
|
||||
Revisions_CrossServiceTokenDecoder: Symbol.for('Revisions_CrossServiceTokenDecoder'),
|
||||
Revisions_DomainEventSubscriberFactory: Symbol.for('Revisions_DomainEventSubscriberFactory'),
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { DomainEventHandlerInterface, ItemRemovedFromSharedVaultEvent } from '@standardnotes/domain-events'
|
||||
import { RemoveRevisionsFromSharedVault } from '../UseCase/RemoveRevisionsFromSharedVault/RemoveRevisionsFromSharedVault'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
export class ItemRemovedFromSharedVaultEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private removeRevisionsFromSharedVault: RemoveRevisionsFromSharedVault,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async handle(event: ItemRemovedFromSharedVaultEvent): Promise<void> {
|
||||
const result = await this.removeRevisionsFromSharedVault.execute({
|
||||
sharedVaultUuid: event.payload.sharedVaultUuid,
|
||||
itemUuid: event.payload.itemUuid,
|
||||
roleNames: event.payload.roleNames,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to remove revisions from shared vault: ${result.getError()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface KeySystemAssociationProps {
|
||||
keySystemIdentifier: string
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { KeySystemAssociation } from './KeySystemAssociation'
|
||||
|
||||
describe('KeySystemAssociation', () => {
|
||||
it('should create a value object', () => {
|
||||
const entityOrError = KeySystemAssociation.create('00000000-0000-0000-0000-000000000000')
|
||||
|
||||
expect(entityOrError.isFailed()).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should fail to create a value object with an empty key system identifier', () => {
|
||||
const entityOrError = KeySystemAssociation.create('')
|
||||
|
||||
expect(entityOrError.isFailed()).toBeTruthy()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Result, Validator, ValueObject } from '@standardnotes/domain-core'
|
||||
|
||||
import { KeySystemAssociationProps } from './KeySystemAssocationProps'
|
||||
|
||||
export class KeySystemAssociation extends ValueObject<KeySystemAssociationProps> {
|
||||
private constructor(props: KeySystemAssociationProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static create(keySystemIdentifier: string): Result<KeySystemAssociation> {
|
||||
const validationResult = Validator.isNotEmptyString(keySystemIdentifier)
|
||||
if (validationResult.isFailed()) {
|
||||
return Result.fail<KeySystemAssociation>(validationResult.getError())
|
||||
}
|
||||
|
||||
return Result.ok<KeySystemAssociation>(new KeySystemAssociation({ keySystemIdentifier }))
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import { ContentType, Dates, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultAssociation } from '../SharedVault/SharedVaultAssociation'
|
||||
import { KeySystemAssociation } from '../KeySystem/KeySystemAssociation'
|
||||
|
||||
export interface RevisionProps {
|
||||
itemUuid: Uuid
|
||||
userUuid: Uuid | null
|
||||
@@ -10,4 +13,6 @@ export interface RevisionProps {
|
||||
authHash: string | null
|
||||
creationDate: Date
|
||||
dates: Dates
|
||||
sharedVaultAssociation?: SharedVaultAssociation
|
||||
keySystemAssociation?: KeySystemAssociation
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ export interface RevisionRepositoryInterface {
|
||||
countByUserUuid(userUuid: Uuid): Promise<number>
|
||||
removeByUserUuid(userUuid: Uuid): Promise<void>
|
||||
removeOneByUuid(revisionUuid: Uuid, userUuid: Uuid): Promise<void>
|
||||
findOneByUuid(revisionUuid: Uuid, userUuid: Uuid): Promise<Revision | null>
|
||||
findOneByUuid(revisionUuid: Uuid, userUuid: Uuid, sharedVaultUuids: Uuid[]): Promise<Revision | null>
|
||||
findByItemUuid(itemUuid: Uuid): Promise<Array<Revision>>
|
||||
findMetadataByItemId(itemUuid: Uuid, userUuid: Uuid): Promise<Array<RevisionMetadata>>
|
||||
findMetadataByItemId(itemUuid: Uuid, userUuid: Uuid, sharedVaultUuids: Uuid[]): Promise<Array<RevisionMetadata>>
|
||||
updateUserUuid(itemUuid: Uuid, userUuid: Uuid): Promise<void>
|
||||
findByUserUuid(dto: { userUuid: Uuid; offset?: number; limit?: number }): Promise<Array<Revision>>
|
||||
insert(revision: Revision): Promise<boolean>
|
||||
clearSharedVaultAndKeySystemAssociations(itemUuid: Uuid, sharedVaultUuid: Uuid): Promise<void>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultAssociation } from './SharedVaultAssociation'
|
||||
|
||||
describe('SharedVaultAssociation', () => {
|
||||
it('should create a value object', () => {
|
||||
const entityOrError = SharedVaultAssociation.create({
|
||||
editedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
})
|
||||
|
||||
expect(entityOrError.isFailed()).toBeFalsy()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Result, ValueObject } from '@standardnotes/domain-core'
|
||||
|
||||
import { SharedVaultAssociationProps } from './SharedVaultAssociationProps'
|
||||
|
||||
export class SharedVaultAssociation extends ValueObject<SharedVaultAssociationProps> {
|
||||
private constructor(props: SharedVaultAssociationProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static create(props: SharedVaultAssociationProps): Result<SharedVaultAssociation> {
|
||||
return Result.ok<SharedVaultAssociation>(new SharedVaultAssociation(props))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export interface SharedVaultAssociationProps {
|
||||
editedBy: Uuid
|
||||
sharedVaultUuid: Uuid
|
||||
}
|
||||
@@ -22,17 +22,30 @@ describe('GetRevision', () => {
|
||||
revisionUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: ['84c0f8e8-544a-4c7e-9adf-26209303bc1d'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(result.getValue()).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should do nothing if shared vault uuid is invalid', async () => {
|
||||
const result = await createUseCase().execute({
|
||||
revisionUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: ['INVALID_SHARED_VAULT_UUID'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should do nothing if role names are not valid', async () => {
|
||||
const result = await createUseCase().execute({
|
||||
revisionUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['INVALID_ROLE_NAME'],
|
||||
sharedVaultUuids: ['84c0f8e8-544a-4c7e-9adf-26209303bc1d'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
@@ -45,6 +58,7 @@ describe('GetRevision', () => {
|
||||
revisionUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: ['84c0f8e8-544a-4c7e-9adf-26209303bc1d'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
@@ -55,6 +69,7 @@ describe('GetRevision', () => {
|
||||
revisionUuid: '1-2-3',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: ['84c0f8e8-544a-4c7e-9adf-26209303bc1d'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
@@ -65,6 +80,7 @@ describe('GetRevision', () => {
|
||||
userUuid: '1-2-3',
|
||||
revisionUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: ['84c0f8e8-544a-4c7e-9adf-26209303bc1d'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
|
||||
@@ -26,9 +26,18 @@ export class GetRevision implements UseCaseInterface<Revision> {
|
||||
}
|
||||
const roleNames = roleNamesOrError.getValue()
|
||||
|
||||
const sharedVaultUuids = []
|
||||
for (const sharedVaultUuid of dto.sharedVaultUuids) {
|
||||
const sharedVaultUuidOrError = Uuid.create(sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
return Result.fail(`Could not get revision: ${sharedVaultUuidOrError.getError()}`)
|
||||
}
|
||||
sharedVaultUuids.push(sharedVaultUuidOrError.getValue())
|
||||
}
|
||||
|
||||
const revisionRepository = this.revisionRepositoryResolver.resolve(roleNames)
|
||||
|
||||
const revision = await revisionRepository.findOneByUuid(revisionUuid, userUuid)
|
||||
const revision = await revisionRepository.findOneByUuid(revisionUuid, userUuid, sharedVaultUuids)
|
||||
|
||||
if (revision === null) {
|
||||
return Result.fail<Revision>(`Could not find revision with uuid: ${revisionUuid.value}`)
|
||||
|
||||
@@ -2,4 +2,5 @@ export interface GetRevisionDTO {
|
||||
userUuid: string
|
||||
revisionUuid: string
|
||||
roleNames: string[]
|
||||
sharedVaultUuids: string[]
|
||||
}
|
||||
|
||||
@@ -22,17 +22,30 @@ describe('GetRevisionsMetada', () => {
|
||||
itemUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: ['84c0f8e8-544a-4c7e-9adf-26209303bc1d'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(result.getValue().length).toEqual(1)
|
||||
})
|
||||
|
||||
it('should not return revisions metadata for an invalid shared vault uuid', async () => {
|
||||
const result = await createUseCase().execute({
|
||||
itemUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: ['1-2-3'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should not return revisions metadata for a an invalid item uuid', async () => {
|
||||
const result = await createUseCase().execute({
|
||||
itemUuid: '1-2-3',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: [],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
@@ -43,6 +56,7 @@ describe('GetRevisionsMetada', () => {
|
||||
userUuid: '1-2-3',
|
||||
itemUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['CORE_USER'],
|
||||
sharedVaultUuids: [],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
@@ -53,6 +67,7 @@ describe('GetRevisionsMetada', () => {
|
||||
itemUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
userUuid: '84c0f8e8-544a-4c7e-9adf-26209303bc1d',
|
||||
roleNames: ['INVALID_ROLE_NAME'],
|
||||
sharedVaultUuids: [],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
|
||||
@@ -19,6 +19,15 @@ export class GetRevisionsMetada implements UseCaseInterface<RevisionMetadata[]>
|
||||
return Result.fail<RevisionMetadata[]>(`Could not get revisions: ${userUuidOrError.getError()}`)
|
||||
}
|
||||
|
||||
const sharedVaultUuids = []
|
||||
for (const sharedVaultUuid of dto.sharedVaultUuids) {
|
||||
const sharedVaultUuidOrError = Uuid.create(sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
return Result.fail<RevisionMetadata[]>(`Could not get revisions: ${sharedVaultUuidOrError.getError()}`)
|
||||
}
|
||||
sharedVaultUuids.push(sharedVaultUuidOrError.getValue())
|
||||
}
|
||||
|
||||
const roleNamesOrError = RoleNameCollection.create(dto.roleNames)
|
||||
if (roleNamesOrError.isFailed()) {
|
||||
return Result.fail(roleNamesOrError.getError())
|
||||
@@ -30,6 +39,7 @@ export class GetRevisionsMetada implements UseCaseInterface<RevisionMetadata[]>
|
||||
const revisionsMetdata = await revisionRepository.findMetadataByItemId(
|
||||
itemUuidOrError.getValue(),
|
||||
userUuidOrError.getValue(),
|
||||
sharedVaultUuids,
|
||||
)
|
||||
|
||||
return Result.ok<RevisionMetadata[]>(revisionsMetdata)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export interface GetRevisionsMetadaDTO {
|
||||
itemUuid: string
|
||||
sharedVaultUuids: string[]
|
||||
userUuid: string
|
||||
roleNames: string[]
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import { RevisionRepositoryInterface } from '../../Revision/RevisionRepositoryInterface'
|
||||
import { RevisionRepositoryResolverInterface } from '../../Revision/RevisionRepositoryResolverInterface'
|
||||
import { RemoveRevisionsFromSharedVault } from './RemoveRevisionsFromSharedVault'
|
||||
|
||||
describe('RemoveRevisionsFromSharedVault', () => {
|
||||
let revisionRepositoryResolver: RevisionRepositoryResolverInterface
|
||||
let revisionRepository: RevisionRepositoryInterface
|
||||
|
||||
const createUseCase = () => new RemoveRevisionsFromSharedVault(revisionRepositoryResolver)
|
||||
|
||||
beforeEach(() => {
|
||||
revisionRepository = {} as jest.Mocked<RevisionRepositoryInterface>
|
||||
revisionRepository.clearSharedVaultAndKeySystemAssociations = jest.fn()
|
||||
|
||||
revisionRepositoryResolver = {} as jest.Mocked<RevisionRepositoryResolverInterface>
|
||||
revisionRepositoryResolver.resolve = jest.fn().mockReturnValue(revisionRepository)
|
||||
})
|
||||
|
||||
it('should clear shared vault and key system associations', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
await useCase.execute({
|
||||
itemUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000001',
|
||||
roleNames: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(revisionRepository.clearSharedVaultAndKeySystemAssociations).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return error when shared vault uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
itemUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: 'invalid',
|
||||
roleNames: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
|
||||
it('should return error when item uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
itemUuid: 'invalid',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000001',
|
||||
roleNames: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
|
||||
it('should return error when role names are invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
itemUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000001',
|
||||
roleNames: ['invalid'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
})
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
import { Result, RoleNameCollection, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { RevisionRepositoryResolverInterface } from '../../Revision/RevisionRepositoryResolverInterface'
|
||||
import { RemoveRevisionsFromSharedVaultDTO } from './RemoveRevisionsFromSharedVaultDTO'
|
||||
|
||||
export class RemoveRevisionsFromSharedVault implements UseCaseInterface<void> {
|
||||
constructor(private revisionRepositoryResolver: RevisionRepositoryResolverInterface) {}
|
||||
|
||||
async execute(dto: RemoveRevisionsFromSharedVaultDTO): Promise<Result<void>> {
|
||||
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultUuidOrError.getError())
|
||||
}
|
||||
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||
|
||||
const itemUuidOrError = Uuid.create(dto.itemUuid)
|
||||
if (itemUuidOrError.isFailed()) {
|
||||
return Result.fail(itemUuidOrError.getError())
|
||||
}
|
||||
const itemUuid = itemUuidOrError.getValue()
|
||||
|
||||
const roleNamesOrError = RoleNameCollection.create(dto.roleNames)
|
||||
if (roleNamesOrError.isFailed()) {
|
||||
return Result.fail(roleNamesOrError.getError())
|
||||
}
|
||||
const roleNames = roleNamesOrError.getValue()
|
||||
|
||||
const revisionRepository = this.revisionRepositoryResolver.resolve(roleNames)
|
||||
|
||||
await revisionRepository.clearSharedVaultAndKeySystemAssociations(itemUuid, sharedVaultUuid)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
export interface RemoveRevisionsFromSharedVaultDTO {
|
||||
itemUuid: string
|
||||
sharedVaultUuid: string
|
||||
roleNames: string[]
|
||||
}
|
||||
+24
-3
@@ -131,7 +131,7 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(2)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(3)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
@@ -344,7 +344,7 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
'Total revisions count for user 00000000-0000-0000-0000-000000000000 in primary database (2) does not match total revisions count in secondary database (1)',
|
||||
)
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(2)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(3)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
@@ -368,7 +368,7 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toEqual('Revision 00000000-0000-0000-0000-000000000001 not found in secondary database')
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(2)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(3)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
@@ -413,4 +413,25 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
expect((secondaryRevisionRepository as RevisionRepositoryInterface).removeByUserUuid).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('should not migrate revisions if there are no revisions in the primary database', async () => {
|
||||
primaryRevisionRepository.countByUserUuid = jest.fn().mockResolvedValue(0)
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledTimes(1)
|
||||
expect(primaryRevisionRepository.countByUserUuid).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
)
|
||||
expect(primaryRevisionRepository.findByUserUuid).not.toHaveBeenCalled()
|
||||
expect((secondaryRevisionRepository as RevisionRepositoryInterface).insert).not.toHaveBeenCalled()
|
||||
expect(primaryRevisionRepository.removeByUserUuid).not.toHaveBeenCalled()
|
||||
expect((secondaryRevisionRepository as RevisionRepositoryInterface).removeByUserUuid).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
+13
-1
@@ -24,6 +24,12 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuid)) {
|
||||
this.logger.info(`Revisions for user ${userUuid.value} are already migrated`)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
const migrationTimeStart = this.timer.getTimestampInMicroseconds()
|
||||
|
||||
this.logger.debug(`Transitioning revisions for user ${userUuid.value}`)
|
||||
@@ -137,6 +143,12 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
await this.timer.sleep(twoSecondsInMilliseconds)
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: Uuid): Promise<boolean> {
|
||||
const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
|
||||
|
||||
return totalRevisionsCountForUserInPrimary === 0
|
||||
}
|
||||
|
||||
private async checkIntegrityBetweenPrimaryAndSecondaryDatabase(userUuid: Uuid): Promise<Result<boolean>> {
|
||||
try {
|
||||
const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
|
||||
@@ -162,7 +174,7 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
|
||||
const revisionInSecondary = await (
|
||||
this.secondRevisionsRepository as RevisionRepositoryInterface
|
||||
).findOneByUuid(revisionUuid, userUuid)
|
||||
).findOneByUuid(revisionUuid, userUuid, [])
|
||||
if (!revisionInSecondary) {
|
||||
return Result.fail(`Revision ${revision.id.toString()} not found in secondary database`)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user