mirror of
https://github.com/standardnotes/server
synced 2026-03-26 03:01:13 -04:00
Compare commits
18 Commits
@standardn
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0055edc3e4 | ||
|
|
2742075edc | ||
|
|
7f16232f8b | ||
|
|
0b0703e6d1 | ||
|
|
3e376c44e3 | ||
|
|
bfe2d4bb4a | ||
|
|
7253a0a1d9 | ||
|
|
f2c5810023 | ||
|
|
2e5b9105b8 | ||
|
|
d14411d72e | ||
|
|
5226513b26 | ||
|
|
334449f8aa | ||
|
|
7f43d0c69d | ||
|
|
6f18276e7a | ||
|
|
9ff18a18a5 | ||
|
|
999e72fb1f | ||
|
|
4733e663a3 | ||
|
|
b48eeb16c3 |
6
.github/workflows/common-docker-image.yml
vendored
6
.github/workflows/common-docker-image.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
key: ${{ runner.os }}-${{ inputs.service_name }}-build-${{ github.sha }}
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
run: yarn build
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
|
||||
- name: Login to Amazon ECR
|
||||
id: login-ecr
|
||||
uses: aws-actions/amazon-ecr-login@v1
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@master
|
||||
|
||||
2
.github/workflows/common-self-hosting.yml
vendored
2
.github/workflows/common-self-hosting.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
2
.github/workflows/e2e-home-server.yml
vendored
2
.github/workflows/e2e-home-server.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
2
.github/workflows/e2e-self-hosted.yml
vendored
2
.github/workflows/e2e-self-hosted.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
6
.github/workflows/pr.yml
vendored
6
.github/workflows/pr.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
10
.github/workflows/publish.yml
vendored
10
.github/workflows/publish.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
git config --global user.email "ci@standardnotes.com"
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v5
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.PASSPHRASE }}
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
git_commit_gpgsign: true
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
12
.pnp.cjs
generated
12
.pnp.cjs
generated
@@ -5566,7 +5566,7 @@ const RAW_RUNTIME_STATE =
|
||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
||||
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.17"],\
|
||||
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
|
||||
["ua-parser-js", "npm:1.0.35"],\
|
||||
["ua-parser-js", "npm:1.0.37"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["winston", "npm:3.9.0"]\
|
||||
],\
|
||||
@@ -5785,7 +5785,6 @@ const RAW_RUNTIME_STATE =
|
||||
["@standardnotes/syncing-server", "workspace:packages/syncing-server"],\
|
||||
["@types/cors", "npm:2.8.13"],\
|
||||
["@types/express", "npm:4.17.17"],\
|
||||
["@types/prettyjson", "npm:0.0.30"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||
["@typescript-eslint/parser", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:6.5.0"],\
|
||||
["cors", "npm:2.8.5"],\
|
||||
@@ -5798,7 +5797,6 @@ const RAW_RUNTIME_STATE =
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["inversify-express-utils", "npm:6.4.3"],\
|
||||
["prettier", "npm:3.0.3"],\
|
||||
["prettyjson", "npm:1.2.5"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
|
||||
["winston", "npm:3.9.0"]\
|
||||
@@ -6080,7 +6078,7 @@ const RAW_RUNTIME_STATE =
|
||||
["ts-jest", "virtual:fd909b174d079e30b336c4ce72c38a88c1e447767b1a8dd7655e07719a1e31b97807f0931368724fc78897ff15e6a6d00b83316c0f76d11f85111f342e08bb79#npm:29.1.0"],\
|
||||
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.17"],\
|
||||
["typescript", "patch:typescript@npm%3A5.0.4#optional!builtin<compat/typescript>::version=5.0.4&hash=b5f058"],\
|
||||
["ua-parser-js", "npm:1.0.35"],\
|
||||
["ua-parser-js", "npm:1.0.37"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["winston", "npm:3.9.0"]\
|
||||
],\
|
||||
@@ -16149,10 +16147,10 @@ const RAW_RUNTIME_STATE =
|
||||
}]\
|
||||
]],\
|
||||
["ua-parser-js", [\
|
||||
["npm:1.0.35", {\
|
||||
"packageLocation": "./.yarn/cache/ua-parser-js-npm-1.0.35-38ecdb7612-b69c99c20f.zip/node_modules/ua-parser-js/",\
|
||||
["npm:1.0.37", {\
|
||||
"packageLocation": "./.yarn/cache/ua-parser-js-npm-1.0.37-b79655e1b5-56508f2428.zip/node_modules/ua-parser-js/",\
|
||||
"packageDependencies": [\
|
||||
["ua-parser-js", "npm:1.0.35"]\
|
||||
["ua-parser-js", "npm:1.0.37"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
|
||||
Binary file not shown.
BIN
.yarn/cache/ua-parser-js-npm-1.0.37-b79655e1b5-56508f2428.zip
vendored
Normal file
BIN
.yarn/cache/ua-parser-js-npm-1.0.37-b79655e1b5-56508f2428.zip
vendored
Normal file
Binary file not shown.
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.81.8](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.7...@standardnotes/api-gateway@1.81.8) (2023-11-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* retry attempts on session validation and more verbose logs ([#898](https://github.com/standardnotes/api-gateway/issues/898)) ([3e376c4](https://github.com/standardnotes/api-gateway/commit/3e376c44e3a6c336dcff3d8ef5eb3ab040d9a561))
|
||||
|
||||
## [1.81.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.81.6...@standardnotes/api-gateway@1.81.7) (2023-10-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.81.7",
|
||||
"version": "1.81.8",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -74,13 +74,16 @@ export abstract class AuthMiddleware extends BaseMiddleware {
|
||||
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)
|
||||
: (error as Error).message
|
||||
let detailedErrorMessage = (error as Error).message
|
||||
if (error instanceof AxiosError) {
|
||||
detailedErrorMessage = `Status: ${error.status}, code: ${error.code}, message: ${error.message}`
|
||||
}
|
||||
|
||||
this.logger.error(`Could not pass the request to sessions/validate on underlying service: ${errorMessage}`)
|
||||
this.logger.error(
|
||||
`Could not pass the request to sessions/validate on underlying service: ${detailedErrorMessage}`,
|
||||
)
|
||||
|
||||
this.logger.debug('Response error: %O', (error as AxiosError).response ?? error)
|
||||
this.logger.debug(`Response error: ${JSON.stringify(error)}`)
|
||||
|
||||
if ((error as AxiosError).response?.headers['content-type']) {
|
||||
response.setHeader('content-type', (error as AxiosError).response?.headers['content-type'] as string)
|
||||
@@ -91,7 +94,14 @@ export abstract class AuthMiddleware extends BaseMiddleware {
|
||||
? +((error as AxiosError).code as string)
|
||||
: 500
|
||||
|
||||
response.status(errorCode).send(errorMessage)
|
||||
const responseErrorMessage = (error as AxiosError).response?.data
|
||||
|
||||
response
|
||||
.status(errorCode)
|
||||
.send(
|
||||
responseErrorMessage ??
|
||||
"Unfortunately, we couldn't handle your request. Please try again or contact our support if the error persists.",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -55,10 +55,9 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
const requestTimedOut =
|
||||
'code' in (error as Record<string, unknown>) && (error as Record<string, unknown>).code === 'ETIMEDOUT'
|
||||
const requestDidNotMakeIt = this.requestTimedOutOrDidNotReachDestination(error as Record<string, unknown>)
|
||||
const tooManyRetryAttempts = retryAttempt && retryAttempt > 2
|
||||
if (!tooManyRetryAttempts && requestTimedOut) {
|
||||
if (!tooManyRetryAttempts && requestDidNotMakeIt) {
|
||||
await this.timer.sleep(50)
|
||||
|
||||
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
|
||||
|
||||
@@ -50,7 +50,13 @@ export interface ServiceProxyInterface {
|
||||
endpointOrMethodIdentifier: string,
|
||||
payload?: Record<string, unknown> | string,
|
||||
): Promise<void>
|
||||
validateSession(headers: { authorization: string; sharedVaultOwnerContext?: string }): Promise<{
|
||||
validateSession(
|
||||
headers: {
|
||||
authorization: string
|
||||
sharedVaultOwnerContext?: string
|
||||
},
|
||||
retryAttempt?: number,
|
||||
): Promise<{
|
||||
status: number
|
||||
data: unknown
|
||||
headers: {
|
||||
|
||||
@@ -9,10 +9,13 @@ export class DirectCallServiceProxy implements ServiceProxyInterface {
|
||||
private filesServerUrl: string,
|
||||
) {}
|
||||
|
||||
async validateSession(headers: {
|
||||
authorization: string
|
||||
sharedVaultOwnerContext?: string
|
||||
}): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
|
||||
async validateSession(
|
||||
headers: {
|
||||
authorization: string
|
||||
sharedVaultOwnerContext?: string
|
||||
},
|
||||
_retryAttempt?: number,
|
||||
): Promise<{ status: number; data: unknown; headers: { contentType: string } }> {
|
||||
const authService = this.serviceContainer.get(ServiceIdentifier.create(ServiceIdentifier.NAMES.Auth).getValue())
|
||||
if (!authService) {
|
||||
throw new Error('Auth service not found')
|
||||
|
||||
@@ -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.165.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.1...@standardnotes/auth-server@1.165.2) (2023-11-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** change log severity on user authentication ([7f16232](https://github.com/standardnotes/server/commit/7f16232f8b13e3736801b6dc0af799e0559a3cfa))
|
||||
|
||||
## [1.165.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.165.0...@standardnotes/auth-server@1.165.1) (2023-11-03)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* retry attempts on session validation and more verbose logs ([#898](https://github.com/standardnotes/server/issues/898)) ([3e376c4](https://github.com/standardnotes/server/commit/3e376c44e3a6c336dcff3d8ef5eb3ab040d9a561))
|
||||
|
||||
# [1.165.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.164.2...@standardnotes/auth-server@1.165.0) (2023-11-02)
|
||||
|
||||
### Features
|
||||
|
||||
* add shared vault invitation email notifications ([#897](https://github.com/standardnotes/server/issues/897)) ([7253a0a](https://github.com/standardnotes/server/commit/7253a0a1d92099df844c9baf6541b440bbcb0a68))
|
||||
|
||||
## [1.164.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.164.1...@standardnotes/auth-server@1.164.2) (2023-11-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.164.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.164.0...@standardnotes/auth-server@1.164.1) (2023-11-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** creating valet tokens for shared subscription users ([#895](https://github.com/standardnotes/server/issues/895)) ([b48eeb1](https://github.com/standardnotes/server/commit/b48eeb16c32031e73e9757e34c4b50ca0a3a773d))
|
||||
|
||||
# [1.164.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.163.2...@standardnotes/auth-server@1.164.0) (2023-11-01)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.164.0",
|
||||
"version": "1.165.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -275,6 +275,7 @@ import { SettingPersistenceMapper } from '../Mapping/Persistence/SettingPersiste
|
||||
import { SubscriptionSettingPersistenceMapper } from '../Mapping/Persistence/SubscriptionSettingPersistenceMapper'
|
||||
import { ApplyDefaultSettings } from '../Domain/UseCase/ApplyDefaultSettings/ApplyDefaultSettings'
|
||||
import { AuthResponseFactoryResolverInterface } from '../Domain/Auth/AuthResponseFactoryResolverInterface'
|
||||
import { UserInvitedToSharedVaultEventHandler } from '../Domain/Handler/UserInvitedToSharedVaultEventHandler'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
constructor(private mode: 'server' | 'worker' = 'server') {}
|
||||
@@ -1449,6 +1450,15 @@ export class ContainerConfigLoader {
|
||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<UserInvitedToSharedVaultEventHandler>(TYPES.Auth_UserInvitedToSharedVaultEventHandler)
|
||||
.toConstantValue(
|
||||
new UserInvitedToSharedVaultEventHandler(
|
||||
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||
),
|
||||
)
|
||||
|
||||
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
||||
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Auth_AccountDeletionRequestedEventHandler)],
|
||||
@@ -1484,6 +1494,7 @@ export class ContainerConfigLoader {
|
||||
'USER_DESIGNATED_AS_SURVIVOR_IN_SHARED_VAULT',
|
||||
container.get(TYPES.Auth_UserDesignatedAsSurvivorInSharedVaultEventHandler),
|
||||
],
|
||||
['USER_INVITED_TO_SHARED_VAULT', container.get(TYPES.Auth_UserInvitedToSharedVaultEventHandler)],
|
||||
])
|
||||
|
||||
if (isConfiguredForHomeServer) {
|
||||
|
||||
@@ -195,6 +195,7 @@ const TYPES = {
|
||||
Auth_UserDesignatedAsSurvivorInSharedVaultEventHandler: Symbol.for(
|
||||
'Auth_UserDesignatedAsSurvivorInSharedVaultEventHandler',
|
||||
),
|
||||
Auth_UserInvitedToSharedVaultEventHandler: Symbol.for('Auth_UserInvitedToSharedVaultEventHandler'),
|
||||
// Services
|
||||
Auth_DeviceDetector: Symbol.for('Auth_DeviceDetector'),
|
||||
Auth_SessionService: Symbol.for('Auth_SessionService'),
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { html } from './user-invited-to-shared-vault.html'
|
||||
|
||||
export function getSubject(): string {
|
||||
return "You're Invited to a Shared Vault!"
|
||||
}
|
||||
|
||||
export function getBody(): string {
|
||||
return html()
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
export const html = (newEmail: string) => `
|
||||
<p>Dear User,</p>
|
||||
<p>We trust you're doing well. We are writing to inform you that your request to update your email address in our application has been successfully processed. Your email address associated with your Standard Notes account has now been changed to the following:</p>
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>We are writing to inform you that your request to update your email address has been successfully processed. The email address associated with your Standard Notes account has now been changed to the following:</p>
|
||||
<p>New Email Address: ${newEmail}</p>
|
||||
<p>We understand that email address changes may occur for various reasons, and we appreciate your diligence in ensuring your account information is up to date.</p>
|
||||
<p>From now on, you can log in to your account using your new email address. Your password and all other account details remain the same. If you did not initiate this change or have any concerns about the update, please contact our support team by visiting our <a href="https://standardnotes.com/help">help page</a>
|
||||
|
||||
<p>From now on, you can log in to your account using your new email address. Your password and all other account details remain the same. If you did not initiate this change or have any concerns about this update, please contact our support team by visiting our <a href="https://standardnotes.com/help">help page</a>
|
||||
or by replying directly to this email.</p>
|
||||
<p>We thank you for choosing Standard Notes, and we are committed to providing you with the best experience possible. Should you have any questions or require further assistance, please do not hesitate to reach out to our support team.</p>
|
||||
<p>Your satisfaction and security are our top priorities, and we appreciate your continued trust in our services.</p>
|
||||
|
||||
<p>Best regards,</p>
|
||||
<p>
|
||||
Standard Notes
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
export const html = () => `
|
||||
<p>Hello,</p>
|
||||
|
||||
<p>You've been invited to join a shared vault. This shared workspace will help you collaborate and securely manage notes and files.</p>
|
||||
|
||||
<p>To accept this invitation and access the shared vault, please follow these steps:</p>
|
||||
|
||||
<ol>
|
||||
<li>Go to your account settings.</li>
|
||||
<li>Navigate to the "Vaults" section.</li>
|
||||
<li>You will find the invitation there — simply click to accept.</li>
|
||||
</ol>
|
||||
|
||||
<p>If you have any questions, please contact our support team by visiting our <a href="https://standardnotes.com/help">help page</a>
|
||||
or by replying directly to this email.</p>
|
||||
|
||||
<p>Best regards,</p>
|
||||
<p>
|
||||
Standard Notes
|
||||
</p>
|
||||
`
|
||||
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
DomainEventHandlerInterface,
|
||||
DomainEventPublisherInterface,
|
||||
UserInvitedToSharedVaultEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { EmailLevel, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
||||
import { getBody, getSubject } from '../Email/UserInvitedToSharedVault'
|
||||
|
||||
export class UserInvitedToSharedVaultEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private userRepository: UserRepositoryInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
) {}
|
||||
|
||||
async handle(event: UserInvitedToSharedVaultEvent): Promise<void> {
|
||||
const userUuidOrError = Uuid.create(event.payload.invite.user_uuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const user = await this.userRepository.findOneByUuid(userUuid)
|
||||
if (!user) {
|
||||
return
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createEmailRequestedEvent({
|
||||
body: getBody(),
|
||||
level: EmailLevel.LEVELS.System,
|
||||
subject: getSubject(),
|
||||
messageIdentifier: 'USER_INVITED_TO_SHARED_VAULT',
|
||||
userEmail: user.email,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ export class AuthenticateRequest implements UseCaseInterface {
|
||||
|
||||
async execute(dto: AuthenticateRequestDTO): Promise<AuthenticateRequestResponse> {
|
||||
if (!dto.authorizationHeader) {
|
||||
this.logger.debug('Authorization header not provided.')
|
||||
this.logger.debug('[authenticate-request] Authorization header not provided.')
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -32,7 +32,9 @@ export class AuthenticateRequest implements UseCaseInterface {
|
||||
token: dto.authorizationHeader.replace('Bearer ', ''),
|
||||
})
|
||||
} catch (error) {
|
||||
this.logger.error('Error occurred during authentication of a user %o', error)
|
||||
this.logger.error(
|
||||
`[authenticate-request] Error occurred during authentication of a user ${(error as Error).message}`,
|
||||
)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
|
||||
@@ -23,6 +23,8 @@ describe('AuthenticateUser', () => {
|
||||
beforeEach(() => {
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.debug = jest.fn()
|
||||
logger.error = jest.fn()
|
||||
logger.warn = jest.fn()
|
||||
|
||||
user = {} as jest.Mocked<User>
|
||||
user.supportsSessions = jest.fn().mockReturnValue(false)
|
||||
|
||||
@@ -24,7 +24,7 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
async execute(dto: AuthenticateUserDTO): Promise<AuthenticateUserResponse> {
|
||||
const authenticationMethod = await this.authenticationMethodResolver.resolve(dto.token)
|
||||
if (!authenticationMethod) {
|
||||
this.logger.debug('No authentication method found for token.')
|
||||
this.logger.debug(`[authenticate-user] No authentication method found for token: ${dto.token}`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -33,6 +33,8 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
}
|
||||
|
||||
if (authenticationMethod.type === 'revoked') {
|
||||
this.logger.debug(`[authenticate-user] Session has been revoked: ${dto.token}`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
failureType: 'REVOKED_SESSION',
|
||||
@@ -41,7 +43,7 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
|
||||
const user = authenticationMethod.user
|
||||
if (!user) {
|
||||
this.logger.debug('No user found for authentication method.')
|
||||
this.logger.debug(`[authenticate-user] No user found for authentication method. Token: ${dto.token}`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -50,7 +52,9 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
}
|
||||
|
||||
if (authenticationMethod.type == 'jwt' && user.supportsSessions()) {
|
||||
this.logger.debug('User supports sessions but is trying to authenticate with a JWT.')
|
||||
this.logger.debug(
|
||||
`[authenticate-user][${user.uuid}] User supports sessions but is trying to authenticate with a JWT.`,
|
||||
)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -64,7 +68,7 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
const encryptedPasswordDigest = crypto.createHash('sha256').update(user.encryptedPassword).digest('hex')
|
||||
|
||||
if (!pwHash || !crypto.timingSafeEqual(Buffer.from(pwHash), Buffer.from(encryptedPasswordDigest))) {
|
||||
this.logger.debug('Password hash does not match.')
|
||||
this.logger.debug(`[authenticate-user][${user.uuid}] Password hash does not match.`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -76,7 +80,7 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
case 'session_token': {
|
||||
const session = authenticationMethod.session
|
||||
if (!session) {
|
||||
this.logger.debug('No session found for authentication method.')
|
||||
this.logger.debug(`[authenticate-user][${user.uuid}] No session found for authentication method.`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -85,7 +89,7 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
}
|
||||
|
||||
if (session.refreshExpiration < this.timer.getUTCDate()) {
|
||||
this.logger.debug('Session refresh token has expired.')
|
||||
this.logger.debug(`[authenticate-user][${user.uuid}] Session refresh token has expired.`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -94,6 +98,8 @@ export class AuthenticateUser implements UseCaseInterface {
|
||||
}
|
||||
|
||||
if (this.sessionIsExpired(session)) {
|
||||
this.logger.debug(`[authenticate-user][${user.uuid}] Session access token has expired.`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
failureType: 'EXPIRED_TOKEN',
|
||||
|
||||
@@ -12,6 +12,7 @@ import { GetRegularSubscriptionForUser } from '../GetRegularSubscriptionForUser/
|
||||
import { GetSharedSubscriptionForUser } from '../GetSharedSubscriptionForUser/GetSharedSubscriptionForUser'
|
||||
import { GetSubscriptionSetting } from '../GetSubscriptionSetting/GetSubscriptionSetting'
|
||||
import { SettingName } from '@standardnotes/domain-core'
|
||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||
|
||||
export class CreateValetToken implements UseCaseInterface {
|
||||
constructor(
|
||||
@@ -27,8 +28,17 @@ export class CreateValetToken implements UseCaseInterface {
|
||||
async execute(dto: CreateValetTokenDTO): Promise<CreateValetTokenResponseData> {
|
||||
const { userUuid, ...payload } = dto
|
||||
|
||||
let sharedSubscription: UserSubscription | undefined
|
||||
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
|
||||
userUuid,
|
||||
})
|
||||
if (!sharedSubscriptionOrError.isFailed()) {
|
||||
sharedSubscription = sharedSubscriptionOrError.getValue()
|
||||
}
|
||||
|
||||
const regularSubscriptionOrError = await this.getRegularSubscription.execute({
|
||||
userUuid: dto.userUuid,
|
||||
userUuid: sharedSubscription ? undefined : dto.userUuid,
|
||||
subscriptionId: sharedSubscription ? (sharedSubscription.subscriptionId as number) : undefined,
|
||||
})
|
||||
if (regularSubscriptionOrError.isFailed()) {
|
||||
return {
|
||||
@@ -77,22 +87,13 @@ export class CreateValetToken implements UseCaseInterface {
|
||||
uploadBytesLimit = +(overwriteWithUserUploadBytesLimitSetting.setting.props.value as string)
|
||||
}
|
||||
|
||||
let sharedSubscriptionUuid = undefined
|
||||
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
|
||||
userUuid,
|
||||
})
|
||||
if (!sharedSubscriptionOrError.isFailed()) {
|
||||
const sharedSubscription = sharedSubscriptionOrError.getValue()
|
||||
sharedSubscriptionUuid = sharedSubscription.uuid
|
||||
}
|
||||
|
||||
const tokenData: ValetTokenData = {
|
||||
userUuid: dto.userUuid,
|
||||
permittedOperation: dto.operation,
|
||||
permittedResources: dto.resources,
|
||||
uploadBytesUsed,
|
||||
uploadBytesLimit,
|
||||
sharedSubscriptionUuid,
|
||||
sharedSubscriptionUuid: sharedSubscription ? sharedSubscription.uuid : undefined,
|
||||
regularSubscriptionUuid: regularSubscription.uuid,
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('GetRegularSubscriptionForUser', () => {
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
|
||||
it('returns regular subscription when user subscription is regular', async () => {
|
||||
it('returns regular subscription for user uuid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({ userUuid: '00000000-0000-0000-0000-000000000000' })
|
||||
@@ -43,4 +43,31 @@ describe('GetRegularSubscriptionForUser', () => {
|
||||
expect(result.isFailed()).toBe(false)
|
||||
expect(result.getValue()).toBe(regularSubscription)
|
||||
})
|
||||
|
||||
it('returns regular subscription for shared subscription id', async () => {
|
||||
const useCase = createUseCase()
|
||||
userSubscriptionRepository.findBySubscriptionIdAndType = jest.fn().mockResolvedValue([regularSubscription])
|
||||
|
||||
const result = await useCase.execute({ subscriptionId: 1 })
|
||||
|
||||
expect(result.isFailed()).toBe(false)
|
||||
expect(result.getValue()).toBe(regularSubscription)
|
||||
})
|
||||
|
||||
it('returns error if subscription for shared subscription id is not found', async () => {
|
||||
const useCase = createUseCase()
|
||||
userSubscriptionRepository.findBySubscriptionIdAndType = jest.fn().mockResolvedValue([])
|
||||
|
||||
const result = await useCase.execute({ subscriptionId: 1 })
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
|
||||
it('returns error if no parameters are specified', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -9,7 +9,18 @@ export class GetRegularSubscriptionForUser implements UseCaseInterface<UserSubsc
|
||||
constructor(private userSubscriptionRepository: UserSubscriptionRepositoryInterface) {}
|
||||
|
||||
async execute(dto: GetRegularSubscriptionForUserDTO): Promise<Result<UserSubscription>> {
|
||||
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||
if (dto.userUuid !== undefined) {
|
||||
return this.getRegularSubscriptionForUser(dto.userUuid)
|
||||
}
|
||||
if (dto.subscriptionId !== undefined) {
|
||||
return this.getRegularSubscriptionForSharedSubscription(dto.subscriptionId)
|
||||
}
|
||||
|
||||
return Result.fail('Invalid parameters.')
|
||||
}
|
||||
|
||||
private async getRegularSubscriptionForUser(userUuidString: string): Promise<Result<UserSubscription>> {
|
||||
const userUuidOrError = Uuid.create(userUuidString)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return Result.fail(`Could not get regular subscription for user: ${userUuidOrError.getError()}`)
|
||||
}
|
||||
@@ -25,4 +36,16 @@ export class GetRegularSubscriptionForUser implements UseCaseInterface<UserSubsc
|
||||
|
||||
return Result.ok(userSubscription)
|
||||
}
|
||||
|
||||
private async getRegularSubscriptionForSharedSubscription(subscriptionId: number): Promise<Result<UserSubscription>> {
|
||||
const userSubscription = await this.userSubscriptionRepository.findBySubscriptionIdAndType(
|
||||
subscriptionId,
|
||||
UserSubscriptionType.Regular,
|
||||
)
|
||||
if (userSubscription.length === 0) {
|
||||
return Result.fail(`User subscription for shared subscription ${subscriptionId} not found.`)
|
||||
}
|
||||
|
||||
return Result.ok(userSubscription[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export interface GetRegularSubscriptionForUserDTO {
|
||||
userUuid: string
|
||||
userUuid?: string
|
||||
subscriptionId?: number
|
||||
}
|
||||
|
||||
@@ -31,9 +31,19 @@ export class UpdateStorageQuotaUsedForUser implements UseCaseInterface<void> {
|
||||
return Result.fail(`Could not find user with uuid: ${userUuid.value}`)
|
||||
}
|
||||
|
||||
const regularSubscriptionOrError = await this.getRegularSubscription.execute({
|
||||
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
|
||||
userUuid: user.uuid,
|
||||
})
|
||||
let sharedSubscription: UserSubscription | undefined
|
||||
if (!sharedSubscriptionOrError.isFailed()) {
|
||||
sharedSubscription = sharedSubscriptionOrError.getValue()
|
||||
await this.updateUploadBytesUsedSetting(sharedSubscription, dto.bytesUsed)
|
||||
}
|
||||
|
||||
const regularSubscriptionOrError = await this.getRegularSubscription.execute({
|
||||
userUuid: sharedSubscription ? undefined : user.uuid,
|
||||
subscriptionId: sharedSubscription ? (sharedSubscription.subscriptionId as number) : undefined,
|
||||
})
|
||||
if (regularSubscriptionOrError.isFailed()) {
|
||||
return Result.fail(`Could not find regular user subscription for user with uuid: ${userUuid.value}`)
|
||||
}
|
||||
@@ -41,14 +51,6 @@ export class UpdateStorageQuotaUsedForUser implements UseCaseInterface<void> {
|
||||
|
||||
await this.updateUploadBytesUsedSetting(regularSubscription, dto.bytesUsed)
|
||||
|
||||
const sharedSubscriptionOrError = await this.getSharedSubscription.execute({
|
||||
userUuid: user.uuid,
|
||||
})
|
||||
if (!sharedSubscriptionOrError.isFailed()) {
|
||||
const sharedSubscription = sharedSubscriptionOrError.getValue()
|
||||
await this.updateUploadBytesUsedSetting(sharedSubscription, dto.bytesUsed)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.18.20](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.19...@standardnotes/home-server@1.18.20) (2023-11-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.18.19](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.18...@standardnotes/home-server@1.18.19) (2023-11-03)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.18.18](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.17...@standardnotes/home-server@1.18.18) (2023-11-02)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.18.17](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.16...@standardnotes/home-server@1.18.17) (2023-11-02)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **home-server:** remove unused dep ([2e5b910](https://github.com/standardnotes/server/commit/2e5b9105b8462385f060ed5a4ff8301c675e81b2))
|
||||
|
||||
## [1.18.16](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.15...@standardnotes/home-server@1.18.16) (2023-11-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.18.15](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.14...@standardnotes/home-server@1.18.15) (2023-11-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.18.14](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.18.13...@standardnotes/home-server@1.18.14) (2023-11-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/home-server",
|
||||
"version": "1.18.14",
|
||||
"version": "1.18.20",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
@@ -35,14 +35,12 @@
|
||||
"helmet": "^7.0.0",
|
||||
"inversify": "^6.0.1",
|
||||
"inversify-express-utils": "^6.4.3",
|
||||
"prettyjson": "^1.2.5",
|
||||
"reflect-metadata": "0.1.13",
|
||||
"winston": "^3.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.9",
|
||||
"@types/express": "^4.17.14",
|
||||
"@types/prettyjson": "^0.0.30",
|
||||
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
||||
"@typescript-eslint/parser": "^6.5.0",
|
||||
"eslint": "^8.39.0",
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.120.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.119.4...@standardnotes/syncing-server@1.120.0) (2023-11-02)
|
||||
|
||||
### Features
|
||||
|
||||
* add shared vault invitation email notifications ([#897](https://github.com/standardnotes/syncing-server-js/issues/897)) ([7253a0a](https://github.com/standardnotes/syncing-server-js/commit/7253a0a1d92099df844c9baf6541b440bbcb0a68))
|
||||
|
||||
## [1.119.4](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.119.3...@standardnotes/syncing-server@1.119.4) (2023-10-31)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.119.4",
|
||||
"version": "1.120.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -652,6 +652,7 @@ export class ContainerConfigLoader {
|
||||
container.get<SharedVaultUserRepositoryInterface>(TYPES.Sync_SharedVaultUserRepository),
|
||||
container.get<TimerInterface>(TYPES.Sync_Timer),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory),
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher),
|
||||
container.get<SendEventToClient>(TYPES.Sync_SendEventToClient),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { Uuid, Timestamps, Result, SharedVaultUserPermission, SharedVaultUser } from '@standardnotes/domain-core'
|
||||
import { UserInvitedToSharedVaultEvent } from '@standardnotes/domain-events'
|
||||
import { DomainEventPublisherInterface, UserInvitedToSharedVaultEvent } from '@standardnotes/domain-events'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
|
||||
@@ -20,6 +20,7 @@ describe('InviteUserToSharedVault', () => {
|
||||
let sharedVault: SharedVault
|
||||
let sharedVaultUser: SharedVaultUser
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
let domainEventPublisher: DomainEventPublisherInterface
|
||||
let sendEventToClientUseCase: SendEventToClient
|
||||
let logger: Logger
|
||||
|
||||
@@ -30,6 +31,7 @@ describe('InviteUserToSharedVault', () => {
|
||||
sharedVaultUserRepository,
|
||||
timer,
|
||||
domainEventFactory,
|
||||
domainEventPublisher,
|
||||
sendEventToClientUseCase,
|
||||
logger,
|
||||
)
|
||||
@@ -67,6 +69,9 @@ describe('InviteUserToSharedVault', () => {
|
||||
type: 'USER_INVITED_TO_SHARED_VAULT',
|
||||
} as jest.Mocked<UserInvitedToSharedVaultEvent>)
|
||||
|
||||
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||
domainEventPublisher.publish = jest.fn()
|
||||
|
||||
sendEventToClientUseCase = {} as jest.Mocked<SendEventToClient>
|
||||
sendEventToClientUseCase.execute = jest.fn().mockReturnValue(Result.ok())
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/Sh
|
||||
import { Logger } from 'winston'
|
||||
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
|
||||
import { SendEventToClient } from '../../Syncing/SendEventToClient/SendEventToClient'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
|
||||
export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvite> {
|
||||
constructor(
|
||||
@@ -17,6 +18,7 @@ export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvi
|
||||
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
|
||||
private timer: TimerInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
private sendEventToClientUseCase: SendEventToClient,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
@@ -101,6 +103,8 @@ export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvi
|
||||
},
|
||||
})
|
||||
|
||||
await this.domainEventPublisher.publish(event)
|
||||
|
||||
const result = await this.sendEventToClientUseCase.execute({
|
||||
userUuid: sharedVaultInvite.props.userUuid.value,
|
||||
event,
|
||||
|
||||
@@ -4588,7 +4588,6 @@ __metadata:
|
||||
"@standardnotes/syncing-server": "workspace:^"
|
||||
"@types/cors": "npm:^2.8.9"
|
||||
"@types/express": "npm:^4.17.14"
|
||||
"@types/prettyjson": "npm:^0.0.30"
|
||||
"@typescript-eslint/eslint-plugin": "npm:^6.5.0"
|
||||
"@typescript-eslint/parser": "npm:^6.5.0"
|
||||
cors: "npm:2.8.5"
|
||||
@@ -4601,7 +4600,6 @@ __metadata:
|
||||
inversify: "npm:^6.0.1"
|
||||
inversify-express-utils: "npm:^6.4.3"
|
||||
prettier: "npm:^3.0.3"
|
||||
prettyjson: "npm:^1.2.5"
|
||||
reflect-metadata: "npm:0.1.13"
|
||||
typescript: "npm:^5.0.4"
|
||||
winston: "npm:^3.8.1"
|
||||
@@ -13486,9 +13484,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"ua-parser-js@npm:^1.0.35":
|
||||
version: 1.0.35
|
||||
resolution: "ua-parser-js@npm:1.0.35"
|
||||
checksum: b69c99c20f90e1d441939be591a3e4c848d12b88671953fc0de7664bdcdb660f4e9db236099ae966cfb20504d8894825bbdee0fcc31326f2823bf439eadfc02c
|
||||
version: 1.0.37
|
||||
resolution: "ua-parser-js@npm:1.0.37"
|
||||
checksum: 56508f2428ebac64382c4d41da14189e5013e3e2a5f5918aff4bee3ba77df1f4eaad6f81f90c24999f1cf12cc1596764684497fec07e0ff5182ce9a323a8c05b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user