Compare commits

..

27 Commits

Author SHA1 Message Date
standardci
fee1f1a3a7 chore(release): publish new version
- @standardnotes/analytics@2.25.6
 - @standardnotes/api-gateway@1.68.1
 - @standardnotes/auth-server@1.126.5
 - @standardnotes/domain-core@1.24.1
 - @standardnotes/event-store@1.11.13
 - @standardnotes/files-server@1.19.15
 - @standardnotes/home-server@1.13.16
 - @standardnotes/revisions-server@1.25.6
 - @standardnotes/scheduler-server@1.20.15
 - @standardnotes/settings@1.21.20
 - @standardnotes/syncing-server@1.72.1
 - @standardnotes/websockets-server@1.10.8
2023-07-27 11:10:28 +00:00
Karol Sójko
b0fbe0bb58 fix: extended access token refresh ttl during home server e2e 2023-07-27 12:54:50 +02:00
Karol Sójko
0087c70007 fix: missing env var on e2e 2023-07-27 12:25:31 +02:00
Karol Sójko
36e496dd7c fix: remove dns aliases on accessing mysql and redis in home server e2e 2023-07-27 12:19:01 +02:00
Karol Sójko
f2e2030e85 fix: disable fail-fast on common e2e suite 2023-07-27 12:11:38 +02:00
Karol Sójko
0c3737dc19 fix: redirect STDERR for e2e to common output 2023-07-27 12:07:32 +02:00
Karol Sójko
f7471119e1 fix: add logging error stack on home server failure 2023-07-27 12:00:40 +02:00
Karol Sójko
9bd97b95e9 fix: unset the custom dbsqlite path for e2e 2023-07-27 11:46:48 +02:00
Karol Sójko
b7400c198f fix: setting env vars on common-e2e test suite 2023-07-27 11:30:49 +02:00
Karol Sójko
f87036e3a8 fix: setting env vars on home server in e2e environment 2023-07-27 11:26:05 +02:00
Karol Sójko
a43e5ef724 fix: outputing logs on e2e - already existing logs directory 2023-07-27 10:32:43 +02:00
Karol Sójko
913ced70b0 fix: outputing logs on e2e 2023-07-27 08:33:49 +02:00
standardci
6ffce30a36 chore(release): publish new version
- @standardnotes/api-gateway@1.68.0
 - @standardnotes/home-server@1.13.15
 - @standardnotes/syncing-server@1.72.0
2023-07-27 06:28:46 +00:00
Karol Sójko
f5a57d886c fix: show logs on failing suite 2023-07-27 08:13:49 +02:00
Karol Sójko
e8ba49ecca feat(syncing-server): add deleting outbound messages
Co-authored-by: Mo <mo@standardnotes.com>
2023-07-27 08:06:56 +02:00
Karol Sójko
c79a5dc94b fix: add e2e yarn command for convenience 2023-07-26 15:23:08 +02:00
standardci
4db83ae678 chore(release): publish new version
- @standardnotes/analytics@2.25.5
 - @standardnotes/api-gateway@1.67.4
 - @standardnotes/auth-server@1.126.4
 - @standardnotes/domain-core@1.24.0
 - @standardnotes/event-store@1.11.12
 - @standardnotes/files-server@1.19.14
 - @standardnotes/home-server@1.13.14
 - @standardnotes/revisions-server@1.25.5
 - @standardnotes/scheduler-server@1.20.14
 - @standardnotes/settings@1.21.19
 - @standardnotes/syncing-server@1.71.0
 - @standardnotes/websockets-server@1.10.7
2023-07-26 12:07:57 +00:00
basiljelly
84ceb7ffd2 Update docker-compose.example.yml (#673)
added restart policy for container server_self_hosted so it restarts after rebooting system
2023-07-26 13:52:40 +02:00
Karol Sójko
e215ac4343 feat: extract shared vault user permission to domain-core 2023-07-26 13:45:53 +02:00
standardci
bc8048790f chore(release): publish new version
- @standardnotes/home-server@1.13.13
 - @standardnotes/syncing-server@1.70.5
2023-07-26 11:19:11 +00:00
Karol Sójko
886ccf84c1 fix(syncing-server): uuid comparison when removing user 2023-07-26 13:02:03 +02:00
standardci
c067cb9fe4 chore(release): publish new version
- @standardnotes/home-server@1.13.12
 - @standardnotes/syncing-server@1.70.4
2023-07-26 10:54:46 +00:00
Karol Sójko
6b2389cdc3 fix(syncing-serve): removing other users from shared vault 2023-07-26 12:39:24 +02:00
standardci
d93916b159 chore(release): publish new version
- @standardnotes/analytics@2.25.4
 - @standardnotes/api-gateway@1.67.3
 - @standardnotes/auth-server@1.126.3
 - @standardnotes/domain-core@1.23.4
 - @standardnotes/event-store@1.11.11
 - @standardnotes/files-server@1.19.13
 - @standardnotes/home-server@1.13.11
 - @standardnotes/revisions-server@1.25.4
 - @standardnotes/scheduler-server@1.20.13
 - @standardnotes/settings@1.21.18
 - @standardnotes/syncing-server@1.70.3
 - @standardnotes/websockets-server@1.10.6
2023-07-26 10:38:44 +00:00
Karol Sójko
c34f548e45 fix(syncing-server): persisting aggregate changes from root (#674) 2023-07-26 12:23:10 +02:00
standardci
6fcd56cc86 chore(release): publish new version
- @standardnotes/home-server@1.13.10
 - @standardnotes/syncing-server@1.70.2
2023-07-25 14:07:10 +00:00
Karol Sójko
8f88a87c93 fix(syncing-server): remove notifications after adding item to vault (#672) 2023-07-25 15:51:42 +02:00
85 changed files with 1137 additions and 193 deletions

View File

@@ -55,6 +55,7 @@ jobs:
e2e-home-server:
name: (Home Server) E2E Test Suite
strategy:
fail-fast: false
matrix:
db_type: [mysql, sqlite]
cache_type: [redis, memory]
@@ -106,20 +107,21 @@ jobs:
sed -i "s/PSEUDO_KEY_PARAMS_KEY=/PSEUDO_KEY_PARAMS_KEY=$(openssl rand -hex 32)/g" packages/home-server/.env
sed -i "s/VALET_TOKEN_SECRET=/VALET_TOKEN_SECRET=$(openssl rand -hex 32)/g" packages/home-server/.env
echo "ACCESS_TOKEN_AGE=4" >> packages/home-server/.env
echo "REFRESH_TOKEN_AGE=7" >> packages/home-server/.env
echo "REFRESH_TOKEN_AGE=10" >> packages/home-server/.env
echo "REVISIONS_FREQUENCY=5" >> packages/home-server/.env
echo "DB_HOST=db" >> packages/home-server/.env
echo "DB_HOST=localhost" >> packages/home-server/.env
echo "DB_PORT=3306" >> packages/home-server/.env
echo "DB_DATABASE=standardnotes" >> packages/home-server/.env
echo "DB_USERNAME=standardnotes" >> packages/home-server/.env
echo "DB_PASSWORD=standardnotes" >> packages/home-server/.env
echo "DB_TYPE=${{ matrix.db_type }}" >> packages/home-server/.env
echo "REDIS_URL=redis://cache" >> packages/home-server/.env
echo "REDIS_URL=redis://localhost" >> packages/home-server/.env
echo "CACHE_TYPE=${{ matrix.cache_type }}" >> packages/home-server/.env
echo "FILES_SERVER_URL=http://localhost:3123" >> packages/home-server/.env
echo "E2E_TESTING=true" >> packages/home-server/.env
- name: Run Server
run: nohup yarn workspace @standardnotes/home-server start &
run: nohup yarn workspace @standardnotes/home-server start > logs/output.log 2>&1 &
env:
PORT: 3123
@@ -128,3 +130,7 @@ jobs:
- name: Run E2E Test Suite
run: yarn dlx mocha-headless-chrome --timeout 1200000 -f http://localhost:9001/mocha/test.html
- name: Show logs on failure
if: ${{ failure() }}
run: tail -n 500 logs/output.log

View File

@@ -3,6 +3,7 @@ services:
image: standardnotes/server
env_file: .env
container_name: server_self_hosted
restart: unless-stopped
ports:
- 3000:3000
- 3125:3104

View File

@@ -17,7 +17,8 @@
"release": "lerna version --conventional-graduate --conventional-commits --yes -m \"chore(release): publish new version\"",
"publish": "lerna publish from-git --yes --no-verify-access --loglevel verbose",
"postversion": "./scripts/push-tags-one-by-one.sh",
"upgrade:snjs": "yarn workspaces foreach --verbose run upgrade:snjs"
"upgrade:snjs": "yarn workspaces foreach --verbose run upgrade:snjs",
"e2e": "yarn build packages/home-server && PORT=3123 yarn workspace @standardnotes/home-server start"
},
"devDependencies": {
"@commitlint/cli": "^17.0.2",

View File

@@ -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.25.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.5...@standardnotes/analytics@2.25.6) (2023-07-27)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.4...@standardnotes/analytics@2.25.5) (2023-07-26)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.3...@standardnotes/analytics@2.25.4) (2023-07-26)
**Note:** Version bump only for package @standardnotes/analytics
## [2.25.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.2...@standardnotes/analytics@2.25.3) (2023-07-21)
**Note:** Version bump only for package @standardnotes/analytics

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "2.25.3",
"version": "2.25.6",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.68.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.68.0...@standardnotes/api-gateway@1.68.1) (2023-07-27)
**Note:** Version bump only for package @standardnotes/api-gateway
# [1.68.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.4...@standardnotes/api-gateway@1.68.0) (2023-07-27)
### Features
* **syncing-server:** add deleting outbound messages ([e8ba49e](https://github.com/standardnotes/api-gateway/commit/e8ba49ecca38ab10c0ea0e1f4cf4db9fb17366db))
## [1.67.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.3...@standardnotes/api-gateway@1.67.4) (2023-07-26)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.67.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.2...@standardnotes/api-gateway@1.67.3) (2023-07-26)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.67.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.1...@standardnotes/api-gateway@1.67.2) (2023-07-21)
**Note:** Version bump only for package @standardnotes/api-gateway

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.67.2",
"version": "1.68.1",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -83,6 +83,16 @@ export class SharedVaultInvitesController extends BaseHttpController {
)
}
@httpDelete('/invites/outbound')
async deleteOutboundUserInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(
request,
response,
this.endpointResolver.resolveEndpointOrMethodIdentifier('DELETE', 'shared-vaults/invites/outbound'),
request.body,
)
}
@httpGet('/invites/outbound')
async getOutboundUserInvites(request: Request, response: Response): Promise<void> {
await this.httpService.callSyncingServer(

View File

@@ -79,6 +79,7 @@ export class EndpointResolver implements EndpointResolverInterface {
['[POST]:shared-vaults/:sharedVaultUuid/invites/:inviteUuid/accept', 'sync.shared-vault-invites.accept'],
['[POST]:shared-vaults/:sharedVaultUuid/invites/:inviteUuid/decline', 'sync.shared-vault-invites.decline'],
['[DELETE]:shared-vaults/invites/inbound', 'sync.shared-vault-invites.delete-inbound'],
['[DELETE]:shared-vaults/invites/outbound', 'sync.shared-vault-invites.delete-outbound'],
['[GET]:shared-vaults/invites/outbound', 'sync.shared-vault-invites.get-outbound'],
['[GET]:shared-vaults/invites', 'sync.shared-vault-invites.get-user-invites'],
['[GET]:shared-vaults/:sharedVaultUuid/invites', 'sync.shared-vault-invites.get-vault-invites'],

View File

@@ -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.126.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.4...@standardnotes/auth-server@1.126.5) (2023-07-27)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.126.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.3...@standardnotes/auth-server@1.126.4) (2023-07-26)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.126.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.2...@standardnotes/auth-server@1.126.3) (2023-07-26)
**Note:** Version bump only for package @standardnotes/auth-server
## [1.126.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.1...@standardnotes/auth-server@1.126.2) (2023-07-21)
**Note:** Version bump only for package @standardnotes/auth-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.126.2",
"version": "1.126.5",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.24.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.24.0...@standardnotes/domain-core@1.24.1) (2023-07-27)
### Bug Fixes
* setting env vars on home server in e2e environment ([f87036e](https://github.com/standardnotes/server/commit/f87036e3a8dc6b7784e74e5f32ffd220033724f5))
# [1.24.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.23.4...@standardnotes/domain-core@1.24.0) (2023-07-26)
### Features
* extract shared vault user permission to domain-core ([e215ac4](https://github.com/standardnotes/server/commit/e215ac4343e9f8818f40004d31390d6ac23e369d))
## [1.23.4](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.23.3...@standardnotes/domain-core@1.23.4) (2023-07-26)
### Bug Fixes
* **syncing-server:** persisting aggregate changes from root ([#674](https://github.com/standardnotes/server/issues/674)) ([c34f548](https://github.com/standardnotes/server/commit/c34f548e45bbd8defb8d490936e90755fd284e78))
## [1.23.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.23.2...@standardnotes/domain-core@1.23.3) (2023-07-21)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-core",
"version": "1.23.3",
"version": "1.24.1",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -1,5 +1,20 @@
/* istanbul ignore file */
import { Change } from './Change'
import { Entity } from './Entity'
export abstract class Aggregate<T> extends Entity<T> {}
export abstract class Aggregate<T> extends Entity<T> {
private changesOnAggregateRoot: Change[] = []
addChange(change: Change): void {
this.changesOnAggregateRoot.push(change)
}
flushChanges(): void {
this.changesOnAggregateRoot = []
}
getChanges(): Change[] {
return this.changesOnAggregateRoot
}
}

View File

@@ -0,0 +1,26 @@
/* istanbul ignore file */
import { ChangeProps } from './ChangeProps'
import { Result } from './Result'
export class Change {
static readonly TYPES = {
Add: 'add',
Remove: 'remove',
Modify: 'modify',
}
public readonly props: ChangeProps
constructor(props: ChangeProps) {
this.props = Object.freeze(props)
}
static create(props: ChangeProps): Result<Change> {
if (!Object.values(Change.TYPES).includes(props.changeType)) {
return Result.fail('Invalid change type')
}
return Result.ok(new Change(props))
}
}

View File

@@ -0,0 +1,9 @@
/* istanbul ignore file */
import { Entity } from './Entity'
export interface ChangeProps {
aggregateRootUuid: string
changeType: string
changeData: Entity<unknown>
}

View File

@@ -23,4 +23,12 @@ export abstract class AbstractEnv {
return <string>process.env[key]
}
getAll(): { [key: string]: string } {
if (!this.env) {
this.load()
}
return this.env as { [key: string]: string }
}
}

View File

@@ -1,4 +1,5 @@
import { Result, ValueObject } from '@standardnotes/domain-core'
import { Result } from '../Core/Result'
import { ValueObject } from '../Core/ValueObject'
import { SharedVaultUserPermissionProps } from './SharedVaultUserPermissionProps'

View File

@@ -27,6 +27,8 @@ export * from './Common/Uuid'
export * from './Common/UuidProps'
export * from './Core/Aggregate'
export * from './Core/Change'
export * from './Core/ChangeProps'
export * from './Core/Entity'
export * from './Core/Id'
export * from './Core/Result'
@@ -57,6 +59,9 @@ export * from './Service/ServiceIdentifier'
export * from './Service/ServiceIdentifierProps'
export * from './Service/ServiceInterface'
export * from './SharedVault/SharedVaultUserPermission'
export * from './SharedVault/SharedVaultUserPermissionProps'
export * from './Subscription/SubscriptionPlanName'
export * from './Subscription/SubscriptionPlanNameProps'

View File

@@ -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.13](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.12...@standardnotes/event-store@1.11.13) (2023-07-27)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.12](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.11...@standardnotes/event-store@1.11.12) (2023-07-26)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.11](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.10...@standardnotes/event-store@1.11.11) (2023-07-26)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.10](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.9...@standardnotes/event-store@1.11.10) (2023-07-21)
**Note:** Version bump only for package @standardnotes/event-store

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/event-store",
"version": "1.11.10",
"version": "1.11.13",
"description": "Event Store Service",
"private": true,
"main": "dist/src/index.js",

View File

@@ -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.19.15](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.14...@standardnotes/files-server@1.19.15) (2023-07-27)
**Note:** Version bump only for package @standardnotes/files-server
## [1.19.14](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.13...@standardnotes/files-server@1.19.14) (2023-07-26)
**Note:** Version bump only for package @standardnotes/files-server
## [1.19.13](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.12...@standardnotes/files-server@1.19.13) (2023-07-26)
**Note:** Version bump only for package @standardnotes/files-server
## [1.19.12](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.11...@standardnotes/files-server@1.19.12) (2023-07-21)
**Note:** Version bump only for package @standardnotes/files-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files-server",
"version": "1.19.12",
"version": "1.19.15",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,37 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.13.16](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.15...@standardnotes/home-server@1.13.16) (2023-07-27)
### Bug Fixes
* add logging error stack on home server failure ([f747111](https://github.com/standardnotes/server/commit/f7471119e1c4107dd36d37dcda4660870931fc83))
* setting env vars on home server in e2e environment ([f87036e](https://github.com/standardnotes/server/commit/f87036e3a8dc6b7784e74e5f32ffd220033724f5))
## [1.13.15](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.14...@standardnotes/home-server@1.13.15) (2023-07-27)
**Note:** Version bump only for package @standardnotes/home-server
## [1.13.14](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.13...@standardnotes/home-server@1.13.14) (2023-07-26)
**Note:** Version bump only for package @standardnotes/home-server
## [1.13.13](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.12...@standardnotes/home-server@1.13.13) (2023-07-26)
**Note:** Version bump only for package @standardnotes/home-server
## [1.13.12](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.11...@standardnotes/home-server@1.13.12) (2023-07-26)
**Note:** Version bump only for package @standardnotes/home-server
## [1.13.11](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.10...@standardnotes/home-server@1.13.11) (2023-07-26)
**Note:** Version bump only for package @standardnotes/home-server
## [1.13.10](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.9...@standardnotes/home-server@1.13.10) (2023-07-25)
**Note:** Version bump only for package @standardnotes/home-server
## [1.13.9](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.8...@standardnotes/home-server@1.13.9) (2023-07-25)
**Note:** Version bump only for package @standardnotes/home-server

View File

@@ -1,16 +1,26 @@
import { Env } from '../src/Bootstrap/Env'
import { HomeServer } from '../src/Server/HomeServer'
const homeServer = new HomeServer()
Promise.resolve(
homeServer.start({
dataDirectoryPath: `${__dirname}/../data`,
logStreamCallback: (chunk: Buffer) => {
// eslint-disable-next-line no-console
console.log(chunk.toString())
},
}),
).catch((error) => {
const env: Env = new Env()
env.load()
try {
Promise.resolve(
homeServer.start({
dataDirectoryPath: `${__dirname}/../data`,
logStreamCallback: (chunk: Buffer) => {
// eslint-disable-next-line no-console
console.log(chunk.toString())
},
environment: env.getAll(),
}),
).catch((error) => {
// eslint-disable-next-line no-console
console.error(`Could not start server: ${error.message}`)
})
} catch (error) {
// eslint-disable-next-line no-console
console.log(`Could not start server: ${error.message}`)
})
console.error((error as Error).stack)
}

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/home-server",
"version": "1.13.9",
"version": "1.13.16",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -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.25.6](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.25.5...@standardnotes/revisions-server@1.25.6) (2023-07-27)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.25.5](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.25.4...@standardnotes/revisions-server@1.25.5) (2023-07-26)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.25.4](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.25.3...@standardnotes/revisions-server@1.25.4) (2023-07-26)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.25.3](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.25.2...@standardnotes/revisions-server@1.25.3) (2023-07-21)
**Note:** Version bump only for package @standardnotes/revisions-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/revisions-server",
"version": "1.25.3",
"version": "1.25.6",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -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.20.15](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.14...@standardnotes/scheduler-server@1.20.15) (2023-07-27)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.20.14](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.13...@standardnotes/scheduler-server@1.20.14) (2023-07-26)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.20.13](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.12...@standardnotes/scheduler-server@1.20.13) (2023-07-26)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.20.12](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.11...@standardnotes/scheduler-server@1.20.12) (2023-07-21)
**Note:** Version bump only for package @standardnotes/scheduler-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/scheduler-server",
"version": "1.20.12",
"version": "1.20.15",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -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.21.20](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.19...@standardnotes/settings@1.21.20) (2023-07-27)
**Note:** Version bump only for package @standardnotes/settings
## [1.21.19](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.18...@standardnotes/settings@1.21.19) (2023-07-26)
**Note:** Version bump only for package @standardnotes/settings
## [1.21.18](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.17...@standardnotes/settings@1.21.18) (2023-07-26)
**Note:** Version bump only for package @standardnotes/settings
## [1.21.17](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.16...@standardnotes/settings@1.21.17) (2023-07-21)
**Note:** Version bump only for package @standardnotes/settings

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/settings",
"version": "1.21.17",
"version": "1.21.20",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,46 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.72.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.72.0...@standardnotes/syncing-server@1.72.1) (2023-07-27)
**Note:** Version bump only for package @standardnotes/syncing-server
# [1.72.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.71.0...@standardnotes/syncing-server@1.72.0) (2023-07-27)
### Features
* **syncing-server:** add deleting outbound messages ([e8ba49e](https://github.com/standardnotes/syncing-server-js/commit/e8ba49ecca38ab10c0ea0e1f4cf4db9fb17366db))
# [1.71.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.70.5...@standardnotes/syncing-server@1.71.0) (2023-07-26)
### Features
* extract shared vault user permission to domain-core ([e215ac4](https://github.com/standardnotes/syncing-server-js/commit/e215ac4343e9f8818f40004d31390d6ac23e369d))
## [1.70.5](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.70.4...@standardnotes/syncing-server@1.70.5) (2023-07-26)
### Bug Fixes
* **syncing-server:** uuid comparison when removing user ([886ccf8](https://github.com/standardnotes/syncing-server-js/commit/886ccf84c1f3b9309ce7d01354ca815af1424b72))
## [1.70.4](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.70.3...@standardnotes/syncing-server@1.70.4) (2023-07-26)
### Bug Fixes
* **syncing-serve:** removing other users from shared vault ([6b2389c](https://github.com/standardnotes/syncing-server-js/commit/6b2389cdc3da6d522f9ce0ba3ddff3ef1e99674f))
## [1.70.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.70.2...@standardnotes/syncing-server@1.70.3) (2023-07-26)
### Bug Fixes
* **syncing-server:** persisting aggregate changes from root ([#674](https://github.com/standardnotes/syncing-server-js/issues/674)) ([c34f548](https://github.com/standardnotes/syncing-server-js/commit/c34f548e45bbd8defb8d490936e90755fd284e78))
## [1.70.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.70.1...@standardnotes/syncing-server@1.70.2) (2023-07-25)
### Bug Fixes
* **syncing-server:** remove notifications after adding item to vault ([#672](https://github.com/standardnotes/syncing-server-js/issues/672)) ([8f88a87](https://github.com/standardnotes/syncing-server-js/commit/8f88a87c93e21f52a029167f2408ff061e2a4e93))
## [1.70.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.70.0...@standardnotes/syncing-server@1.70.1) (2023-07-25)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/syncing-server",
"version": "1.70.1",
"version": "1.72.1",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -152,6 +152,7 @@ import { NotificationHttpMapper } from '../Mapping/Http/NotificationHttpMapper'
import { NotificationHttpRepresentation } from '../Mapping/Http/NotificationHttpRepresentation'
import { DetermineSharedVaultOperationOnItem } from '../Domain/UseCase/SharedVaults/DetermineSharedVaultOperationOnItem/DetermineSharedVaultOperationOnItem'
import { SharedVaultFilter } from '../Domain/Item/SaveRule/SharedVaultFilter'
import { RemoveNotificationsForUser } from '../Domain/UseCase/Messaging/RemoveNotificationsForUser/RemoveNotificationsForUser'
export class ContainerConfigLoader {
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
@@ -549,6 +550,14 @@ export class ContainerConfigLoader {
container.get(TYPES.Sync_DomainEventFactory),
),
)
container
.bind<AddNotificationForUser>(TYPES.Sync_AddNotificationForUser)
.toConstantValue(
new AddNotificationForUser(container.get(TYPES.Sync_NotificationRepository), container.get(TYPES.Sync_Timer)),
)
container
.bind<RemoveNotificationsForUser>(TYPES.Sync_RemoveNotificationsForUser)
.toConstantValue(new RemoveNotificationsForUser(container.get(TYPES.Sync_NotificationRepository)))
container
.bind<UpdateExistingItem>(TYPES.Sync_UpdateExistingItem)
.toConstantValue(
@@ -558,6 +567,9 @@ export class ContainerConfigLoader {
container.get(TYPES.Sync_DomainEventPublisher),
container.get(TYPES.Sync_DomainEventFactory),
container.get(TYPES.Sync_REVISIONS_FREQUENCY),
container.get(TYPES.Sync_DetermineSharedVaultOperationOnItem),
container.get(TYPES.Sync_AddNotificationForUser),
container.get(TYPES.Sync_RemoveNotificationsForUser),
),
)
container
@@ -673,11 +685,6 @@ export class ContainerConfigLoader {
container.get(TYPES.Sync_SharedVaultRepository),
),
)
container
.bind<AddNotificationForUser>(TYPES.Sync_AddNotificationForUser)
.toConstantValue(
new AddNotificationForUser(container.get(TYPES.Sync_NotificationRepository), container.get(TYPES.Sync_Timer)),
)
container
.bind<RemoveUserFromSharedVault>(TYPES.Sync_RemoveSharedVaultUser)
.toConstantValue(

View File

@@ -57,6 +57,7 @@ const TYPES = {
Sync_GetSharedVaultUsers: Symbol.for('Sync_GetSharedVaultUsers'),
Sync_AddUserToSharedVault: Symbol.for('Sync_AddUserToSharedVault'),
Sync_AddNotificationForUser: Symbol.for('Sync_AddNotificationForUser'),
Sync_RemoveNotificationsForUser: Symbol.for('Sync_RemoveNotificationsForUser'),
Sync_RemoveSharedVaultUser: Symbol.for('Sync_RemoveSharedVaultUser'),
Sync_InviteUserToSharedVault: Symbol.for('Sync_InviteUserToSharedVault'),
Sync_UpdateSharedVaultInvite: Symbol.for('Sync_UpdateSharedVaultInvite'),

View File

@@ -2,6 +2,7 @@ import { ContentType, Dates, Timestamps, UniqueEntityId, Uuid } from '@standardn
import { Item } from './Item'
import { SharedVaultAssociation } from '../SharedVault/SharedVaultAssociation'
import { KeySystemAssociation } from '../KeySystem/KeySystemAssociation'
describe('Item', () => {
it('should create an aggregate', () => {
@@ -97,4 +98,155 @@ describe('Item', () => {
.isAssociatedWithSharedVault(Uuid.create('00000000-0000-0000-0000-000000000000').getValue()),
).toBeFalsy()
})
it('should tell if an item is associated with a key system', () => {
const entityOrError = Item.create({
duplicateOf: null,
itemsKeyId: 'items-key-id',
content: 'content',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: 'enc-item-key',
authHash: 'auth-hash',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
deleted: false,
updatedWithSession: null,
dates: Dates.create(new Date(123), new Date(123)).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
keySystemAssociation: KeySystemAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
keySystemIdentifier: 'key-system-identifier',
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
})
expect(entityOrError.isFailed()).toBeFalsy()
expect(entityOrError.getValue().isAssociatedWithKeySystem('key-system-identifier')).toBeTruthy()
})
it('should tell that an item is not associated with a key system', () => {
const entityOrError = Item.create({
duplicateOf: null,
itemsKeyId: 'items-key-id',
content: 'content',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: 'enc-item-key',
authHash: 'auth-hash',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
deleted: false,
updatedWithSession: null,
dates: Dates.create(new Date(123), new Date(123)).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
})
expect(entityOrError.isFailed()).toBeFalsy()
expect(entityOrError.getValue().isAssociatedWithKeySystem('key-system-identifier')).toBeFalsy()
})
it('should set shared vault association', () => {
const sharedVaultAssociation = SharedVaultAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
const entity = Item.create({
duplicateOf: null,
itemsKeyId: 'items-key-id',
content: 'content',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: 'enc-item-key',
authHash: 'auth-hash',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
deleted: false,
updatedWithSession: null,
dates: Dates.create(new Date(123), new Date(123)).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
entity.setSharedVaultAssociation(sharedVaultAssociation)
expect(entity.props.sharedVaultAssociation).toEqual(sharedVaultAssociation)
expect(entity.getChanges()).toHaveLength(1)
})
it('should unset a shared vault association', () => {
const entity = Item.create({
duplicateOf: null,
itemsKeyId: 'items-key-id',
content: 'content',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: 'enc-item-key',
authHash: 'auth-hash',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
deleted: false,
updatedWithSession: null,
dates: Dates.create(new Date(123), new Date(123)).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
sharedVaultAssociation: SharedVaultAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
}).getValue()
entity.unsetSharedVaultAssociation()
expect(entity.props.sharedVaultAssociation).toBeUndefined()
expect(entity.getChanges()).toHaveLength(1)
})
it('should set key system association', () => {
const keySystemAssociation = KeySystemAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
keySystemIdentifier: 'key-system-identifier',
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
const entity = Item.create({
duplicateOf: null,
itemsKeyId: 'items-key-id',
content: 'content',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: 'enc-item-key',
authHash: 'auth-hash',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
deleted: false,
updatedWithSession: null,
dates: Dates.create(new Date(123), new Date(123)).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
entity.setKeySystemAssociation(keySystemAssociation)
expect(entity.props.keySystemAssociation).toEqual(keySystemAssociation)
expect(entity.getChanges()).toHaveLength(1)
})
it('should unset a key system association', () => {
const entity = Item.create({
duplicateOf: null,
itemsKeyId: 'items-key-id',
content: 'content',
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
encItemKey: 'enc-item-key',
authHash: 'auth-hash',
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
deleted: false,
updatedWithSession: null,
dates: Dates.create(new Date(123), new Date(123)).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
keySystemAssociation: KeySystemAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
keySystemIdentifier: 'key-system-identifier',
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
}).getValue()
entity.unsetKeySystemAssociation()
expect(entity.props.keySystemAssociation).toBeUndefined()
expect(entity.getChanges()).toHaveLength(1)
})
})

View File

@@ -1,8 +1,23 @@
import { Aggregate, Result, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
import { Aggregate, Change, Result, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
import { ItemProps } from './ItemProps'
import { SharedVaultAssociation } from '../SharedVault/SharedVaultAssociation'
import { KeySystemAssociation } from '../KeySystem/KeySystemAssociation'
export class Item extends Aggregate<ItemProps> {
private constructor(props: ItemProps, id?: UniqueEntityId) {
super(props, id)
}
static create(props: ItemProps, id?: UniqueEntityId): Result<Item> {
if (!props.contentSize) {
const contentSize = Buffer.byteLength(JSON.stringify(props))
props.contentSize = contentSize
}
return Result.ok<Item>(new Item(props, id))
}
get uuid(): Uuid {
const uuidOrError = Uuid.create(this._id.toString())
if (uuidOrError.isFailed()) {
@@ -40,16 +55,57 @@ export class Item extends Aggregate<ItemProps> {
return this.props.keySystemAssociation.props.keySystemIdentifier === keySystemIdentifier
}
private constructor(props: ItemProps, id?: UniqueEntityId) {
super(props, id)
setSharedVaultAssociation(sharedVaultAssociation: SharedVaultAssociation): void {
this.addChange(
Change.create({
aggregateRootUuid: this.uuid.value,
changeType: this.props.sharedVaultAssociation ? Change.TYPES.Modify : Change.TYPES.Add,
changeData: sharedVaultAssociation,
}).getValue(),
)
this.props.sharedVaultAssociation = sharedVaultAssociation
}
static create(props: ItemProps, id?: UniqueEntityId): Result<Item> {
if (!props.contentSize) {
const contentSize = Buffer.byteLength(JSON.stringify(props))
props.contentSize = contentSize
unsetSharedVaultAssociation(): void {
if (!this.props.sharedVaultAssociation) {
return
}
return Result.ok<Item>(new Item(props, id))
this.addChange(
Change.create({
aggregateRootUuid: this.uuid.value,
changeType: Change.TYPES.Remove,
changeData: this.props.sharedVaultAssociation,
}).getValue(),
)
this.props.sharedVaultAssociation = undefined
}
setKeySystemAssociation(keySystemAssociation: KeySystemAssociation): void {
this.addChange(
Change.create({
aggregateRootUuid: this.uuid.value,
changeType: this.props.keySystemAssociation ? Change.TYPES.Modify : Change.TYPES.Add,
changeData: keySystemAssociation,
}).getValue(),
)
this.props.keySystemAssociation = keySystemAssociation
}
unsetKeySystemAssociation(): void {
if (!this.props.keySystemAssociation) {
return
}
this.addChange(
Change.create({
aggregateRootUuid: this.uuid.value,
changeType: Change.TYPES.Remove,
changeData: this.props.keySystemAssociation,
}).getValue(),
)
this.props.keySystemAssociation = undefined
}
}

View File

@@ -1,6 +1,13 @@
import { ContentType, Dates, Result, Timestamps, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
import {
ContentType,
Dates,
Result,
SharedVaultUserPermission,
Timestamps,
UniqueEntityId,
Uuid,
} from '@standardnotes/domain-core'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { DetermineSharedVaultOperationOnItem } from '../../UseCase/SharedVaults/DetermineSharedVaultOperationOnItem/DetermineSharedVaultOperationOnItem'
import { SharedVaultFilter } from './SharedVaultFilter'
@@ -72,24 +79,11 @@ describe('SharedVaultFilter', () => {
.mockResolvedValueOnce(null)
})
it('should return as passed if the item hash does not represent a shared vault item', async () => {
it('should return as passed if the item hash does not represent a shared vault item and existing item is not a shared vault item', async () => {
itemHash = ItemHash.create({
...itemHash.props,
shared_vault_uuid: null,
}).getValue()
const filter = createFilter()
const result = await filter.check({
apiVersion: '001',
existingItem: existingItem,
itemHash: itemHash,
userUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.passed).toBe(true)
})
it('should return as passed if the item is not a shared vault item', async () => {
existingItem = Item.create({
...existingItem.props,
sharedVaultAssociation: undefined,

View File

@@ -1,12 +1,11 @@
import { ConflictType } from '@standardnotes/responses'
import { ContentType, Result, Uuid } from '@standardnotes/domain-core'
import { ContentType, Result, SharedVaultUserPermission, Uuid } from '@standardnotes/domain-core'
import { ItemSaveValidationDTO } from '../SaveValidator/ItemSaveValidationDTO'
import { ItemSaveRuleResult } from './ItemSaveRuleResult'
import { ItemSaveRuleInterface } from './ItemSaveRuleInterface'
import { DetermineSharedVaultOperationOnItem } from '../../UseCase/SharedVaults/DetermineSharedVaultOperationOnItem/DetermineSharedVaultOperationOnItem'
import { SharedVaultOperationOnItem } from '../../SharedVault/SharedVaultOperationOnItem'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
export class SharedVaultFilter implements ItemSaveRuleInterface {
@@ -16,7 +15,7 @@ export class SharedVaultFilter implements ItemSaveRuleInterface {
) {}
async check(dto: ItemSaveValidationDTO): Promise<ItemSaveRuleResult> {
if (!dto.itemHash.representsASharedVaultItem() || !dto.existingItem?.isAssociatedWithASharedVault()) {
if (!dto.itemHash.representsASharedVaultItem() && !dto.existingItem?.isAssociatedWithASharedVault()) {
return {
passed: true,
}

View File

@@ -1,4 +1,4 @@
import { Uuid } from '@standardnotes/domain-core'
import { NotificationType, Uuid } from '@standardnotes/domain-core'
import { Notification } from './Notification'
@@ -6,4 +6,6 @@ export interface NotificationRepositoryInterface {
save(notification: Notification): Promise<void>
findByUserUuidUpdatedAfter(userUuid: Uuid, lastSyncTime: number): Promise<Notification[]>
findByUserUuid(userUuid: Uuid): Promise<Notification[]>
findByUserUuidAndType(userUuid: Uuid, type: NotificationType): Promise<Notification[]>
remove(notification: Notification): Promise<void>
}

View File

@@ -1,7 +1,6 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInvite } from './SharedVaultInvite'
import { SharedVaultUserPermission } from '../SharedVaultUserPermission'
describe('SharedVaultInvite', () => {
it('should create an entity', () => {

View File

@@ -1,5 +1,4 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission } from '../SharedVaultUserPermission'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
export interface SharedVaultInviteProps {
sharedVaultUuid: Uuid

View File

@@ -1,7 +1,6 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUser } from './SharedVaultUser'
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
describe('SharedVaultUser', () => {
it('should create an entity', () => {

View File

@@ -1,6 +1,4 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
export interface SharedVaultUserProps {
sharedVaultUuid: Uuid

View File

@@ -0,0 +1,64 @@
import { NotificationPayload, NotificationType, Timestamps, Uuid } from '@standardnotes/domain-core'
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
import { RemoveNotificationsForUser } from './RemoveNotificationsForUser'
import { Notification } from '../../../Notifications/Notification'
describe('RemoveNotificationsForUser', () => {
let notificationRepository: NotificationRepositoryInterface
let notification: Notification
const createUseCase = () => new RemoveNotificationsForUser(notificationRepository)
beforeEach(() => {
notification = Notification.create({
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
type: NotificationType.create(NotificationType.TYPES.SharedVaultItemRemoved).getValue(),
payload: NotificationPayload.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
type: NotificationType.create(NotificationType.TYPES.SharedVaultItemRemoved).getValue(),
version: '1.0',
}).getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
notificationRepository = {} as jest.Mocked<NotificationRepositoryInterface>
notificationRepository.findByUserUuidAndType = jest.fn().mockResolvedValue([notification])
notificationRepository.remove = jest.fn()
})
it('should remove notifications for user', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
type: NotificationType.TYPES.SharedVaultItemRemoved,
})
expect(result.isFailed()).toBeFalsy()
expect(notificationRepository.remove).toHaveBeenCalledWith(notification)
})
it('should fail if user uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: 'invalid',
type: NotificationType.TYPES.SharedVaultItemRemoved,
})
expect(result.isFailed()).toBeTruthy()
})
it('should fail if notification type is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
type: 'invalid',
})
expect(result.isFailed()).toBeTruthy()
})
})

View File

@@ -0,0 +1,29 @@
import { NotificationType, Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { RemoveNotificationsForUserDTO } from './RemoveNotificationsForUserDTO'
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
export class RemoveNotificationsForUser implements UseCaseInterface<void> {
constructor(private notificationRepository: NotificationRepositoryInterface) {}
async execute(dto: RemoveNotificationsForUserDTO): Promise<Result<void>> {
const userUuidOrError = Uuid.create(dto.userUuid)
if (userUuidOrError.isFailed()) {
return Result.fail(userUuidOrError.getError())
}
const userUuid = userUuidOrError.getValue()
const typeOrError = NotificationType.create(dto.type)
if (typeOrError.isFailed()) {
return Result.fail(typeOrError.getError())
}
const type = typeOrError.getValue()
const notifications = await this.notificationRepository.findByUserUuidAndType(userUuid, type)
for (const notification of notifications) {
await this.notificationRepository.remove(notification)
}
return Result.ok()
}
}

View File

@@ -0,0 +1,4 @@
export interface RemoveNotificationsForUserDTO {
type: string
userUuid: string
}

View File

@@ -1,9 +1,8 @@
import { Result, Timestamps, Uuid } from '@standardnotes/domain-core'
import { Result, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { AddUserToSharedVault } from '../AddUserToSharedVault/AddUserToSharedVault'
import { AcceptInviteToSharedVault } from './AcceptInviteToSharedVault'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('AcceptInviteToSharedVault', () => {
let addUserToSharedVault: AddUserToSharedVault

View File

@@ -1,11 +1,10 @@
import { Result, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { Result, SharedVaultUserPermission, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { TimerInterface } from '@standardnotes/time'
import { AddUserToSharedVaultDTO } from './AddUserToSharedVaultDTO'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
export class AddUserToSharedVault implements UseCaseInterface<SharedVaultUser> {
constructor(

View File

@@ -4,8 +4,7 @@ import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/Sh
import { CreateSharedVaultFileValetToken } from './CreateSharedVaultFileValetToken'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
describe('CreateSharedVaultFileValetToken', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface

View File

@@ -1,10 +1,9 @@
import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
import { Result, SharedVaultUserPermission, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { CreateSharedVaultFileValetTokenDTO } from './CreateSharedVaultFileValetTokenDTO'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
export class CreateSharedVaultFileValetToken implements UseCaseInterface<string> {
constructor(

View File

@@ -1,8 +1,7 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { DeclineInviteToSharedVault } from './DeclineInviteToSharedVault'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('DeclineInviteToSharedVault', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface

View File

@@ -1,4 +1,4 @@
import { Uuid, Timestamps, Result } from '@standardnotes/domain-core'
import { Uuid, Timestamps, Result, SharedVaultUserPermission } from '@standardnotes/domain-core'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
@@ -6,7 +6,6 @@ import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/Sh
import { DeleteSharedVault } from './DeleteSharedVault'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
describe('DeleteSharedVault', () => {

View File

@@ -1,9 +1,8 @@
import { Result, Timestamps, Uuid } from '@standardnotes/domain-core'
import { Result, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { DeleteSharedVaultInvitesSentByUser } from './DeleteSharedVaultInvitesSentByUser'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('DeleteSharedVaultInvitesSentByUser', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
@@ -25,6 +24,7 @@ describe('DeleteSharedVaultInvitesSentByUser', () => {
sharedVaultInviteRepository = {} as jest.Mocked<SharedVaultInviteRepositoryInterface>
sharedVaultInviteRepository.findBySenderUuidAndSharedVaultUuid = jest.fn().mockReturnValue([sharedVaultInvite])
sharedVaultInviteRepository.findBySenderUuid = jest.fn().mockReturnValue([sharedVaultInvite])
declineInviteToSharedVault = {} as jest.Mocked<DeclineInviteToSharedVault>
declineInviteToSharedVault.execute = jest.fn().mockReturnValue(Result.ok())
@@ -76,4 +76,15 @@ describe('DeleteSharedVaultInvitesSentByUser', () => {
expect(result.isFailed()).toBeTruthy()
})
it('should decline all invites by user to all shared vaults', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeFalsy()
expect(declineInviteToSharedVault.execute).toHaveBeenCalled()
})
})

View File

@@ -16,16 +16,22 @@ export class DeleteSharedVaultInvitesSentByUser implements UseCaseInterface<void
}
const userUuid = userUuidOrError.getValue()
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
if (sharedVaultUuidOrError.isFailed()) {
return Result.fail(sharedVaultUuidOrError.getError())
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
let inboundInvites = []
if (dto.sharedVaultUuid !== undefined) {
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
if (sharedVaultUuidOrError.isFailed()) {
return Result.fail(sharedVaultUuidOrError.getError())
}
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
inboundInvites = await this.sharedVaultInviteRepository.findBySenderUuidAndSharedVaultUuid({
senderUuid: userUuid,
sharedVaultUuid,
})
} else {
inboundInvites = await this.sharedVaultInviteRepository.findBySenderUuid(userUuid)
}
const inboundInvites = await this.sharedVaultInviteRepository.findBySenderUuidAndSharedVaultUuid({
senderUuid: userUuid,
sharedVaultUuid,
})
for (const invite of inboundInvites) {
const result = await this.declineInviteToSharedVault.execute({
inviteUuid: invite.id.toString(),

View File

@@ -1,4 +1,4 @@
export interface DeleteSharedVaultInvitesSentByUserDTO {
userUuid: string
sharedVaultUuid: string
sharedVaultUuid?: string
}

View File

@@ -1,9 +1,8 @@
import { Result, Timestamps, Uuid } from '@standardnotes/domain-core'
import { Result, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
import { DeleteSharedVaultInvitesToUser } from './DeleteSharedVaultInvitesToUser'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('DeleteSharedVaultInvitesToUser', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface

View File

@@ -1,8 +1,7 @@
import { Uuid, Timestamps } from '@standardnotes/domain-core'
import { Uuid, Timestamps, SharedVaultUserPermission } from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { GetSharedVaultInvitesSentByUser } from './GetSharedVaultInvitesSentByUser'
describe('GetSharedVaultInvitesSentByUser', () => {

View File

@@ -1,8 +1,7 @@
import { Uuid, Timestamps } from '@standardnotes/domain-core'
import { Uuid, Timestamps, SharedVaultUserPermission } from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { GetSharedVaultInvitesSentToUser } from './GetSharedVaultInvitesSentToUser'
describe('GetSharedVaultInvitesSentToUser', () => {

View File

@@ -1,8 +1,7 @@
import { Uuid, Timestamps } from '@standardnotes/domain-core'
import { Uuid, Timestamps, SharedVaultUserPermission } from '@standardnotes/domain-core'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { GetSharedVaultUsers } from './GetSharedVaultUsers'

View File

@@ -1,8 +1,7 @@
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { GetSharedVaults } from './GetSharedVaults'

View File

@@ -1,11 +1,11 @@
import { TimerInterface } from '@standardnotes/time'
import { Uuid, Timestamps, Result, SharedVaultUserPermission } from '@standardnotes/domain-core'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { InviteUserToSharedVault } from './InviteUserToSharedVault'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { Uuid, Timestamps, Result } from '@standardnotes/domain-core'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
describe('InviteUserToSharedVault', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface

View File

@@ -1,10 +1,10 @@
import { Result, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { Result, SharedVaultUserPermission, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { InviteUserToSharedVaultDTO } from './InviteUserToSharedVaultDTO'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvite> {
constructor(

View File

@@ -1,9 +1,8 @@
import { Uuid, Timestamps, Result, NotificationPayload } from '@standardnotes/domain-core'
import { Uuid, Timestamps, Result, NotificationPayload, SharedVaultUserPermission } from '@standardnotes/domain-core'
import { SharedVault } from '../../../SharedVault/SharedVault'
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { RemoveUserFromSharedVault } from './RemoveUserFromSharedVault'
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
@@ -45,12 +44,13 @@ describe('RemoveUserFromSharedVault', () => {
it('should remove user from shared vault', async () => {
const useCase = createUseCase()
await useCase.execute({
const result = await useCase.execute({
originatorUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
userUuid: '00000000-0000-0000-0000-000000000001',
})
expect(result.isFailed()).toBeFalsy()
expect(sharedVaultUserRepository.remove).toHaveBeenCalledWith(sharedVaultUser)
})
@@ -99,7 +99,7 @@ describe('RemoveUserFromSharedVault', () => {
})
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Only owner can remove users from shared vault')
expect(result.getError()).toBe('Only owner can remove other users from shared vault')
})
it('should remove shared vault user if user is owner and is being force removed', async () => {

View File

@@ -37,8 +37,9 @@ export class RemoveUserFromSharedVault implements UseCaseInterface<void> {
}
const originatorIsOwner = sharedVault.props.userUuid.equals(originatorUuid)
if (!originatorIsOwner) {
return Result.fail('Only owner can remove users from shared vault')
const removingSomeoneElseWhenNotOwner = !originatorIsOwner && !userUuid.equals(originatorUuid)
if (removingSomeoneElseWhenNotOwner) {
return Result.fail('Only owner can remove other users from shared vault')
}
const removingOwner = sharedVault.props.userUuid.equals(userUuid)

View File

@@ -2,8 +2,7 @@ import { TimerInterface } from '@standardnotes/time'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { UpdateSharedVaultInvite } from './UpdateSharedVaultInvite'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
describe('UpdateSharedVaultInvite', () => {
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface

View File

@@ -1,9 +1,15 @@
import { Result, Timestamps, UseCaseInterface, Uuid, Validator } from '@standardnotes/domain-core'
import {
Result,
SharedVaultUserPermission,
Timestamps,
UseCaseInterface,
Uuid,
Validator,
} from '@standardnotes/domain-core'
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
import { UpdateSharedVaultInviteDTO } from './UpdateSharedVaultInviteDTO'
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
import { TimerInterface } from '@standardnotes/time'
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
export class UpdateSharedVaultInvite implements UseCaseInterface<SharedVaultInvite> {

View File

@@ -87,7 +87,27 @@ export class SaveNewItem implements UseCaseInterface<Item> {
}
const timestamps = timestampsOrError.getValue()
let sharedVaultAssociation = undefined
const itemOrError = Item.create(
{
updatedWithSession,
content: dto.itemHash.props.content ?? null,
userUuid,
contentType,
encItemKey: dto.itemHash.props.enc_item_key ?? null,
authHash: dto.itemHash.props.auth_hash ?? null,
itemsKeyId: dto.itemHash.props.items_key_id ?? null,
duplicateOf,
deleted: dto.itemHash.props.deleted ?? false,
dates,
timestamps,
},
new UniqueEntityId(uuid.value),
)
if (itemOrError.isFailed()) {
return Result.fail(itemOrError.getError())
}
const newItem = itemOrError.getValue()
if (dto.itemHash.representsASharedVaultItem()) {
const sharedVaultAssociationOrError = SharedVaultAssociation.create({
lastEditedBy: userUuid,
@@ -101,10 +121,9 @@ export class SaveNewItem implements UseCaseInterface<Item> {
if (sharedVaultAssociationOrError.isFailed()) {
return Result.fail(sharedVaultAssociationOrError.getError())
}
sharedVaultAssociation = sharedVaultAssociationOrError.getValue()
newItem.setSharedVaultAssociation(sharedVaultAssociationOrError.getValue())
}
let keySystemAssociation = undefined
if (dto.itemHash.hasDedicatedKeySystemAssociation()) {
const keySystemIdentifiedValidationResult = Validator.isNotEmptyString(dto.itemHash.props.key_system_identifier)
if (keySystemIdentifiedValidationResult.isFailed()) {
@@ -123,32 +142,9 @@ export class SaveNewItem implements UseCaseInterface<Item> {
if (keySystemAssociationOrError.isFailed()) {
return Result.fail(keySystemAssociationOrError.getError())
}
keySystemAssociation = keySystemAssociationOrError.getValue()
newItem.setKeySystemAssociation(keySystemAssociationOrError.getValue())
}
const itemOrError = Item.create(
{
updatedWithSession,
content: dto.itemHash.props.content ?? null,
userUuid,
contentType,
encItemKey: dto.itemHash.props.enc_item_key ?? null,
authHash: dto.itemHash.props.auth_hash ?? null,
itemsKeyId: dto.itemHash.props.items_key_id ?? null,
duplicateOf,
deleted: dto.itemHash.props.deleted ?? false,
dates,
timestamps,
keySystemAssociation,
sharedVaultAssociation,
},
new UniqueEntityId(uuid.value),
)
if (itemOrError.isFailed()) {
return Result.fail(itemOrError.getError())
}
const newItem = itemOrError.getValue()
await this.itemRepository.save(newItem)
if (contentType.value !== null && [ContentType.TYPES.Note, ContentType.TYPES.File].includes(contentType.value)) {

View File

@@ -177,7 +177,7 @@ describe('SyncItems', () => {
})
})
it('should sync items and return items keys on top for first sync', async () => {
it('should sync items and return items keys on top for first sync that is not a shared vault exclusive sync', async () => {
const result = await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
@@ -202,6 +202,32 @@ describe('SyncItems', () => {
})
})
it('should sync items and not return items keys on top for first sync that is a shared vault exclusive sync', async () => {
const result = await createUseCase().execute({
userUuid: '1-2-3',
itemHashes: [itemHash],
computeIntegrityHash: false,
limit: 10,
readOnlyAccess: false,
sessionUuid: '2-3-4',
contentType: 'Note',
apiVersion: ApiVersion.v20200115,
snjsVersion: '1.2.3',
sharedVaultUuids: ['00000000-0000-0000-0000-000000000000'],
})
expect(result.getValue()).toEqual({
conflicts: [],
cursorToken: 'asdzxc',
retrievedItems: [item1],
savedItems: [item2],
syncToken: 'qwerty',
sharedVaults: [],
sharedVaultInvites: [],
notifications: [],
messages: [],
})
})
it('should sync items and return filtered out sync conflicts for consecutive sync operations', async () => {
getItemsUseCase.execute = jest.fn().mockReturnValue(
Result.ok({

View File

@@ -50,7 +50,8 @@ export class SyncItems implements UseCaseInterface<SyncItemsResponse> {
const saveItemsResult = saveItemsResultOrError.getValue()
let retrievedItems = this.filterOutSyncConflictsForConsecutiveSyncs(getItemsResult.items, saveItemsResult.conflicts)
if (this.isFirstSync(dto)) {
const isSharedVaultExclusiveSync = dto.sharedVaultUuids && dto.sharedVaultUuids.length > 0
if (this.isFirstSync(dto) && !isSharedVaultExclusiveSync) {
retrievedItems = await this.frontLoadKeysItemsToTop(dto.userUuid, retrievedItems)
}

View File

@@ -5,9 +5,21 @@ import { Item } from '../../../Item/Item'
import { ItemHash } from '../../../Item/ItemHash'
import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
import { UpdateExistingItem } from './UpdateExistingItem'
import { Uuid, ContentType, Dates, Timestamps, UniqueEntityId, Result } from '@standardnotes/domain-core'
import {
Uuid,
ContentType,
Dates,
Timestamps,
UniqueEntityId,
Result,
NotificationPayload,
} from '@standardnotes/domain-core'
import { SharedVaultAssociation } from '../../../SharedVault/SharedVaultAssociation'
import { KeySystemAssociation } from '../../../KeySystem/KeySystemAssociation'
import { DetermineSharedVaultOperationOnItem } from '../../SharedVaults/DetermineSharedVaultOperationOnItem/DetermineSharedVaultOperationOnItem'
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
import { RemoveNotificationsForUser } from '../../Messaging/RemoveNotificationsForUser/RemoveNotificationsForUser'
import { SharedVaultOperationOnItem } from '../../../SharedVault/SharedVaultOperationOnItem'
describe('UpdateExistingItem', () => {
let itemRepository: ItemRepositoryInterface
@@ -16,8 +28,21 @@ describe('UpdateExistingItem', () => {
let domainEventFactory: DomainEventFactoryInterface
let itemHash1: ItemHash
let item1: Item
let determineSharedVaultOperationOnItem: DetermineSharedVaultOperationOnItem
let addNotificationForUser: AddNotificationForUser
let removeNotificationsForUser: RemoveNotificationsForUser
const createUseCase = () => new UpdateExistingItem(itemRepository, timer, domainEventPublisher, domainEventFactory, 5)
const createUseCase = () =>
new UpdateExistingItem(
itemRepository,
timer,
domainEventPublisher,
domainEventFactory,
5,
determineSharedVaultOperationOnItem,
addNotificationForUser,
removeNotificationsForUser,
)
beforeEach(() => {
const timeHelper = new Timer()
@@ -80,6 +105,25 @@ describe('UpdateExistingItem', () => {
domainEventFactory.createItemRevisionCreationRequested = jest
.fn()
.mockReturnValue({} as jest.Mocked<DomainEventInterface>)
determineSharedVaultOperationOnItem = {} as jest.Mocked<DetermineSharedVaultOperationOnItem>
determineSharedVaultOperationOnItem.execute = jest.fn().mockResolvedValue(
Result.ok(
SharedVaultOperationOnItem.create({
existingItem: item1,
incomingItemHash: itemHash1,
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
type: SharedVaultOperationOnItem.TYPES.AddToSharedVault,
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
}).getValue(),
),
)
addNotificationForUser = {} as jest.Mocked<AddNotificationForUser>
addNotificationForUser.execute = jest.fn().mockReturnValue(Result.ok())
removeNotificationsForUser = {} as jest.Mocked<RemoveNotificationsForUser>
removeNotificationsForUser.execute = jest.fn().mockReturnValue(Result.ok())
})
it('should update item', async () => {
@@ -306,12 +350,14 @@ describe('UpdateExistingItem', () => {
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
}).getValue()
item1.props.sharedVaultAssociation = SharedVaultAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
item1.setSharedVaultAssociation(
SharedVaultAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
const idBefore = item1.props.sharedVaultAssociation?.id.toString()
const result = await useCase.execute({
@@ -324,7 +370,7 @@ describe('UpdateExistingItem', () => {
expect(result.isFailed()).toBeFalsy()
expect(item1.props.sharedVaultAssociation).not.toBeUndefined()
expect(item1.props.sharedVaultAssociation.id.toString()).toEqual(idBefore)
expect((item1.props.sharedVaultAssociation as SharedVaultAssociation).id.toString()).toEqual(idBefore)
})
it('should return error if shared vault association could not be created', async () => {
@@ -349,6 +395,111 @@ describe('UpdateExistingItem', () => {
expect(result.isFailed()).toBeTruthy()
mock.mockRestore()
})
it('should return error if it fails to determine the shared vault operation on item', async () => {
const useCase = createUseCase()
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(Result.fail('Oops'))
const itemHash = ItemHash.create({
...itemHash1.props,
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
}).getValue()
const result = await useCase.execute({
existingItem: item1,
itemHash,
sessionUuid: '00000000-0000-0000-0000-000000000000',
performingUserUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
})
it('should return error if it fails to add notification for user', async () => {
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
Result.ok(
SharedVaultOperationOnItem.create({
existingItem: item1,
incomingItemHash: itemHash1,
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
type: SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault,
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
}).getValue(),
),
)
addNotificationForUser.execute = jest.fn().mockReturnValue(Result.fail('Oops'))
const useCase = createUseCase()
const itemHash = ItemHash.create({
...itemHash1.props,
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
}).getValue()
const result = await useCase.execute({
existingItem: item1,
itemHash,
sessionUuid: '00000000-0000-0000-0000-000000000000',
performingUserUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
})
it('should return error if it fails to create notification payload for user', async () => {
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
Result.ok(
SharedVaultOperationOnItem.create({
existingItem: item1,
incomingItemHash: itemHash1,
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
type: SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault,
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
}).getValue(),
),
)
const mock = jest.spyOn(NotificationPayload, 'create')
mock.mockImplementation(() => {
return Result.fail('Oops')
})
const useCase = createUseCase()
const itemHash = ItemHash.create({
...itemHash1.props,
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
}).getValue()
const result = await useCase.execute({
existingItem: item1,
itemHash,
sessionUuid: '00000000-0000-0000-0000-000000000000',
performingUserUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
mock.mockRestore()
})
it('should return error if it fails to remove notifications for user', async () => {
const useCase = createUseCase()
removeNotificationsForUser.execute = jest.fn().mockReturnValue(Result.fail('Oops'))
const itemHash = ItemHash.create({
...itemHash1.props,
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
}).getValue()
const result = await useCase.execute({
existingItem: item1,
itemHash,
sessionUuid: '00000000-0000-0000-0000-000000000000',
performingUserUuid: '00000000-0000-0000-0000-000000000000',
})
expect(result.isFailed()).toBeTruthy()
})
})
describe('when item is associated to a key system', () => {
@@ -379,11 +530,13 @@ describe('UpdateExistingItem', () => {
key_system_identifier: '00000000-0000-0000-0000-000000000000',
}).getValue()
item1.props.keySystemAssociation = KeySystemAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
keySystemIdentifier: '00000000-0000-0000-0000-000000000000',
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue()
item1.setKeySystemAssociation(
KeySystemAssociation.create({
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
keySystemIdentifier: '00000000-0000-0000-0000-000000000000',
timestamps: Timestamps.create(123, 123).getValue(),
}).getValue(),
)
const idBefore = item1.props.keySystemAssociation?.id.toString()
const result = await useCase.execute({
@@ -396,7 +549,7 @@ describe('UpdateExistingItem', () => {
expect(result.isFailed()).toBeFalsy()
expect(item1.props.keySystemAssociation).not.toBeUndefined()
expect(item1.props.keySystemAssociation.id.toString()).toEqual(idBefore)
expect((item1.props.keySystemAssociation as KeySystemAssociation).id.toString()).toEqual(idBefore)
})
it('should return error if key system identifier is invalid', async () => {

View File

@@ -1,6 +1,8 @@
import {
ContentType,
Dates,
NotificationPayload,
NotificationType,
Result,
Timestamps,
UniqueEntityId,
@@ -17,6 +19,10 @@ import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
import { SharedVaultAssociation } from '../../../SharedVault/SharedVaultAssociation'
import { KeySystemAssociation } from '../../../KeySystem/KeySystemAssociation'
import { DetermineSharedVaultOperationOnItem } from '../../SharedVaults/DetermineSharedVaultOperationOnItem/DetermineSharedVaultOperationOnItem'
import { SharedVaultOperationOnItem } from '../../../SharedVault/SharedVaultOperationOnItem'
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
import { RemoveNotificationsForUser } from '../../Messaging/RemoveNotificationsForUser/RemoveNotificationsForUser'
export class UpdateExistingItem implements UseCaseInterface<Item> {
constructor(
@@ -25,6 +31,9 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
private domainEventPublisher: DomainEventPublisherInterface,
private domainEventFactory: DomainEventFactoryInterface,
private revisionFrequency: number,
private determineSharedVaultOperationOnItem: DetermineSharedVaultOperationOnItem,
private addNotificationForUser: AddNotificationForUser,
private removeNotificationsForUser: RemoveNotificationsForUser,
) {}
async execute(dto: UpdateExistingItemDTO): Promise<Result<Item>> {
@@ -113,6 +122,7 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
dto.existingItem.props.contentSize = Buffer.byteLength(JSON.stringify(dto.existingItem))
let sharedVaultOperation: SharedVaultOperationOnItem | null = null
if (dto.itemHash.representsASharedVaultItem()) {
const sharedVaultAssociationOrError = SharedVaultAssociation.create(
{
@@ -137,32 +147,50 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
return Result.fail(sharedVaultAssociationOrError.getError())
}
dto.existingItem.props.sharedVaultAssociation = sharedVaultAssociationOrError.getValue()
dto.existingItem.setSharedVaultAssociation(sharedVaultAssociationOrError.getValue())
const sharedVaultOperationOrError = await this.determineSharedVaultOperationOnItem.execute({
existingItem: dto.existingItem,
itemHash: dto.itemHash,
userUuid: userUuid.value,
})
if (sharedVaultOperationOrError.isFailed()) {
return Result.fail(sharedVaultOperationOrError.getError())
}
sharedVaultOperation = sharedVaultOperationOrError.getValue()
} else {
dto.existingItem.unsetSharedVaultAssociation()
}
if (
dto.itemHash.hasDedicatedKeySystemAssociation() &&
!dto.existingItem.isAssociatedWithKeySystem(dto.itemHash.props.key_system_identifier as string)
) {
if (dto.itemHash.hasDedicatedKeySystemAssociation()) {
const keySystemIdentifiedValidationResult = Validator.isNotEmptyString(dto.itemHash.props.key_system_identifier)
if (keySystemIdentifiedValidationResult.isFailed()) {
return Result.fail(keySystemIdentifiedValidationResult.getError())
}
const keySystemIdentifier = dto.itemHash.props.key_system_identifier as string
const keySystemAssociationOrError = KeySystemAssociation.create({
itemUuid: Uuid.create(dto.existingItem.id.toString()).getValue(),
timestamps: Timestamps.create(
this.timer.getTimestampInMicroseconds(),
this.timer.getTimestampInMicroseconds(),
).getValue(),
keySystemIdentifier,
})
const keySystemAssociationOrError = KeySystemAssociation.create(
{
itemUuid: Uuid.create(dto.existingItem.id.toString()).getValue(),
timestamps: Timestamps.create(
this.timer.getTimestampInMicroseconds(),
this.timer.getTimestampInMicroseconds(),
).getValue(),
keySystemIdentifier,
},
new UniqueEntityId(
dto.existingItem.props.keySystemAssociation
? dto.existingItem.props.keySystemAssociation.id.toString()
: undefined,
),
)
if (keySystemAssociationOrError.isFailed()) {
return Result.fail(keySystemAssociationOrError.getError())
}
dto.existingItem.props.keySystemAssociation = keySystemAssociationOrError.getValue()
dto.existingItem.setKeySystemAssociation(keySystemAssociationOrError.getValue())
} else {
dto.existingItem.unsetKeySystemAssociation()
}
if (dto.itemHash.props.deleted === true) {
@@ -199,6 +227,55 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
)
}
const notificationsResult = await this.addNotifications(dto.existingItem.uuid, userUuid, sharedVaultOperation)
if (notificationsResult.isFailed()) {
return Result.fail(notificationsResult.getError())
}
return Result.ok(dto.existingItem)
}
private async addNotifications(
itemUuid: Uuid,
userUuid: Uuid,
sharedVaultOperation: SharedVaultOperationOnItem | null,
): Promise<Result<void>> {
if (
sharedVaultOperation &&
sharedVaultOperation.props.type === SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault
) {
const notificationPayloadOrError = NotificationPayload.create({
sharedVaultUuid: sharedVaultOperation.props.sharedVaultUuid,
type: NotificationType.create(NotificationType.TYPES.SharedVaultItemRemoved).getValue(),
itemUuid: itemUuid,
version: '1.0',
})
if (notificationPayloadOrError.isFailed()) {
return Result.fail(notificationPayloadOrError.getError())
}
const payload = notificationPayloadOrError.getValue()
const result = await this.addNotificationForUser.execute({
payload,
type: NotificationType.TYPES.SharedVaultItemRemoved,
userUuid: userUuid.value,
version: '1.0',
})
if (result.isFailed()) {
return Result.fail(result.getError())
}
}
if (sharedVaultOperation && sharedVaultOperation.props.type === SharedVaultOperationOnItem.TYPES.AddToSharedVault) {
const result = await this.removeNotificationsForUser.execute({
type: NotificationType.TYPES.SharedVaultItemRemoved,
userUuid: userUuid.value,
})
if (result.isFailed()) {
return Result.fail(result.getError())
}
}
return Result.ok()
}
}

View File

@@ -38,6 +38,10 @@ export class HomeServerSharedVaultInvitesController extends BaseHttpController {
'sync.shared-vault-invites.delete-inbound',
this.deleteInboundUserInvites.bind(this),
)
this.controllerContainer.register(
'sync.shared-vault-invites.delete-outbound',
this.deleteOutboundUserInvites.bind(this),
)
this.controllerContainer.register(
'sync.shared-vault-invites.get-outbound',
this.getOutboundUserInvites.bind(this),
@@ -172,6 +176,27 @@ export class HomeServerSharedVaultInvitesController extends BaseHttpController {
})
}
async deleteOutboundUserInvites(_request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.deleteSharedVaultInvitesSentByUserUseCase.execute({
userUuid: response.locals.user.uuid,
})
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
HttpStatusCode.BadRequest,
)
}
return this.json({
success: true,
})
}
async getOutboundUserInvites(_request: Request, response: Response): Promise<results.JsonResult> {
const result = await this.getSharedVaultInvitesSentByUserUseCase.execute({
senderUuid: response.locals.user.uuid,

View File

@@ -72,6 +72,11 @@ export class InversifyExpressSharedVaultInvitesController extends HomeServerShar
return super.deleteInboundUserInvites(request, response)
}
@httpDelete('/invites/outbound')
override async deleteOutboundUserInvites(request: Request, response: Response): Promise<results.JsonResult> {
return super.deleteOutboundUserInvites(request, response)
}
@httpGet('/invites/outbound')
override async getOutboundUserInvites(request: Request, response: Response): Promise<results.JsonResult> {
return super.getOutboundUserInvites(request, response)

View File

@@ -1,6 +1,6 @@
import { ReadStream } from 'fs'
import { Repository, SelectQueryBuilder } from 'typeorm'
import { MapperInterface, Uuid } from '@standardnotes/domain-core'
import { Change, MapperInterface, Uuid } from '@standardnotes/domain-core'
import { Item } from '../../Domain/Item/Item'
import { ItemQuery } from '../../Domain/Item/ItemQuery'
@@ -10,6 +10,8 @@ import { TypeORMItem } from './TypeORMItem'
import { KeySystemAssociationRepositoryInterface } from '../../Domain/KeySystem/KeySystemAssociationRepositoryInterface'
import { SharedVaultAssociationRepositoryInterface } from '../../Domain/SharedVault/SharedVaultAssociationRepositoryInterface'
import { TypeORMSharedVaultAssociation } from './TypeORMSharedVaultAssociation'
import { SharedVaultAssociation } from '../../Domain/SharedVault/SharedVaultAssociation'
import { KeySystemAssociation } from '../../Domain/KeySystem/KeySystemAssociation'
export class TypeORMItemRepository implements ItemRepositoryInterface {
constructor(
@@ -24,13 +26,7 @@ export class TypeORMItemRepository implements ItemRepositoryInterface {
await this.ormRepository.save(persistence)
if (item.props.sharedVaultAssociation) {
await this.sharedVaultAssociationRepository.save(item.props.sharedVaultAssociation)
}
if (item.props.keySystemAssociation) {
await this.keySystemAssociationRepository.save(item.props.keySystemAssociation)
}
await this.persistAssociationChanges(item)
}
async remove(item: Item): Promise<void> {
@@ -273,4 +269,27 @@ export class TypeORMItemRepository implements ItemRepositoryInterface {
item.props.sharedVaultAssociation = sharedVaultAssociation
}
}
private async persistAssociationChanges(item: Item): Promise<void> {
for (const change of item.getChanges()) {
if (change.props.changeData instanceof SharedVaultAssociation) {
if ([Change.TYPES.Add, Change.TYPES.Modify].includes(change.props.changeType)) {
await this.sharedVaultAssociationRepository.save(change.props.changeData)
}
if (change.props.changeType === Change.TYPES.Remove) {
await this.sharedVaultAssociationRepository.remove(change.props.changeData)
}
}
if (change.props.changeData instanceof KeySystemAssociation) {
if ([Change.TYPES.Add, Change.TYPES.Modify].includes(change.props.changeType)) {
await this.keySystemAssociationRepository.save(change.props.changeData)
}
if (change.props.changeType === Change.TYPES.Remove) {
await this.keySystemAssociationRepository.remove(change.props.changeData)
}
}
}
item.flushChanges()
}
}

View File

@@ -1,5 +1,5 @@
import { Repository } from 'typeorm'
import { MapperInterface, Uuid } from '@standardnotes/domain-core'
import { MapperInterface, NotificationType, Uuid } from '@standardnotes/domain-core'
import { NotificationRepositoryInterface } from '../../Domain/Notifications/NotificationRepositoryInterface'
import { TypeORMNotification } from './TypeORMNotification'
@@ -11,6 +11,24 @@ export class TypeORMNotificationRepository implements NotificationRepositoryInte
private mapper: MapperInterface<Notification, TypeORMNotification>,
) {}
async findByUserUuidAndType(userUuid: Uuid, type: NotificationType): Promise<Notification[]> {
const persistence = await this.ormRepository
.createQueryBuilder('notification')
.where('notification.user_uuid = :userUuid', {
userUuid: userUuid.value,
})
.andWhere('notification.type = :type', {
type: type.value,
})
.getMany()
return persistence.map((p) => this.mapper.toDomain(p))
}
async remove(notification: Notification): Promise<void> {
await this.ormRepository.remove(this.mapper.toProjection(notification))
}
async save(sharedVault: Notification): Promise<void> {
const persistence = this.mapper.toProjection(sharedVault)

View File

@@ -14,6 +14,7 @@ export class MessageHttpMapper implements MapperInterface<Message, MessageHttpRe
recipient_uuid: domain.props.recipientUuid.value,
sender_uuid: domain.props.senderUuid.value,
encrypted_message: domain.props.encryptedMessage,
replaceability_identifier: domain.props.replaceabilityIdentifier,
created_at_timestamp: domain.props.timestamps.createdAt,
updated_at_timestamp: domain.props.timestamps.updatedAt,
}

View File

@@ -3,6 +3,7 @@ export interface MessageHttpRepresentation {
recipient_uuid: string
sender_uuid: string
encrypted_message: string
replaceability_identifier: string | null
created_at_timestamp: number
updated_at_timestamp: number
}

View File

@@ -1,8 +1,14 @@
import { Timestamps, MapperInterface, UniqueEntityId, Uuid, Validator } from '@standardnotes/domain-core'
import {
Timestamps,
MapperInterface,
UniqueEntityId,
Uuid,
Validator,
SharedVaultUserPermission,
} from '@standardnotes/domain-core'
import { SharedVaultInvite } from '../../Domain/SharedVault/User/Invite/SharedVaultInvite'
import { TypeORMSharedVaultInvite } from '../../Infra/TypeORM/TypeORMSharedVaultInvite'
import { SharedVaultUserPermission } from '../../Domain/SharedVault/User/SharedVaultUserPermission'
export class SharedVaultInvitePersistenceMapper
implements MapperInterface<SharedVaultInvite, TypeORMSharedVaultInvite>

View File

@@ -1,8 +1,13 @@
import { Timestamps, MapperInterface, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
import {
Timestamps,
MapperInterface,
UniqueEntityId,
Uuid,
SharedVaultUserPermission,
} from '@standardnotes/domain-core'
import { SharedVaultUser } from '../../Domain/SharedVault/User/SharedVaultUser'
import { TypeORMSharedVaultUser } from '../../Infra/TypeORM/TypeORMSharedVaultUser'
import { SharedVaultUserPermission } from '../../Domain/SharedVault/User/SharedVaultUserPermission'
export class SharedVaultUserPersistenceMapper implements MapperInterface<SharedVaultUser, TypeORMSharedVaultUser> {
toDomain(projection: TypeORMSharedVaultUser): SharedVaultUser {

View File

@@ -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.10.8](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.7...@standardnotes/websockets-server@1.10.8) (2023-07-27)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.10.7](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.6...@standardnotes/websockets-server@1.10.7) (2023-07-26)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.10.6](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.5...@standardnotes/websockets-server@1.10.6) (2023-07-26)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.10.5](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.4...@standardnotes/websockets-server@1.10.5) (2023-07-21)
**Note:** Version bump only for package @standardnotes/websockets-server

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/websockets-server",
"version": "1.10.5",
"version": "1.10.8",
"engines": {
"node": ">=18.0.0 <21.0.0"
},