mirror of
https://github.com/standardnotes/server
synced 2026-05-14 12:57:38 -04:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4db83ae678 | |||
| 84ceb7ffd2 | |||
| e215ac4343 | |||
| bc8048790f | |||
| 886ccf84c1 | |||
| c067cb9fe4 | |||
| 6b2389cdc3 | |||
| d93916b159 | |||
| c34f548e45 | |||
| 6fcd56cc86 | |||
| 8f88a87c93 | |||
| f8c2f84322 | |||
| 46c4947871 | |||
| 64759ec2da | |||
| 5f7e768e64 | |||
| 4bc189f1c5 | |||
| 71721ab198 | |||
| 5536a48966 | |||
| f77e29d3c9 | |||
| 4b1fc718a2 | |||
| 1708c3f8a0 | |||
| 352e02028d | |||
| 1bbb639c83 | |||
| c14265f103 | |||
| c030a6b3d8 | |||
| af997ea658 | |||
| efa4d7fc60 | |||
| f714aaa0e9 | |||
| aee6e60583 |
@@ -3,6 +3,7 @@ services:
|
|||||||
image: standardnotes/server
|
image: standardnotes/server
|
||||||
env_file: .env
|
env_file: .env
|
||||||
container_name: server_self_hosted
|
container_name: server_self_hosted
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
- 3125:3104
|
- 3125:3104
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [2.25.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.1...@standardnotes/analytics@2.25.2) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
## [2.25.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.0...@standardnotes/analytics@2.25.1) (2023-07-19)
|
## [2.25.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.0...@standardnotes/analytics@2.25.1) (2023-07-19)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/analytics
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/analytics",
|
"name": "@standardnotes/analytics",
|
||||||
"version": "2.25.1",
|
"version": "2.25.5",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,34 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.67.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.67.0...@standardnotes/api-gateway@1.67.1) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||||
|
|
||||||
|
# [1.67.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.66.1...@standardnotes/api-gateway@1.67.0) (2023-07-20)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **syncing-server:** add shared vaults, invites, messages and notifications to sync response ([#665](https://github.com/standardnotes/api-gateway/issues/665)) ([efa4d7f](https://github.com/standardnotes/api-gateway/commit/efa4d7fc6007ef668e3de3b04853ac11b2d13c30))
|
||||||
|
|
||||||
|
## [1.66.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.66.0...@standardnotes/api-gateway@1.66.1) (2023-07-19)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add missing imports and exports for controllers ([#664](https://github.com/standardnotes/api-gateway/issues/664)) ([aee6e60](https://github.com/standardnotes/api-gateway/commit/aee6e6058359e2b5231cc13387656f837699300f))
|
||||||
|
|
||||||
# [1.66.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.7...@standardnotes/api-gateway@1.66.0) (2023-07-19)
|
# [1.66.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.7...@standardnotes/api-gateway@1.66.0) (2023-07-19)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/api-gateway",
|
"name": "@standardnotes/api-gateway",
|
||||||
"version": "1.66.0",
|
"version": "1.67.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export * from './v1/OfflineController'
|
|||||||
export * from './v1/PaymentsController'
|
export * from './v1/PaymentsController'
|
||||||
export * from './v1/RevisionsController'
|
export * from './v1/RevisionsController'
|
||||||
export * from './v1/SessionsController'
|
export * from './v1/SessionsController'
|
||||||
|
export * from './v1/SharedVaultInvitesController'
|
||||||
|
export * from './v1/SharedVaultUsersController'
|
||||||
export * from './v1/SharedVaultsController'
|
export * from './v1/SharedVaultsController'
|
||||||
export * from './v1/SubscriptionInvitesController'
|
export * from './v1/SubscriptionInvitesController'
|
||||||
export * from './v1/TokensController'
|
export * from './v1/TokensController'
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class SharedVaultUsersController extends BaseHttpController {
|
|||||||
response,
|
response,
|
||||||
this.endpointResolver.resolveEndpointOrMethodIdentifier(
|
this.endpointResolver.resolveEndpointOrMethodIdentifier(
|
||||||
'GET',
|
'GET',
|
||||||
'/shared-vaults/:sharedVaultUuid/users',
|
'shared-vaults/:sharedVaultUuid/users',
|
||||||
request.params.sharedVaultUuid,
|
request.params.sharedVaultUuid,
|
||||||
),
|
),
|
||||||
request.body,
|
request.body,
|
||||||
@@ -35,7 +35,7 @@ export class SharedVaultUsersController extends BaseHttpController {
|
|||||||
response,
|
response,
|
||||||
this.endpointResolver.resolveEndpointOrMethodIdentifier(
|
this.endpointResolver.resolveEndpointOrMethodIdentifier(
|
||||||
'DELETE',
|
'DELETE',
|
||||||
'/shared-vaults/:sharedVaultUuid/users/:userUuid',
|
'shared-vaults/:sharedVaultUuid/users/:userUuid',
|
||||||
request.params.sharedVaultUuid,
|
request.params.sharedVaultUuid,
|
||||||
request.params.userUuid,
|
request.params.userUuid,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export class EndpointResolver implements EndpointResolverInterface {
|
|||||||
const identifier = this.endpointToIdentifierMap.get(`[${method}]:${endpoint}`)
|
const identifier = this.endpointToIdentifierMap.get(`[${method}]:${endpoint}`)
|
||||||
|
|
||||||
if (!identifier) {
|
if (!identifier) {
|
||||||
throw new Error(`Endpoint ${endpoint} not found`)
|
throw new Error(`Endpoint [${method}]:${endpoint} not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return identifier
|
return identifier
|
||||||
|
|||||||
@@ -3,6 +3,28 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.126.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.126.0...@standardnotes/auth-server@1.126.1) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|
||||||
|
# [1.126.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.125.1...@standardnotes/auth-server@1.126.0) (2023-07-20)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **syncing-server:** add shared vaults, invites, messages and notifications to sync response ([#665](https://github.com/standardnotes/server/issues/665)) ([efa4d7f](https://github.com/standardnotes/server/commit/efa4d7fc6007ef668e3de3b04853ac11b2d13c30))
|
||||||
|
|
||||||
## [1.125.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.125.0...@standardnotes/auth-server@1.125.1) (2023-07-19)
|
## [1.125.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.125.0...@standardnotes/auth-server@1.125.1) (2023-07-19)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/auth-server
|
**Note:** Version bump only for package @standardnotes/auth-server
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
||||||
|
|
||||||
export class AddNotifications1688540448427 implements MigrationInterface {
|
|
||||||
name = 'AddNotifications1688540448427'
|
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query(
|
|
||||||
'CREATE TABLE `notifications` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `type` varchar(36) NOT NULL, `payload` text NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `index_notifications_on_user_uuid` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query('DROP INDEX `index_notifications_on_user_uuid` ON `notifications`')
|
|
||||||
await queryRunner.query('DROP TABLE `notifications`')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
||||||
|
|
||||||
export class RemoveNotifications1688540448428 implements MigrationInterface {
|
|
||||||
name = 'RemoveNotifications1688540448428'
|
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query('DROP INDEX `index_notifications_on_user_uuid` ON `notifications`')
|
|
||||||
await queryRunner.query('DROP TABLE `notifications`')
|
|
||||||
}
|
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query(
|
|
||||||
'CREATE TABLE `notifications` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `type` varchar(36) NOT NULL, `payload` text NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `index_notifications_on_user_uuid` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
||||||
|
|
||||||
export class AddNotifications1688540623272 implements MigrationInterface {
|
|
||||||
name = 'AddNotifications1688540623272'
|
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query(
|
|
||||||
'CREATE TABLE "notifications" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(36) NOT NULL, "type" varchar(36) NOT NULL, "payload" text NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL)',
|
|
||||||
)
|
|
||||||
await queryRunner.query('CREATE INDEX "index_notifications_on_user_uuid" ON "notifications" ("user_uuid") ')
|
|
||||||
}
|
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query('DROP INDEX "index_notifications_on_user_uuid"')
|
|
||||||
await queryRunner.query('DROP TABLE "notifications"')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
||||||
|
|
||||||
export class RemoveNotifications1688540623273 implements MigrationInterface {
|
|
||||||
name = 'RemoveNotifications1688540623273'
|
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query('DROP INDEX "index_notifications_on_user_uuid"')
|
|
||||||
await queryRunner.query('DROP TABLE "notifications"')
|
|
||||||
}
|
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query(
|
|
||||||
'CREATE TABLE "notifications" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(36) NOT NULL, "type" varchar(36) NOT NULL, "payload" text NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL)',
|
|
||||||
)
|
|
||||||
await queryRunner.query('CREATE INDEX "index_notifications_on_user_uuid" ON "notifications" ("user_uuid") ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/auth-server",
|
"name": "@standardnotes/auth-server",
|
||||||
"version": "1.125.1",
|
"version": "1.126.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,30 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [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
|
||||||
|
|
||||||
|
* **domain-core:** notification payload creation from string ([1708c3f](https://github.com/standardnotes/server/commit/1708c3f8a00897369585e1ef8022950a7c3c610e))
|
||||||
|
|
||||||
|
## [1.23.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.23.1...@standardnotes/domain-core@1.23.2) (2023-07-21)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* user notifications structure ([#667](https://github.com/standardnotes/server/issues/667)) ([1bbb639](https://github.com/standardnotes/server/commit/1bbb639c83922ec09e3778f85419d76669d36ae3))
|
||||||
|
|
||||||
## [1.23.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.23.0...@standardnotes/domain-core@1.23.1) (2023-07-19)
|
## [1.23.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.23.0...@standardnotes/domain-core@1.23.1) (2023-07-19)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/domain-core",
|
"name": "@standardnotes/domain-core",
|
||||||
"version": "1.23.1",
|
"version": "1.24.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
/* istanbul ignore file */
|
/* istanbul ignore file */
|
||||||
|
|
||||||
|
import { Change } from './Change'
|
||||||
import { Entity } from './Entity'
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
|
||||||
|
import { Entity } from './Entity'
|
||||||
|
|
||||||
|
export interface ChangeProps {
|
||||||
|
aggregateRootUuid: string
|
||||||
|
changeType: string
|
||||||
|
changeData: Entity<unknown>
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { ValueObject } from '../Core/ValueObject'
|
||||||
|
import { Result } from '../Core/Result'
|
||||||
|
|
||||||
|
import { NotificationPayloadProps } from './NotificationPayloadProps'
|
||||||
|
import { NotificationType } from './NotificationType'
|
||||||
|
import { Uuid } from '../Common/Uuid'
|
||||||
|
|
||||||
|
export class NotificationPayload extends ValueObject<NotificationPayloadProps> {
|
||||||
|
private constructor(props: NotificationPayloadProps) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
override toString(): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
version: this.props.version,
|
||||||
|
type: this.props.type.value,
|
||||||
|
sharedVaultUuid: this.props.sharedVaultUuid.value,
|
||||||
|
itemUuid: this.props.itemUuid ? this.props.itemUuid.value : undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static createFromString(jsonPayload: string): Result<NotificationPayload> {
|
||||||
|
try {
|
||||||
|
const props = JSON.parse(jsonPayload)
|
||||||
|
|
||||||
|
const typeOrError = NotificationType.create(props.type)
|
||||||
|
if (typeOrError.isFailed()) {
|
||||||
|
return Result.fail<NotificationPayload>(typeOrError.getError())
|
||||||
|
}
|
||||||
|
const type = typeOrError.getValue()
|
||||||
|
|
||||||
|
const sharedVaultUuidOrError = Uuid.create(props.sharedVaultUuid)
|
||||||
|
if (sharedVaultUuidOrError.isFailed()) {
|
||||||
|
return Result.fail<NotificationPayload>(sharedVaultUuidOrError.getError())
|
||||||
|
}
|
||||||
|
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||||
|
|
||||||
|
let itemUuid: Uuid | undefined = undefined
|
||||||
|
if (props.itemUuid) {
|
||||||
|
const itemUuidOrError = Uuid.create(props.itemUuid)
|
||||||
|
if (itemUuidOrError.isFailed()) {
|
||||||
|
return Result.fail<NotificationPayload>(itemUuidOrError.getError())
|
||||||
|
}
|
||||||
|
itemUuid = itemUuidOrError.getValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotificationPayload.create({
|
||||||
|
version: props.version,
|
||||||
|
type,
|
||||||
|
sharedVaultUuid,
|
||||||
|
itemUuid,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
return Result.fail<NotificationPayload>((error as Error).message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(props: NotificationPayloadProps): Result<NotificationPayload> {
|
||||||
|
if (
|
||||||
|
props.itemUuid === undefined &&
|
||||||
|
props.type.equals(NotificationType.create(NotificationType.TYPES.SharedVaultItemRemoved).getValue())
|
||||||
|
) {
|
||||||
|
return Result.fail<NotificationPayload>(
|
||||||
|
`Item uuid is required for ${NotificationType.TYPES.SharedVaultItemRemoved} notification type`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok<NotificationPayload>(new NotificationPayload(props))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { Uuid } from '../Common/Uuid'
|
||||||
|
import { NotificationType } from './NotificationType'
|
||||||
|
|
||||||
|
export interface NotificationPayloadProps {
|
||||||
|
type: NotificationType
|
||||||
|
sharedVaultUuid: Uuid
|
||||||
|
version: string
|
||||||
|
itemUuid?: Uuid
|
||||||
|
}
|
||||||
+5
-5
@@ -1,5 +1,5 @@
|
|||||||
import { ValueObject, Result } from '@standardnotes/domain-core'
|
import { Result } from '../Core/Result'
|
||||||
|
import { ValueObject } from '../Core/ValueObject'
|
||||||
import { NotificationTypeProps } from './NotificationTypeProps'
|
import { NotificationTypeProps } from './NotificationTypeProps'
|
||||||
|
|
||||||
export class NotificationType extends ValueObject<NotificationTypeProps> {
|
export class NotificationType extends ValueObject<NotificationTypeProps> {
|
||||||
@@ -17,9 +17,9 @@ export class NotificationType extends ValueObject<NotificationTypeProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static create(notificationType: string): Result<NotificationType> {
|
static create(notificationType: string): Result<NotificationType> {
|
||||||
const isValidPermission = Object.values(this.TYPES).includes(notificationType)
|
const isValidType = Object.values(this.TYPES).includes(notificationType)
|
||||||
if (!isValidPermission) {
|
if (!isValidType) {
|
||||||
return Result.fail<NotificationType>(`Invalid shared vault user permission ${notificationType}`)
|
return Result.fail<NotificationType>(`Invalid notification type: ${notificationType}`)
|
||||||
} else {
|
} else {
|
||||||
return Result.ok<NotificationType>(new NotificationType({ value: notificationType }))
|
return Result.ok<NotificationType>(new NotificationType({ value: notificationType }))
|
||||||
}
|
}
|
||||||
+2
-1
@@ -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'
|
import { SharedVaultUserPermissionProps } from './SharedVaultUserPermissionProps'
|
||||||
|
|
||||||
@@ -27,6 +27,8 @@ export * from './Common/Uuid'
|
|||||||
export * from './Common/UuidProps'
|
export * from './Common/UuidProps'
|
||||||
|
|
||||||
export * from './Core/Aggregate'
|
export * from './Core/Aggregate'
|
||||||
|
export * from './Core/Change'
|
||||||
|
export * from './Core/ChangeProps'
|
||||||
export * from './Core/Entity'
|
export * from './Core/Entity'
|
||||||
export * from './Core/Id'
|
export * from './Core/Id'
|
||||||
export * from './Core/Result'
|
export * from './Core/Result'
|
||||||
@@ -45,6 +47,11 @@ export * from './Env/AbstractEnv'
|
|||||||
|
|
||||||
export * from './Mapping/MapperInterface'
|
export * from './Mapping/MapperInterface'
|
||||||
|
|
||||||
|
export * from './Notification/NotificationPayload'
|
||||||
|
export * from './Notification/NotificationPayloadProps'
|
||||||
|
export * from './Notification/NotificationType'
|
||||||
|
export * from './Notification/NotificationTypeProps'
|
||||||
|
|
||||||
export * from './Service/ServiceConfiguration'
|
export * from './Service/ServiceConfiguration'
|
||||||
export * from './Service/ServiceContainer'
|
export * from './Service/ServiceContainer'
|
||||||
export * from './Service/ServiceContainerInterface'
|
export * from './Service/ServiceContainerInterface'
|
||||||
@@ -52,6 +59,9 @@ export * from './Service/ServiceIdentifier'
|
|||||||
export * from './Service/ServiceIdentifierProps'
|
export * from './Service/ServiceIdentifierProps'
|
||||||
export * from './Service/ServiceInterface'
|
export * from './Service/ServiceInterface'
|
||||||
|
|
||||||
|
export * from './SharedVault/SharedVaultUserPermission'
|
||||||
|
export * from './SharedVault/SharedVaultUserPermissionProps'
|
||||||
|
|
||||||
export * from './Subscription/SubscriptionPlanName'
|
export * from './Subscription/SubscriptionPlanName'
|
||||||
export * from './Subscription/SubscriptionPlanNameProps'
|
export * from './Subscription/SubscriptionPlanNameProps'
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.11.9](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.8...@standardnotes/event-store@1.11.9) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/event-store
|
||||||
|
|
||||||
## [1.11.8](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.7...@standardnotes/event-store@1.11.8) (2023-07-19)
|
## [1.11.8](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.7...@standardnotes/event-store@1.11.8) (2023-07-19)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/event-store
|
**Note:** Version bump only for package @standardnotes/event-store
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/event-store",
|
"name": "@standardnotes/event-store",
|
||||||
"version": "1.11.8",
|
"version": "1.11.12",
|
||||||
"description": "Event Store Service",
|
"description": "Event Store Service",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "dist/src/index.js",
|
"main": "dist/src/index.js",
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.19.11](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.10...@standardnotes/files-server@1.19.11) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/files-server
|
||||||
|
|
||||||
## [1.19.10](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.9...@standardnotes/files-server@1.19.10) (2023-07-19)
|
## [1.19.10](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.9...@standardnotes/files-server@1.19.10) (2023-07-19)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/files-server
|
**Note:** Version bump only for package @standardnotes/files-server
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/files-server",
|
"name": "@standardnotes/files-server",
|
||||||
"version": "1.19.10",
|
"version": "1.19.14",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,62 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.13.8](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.7...@standardnotes/home-server@1.13.8) (2023-07-25)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.13.7](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.6...@standardnotes/home-server@1.13.7) (2023-07-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.13.6](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.5...@standardnotes/home-server@1.13.6) (2023-07-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.13.5](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.4...@standardnotes/home-server@1.13.5) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.13.4](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.3...@standardnotes/home-server@1.13.4) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.13.3](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.2...@standardnotes/home-server@1.13.3) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.13.2](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.1...@standardnotes/home-server@1.13.2) (2023-07-20)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
|
## [1.13.1](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.13.0...@standardnotes/home-server@1.13.1) (2023-07-19)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/home-server
|
||||||
|
|
||||||
# [1.13.0](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.12.6...@standardnotes/home-server@1.13.0) (2023-07-19)
|
# [1.13.0](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.12.6...@standardnotes/home-server@1.13.0) (2023-07-19)
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/home-server",
|
"name": "@standardnotes/home-server",
|
||||||
"version": "1.13.0",
|
"version": "1.13.14",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.25.2](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.25.1...@standardnotes/revisions-server@1.25.2) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||||
|
|
||||||
## [1.25.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.25.0...@standardnotes/revisions-server@1.25.1) (2023-07-19)
|
## [1.25.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.25.0...@standardnotes/revisions-server@1.25.1) (2023-07-19)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/revisions-server",
|
"name": "@standardnotes/revisions-server",
|
||||||
"version": "1.25.1",
|
"version": "1.25.5",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.20.11](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.10...@standardnotes/scheduler-server@1.20.11) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||||
|
|
||||||
## [1.20.10](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.9...@standardnotes/scheduler-server@1.20.10) (2023-07-19)
|
## [1.20.10](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.9...@standardnotes/scheduler-server@1.20.10) (2023-07-19)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/scheduler-server",
|
"name": "@standardnotes/scheduler-server",
|
||||||
"version": "1.20.10",
|
"version": "1.20.14",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [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
|
||||||
|
|
||||||
|
## [1.21.16](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.15...@standardnotes/settings@1.21.16) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/settings
|
||||||
|
|
||||||
## [1.21.15](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.14...@standardnotes/settings@1.21.15) (2023-07-19)
|
## [1.21.15](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.14...@standardnotes/settings@1.21.15) (2023-07-19)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/settings
|
**Note:** Version bump only for package @standardnotes/settings
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/settings",
|
"name": "@standardnotes/settings",
|
||||||
"version": "1.21.15",
|
"version": "1.21.19",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,88 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [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
|
||||||
|
|
||||||
|
* **syncing-server:** allow sender to decline the invite ([#671](https://github.com/standardnotes/syncing-server-js/issues/671)) ([46c4947](https://github.com/standardnotes/syncing-server-js/commit/46c4947871f342f0a07c68562b0e3e77e7e114d4))
|
||||||
|
|
||||||
|
# [1.70.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.69.0...@standardnotes/syncing-server@1.70.0) (2023-07-25)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **syncing-server:** filtering items by shared vault permissions ([#670](https://github.com/standardnotes/syncing-server-js/issues/670)) ([5f7e768](https://github.com/standardnotes/syncing-server-js/commit/5f7e768e64da0452e6efcf70e36cb5e867291456))
|
||||||
|
|
||||||
|
# [1.69.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.68.4...@standardnotes/syncing-server@1.69.0) (2023-07-24)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **syncing-server:** determin shared vault operation type ([#669](https://github.com/standardnotes/syncing-server-js/issues/669)) ([71721ab](https://github.com/standardnotes/syncing-server-js/commit/71721ab1982b65feb4c84b44b267a249b573c537))
|
||||||
|
|
||||||
|
## [1.68.4](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.68.3...@standardnotes/syncing-server@1.68.4) (2023-07-24)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **syncing-server:** force remove shared vault owner when removing shared vault ([f77e29d](https://github.com/standardnotes/syncing-server-js/commit/f77e29d3c9c9a28be3c5624d2c9bf0ffd6348377))
|
||||||
|
|
||||||
|
## [1.68.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.68.2...@standardnotes/syncing-server@1.68.3) (2023-07-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||||
|
|
||||||
|
## [1.68.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.68.1...@standardnotes/syncing-server@1.68.2) (2023-07-21)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* user notifications structure ([#667](https://github.com/standardnotes/syncing-server-js/issues/667)) ([1bbb639](https://github.com/standardnotes/syncing-server-js/commit/1bbb639c83922ec09e3778f85419d76669d36ae3))
|
||||||
|
|
||||||
|
## [1.68.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.68.0...@standardnotes/syncing-server@1.68.1) (2023-07-21)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **syncing-server:** fetching items associated with shared vaults ([#666](https://github.com/standardnotes/syncing-server-js/issues/666)) ([c030a6b](https://github.com/standardnotes/syncing-server-js/commit/c030a6b3d838b1f09593905d28ace65097a3a940))
|
||||||
|
|
||||||
|
# [1.68.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.67.1...@standardnotes/syncing-server@1.68.0) (2023-07-20)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **syncing-server:** add shared vaults, invites, messages and notifications to sync response ([#665](https://github.com/standardnotes/syncing-server-js/issues/665)) ([efa4d7f](https://github.com/standardnotes/syncing-server-js/commit/efa4d7fc6007ef668e3de3b04853ac11b2d13c30))
|
||||||
|
|
||||||
|
## [1.67.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.67.0...@standardnotes/syncing-server@1.67.1) (2023-07-19)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add missing imports and exports for controllers ([#664](https://github.com/standardnotes/syncing-server-js/issues/664)) ([aee6e60](https://github.com/standardnotes/syncing-server-js/commit/aee6e6058359e2b5231cc13387656f837699300f))
|
||||||
|
|
||||||
# [1.67.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.66.0...@standardnotes/syncing-server@1.67.0) (2023-07-19)
|
# [1.67.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.66.0...@standardnotes/syncing-server@1.67.0) (2023-07-19)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import 'reflect-metadata'
|
|||||||
|
|
||||||
import '../src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController'
|
import '../src/Infra/InversifyExpressUtils/InversifyExpressHealthCheckController'
|
||||||
import '../src/Infra/InversifyExpressUtils/InversifyExpressItemsController'
|
import '../src/Infra/InversifyExpressUtils/InversifyExpressItemsController'
|
||||||
|
import '../src/Infra/InversifyExpressUtils/InversifyExpressMessagesController'
|
||||||
|
import '../src/Infra/InversifyExpressUtils/InversifyExpressSharedVaultInvitesController'
|
||||||
|
import '../src/Infra/InversifyExpressUtils/InversifyExpressSharedVaultUsersController'
|
||||||
|
import '../src/Infra/InversifyExpressUtils/InversifyExpressSharedVaultsController'
|
||||||
|
|
||||||
import helmet from 'helmet'
|
import helmet from 'helmet'
|
||||||
import * as cors from 'cors'
|
import * as cors from 'cors'
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
|
||||||
|
|
||||||
export class AddNotifications1688540448427 implements MigrationInterface {
|
|
||||||
name = 'AddNotifications1688540448427'
|
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query(
|
|
||||||
'CREATE TABLE `notifications` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `type` varchar(36) NOT NULL, `payload` text NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `index_notifications_on_user_uuid` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
||||||
await queryRunner.query('DROP INDEX `index_notifications_on_user_uuid` ON `notifications`')
|
|
||||||
await queryRunner.query('DROP TABLE `notifications`')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
|
export class AddNotifications1689671563304 implements MigrationInterface {
|
||||||
|
name = 'AddNotifications1689671563304'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
'CREATE TABLE IF NOT EXISTS `notifications` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `type` varchar(36) NOT NULL, `payload` text NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `index_notifications_on_user_uuid` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query('DROP INDEX `index_notifications_on_user_uuid` ON `notifications`')
|
||||||
|
await queryRunner.query('DROP TABLE `notifications`')
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -1,11 +1,11 @@
|
|||||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||||
|
|
||||||
export class AddNotifications1688540623272 implements MigrationInterface {
|
export class AddNotifications1689672099828 implements MigrationInterface {
|
||||||
name = 'AddNotifications1688540623272'
|
name = 'AddNotifications1689672099828'
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
'CREATE TABLE "notifications" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(36) NOT NULL, "type" varchar(36) NOT NULL, "payload" text NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL)',
|
'CREATE TABLE IF NOT EXISTS "notifications" ("uuid" varchar PRIMARY KEY NOT NULL, "user_uuid" varchar(36) NOT NULL, "type" varchar(36) NOT NULL, "payload" text NOT NULL, "created_at_timestamp" bigint NOT NULL, "updated_at_timestamp" bigint NOT NULL)',
|
||||||
)
|
)
|
||||||
await queryRunner.query('CREATE INDEX "index_notifications_on_user_uuid" ON "notifications" ("user_uuid") ')
|
await queryRunner.query('CREATE INDEX "index_notifications_on_user_uuid" ON "notifications" ("user_uuid") ')
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/syncing-server",
|
"name": "@standardnotes/syncing-server",
|
||||||
"version": "1.67.0",
|
"version": "1.71.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -147,6 +147,12 @@ import { DeleteAllMessagesSentToUser } from '../Domain/UseCase/Messaging/DeleteA
|
|||||||
import { DeleteMessage } from '../Domain/UseCase/Messaging/DeleteMessage/DeleteMessage'
|
import { DeleteMessage } from '../Domain/UseCase/Messaging/DeleteMessage/DeleteMessage'
|
||||||
import { MessageHttpRepresentation } from '../Mapping/Http/MessageHttpRepresentation'
|
import { MessageHttpRepresentation } from '../Mapping/Http/MessageHttpRepresentation'
|
||||||
import { MessageHttpMapper } from '../Mapping/Http/MessageHttpMapper'
|
import { MessageHttpMapper } from '../Mapping/Http/MessageHttpMapper'
|
||||||
|
import { GetUserNotifications } from '../Domain/UseCase/Messaging/GetUserNotifications/GetUserNotifications'
|
||||||
|
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 {
|
export class ContainerConfigLoader {
|
||||||
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
|
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
|
||||||
@@ -340,6 +346,9 @@ export class ContainerConfigLoader {
|
|||||||
container
|
container
|
||||||
.bind<MapperInterface<Message, MessageHttpRepresentation>>(TYPES.Sync_MessageHttpMapper)
|
.bind<MapperInterface<Message, MessageHttpRepresentation>>(TYPES.Sync_MessageHttpMapper)
|
||||||
.toConstantValue(new MessageHttpMapper())
|
.toConstantValue(new MessageHttpMapper())
|
||||||
|
container
|
||||||
|
.bind<MapperInterface<Notification, NotificationHttpRepresentation>>(TYPES.Sync_NotificationHttpMapper)
|
||||||
|
.toConstantValue(new NotificationHttpMapper())
|
||||||
|
|
||||||
// ORM
|
// ORM
|
||||||
container
|
container
|
||||||
@@ -488,12 +497,24 @@ export class ContainerConfigLoader {
|
|||||||
.bind<TokenEncoderInterface<SharedVaultValetTokenData>>(TYPES.Sync_SharedVaultValetTokenEncoder)
|
.bind<TokenEncoderInterface<SharedVaultValetTokenData>>(TYPES.Sync_SharedVaultValetTokenEncoder)
|
||||||
.toConstantValue(new TokenEncoder<SharedVaultValetTokenData>(container.get(TYPES.Sync_VALET_TOKEN_SECRET)))
|
.toConstantValue(new TokenEncoder<SharedVaultValetTokenData>(container.get(TYPES.Sync_VALET_TOKEN_SECRET)))
|
||||||
|
|
||||||
|
container
|
||||||
|
.bind<DetermineSharedVaultOperationOnItem>(TYPES.Sync_DetermineSharedVaultOperationOnItem)
|
||||||
|
.toConstantValue(new DetermineSharedVaultOperationOnItem())
|
||||||
|
|
||||||
container.bind<OwnershipFilter>(TYPES.Sync_OwnershipFilter).toConstantValue(new OwnershipFilter())
|
container.bind<OwnershipFilter>(TYPES.Sync_OwnershipFilter).toConstantValue(new OwnershipFilter())
|
||||||
container
|
container
|
||||||
.bind<TimeDifferenceFilter>(TYPES.Sync_TimeDifferenceFilter)
|
.bind<TimeDifferenceFilter>(TYPES.Sync_TimeDifferenceFilter)
|
||||||
.toConstantValue(new TimeDifferenceFilter(container.get(TYPES.Sync_Timer)))
|
.toConstantValue(new TimeDifferenceFilter(container.get(TYPES.Sync_Timer)))
|
||||||
container.bind<ContentTypeFilter>(TYPES.Sync_ContentTypeFilter).toConstantValue(new ContentTypeFilter())
|
container.bind<ContentTypeFilter>(TYPES.Sync_ContentTypeFilter).toConstantValue(new ContentTypeFilter())
|
||||||
container.bind<ContentFilter>(TYPES.Sync_ContentFilter).toConstantValue(new ContentFilter())
|
container.bind<ContentFilter>(TYPES.Sync_ContentFilter).toConstantValue(new ContentFilter())
|
||||||
|
container
|
||||||
|
.bind<SharedVaultFilter>(TYPES.Sync_SharedVaultFilter)
|
||||||
|
.toConstantValue(
|
||||||
|
new SharedVaultFilter(
|
||||||
|
container.get(TYPES.Sync_DetermineSharedVaultOperationOnItem),
|
||||||
|
container.get(TYPES.Sync_SharedVaultUserRepository),
|
||||||
|
),
|
||||||
|
)
|
||||||
container
|
container
|
||||||
.bind<ItemSaveValidatorInterface>(TYPES.Sync_ItemSaveValidator)
|
.bind<ItemSaveValidatorInterface>(TYPES.Sync_ItemSaveValidator)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -502,6 +523,7 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_TimeDifferenceFilter),
|
container.get(TYPES.Sync_TimeDifferenceFilter),
|
||||||
container.get(TYPES.Sync_ContentTypeFilter),
|
container.get(TYPES.Sync_ContentTypeFilter),
|
||||||
container.get(TYPES.Sync_ContentFilter),
|
container.get(TYPES.Sync_ContentFilter),
|
||||||
|
container.get(TYPES.Sync_SharedVaultFilter),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -511,6 +533,7 @@ export class ContainerConfigLoader {
|
|||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
new GetItems(
|
new GetItems(
|
||||||
container.get(TYPES.Sync_ItemRepository),
|
container.get(TYPES.Sync_ItemRepository),
|
||||||
|
container.get(TYPES.Sync_SharedVaultUserRepository),
|
||||||
container.get(TYPES.Sync_CONTENT_SIZE_TRANSFER_LIMIT),
|
container.get(TYPES.Sync_CONTENT_SIZE_TRANSFER_LIMIT),
|
||||||
container.get(TYPES.Sync_ItemTransferCalculator),
|
container.get(TYPES.Sync_ItemTransferCalculator),
|
||||||
container.get(TYPES.Sync_Timer),
|
container.get(TYPES.Sync_Timer),
|
||||||
@@ -527,6 +550,14 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_DomainEventFactory),
|
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
|
container
|
||||||
.bind<UpdateExistingItem>(TYPES.Sync_UpdateExistingItem)
|
.bind<UpdateExistingItem>(TYPES.Sync_UpdateExistingItem)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -536,6 +567,9 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_DomainEventPublisher),
|
container.get(TYPES.Sync_DomainEventPublisher),
|
||||||
container.get(TYPES.Sync_DomainEventFactory),
|
container.get(TYPES.Sync_DomainEventFactory),
|
||||||
container.get(TYPES.Sync_REVISIONS_FREQUENCY),
|
container.get(TYPES.Sync_REVISIONS_FREQUENCY),
|
||||||
|
container.get(TYPES.Sync_DetermineSharedVaultOperationOnItem),
|
||||||
|
container.get(TYPES.Sync_AddNotificationForUser),
|
||||||
|
container.get(TYPES.Sync_RemoveNotificationsForUser),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
@@ -550,6 +584,24 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_Logger),
|
container.get(TYPES.Sync_Logger),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
container
|
||||||
|
.bind<GetUserNotifications>(TYPES.Sync_GetUserNotifications)
|
||||||
|
.toConstantValue(new GetUserNotifications(container.get(TYPES.Sync_NotificationRepository)))
|
||||||
|
container
|
||||||
|
.bind<GetSharedVaults>(TYPES.Sync_GetSharedVaults)
|
||||||
|
.toConstantValue(
|
||||||
|
new GetSharedVaults(
|
||||||
|
container.get(TYPES.Sync_SharedVaultUserRepository),
|
||||||
|
container.get(TYPES.Sync_SharedVaultRepository),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container
|
||||||
|
.bind<GetSharedVaultInvitesSentToUser>(TYPES.Sync_GetSharedVaultInvitesSentToUser)
|
||||||
|
.toConstantValue(new GetSharedVaultInvitesSentToUser(container.get(TYPES.Sync_SharedVaultInviteRepository)))
|
||||||
|
container
|
||||||
|
.bind<GetMessagesSentToUser>(TYPES.Sync_GetMessagesSentToUser)
|
||||||
|
.toConstantValue(new GetMessagesSentToUser(container.get(TYPES.Sync_MessageRepository)))
|
||||||
|
|
||||||
container
|
container
|
||||||
.bind<SyncItems>(TYPES.Sync_SyncItems)
|
.bind<SyncItems>(TYPES.Sync_SyncItems)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -557,6 +609,10 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_ItemRepository),
|
container.get(TYPES.Sync_ItemRepository),
|
||||||
container.get(TYPES.Sync_GetItems),
|
container.get(TYPES.Sync_GetItems),
|
||||||
container.get(TYPES.Sync_SaveItems),
|
container.get(TYPES.Sync_SaveItems),
|
||||||
|
container.get(TYPES.Sync_GetSharedVaults),
|
||||||
|
container.get(TYPES.Sync_GetSharedVaultInvitesSentToUser),
|
||||||
|
container.get(TYPES.Sync_GetMessagesSentToUser),
|
||||||
|
container.get(TYPES.Sync_GetUserNotifications),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container.bind<CheckIntegrity>(TYPES.Sync_CheckIntegrity).toDynamicValue((context: interfaces.Context) => {
|
container.bind<CheckIntegrity>(TYPES.Sync_CheckIntegrity).toDynamicValue((context: interfaces.Context) => {
|
||||||
@@ -621,9 +677,6 @@ export class ContainerConfigLoader {
|
|||||||
container
|
container
|
||||||
.bind<GetSharedVaultInvitesSentByUser>(TYPES.Sync_GetSharedVaultInvitesSentByUser)
|
.bind<GetSharedVaultInvitesSentByUser>(TYPES.Sync_GetSharedVaultInvitesSentByUser)
|
||||||
.toConstantValue(new GetSharedVaultInvitesSentByUser(container.get(TYPES.Sync_SharedVaultInviteRepository)))
|
.toConstantValue(new GetSharedVaultInvitesSentByUser(container.get(TYPES.Sync_SharedVaultInviteRepository)))
|
||||||
container
|
|
||||||
.bind<GetSharedVaultInvitesSentToUser>(TYPES.Sync_GetSharedVaultInvitesSentToUser)
|
|
||||||
.toConstantValue(new GetSharedVaultInvitesSentToUser(container.get(TYPES.Sync_SharedVaultInviteRepository)))
|
|
||||||
container
|
container
|
||||||
.bind<GetSharedVaultUsers>(TYPES.Sync_GetSharedVaultUsers)
|
.bind<GetSharedVaultUsers>(TYPES.Sync_GetSharedVaultUsers)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -632,11 +685,6 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_SharedVaultRepository),
|
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
|
container
|
||||||
.bind<RemoveUserFromSharedVault>(TYPES.Sync_RemoveSharedVaultUser)
|
.bind<RemoveUserFromSharedVault>(TYPES.Sync_RemoveSharedVaultUser)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -646,14 +694,6 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_AddNotificationForUser),
|
container.get(TYPES.Sync_AddNotificationForUser),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
|
||||||
.bind<GetSharedVaults>(TYPES.Sync_GetSharedVaults)
|
|
||||||
.toConstantValue(
|
|
||||||
new GetSharedVaults(
|
|
||||||
container.get(TYPES.Sync_SharedVaultUserRepository),
|
|
||||||
container.get(TYPES.Sync_SharedVaultRepository),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
container
|
container
|
||||||
.bind<CreateSharedVault>(TYPES.Sync_CreateSharedVault)
|
.bind<CreateSharedVault>(TYPES.Sync_CreateSharedVault)
|
||||||
.toConstantValue(
|
.toConstantValue(
|
||||||
@@ -683,9 +723,6 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_VALET_TOKEN_TTL),
|
container.get(TYPES.Sync_VALET_TOKEN_TTL),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
|
||||||
.bind<GetMessagesSentToUser>(TYPES.Sync_GetMessagesSentToUser)
|
|
||||||
.toConstantValue(new GetMessagesSentToUser(container.get(TYPES.Sync_MessageRepository)))
|
|
||||||
container
|
container
|
||||||
.bind<GetMessagesSentByUser>(TYPES.Sync_GetMessagesSentByUser)
|
.bind<GetMessagesSentByUser>(TYPES.Sync_GetMessagesSentByUser)
|
||||||
.toConstantValue(new GetMessagesSentByUser(container.get(TYPES.Sync_MessageRepository)))
|
.toConstantValue(new GetMessagesSentByUser(container.get(TYPES.Sync_MessageRepository)))
|
||||||
@@ -717,6 +754,10 @@ export class ContainerConfigLoader {
|
|||||||
container.get(TYPES.Sync_ItemHttpMapper),
|
container.get(TYPES.Sync_ItemHttpMapper),
|
||||||
container.get(TYPES.Sync_ItemConflictHttpMapper),
|
container.get(TYPES.Sync_ItemConflictHttpMapper),
|
||||||
container.get(TYPES.Sync_SavedItemHttpMapper),
|
container.get(TYPES.Sync_SavedItemHttpMapper),
|
||||||
|
container.get(TYPES.Sync_SharedVaultHttpMapper),
|
||||||
|
container.get(TYPES.Sync_SharedVaultInviteHttpMapper),
|
||||||
|
container.get(TYPES.Sync_MessageHttpMapper),
|
||||||
|
container.get(TYPES.Sync_NotificationHttpMapper),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
container
|
container
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const TYPES = {
|
|||||||
Sync_GetSharedVaultUsers: Symbol.for('Sync_GetSharedVaultUsers'),
|
Sync_GetSharedVaultUsers: Symbol.for('Sync_GetSharedVaultUsers'),
|
||||||
Sync_AddUserToSharedVault: Symbol.for('Sync_AddUserToSharedVault'),
|
Sync_AddUserToSharedVault: Symbol.for('Sync_AddUserToSharedVault'),
|
||||||
Sync_AddNotificationForUser: Symbol.for('Sync_AddNotificationForUser'),
|
Sync_AddNotificationForUser: Symbol.for('Sync_AddNotificationForUser'),
|
||||||
|
Sync_RemoveNotificationsForUser: Symbol.for('Sync_RemoveNotificationsForUser'),
|
||||||
Sync_RemoveSharedVaultUser: Symbol.for('Sync_RemoveSharedVaultUser'),
|
Sync_RemoveSharedVaultUser: Symbol.for('Sync_RemoveSharedVaultUser'),
|
||||||
Sync_InviteUserToSharedVault: Symbol.for('Sync_InviteUserToSharedVault'),
|
Sync_InviteUserToSharedVault: Symbol.for('Sync_InviteUserToSharedVault'),
|
||||||
Sync_UpdateSharedVaultInvite: Symbol.for('Sync_UpdateSharedVaultInvite'),
|
Sync_UpdateSharedVaultInvite: Symbol.for('Sync_UpdateSharedVaultInvite'),
|
||||||
@@ -75,6 +76,8 @@ const TYPES = {
|
|||||||
Sync_UpdateExistingItem: Symbol.for('Sync_UpdateExistingItem'),
|
Sync_UpdateExistingItem: Symbol.for('Sync_UpdateExistingItem'),
|
||||||
Sync_GetItems: Symbol.for('Sync_GetItems'),
|
Sync_GetItems: Symbol.for('Sync_GetItems'),
|
||||||
Sync_SaveItems: Symbol.for('Sync_SaveItems'),
|
Sync_SaveItems: Symbol.for('Sync_SaveItems'),
|
||||||
|
Sync_GetUserNotifications: Symbol.for('Sync_GetUserNotifications'),
|
||||||
|
Sync_DetermineSharedVaultOperationOnItem: Symbol.for('Sync_DetermineSharedVaultOperationOnItem'),
|
||||||
// Handlers
|
// Handlers
|
||||||
Sync_AccountDeletionRequestedEventHandler: Symbol.for('Sync_AccountDeletionRequestedEventHandler'),
|
Sync_AccountDeletionRequestedEventHandler: Symbol.for('Sync_AccountDeletionRequestedEventHandler'),
|
||||||
Sync_DuplicateItemSyncedEventHandler: Symbol.for('Sync_DuplicateItemSyncedEventHandler'),
|
Sync_DuplicateItemSyncedEventHandler: Symbol.for('Sync_DuplicateItemSyncedEventHandler'),
|
||||||
@@ -97,6 +100,7 @@ const TYPES = {
|
|||||||
Sync_ItemBackupService: Symbol.for('Sync_ItemBackupService'),
|
Sync_ItemBackupService: Symbol.for('Sync_ItemBackupService'),
|
||||||
Sync_ItemSaveValidator: Symbol.for('Sync_ItemSaveValidator'),
|
Sync_ItemSaveValidator: Symbol.for('Sync_ItemSaveValidator'),
|
||||||
Sync_OwnershipFilter: Symbol.for('Sync_OwnershipFilter'),
|
Sync_OwnershipFilter: Symbol.for('Sync_OwnershipFilter'),
|
||||||
|
Sync_SharedVaultFilter: Symbol.for('Sync_SharedVaultFilter'),
|
||||||
Sync_TimeDifferenceFilter: Symbol.for('Sync_TimeDifferenceFilter'),
|
Sync_TimeDifferenceFilter: Symbol.for('Sync_TimeDifferenceFilter'),
|
||||||
Sync_ContentTypeFilter: Symbol.for('Sync_ContentTypeFilter'),
|
Sync_ContentTypeFilter: Symbol.for('Sync_ContentTypeFilter'),
|
||||||
Sync_ContentFilter: Symbol.for('Sync_ContentFilter'),
|
Sync_ContentFilter: Symbol.for('Sync_ContentFilter'),
|
||||||
@@ -113,6 +117,7 @@ const TYPES = {
|
|||||||
Sync_SharedVaultInviteHttpMapper: Symbol.for('Sync_SharedVaultInviteHttpMapper'),
|
Sync_SharedVaultInviteHttpMapper: Symbol.for('Sync_SharedVaultInviteHttpMapper'),
|
||||||
Sync_MessagePersistenceMapper: Symbol.for('Sync_MessagePersistenceMapper'),
|
Sync_MessagePersistenceMapper: Symbol.for('Sync_MessagePersistenceMapper'),
|
||||||
Sync_MessageHttpMapper: Symbol.for('Sync_MessageHttpMapper'),
|
Sync_MessageHttpMapper: Symbol.for('Sync_MessageHttpMapper'),
|
||||||
|
Sync_NotificationHttpMapper: Symbol.for('Sync_NotificationHttpMapper'),
|
||||||
Sync_ItemPersistenceMapper: Symbol.for('Sync_ItemPersistenceMapper'),
|
Sync_ItemPersistenceMapper: Symbol.for('Sync_ItemPersistenceMapper'),
|
||||||
Sync_ItemHttpMapper: Symbol.for('Sync_ItemHttpMapper'),
|
Sync_ItemHttpMapper: Symbol.for('Sync_ItemHttpMapper'),
|
||||||
Sync_ItemHashHttpMapper: Symbol.for('Sync_ItemHashHttpMapper'),
|
Sync_ItemHashHttpMapper: Symbol.for('Sync_ItemHashHttpMapper'),
|
||||||
|
|||||||
@@ -0,0 +1,252 @@
|
|||||||
|
import { ContentType, Dates, Timestamps, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
|
import { Item } from './Item'
|
||||||
|
import { SharedVaultAssociation } from '../SharedVault/SharedVaultAssociation'
|
||||||
|
import { KeySystemAssociation } from '../KeySystem/KeySystemAssociation'
|
||||||
|
|
||||||
|
describe('Item', () => {
|
||||||
|
it('should create an aggregate', () => {
|
||||||
|
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().id).not.toBeNull()
|
||||||
|
expect(entityOrError.getValue().uuid.value).toEqual(entityOrError.getValue().id.toString())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if id cannot be cast to uuid', () => {
|
||||||
|
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(),
|
||||||
|
},
|
||||||
|
new UniqueEntityId(1),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(entityOrError.isFailed()).toBeFalsy()
|
||||||
|
expect(() => entityOrError.getValue().uuid).toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should tell if an item is associated with a shared vault', () => {
|
||||||
|
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(),
|
||||||
|
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(),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(entityOrError.isFailed()).toBeFalsy()
|
||||||
|
expect(
|
||||||
|
entityOrError
|
||||||
|
.getValue()
|
||||||
|
.isAssociatedWithSharedVault(Uuid.create('00000000-0000-0000-0000-000000000000').getValue()),
|
||||||
|
).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should tell that an item is not associated with a shared vault', () => {
|
||||||
|
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()
|
||||||
|
.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)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Aggregate, Result, UniqueEntityId } from '@standardnotes/domain-core'
|
import { Aggregate, Change, Result, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { ItemProps } from './ItemProps'
|
import { ItemProps } from './ItemProps'
|
||||||
|
import { SharedVaultAssociation } from '../SharedVault/SharedVaultAssociation'
|
||||||
|
import { KeySystemAssociation } from '../KeySystem/KeySystemAssociation'
|
||||||
|
|
||||||
export class Item extends Aggregate<ItemProps> {
|
export class Item extends Aggregate<ItemProps> {
|
||||||
private constructor(props: ItemProps, id?: UniqueEntityId) {
|
private constructor(props: ItemProps, id?: UniqueEntityId) {
|
||||||
@@ -15,4 +17,95 @@ export class Item extends Aggregate<ItemProps> {
|
|||||||
|
|
||||||
return Result.ok<Item>(new Item(props, id))
|
return Result.ok<Item>(new Item(props, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get uuid(): Uuid {
|
||||||
|
const uuidOrError = Uuid.create(this._id.toString())
|
||||||
|
if (uuidOrError.isFailed()) {
|
||||||
|
throw new Error(uuidOrError.getError())
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuidOrError.getValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
get sharedVaultUuid(): Uuid | null {
|
||||||
|
if (!this.props.sharedVaultAssociation) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.props.sharedVaultAssociation.props.sharedVaultUuid
|
||||||
|
}
|
||||||
|
|
||||||
|
isAssociatedWithASharedVault(): boolean {
|
||||||
|
return this.sharedVaultUuid !== null
|
||||||
|
}
|
||||||
|
|
||||||
|
isAssociatedWithSharedVault(sharedVaultUuid: Uuid): boolean {
|
||||||
|
if (!this.isAssociatedWithASharedVault()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.sharedVaultUuid as Uuid).equals(sharedVaultUuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
isAssociatedWithKeySystem(keySystemIdentifier: string): boolean {
|
||||||
|
if (!this.props.keySystemAssociation) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.props.keySystemAssociation.props.keySystemIdentifier === keySystemIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
unsetSharedVaultAssociation(): void {
|
||||||
|
if (!this.props.sharedVaultAssociation) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { ContentType } from '@standardnotes/domain-core'
|
||||||
|
import { ItemHash } from './ItemHash'
|
||||||
|
|
||||||
|
describe('ItemHash', () => {
|
||||||
|
it('should create a value object', () => {
|
||||||
|
const valueOrError = ItemHash.create({
|
||||||
|
uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content_type: ContentType.TYPES.Note,
|
||||||
|
user_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content: 'foobar',
|
||||||
|
created_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
updated_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
created_at_timestamp: 123,
|
||||||
|
updated_at_timestamp: 123,
|
||||||
|
key_system_identifier: null,
|
||||||
|
shared_vault_uuid: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(valueOrError.isFailed()).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return error if shared vault uuid is not valid', () => {
|
||||||
|
const valueOrError = ItemHash.create({
|
||||||
|
uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content_type: ContentType.TYPES.Note,
|
||||||
|
user_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content: 'foobar',
|
||||||
|
created_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
updated_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
created_at_timestamp: 123,
|
||||||
|
updated_at_timestamp: 123,
|
||||||
|
key_system_identifier: null,
|
||||||
|
shared_vault_uuid: 'invalid',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(valueOrError.isFailed()).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Result, ValueObject } from '@standardnotes/domain-core'
|
import { Result, Uuid, ValueObject } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { ItemHashProps } from './ItemHashProps'
|
import { ItemHashProps } from './ItemHashProps'
|
||||||
|
|
||||||
@@ -8,6 +8,13 @@ export class ItemHash extends ValueObject<ItemHashProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static create(props: ItemHashProps): Result<ItemHash> {
|
static create(props: ItemHashProps): Result<ItemHash> {
|
||||||
|
if (props.shared_vault_uuid) {
|
||||||
|
const sharedVaultUuidOrError = Uuid.create(props.shared_vault_uuid)
|
||||||
|
if (sharedVaultUuidOrError.isFailed()) {
|
||||||
|
return Result.fail<ItemHash>(sharedVaultUuidOrError.getError())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Result.ok<ItemHash>(new ItemHash(props))
|
return Result.ok<ItemHash>(new ItemHash(props))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,6 +22,14 @@ export class ItemHash extends ValueObject<ItemHashProps> {
|
|||||||
return this.props.shared_vault_uuid !== null
|
return this.props.shared_vault_uuid !== null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get sharedVaultUuid(): Uuid | null {
|
||||||
|
if (!this.representsASharedVaultItem()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return Uuid.create(this.props.shared_vault_uuid as string).getValue()
|
||||||
|
}
|
||||||
|
|
||||||
hasDedicatedKeySystemAssociation(): boolean {
|
hasDedicatedKeySystemAssociation(): boolean {
|
||||||
return this.props.key_system_identifier !== null
|
return this.props.key_system_identifier !== null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ export type ItemQuery = {
|
|||||||
limit?: number
|
limit?: number
|
||||||
createdBetween?: Date[]
|
createdBetween?: Date[]
|
||||||
selectString?: string
|
selectString?: string
|
||||||
|
includeSharedVaultUuids?: string[]
|
||||||
|
exclusiveSharedVaultUuids?: string[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,31 @@ describe('OwnershipFilter', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should deffer to the shared vault filter if the item hash represents a shared vault item or existing item is a shared vault item', async () => {
|
||||||
|
const itemHash = ItemHash.create({
|
||||||
|
uuid: '2-3-4',
|
||||||
|
content_type: ContentType.TYPES.Note,
|
||||||
|
user_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content: 'foobar',
|
||||||
|
created_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
updated_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
created_at_timestamp: 123,
|
||||||
|
updated_at_timestamp: 123,
|
||||||
|
key_system_identifier: null,
|
||||||
|
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
}).getValue()
|
||||||
|
const result = await createFilter().check({
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000001',
|
||||||
|
apiVersion: ApiVersion.v20200115,
|
||||||
|
itemHash,
|
||||||
|
existingItem,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
passed: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should leave items belonging to the same user', async () => {
|
it('should leave items belonging to the same user', async () => {
|
||||||
const result = await createFilter().check({
|
const result = await createFilter().check({
|
||||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ import { Uuid } from '@standardnotes/domain-core'
|
|||||||
|
|
||||||
export class OwnershipFilter implements ItemSaveRuleInterface {
|
export class OwnershipFilter implements ItemSaveRuleInterface {
|
||||||
async check(dto: ItemSaveValidationDTO): Promise<ItemSaveRuleResult> {
|
async check(dto: ItemSaveValidationDTO): Promise<ItemSaveRuleResult> {
|
||||||
|
const deferToSharedVaultFilter =
|
||||||
|
dto.existingItem?.isAssociatedWithASharedVault() || dto.itemHash.representsASharedVaultItem()
|
||||||
|
if (deferToSharedVaultFilter) {
|
||||||
|
return {
|
||||||
|
passed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const userUuidOrError = Uuid.create(dto.userUuid)
|
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||||
if (userUuidOrError.isFailed()) {
|
if (userUuidOrError.isFailed()) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -0,0 +1,819 @@
|
|||||||
|
import {
|
||||||
|
ContentType,
|
||||||
|
Dates,
|
||||||
|
Result,
|
||||||
|
SharedVaultUserPermission,
|
||||||
|
Timestamps,
|
||||||
|
UniqueEntityId,
|
||||||
|
Uuid,
|
||||||
|
} from '@standardnotes/domain-core'
|
||||||
|
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
|
||||||
|
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||||
|
import { DetermineSharedVaultOperationOnItem } from '../../UseCase/SharedVaults/DetermineSharedVaultOperationOnItem/DetermineSharedVaultOperationOnItem'
|
||||||
|
import { SharedVaultFilter } from './SharedVaultFilter'
|
||||||
|
import { ItemHash } from '../ItemHash'
|
||||||
|
import { Item } from '../Item'
|
||||||
|
import { SharedVaultOperationOnItem } from '../../SharedVault/SharedVaultOperationOnItem'
|
||||||
|
import { SharedVaultAssociation } from '../../SharedVault/SharedVaultAssociation'
|
||||||
|
|
||||||
|
describe('SharedVaultFilter', () => {
|
||||||
|
let determineSharedVaultOperationOnItem: DetermineSharedVaultOperationOnItem
|
||||||
|
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
||||||
|
let sharedVaultUser: SharedVaultUser
|
||||||
|
let itemHash: ItemHash
|
||||||
|
let existingItem: Item
|
||||||
|
|
||||||
|
const createFilter = () => new SharedVaultFilter(determineSharedVaultOperationOnItem, sharedVaultUserRepository)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
existingItem = Item.create(
|
||||||
|
{
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
updatedWithSession: null,
|
||||||
|
content: 'foobar',
|
||||||
|
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
|
||||||
|
encItemKey: null,
|
||||||
|
authHash: null,
|
||||||
|
itemsKeyId: null,
|
||||||
|
duplicateOf: null,
|
||||||
|
deleted: false,
|
||||||
|
dates: Dates.create(new Date(1616164633241311), new Date(1616164633241311)).getValue(),
|
||||||
|
timestamps: Timestamps.create(1616164633241311, 1616164633241311).getValue(),
|
||||||
|
sharedVaultAssociation: SharedVaultAssociation.create({
|
||||||
|
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue(),
|
||||||
|
},
|
||||||
|
new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
|
||||||
|
).getValue()
|
||||||
|
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
uuid: '2-3-4',
|
||||||
|
content_type: ContentType.TYPES.Note,
|
||||||
|
user_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content: 'foobar',
|
||||||
|
created_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
updated_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
created_at_timestamp: 123,
|
||||||
|
updated_at_timestamp: 123,
|
||||||
|
key_system_identifier: 'key-system-identifier',
|
||||||
|
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
sharedVaultUser = SharedVaultUser.create({
|
||||||
|
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Write).getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem = {} as jest.Mocked<DetermineSharedVaultOperationOnItem>
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn()
|
||||||
|
|
||||||
|
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce(sharedVaultUser)
|
||||||
|
.mockResolvedValueOnce(null)
|
||||||
|
})
|
||||||
|
|
||||||
|
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()
|
||||||
|
existingItem = Item.create({
|
||||||
|
...existingItem.props,
|
||||||
|
sharedVaultAssociation: undefined,
|
||||||
|
}).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 not passed if the operation could not be determined', async () => {
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(Result.fail('error'))
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the item is a shared vault item without a dedicated key system association', async () => {
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.AddToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
uuid: '2-3-4',
|
||||||
|
content_type: ContentType.TYPES.Note,
|
||||||
|
user_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content: 'foobar',
|
||||||
|
created_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
updated_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
created_at_timestamp: 123,
|
||||||
|
updated_at_timestamp: 123,
|
||||||
|
key_system_identifier: null,
|
||||||
|
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
}).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(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the shared vault operation on item is: move to other shared vault', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
targetSharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.MoveToOtherSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce(sharedVaultUser)
|
||||||
|
.mockResolvedValueOnce(sharedVaultUser)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(null)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not a member of the target shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(sharedVaultUser)
|
||||||
|
.mockResolvedValue(null)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as passed if the user is a member of both shared vaults', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
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 not passed if the user is not a member of the target shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValueOnce(sharedVaultUser)
|
||||||
|
.mockReturnValueOnce(null)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the item is deleted', async () => {
|
||||||
|
existingItem = Item.create(
|
||||||
|
{
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
updatedWithSession: null,
|
||||||
|
content: 'foobar',
|
||||||
|
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
|
||||||
|
encItemKey: null,
|
||||||
|
authHash: null,
|
||||||
|
itemsKeyId: null,
|
||||||
|
duplicateOf: null,
|
||||||
|
deleted: true,
|
||||||
|
dates: Dates.create(new Date(1616164633241311), new Date(1616164633241311)).getValue(),
|
||||||
|
timestamps: Timestamps.create(1616164633241311, 1616164633241311).getValue(),
|
||||||
|
sharedVaultAssociation: SharedVaultAssociation.create({
|
||||||
|
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue(),
|
||||||
|
},
|
||||||
|
new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
|
||||||
|
).getValue()
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
targetSharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.MoveToOtherSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).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(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the item is being deleted', async () => {
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
uuid: '2-3-4',
|
||||||
|
content_type: ContentType.TYPES.Note,
|
||||||
|
user_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content: 'foobar',
|
||||||
|
created_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
updated_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
created_at_timestamp: 123,
|
||||||
|
updated_at_timestamp: 123,
|
||||||
|
key_system_identifier: null,
|
||||||
|
shared_vault_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
deleted: true,
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
targetSharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.MoveToOtherSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).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(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user has insufficient permissions to write key system items key', async () => {
|
||||||
|
sharedVaultUser = SharedVaultUser.create({
|
||||||
|
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
...itemHash.props,
|
||||||
|
content_type: ContentType.TYPES.KeySystemItemsKey,
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
targetSharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.MoveToOtherSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the shared vault operation on item is: add to shared vault', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.AddToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(null)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as passed if the user is a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
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 not passed if the item is deleted', async () => {
|
||||||
|
existingItem = Item.create(
|
||||||
|
{
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
updatedWithSession: null,
|
||||||
|
content: 'foobar',
|
||||||
|
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
|
||||||
|
encItemKey: null,
|
||||||
|
authHash: null,
|
||||||
|
itemsKeyId: null,
|
||||||
|
duplicateOf: null,
|
||||||
|
deleted: true,
|
||||||
|
dates: Dates.create(new Date(1616164633241311), new Date(1616164633241311)).getValue(),
|
||||||
|
timestamps: Timestamps.create(1616164633241311, 1616164633241311).getValue(),
|
||||||
|
sharedVaultAssociation: SharedVaultAssociation.create({
|
||||||
|
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue(),
|
||||||
|
},
|
||||||
|
new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
|
||||||
|
).getValue()
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.AddToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).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(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not the owner of the item', async () => {
|
||||||
|
existingItem = Item.create({
|
||||||
|
...existingItem.props,
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000002').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.AddToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000001',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user has insufficient permissions to write key system items key', async () => {
|
||||||
|
sharedVaultUser = SharedVaultUser.create({
|
||||||
|
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
...itemHash.props,
|
||||||
|
content_type: ContentType.TYPES.KeySystemItemsKey,
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.AddToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the shared vault operation on item is: remove from shared vault', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(null)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as passed if the user is a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
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 not passed if the item is deleted', async () => {
|
||||||
|
existingItem = Item.create(
|
||||||
|
{
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
updatedWithSession: null,
|
||||||
|
content: 'foobar',
|
||||||
|
contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
|
||||||
|
encItemKey: null,
|
||||||
|
authHash: null,
|
||||||
|
itemsKeyId: null,
|
||||||
|
duplicateOf: null,
|
||||||
|
deleted: true,
|
||||||
|
dates: Dates.create(new Date(1616164633241311), new Date(1616164633241311)).getValue(),
|
||||||
|
timestamps: Timestamps.create(1616164633241311, 1616164633241311).getValue(),
|
||||||
|
sharedVaultAssociation: SharedVaultAssociation.create({
|
||||||
|
itemUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue(),
|
||||||
|
},
|
||||||
|
new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
|
||||||
|
).getValue()
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).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(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not the owner of the item', async () => {
|
||||||
|
existingItem = Item.create({
|
||||||
|
...existingItem.props,
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000002').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000001',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user has insufficient permissions to write key system items key', async () => {
|
||||||
|
sharedVaultUser = SharedVaultUser.create({
|
||||||
|
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
...itemHash.props,
|
||||||
|
content_type: ContentType.TYPES.KeySystemItemsKey,
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the shared vault operation on item is: save to shared vault', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.SaveToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(null)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as passed if the user is a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
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 not passed if the user has insufficient permissions', async () => {
|
||||||
|
sharedVaultUser = SharedVaultUser.create({
|
||||||
|
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('when the shared vault operation on item is: create to shared vault', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.CreateToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
existingItem,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as not passed if the user is not a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(null)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return as passed if the user is a member of the shared vault', async () => {
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
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 not passed if the user has insufficient permissions to write key system items key', async () => {
|
||||||
|
sharedVaultUser = SharedVaultUser.create({
|
||||||
|
permission: SharedVaultUserPermission.create(SharedVaultUserPermission.PERMISSIONS.Read).getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
timestamps: Timestamps.create(123, 123).getValue(),
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
...itemHash.props,
|
||||||
|
content_type: ContentType.TYPES.KeySystemItemsKey,
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
|
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||||
|
Result.ok(
|
||||||
|
SharedVaultOperationOnItem.create({
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.CreateToSharedVault,
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
}).getValue(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
|
||||||
|
|
||||||
|
const filter = createFilter()
|
||||||
|
const result = await filter.check({
|
||||||
|
apiVersion: '001',
|
||||||
|
existingItem: existingItem,
|
||||||
|
itemHash: itemHash,
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.passed).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
import { ConflictType } from '@standardnotes/responses'
|
||||||
|
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 { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||||
|
|
||||||
|
export class SharedVaultFilter implements ItemSaveRuleInterface {
|
||||||
|
constructor(
|
||||||
|
private determineSharedVaultOperationOnItem: DetermineSharedVaultOperationOnItem,
|
||||||
|
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async check(dto: ItemSaveValidationDTO): Promise<ItemSaveRuleResult> {
|
||||||
|
if (!dto.itemHash.representsASharedVaultItem() && !dto.existingItem?.isAssociatedWithASharedVault()) {
|
||||||
|
return {
|
||||||
|
passed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const operationOrError = await this.determineSharedVaultOperationOnItem.execute({
|
||||||
|
userUuid: dto.userUuid,
|
||||||
|
itemHash: dto.itemHash,
|
||||||
|
existingItem: dto.existingItem,
|
||||||
|
})
|
||||||
|
if (operationOrError.isFailed()) {
|
||||||
|
return {
|
||||||
|
passed: false,
|
||||||
|
conflict: {
|
||||||
|
unsavedItem: dto.itemHash,
|
||||||
|
type: ConflictType.SharedVaultInvalidState,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const operation = operationOrError.getValue()
|
||||||
|
|
||||||
|
if (dto.itemHash.representsASharedVaultItem() && !dto.itemHash.hasDedicatedKeySystemAssociation()) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInvalidState)
|
||||||
|
}
|
||||||
|
|
||||||
|
const sharedVaultPermission = await this.getSharedVaultUserPermission(
|
||||||
|
operation.props.userUuid,
|
||||||
|
operation.props.sharedVaultUuid,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!sharedVaultPermission) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultNotMemberError)
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetSharedVaultPermission: SharedVaultUserPermission | null = null
|
||||||
|
if (operation.props.targetSharedVaultUuid) {
|
||||||
|
targetSharedVaultPermission = await this.getSharedVaultUserPermission(
|
||||||
|
operation.props.userUuid,
|
||||||
|
operation.props.targetSharedVaultUuid,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!targetSharedVaultPermission) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultNotMemberError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultOrError = await this.getResultForOperation(
|
||||||
|
operation,
|
||||||
|
sharedVaultPermission,
|
||||||
|
targetSharedVaultPermission,
|
||||||
|
)
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (resultOrError.isFailed()) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInvalidState)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultOrError.getValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getResultForOperation(
|
||||||
|
operation: SharedVaultOperationOnItem,
|
||||||
|
sharedVaultPermission: SharedVaultUserPermission,
|
||||||
|
targetSharedVaultPermission: SharedVaultUserPermission | null,
|
||||||
|
): Promise<Result<ItemSaveRuleResult>> {
|
||||||
|
switch (operation.props.type) {
|
||||||
|
case SharedVaultOperationOnItem.TYPES.AddToSharedVault:
|
||||||
|
case SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault:
|
||||||
|
return Result.ok(await this.handleAddOrRemoveToSharedVaultOperation(operation, sharedVaultPermission))
|
||||||
|
case SharedVaultOperationOnItem.TYPES.MoveToOtherSharedVault:
|
||||||
|
return Result.ok(
|
||||||
|
await this.handleMoveToOtherSharedVaultOperation(
|
||||||
|
operation,
|
||||||
|
sharedVaultPermission,
|
||||||
|
targetSharedVaultPermission as SharedVaultUserPermission,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case SharedVaultOperationOnItem.TYPES.SaveToSharedVault:
|
||||||
|
case SharedVaultOperationOnItem.TYPES.CreateToSharedVault:
|
||||||
|
return Result.ok(await this.handleSaveOrCreateToSharedVaultOperation(operation, sharedVaultPermission))
|
||||||
|
/* istanbul ignore next */
|
||||||
|
default:
|
||||||
|
return Result.fail(`Unsupported sharedVault operation: ${operation}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isAuthorizedToSaveContentType(contentType: string | null, permission: SharedVaultUserPermission): boolean {
|
||||||
|
if (contentType === ContentType.TYPES.KeySystemItemsKey) {
|
||||||
|
return permission.value === SharedVaultUserPermission.PERMISSIONS.Admin
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleAddOrRemoveToSharedVaultOperation(
|
||||||
|
operation: SharedVaultOperationOnItem,
|
||||||
|
sharedVaultPermission: SharedVaultUserPermission,
|
||||||
|
): Promise<ItemSaveRuleResult> {
|
||||||
|
if (this.isItemDeletedOrBeingDeleted(operation)) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInvalidState)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isOwnerOfTheItem(operation)) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInsufficientPermissionsError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.hasSufficientPermissionsToWriteInVault(operation, sharedVaultPermission)) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInsufficientPermissionsError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.buildSuccessValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleMoveToOtherSharedVaultOperation(
|
||||||
|
operation: SharedVaultOperationOnItem,
|
||||||
|
sourceSharedVaultPermission: SharedVaultUserPermission,
|
||||||
|
targetSharedVaultPermission: SharedVaultUserPermission,
|
||||||
|
): Promise<ItemSaveRuleResult> {
|
||||||
|
if (this.isItemDeletedOrBeingDeleted(operation)) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInvalidState)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const permission of [sourceSharedVaultPermission, targetSharedVaultPermission]) {
|
||||||
|
if (!this.hasSufficientPermissionsToWriteInVault(operation, permission)) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInsufficientPermissionsError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.buildSuccessValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleSaveOrCreateToSharedVaultOperation(
|
||||||
|
operation: SharedVaultOperationOnItem,
|
||||||
|
sharedVaultPermission: SharedVaultUserPermission,
|
||||||
|
): Promise<ItemSaveRuleResult> {
|
||||||
|
if (!this.hasSufficientPermissionsToWriteInVault(operation, sharedVaultPermission)) {
|
||||||
|
return this.buildFailResult(operation, ConflictType.SharedVaultInsufficientPermissionsError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.buildSuccessValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private isItemDeletedOrBeingDeleted(operation: SharedVaultOperationOnItem): boolean {
|
||||||
|
if (operation.props.existingItem?.props.deleted || operation.props.incomingItemHash.props.deleted) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private isOwnerOfTheItem(operation: SharedVaultOperationOnItem): boolean {
|
||||||
|
if (operation.props.userUuid.equals(operation.props.existingItem?.props.userUuid)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasSufficientPermissionsToWriteInVault(
|
||||||
|
operation: SharedVaultOperationOnItem,
|
||||||
|
sharedVaultPermission: SharedVaultUserPermission,
|
||||||
|
): boolean {
|
||||||
|
if (
|
||||||
|
!this.isAuthorizedToSaveContentType(operation.props.incomingItemHash.props.content_type, sharedVaultPermission)
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sharedVaultPermission.value === SharedVaultUserPermission.PERMISSIONS.Read) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getSharedVaultUserPermission(
|
||||||
|
userUuid: Uuid,
|
||||||
|
sharedVaultUuid: Uuid,
|
||||||
|
): Promise<SharedVaultUserPermission | null> {
|
||||||
|
const sharedVaultUser = await this.sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid({
|
||||||
|
userUuid,
|
||||||
|
sharedVaultUuid,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (sharedVaultUser) {
|
||||||
|
return sharedVaultUser.props.permission
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildFailResult(operation: SharedVaultOperationOnItem, type: ConflictType): ItemSaveRuleResult {
|
||||||
|
const includeServerItem = [
|
||||||
|
ConflictType.SharedVaultInvalidState,
|
||||||
|
ConflictType.SharedVaultInsufficientPermissionsError,
|
||||||
|
].includes(type)
|
||||||
|
|
||||||
|
return {
|
||||||
|
passed: false,
|
||||||
|
conflict: {
|
||||||
|
unsavedItem: operation.props.incomingItemHash,
|
||||||
|
serverItem: includeServerItem ? operation.props.existingItem : undefined,
|
||||||
|
type,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildSuccessValue(): ItemSaveRuleResult {
|
||||||
|
return {
|
||||||
|
passed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
import { ItemConflictHttpRepresentation } from '../../../Mapping/Http/ItemConflictHttpRepresentation'
|
import { ItemConflictHttpRepresentation } from '../../../Mapping/Http/ItemConflictHttpRepresentation'
|
||||||
import { ItemHttpRepresentation } from '../../../Mapping/Http/ItemHttpRepresentation'
|
import { ItemHttpRepresentation } from '../../../Mapping/Http/ItemHttpRepresentation'
|
||||||
|
import { MessageHttpRepresentation } from '../../../Mapping/Http/MessageHttpRepresentation'
|
||||||
|
import { NotificationHttpRepresentation } from '../../../Mapping/Http/NotificationHttpRepresentation'
|
||||||
import { SavedItemHttpRepresentation } from '../../../Mapping/Http/SavedItemHttpRepresentation'
|
import { SavedItemHttpRepresentation } from '../../../Mapping/Http/SavedItemHttpRepresentation'
|
||||||
|
import { SharedVaultHttpRepresentation } from '../../../Mapping/Http/SharedVaultHttpRepresentation'
|
||||||
|
import { SharedVaultInviteHttpRepresentation } from '../../../Mapping/Http/SharedVaultInviteHttpRepresentation'
|
||||||
|
|
||||||
export type SyncResponse20200115 = {
|
export type SyncResponse20200115 = {
|
||||||
retrieved_items: Array<ItemHttpRepresentation>
|
retrieved_items: ItemHttpRepresentation[]
|
||||||
saved_items: Array<SavedItemHttpRepresentation>
|
saved_items: SavedItemHttpRepresentation[]
|
||||||
conflicts: Array<ItemConflictHttpRepresentation>
|
conflicts: ItemConflictHttpRepresentation[]
|
||||||
sync_token: string
|
sync_token: string
|
||||||
cursor_token?: string
|
cursor_token?: string
|
||||||
|
messages: MessageHttpRepresentation[]
|
||||||
|
shared_vaults: SharedVaultHttpRepresentation[]
|
||||||
|
shared_vault_invites: SharedVaultInviteHttpRepresentation[]
|
||||||
|
notifications: NotificationHttpRepresentation[]
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -88,6 +88,10 @@ describe('SyncResponseFactory20161215', () => {
|
|||||||
],
|
],
|
||||||
syncToken: 'sync-test',
|
syncToken: 'sync-test',
|
||||||
cursorToken: 'cursor-test',
|
cursorToken: 'cursor-test',
|
||||||
|
sharedVaults: [],
|
||||||
|
sharedVaultInvites: [],
|
||||||
|
messages: [],
|
||||||
|
notifications: [],
|
||||||
}),
|
}),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
retrieved_items: [item1Projection],
|
retrieved_items: [item1Projection],
|
||||||
@@ -133,6 +137,10 @@ describe('SyncResponseFactory20161215', () => {
|
|||||||
],
|
],
|
||||||
syncToken: 'sync-test',
|
syncToken: 'sync-test',
|
||||||
cursorToken: 'cursor-test',
|
cursorToken: 'cursor-test',
|
||||||
|
sharedVaults: [],
|
||||||
|
sharedVaultInvites: [],
|
||||||
|
messages: [],
|
||||||
|
notifications: [],
|
||||||
}),
|
}),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
retrieved_items: [],
|
retrieved_items: [],
|
||||||
|
|||||||
+55
-1
@@ -8,6 +8,14 @@ import { SyncResponseFactory20200115 } from './SyncResponseFactory20200115'
|
|||||||
import { ItemHttpRepresentation } from '../../../Mapping/Http/ItemHttpRepresentation'
|
import { ItemHttpRepresentation } from '../../../Mapping/Http/ItemHttpRepresentation'
|
||||||
import { SavedItemHttpRepresentation } from '../../../Mapping/Http/SavedItemHttpRepresentation'
|
import { SavedItemHttpRepresentation } from '../../../Mapping/Http/SavedItemHttpRepresentation'
|
||||||
import { ItemConflictHttpRepresentation } from '../../../Mapping/Http/ItemConflictHttpRepresentation'
|
import { ItemConflictHttpRepresentation } from '../../../Mapping/Http/ItemConflictHttpRepresentation'
|
||||||
|
import { MessageHttpRepresentation } from '../../../Mapping/Http/MessageHttpRepresentation'
|
||||||
|
import { NotificationHttpRepresentation } from '../../../Mapping/Http/NotificationHttpRepresentation'
|
||||||
|
import { Notification } from '../../Notifications/Notification'
|
||||||
|
import { SharedVaultHttpRepresentation } from '../../../Mapping/Http/SharedVaultHttpRepresentation'
|
||||||
|
import { SharedVaultInviteHttpRepresentation } from '../../../Mapping/Http/SharedVaultInviteHttpRepresentation'
|
||||||
|
import { Message } from '../../Message/Message'
|
||||||
|
import { SharedVault } from '../../SharedVault/SharedVault'
|
||||||
|
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
|
||||||
|
|
||||||
describe('SyncResponseFactory20200115', () => {
|
describe('SyncResponseFactory20200115', () => {
|
||||||
let itemMapper: MapperInterface<Item, ItemHttpRepresentation>
|
let itemMapper: MapperInterface<Item, ItemHttpRepresentation>
|
||||||
@@ -19,8 +27,25 @@ describe('SyncResponseFactory20200115', () => {
|
|||||||
let item1: Item
|
let item1: Item
|
||||||
let item2: Item
|
let item2: Item
|
||||||
let itemConflict: ItemConflict
|
let itemConflict: ItemConflict
|
||||||
|
let sharedVault: SharedVault
|
||||||
|
let sharedVaultInvite: SharedVaultInvite
|
||||||
|
let message: Message
|
||||||
|
let notification: Notification
|
||||||
|
let sharedVaultMapper: MapperInterface<SharedVault, SharedVaultHttpRepresentation>
|
||||||
|
let sharedVaultInvitesMapper: MapperInterface<SharedVaultInvite, SharedVaultInviteHttpRepresentation>
|
||||||
|
let messageMapper: MapperInterface<Message, MessageHttpRepresentation>
|
||||||
|
let notificationMapper: MapperInterface<Notification, NotificationHttpRepresentation>
|
||||||
|
|
||||||
const createFactory = () => new SyncResponseFactory20200115(itemMapper, itemConflictMapper, savedItemMapper)
|
const createFactory = () =>
|
||||||
|
new SyncResponseFactory20200115(
|
||||||
|
itemMapper,
|
||||||
|
itemConflictMapper,
|
||||||
|
savedItemMapper,
|
||||||
|
sharedVaultMapper,
|
||||||
|
sharedVaultInvitesMapper,
|
||||||
|
messageMapper,
|
||||||
|
notificationMapper,
|
||||||
|
)
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
itemProjection = {
|
itemProjection = {
|
||||||
@@ -45,6 +70,27 @@ describe('SyncResponseFactory20200115', () => {
|
|||||||
item2 = {} as jest.Mocked<Item>
|
item2 = {} as jest.Mocked<Item>
|
||||||
|
|
||||||
itemConflict = {} as jest.Mocked<ItemConflict>
|
itemConflict = {} as jest.Mocked<ItemConflict>
|
||||||
|
|
||||||
|
sharedVaultMapper = {} as jest.Mocked<MapperInterface<SharedVault, SharedVaultHttpRepresentation>>
|
||||||
|
sharedVaultMapper.toProjection = jest.fn().mockReturnValue({} as jest.Mocked<SharedVaultHttpRepresentation>)
|
||||||
|
|
||||||
|
sharedVaultInvitesMapper = {} as jest.Mocked<
|
||||||
|
MapperInterface<SharedVaultInvite, SharedVaultInviteHttpRepresentation>
|
||||||
|
>
|
||||||
|
sharedVaultInvitesMapper.toProjection = jest
|
||||||
|
.fn()
|
||||||
|
.mockReturnValue({} as jest.Mocked<SharedVaultInviteHttpRepresentation>)
|
||||||
|
|
||||||
|
messageMapper = {} as jest.Mocked<MapperInterface<Message, MessageHttpRepresentation>>
|
||||||
|
messageMapper.toProjection = jest.fn().mockReturnValue({} as jest.Mocked<MessageHttpRepresentation>)
|
||||||
|
|
||||||
|
notificationMapper = {} as jest.Mocked<MapperInterface<Notification, NotificationHttpRepresentation>>
|
||||||
|
notificationMapper.toProjection = jest.fn().mockReturnValue({} as jest.Mocked<NotificationHttpRepresentation>)
|
||||||
|
|
||||||
|
sharedVault = {} as jest.Mocked<SharedVault>
|
||||||
|
sharedVaultInvite = {} as jest.Mocked<SharedVaultInvite>
|
||||||
|
message = {} as jest.Mocked<Message>
|
||||||
|
notification = {} as jest.Mocked<Notification>
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should turn sync items response into a sync response for API Version 20200115', async () => {
|
it('should turn sync items response into a sync response for API Version 20200115', async () => {
|
||||||
@@ -55,6 +101,10 @@ describe('SyncResponseFactory20200115', () => {
|
|||||||
conflicts: [itemConflict],
|
conflicts: [itemConflict],
|
||||||
syncToken: 'sync-test',
|
syncToken: 'sync-test',
|
||||||
cursorToken: 'cursor-test',
|
cursorToken: 'cursor-test',
|
||||||
|
sharedVaults: [sharedVault],
|
||||||
|
sharedVaultInvites: [sharedVaultInvite],
|
||||||
|
messages: [message],
|
||||||
|
notifications: [notification],
|
||||||
}),
|
}),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
retrieved_items: [itemProjection],
|
retrieved_items: [itemProjection],
|
||||||
@@ -62,6 +112,10 @@ describe('SyncResponseFactory20200115', () => {
|
|||||||
conflicts: [itemConflictProjection],
|
conflicts: [itemConflictProjection],
|
||||||
sync_token: 'sync-test',
|
sync_token: 'sync-test',
|
||||||
cursor_token: 'cursor-test',
|
cursor_token: 'cursor-test',
|
||||||
|
shared_vaults: [{} as jest.Mocked<SharedVaultHttpRepresentation>],
|
||||||
|
shared_vault_invites: [{} as jest.Mocked<SharedVaultInviteHttpRepresentation>],
|
||||||
|
messages: [{} as jest.Mocked<MessageHttpRepresentation>],
|
||||||
|
notifications: [{} as jest.Mocked<NotificationHttpRepresentation>],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,12 +8,24 @@ import { SyncItemsResponse } from '../../UseCase/Syncing/SyncItems/SyncItemsResp
|
|||||||
import { ItemHttpRepresentation } from '../../../Mapping/Http/ItemHttpRepresentation'
|
import { ItemHttpRepresentation } from '../../../Mapping/Http/ItemHttpRepresentation'
|
||||||
import { ItemConflictHttpRepresentation } from '../../../Mapping/Http/ItemConflictHttpRepresentation'
|
import { ItemConflictHttpRepresentation } from '../../../Mapping/Http/ItemConflictHttpRepresentation'
|
||||||
import { SavedItemHttpRepresentation } from '../../../Mapping/Http/SavedItemHttpRepresentation'
|
import { SavedItemHttpRepresentation } from '../../../Mapping/Http/SavedItemHttpRepresentation'
|
||||||
|
import { SharedVault } from '../../SharedVault/SharedVault'
|
||||||
|
import { SharedVaultHttpRepresentation } from '../../../Mapping/Http/SharedVaultHttpRepresentation'
|
||||||
|
import { SharedVaultInvite } from '../../SharedVault/User/Invite/SharedVaultInvite'
|
||||||
|
import { SharedVaultInviteHttpRepresentation } from '../../../Mapping/Http/SharedVaultInviteHttpRepresentation'
|
||||||
|
import { Message } from '../../Message/Message'
|
||||||
|
import { MessageHttpRepresentation } from '../../../Mapping/Http/MessageHttpRepresentation'
|
||||||
|
import { Notification } from '../../Notifications/Notification'
|
||||||
|
import { NotificationHttpRepresentation } from '../../../Mapping/Http/NotificationHttpRepresentation'
|
||||||
|
|
||||||
export class SyncResponseFactory20200115 implements SyncResponseFactoryInterface {
|
export class SyncResponseFactory20200115 implements SyncResponseFactoryInterface {
|
||||||
constructor(
|
constructor(
|
||||||
private httpMapper: MapperInterface<Item, ItemHttpRepresentation>,
|
private httpMapper: MapperInterface<Item, ItemHttpRepresentation>,
|
||||||
private itemConflictMapper: MapperInterface<ItemConflict, ItemConflictHttpRepresentation>,
|
private itemConflictMapper: MapperInterface<ItemConflict, ItemConflictHttpRepresentation>,
|
||||||
private savedItemMapper: MapperInterface<Item, SavedItemHttpRepresentation>,
|
private savedItemMapper: MapperInterface<Item, SavedItemHttpRepresentation>,
|
||||||
|
private sharedVaultMapper: MapperInterface<SharedVault, SharedVaultHttpRepresentation>,
|
||||||
|
private sharedVaultInvitesMapper: MapperInterface<SharedVaultInvite, SharedVaultInviteHttpRepresentation>,
|
||||||
|
private messageMapper: MapperInterface<Message, MessageHttpRepresentation>,
|
||||||
|
private notificationMapper: MapperInterface<Notification, NotificationHttpRepresentation>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createResponse(syncItemsResponse: SyncItemsResponse): Promise<SyncResponse20200115> {
|
async createResponse(syncItemsResponse: SyncItemsResponse): Promise<SyncResponse20200115> {
|
||||||
@@ -32,12 +44,36 @@ export class SyncResponseFactory20200115 implements SyncResponseFactoryInterface
|
|||||||
conflicts.push(this.itemConflictMapper.toProjection(itemConflict))
|
conflicts.push(this.itemConflictMapper.toProjection(itemConflict))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sharedVaults = []
|
||||||
|
for (const sharedVault of syncItemsResponse.sharedVaults) {
|
||||||
|
sharedVaults.push(this.sharedVaultMapper.toProjection(sharedVault))
|
||||||
|
}
|
||||||
|
|
||||||
|
const sharedVaultInvites = []
|
||||||
|
for (const sharedVaultInvite of syncItemsResponse.sharedVaultInvites) {
|
||||||
|
sharedVaultInvites.push(this.sharedVaultInvitesMapper.toProjection(sharedVaultInvite))
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = []
|
||||||
|
for (const contact of syncItemsResponse.messages) {
|
||||||
|
messages.push(this.messageMapper.toProjection(contact))
|
||||||
|
}
|
||||||
|
|
||||||
|
const notifications = []
|
||||||
|
for (const notification of syncItemsResponse.notifications) {
|
||||||
|
notifications.push(this.notificationMapper.toProjection(notification))
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
retrieved_items: retrievedItems,
|
retrieved_items: retrievedItems,
|
||||||
saved_items: savedItems,
|
saved_items: savedItems,
|
||||||
conflicts,
|
conflicts,
|
||||||
sync_token: syncItemsResponse.syncToken,
|
sync_token: syncItemsResponse.syncToken,
|
||||||
cursor_token: syncItemsResponse.cursorToken,
|
cursor_token: syncItemsResponse.cursorToken,
|
||||||
|
messages,
|
||||||
|
shared_vaults: sharedVaults,
|
||||||
|
shared_vault_invites: sharedVaultInvites,
|
||||||
|
notifications,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Message } from './Message'
|
|||||||
export interface MessageRepositoryInterface {
|
export interface MessageRepositoryInterface {
|
||||||
findByUuid: (uuid: Uuid) => Promise<Message | null>
|
findByUuid: (uuid: Uuid) => Promise<Message | null>
|
||||||
findByRecipientUuid: (uuid: Uuid) => Promise<Message[]>
|
findByRecipientUuid: (uuid: Uuid) => Promise<Message[]>
|
||||||
|
findByRecipientUuidUpdatedAfter: (uuid: Uuid, updatedAtTimestamp: number) => Promise<Message[]>
|
||||||
findBySenderUuid: (uuid: Uuid) => Promise<Message[]>
|
findBySenderUuid: (uuid: Uuid) => Promise<Message[]>
|
||||||
findByRecipientUuidAndReplaceabilityIdentifier: (dto: {
|
findByRecipientUuidAndReplaceabilityIdentifier: (dto: {
|
||||||
recipientUuid: Uuid
|
recipientUuid: Uuid
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
import { NotificationPayload, NotificationType, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { Notification } from './Notification'
|
import { Notification } from './Notification'
|
||||||
import { NotificationType } from './NotificationType'
|
|
||||||
|
|
||||||
describe('Notification', () => {
|
describe('Notification', () => {
|
||||||
it('should create an entity', () => {
|
it('should create an entity', () => {
|
||||||
|
const payload = NotificationPayload.create({
|
||||||
|
sharedVaultUuid: Uuid.create('0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e').getValue(),
|
||||||
|
type: NotificationType.create(NotificationType.TYPES.RemovedFromSharedVault).getValue(),
|
||||||
|
version: '1.0',
|
||||||
|
}).getValue()
|
||||||
|
|
||||||
const entityOrError = Notification.create({
|
const entityOrError = Notification.create({
|
||||||
timestamps: Timestamps.create(123456789, 123456789).getValue(),
|
timestamps: Timestamps.create(123456789, 123456789).getValue(),
|
||||||
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
payload: 'payload',
|
payload,
|
||||||
type: NotificationType.create(NotificationType.TYPES.SharedVaultItemRemoved).getValue(),
|
type: NotificationType.create(NotificationType.TYPES.SharedVaultItemRemoved).getValue(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
import { NotificationPayload, NotificationType, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { NotificationType } from './NotificationType'
|
|
||||||
|
|
||||||
export interface NotificationProps {
|
export interface NotificationProps {
|
||||||
userUuid: Uuid
|
userUuid: Uuid
|
||||||
type: NotificationType
|
type: NotificationType
|
||||||
payload: string
|
payload: NotificationPayload
|
||||||
timestamps: Timestamps
|
timestamps: Timestamps
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
import { NotificationType, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { Notification } from './Notification'
|
import { Notification } from './Notification'
|
||||||
|
|
||||||
export interface NotificationRepositoryInterface {
|
export interface NotificationRepositoryInterface {
|
||||||
save(notification: Notification): Promise<void>
|
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>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
import { Timestamps, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { SharedVault } from './SharedVault'
|
import { SharedVault } from './SharedVault'
|
||||||
|
|
||||||
@@ -13,5 +13,21 @@ describe('SharedVault', () => {
|
|||||||
|
|
||||||
expect(entityOrError.isFailed()).toBeFalsy()
|
expect(entityOrError.isFailed()).toBeFalsy()
|
||||||
expect(entityOrError.getValue().id).not.toBeNull()
|
expect(entityOrError.getValue().id).not.toBeNull()
|
||||||
|
expect(entityOrError.getValue().uuid.value).toEqual(entityOrError.getValue().id.toString())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should throw an error if id cannot be cast to uuid', () => {
|
||||||
|
const entityOrError = SharedVault.create(
|
||||||
|
{
|
||||||
|
fileUploadBytesLimit: 1_000_000,
|
||||||
|
fileUploadBytesUsed: 0,
|
||||||
|
timestamps: Timestamps.create(123456789, 123456789).getValue(),
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
},
|
||||||
|
new UniqueEntityId(1),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(entityOrError.isFailed()).toBeFalsy()
|
||||||
|
expect(() => entityOrError.getValue().uuid).toThrow()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Entity, Result, UniqueEntityId } from '@standardnotes/domain-core'
|
import { Entity, Result, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { SharedVaultProps } from './SharedVaultProps'
|
import { SharedVaultProps } from './SharedVaultProps'
|
||||||
|
|
||||||
@@ -7,6 +7,15 @@ export class SharedVault extends Entity<SharedVaultProps> {
|
|||||||
super(props, id)
|
super(props, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get uuid(): Uuid {
|
||||||
|
const uuidOrError = Uuid.create(this._id.toString())
|
||||||
|
if (uuidOrError.isFailed()) {
|
||||||
|
throw new Error(uuidOrError.getError())
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuidOrError.getValue()
|
||||||
|
}
|
||||||
|
|
||||||
static create(props: SharedVaultProps, id?: UniqueEntityId): Result<SharedVault> {
|
static create(props: SharedVaultProps, id?: UniqueEntityId): Result<SharedVault> {
|
||||||
return Result.ok<SharedVault>(new SharedVault(props, id))
|
return Result.ok<SharedVault>(new SharedVault(props, id))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { ContentType, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
|
import { ItemHash } from '../Item/ItemHash'
|
||||||
|
import { SharedVaultOperationOnItem } from './SharedVaultOperationOnItem'
|
||||||
|
|
||||||
|
describe('SharedVaultOperationOnItem', () => {
|
||||||
|
let itemHash: ItemHash
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
itemHash = ItemHash.create({
|
||||||
|
uuid: '2-3-4',
|
||||||
|
content_type: ContentType.TYPES.Note,
|
||||||
|
user_uuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
content: 'foobar',
|
||||||
|
created_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
updated_at: '2020-01-01T00:00:00.000Z',
|
||||||
|
created_at_timestamp: 123,
|
||||||
|
updated_at_timestamp: 123,
|
||||||
|
key_system_identifier: null,
|
||||||
|
shared_vault_uuid: null,
|
||||||
|
}).getValue()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should create a value object', () => {
|
||||||
|
const valueOrError = SharedVaultOperationOnItem.create({
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
targetSharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.AddToSharedVault,
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(valueOrError.isFailed()).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return error if shared vault operation type is invalid', () => {
|
||||||
|
const valueOrError = SharedVaultOperationOnItem.create({
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
targetSharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
type: 'invalid',
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(valueOrError.isFailed()).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return error if operation type is move to other shared vault and target shared vault uuid is not provided', () => {
|
||||||
|
const valueOrError = SharedVaultOperationOnItem.create({
|
||||||
|
incomingItemHash: itemHash,
|
||||||
|
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
targetSharedVaultUuid: undefined,
|
||||||
|
type: SharedVaultOperationOnItem.TYPES.MoveToOtherSharedVault,
|
||||||
|
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(valueOrError.isFailed()).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { ValueObject, Result } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
|
import { SharedVaultOperationOnItemProps } from './SharedVaultOperationOnItemProps'
|
||||||
|
|
||||||
|
export class SharedVaultOperationOnItem extends ValueObject<SharedVaultOperationOnItemProps> {
|
||||||
|
static readonly TYPES = {
|
||||||
|
AddToSharedVault: 'add-to-shared-vault',
|
||||||
|
RemoveFromSharedVault: 'remove-from-shared-vault',
|
||||||
|
MoveToOtherSharedVault: 'move-to-other-shared-vault',
|
||||||
|
SaveToSharedVault: 'save-to-shared-vault',
|
||||||
|
CreateToSharedVault: 'create-to-shared-vault',
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor(props: SharedVaultOperationOnItemProps) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(props: SharedVaultOperationOnItemProps): Result<SharedVaultOperationOnItem> {
|
||||||
|
const isValidType = Object.values(this.TYPES).includes(props.type)
|
||||||
|
if (!isValidType) {
|
||||||
|
return Result.fail<SharedVaultOperationOnItem>(`Invalid shared vault operation type: ${props.type}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.type === this.TYPES.MoveToOtherSharedVault && !props.targetSharedVaultUuid) {
|
||||||
|
return Result.fail<SharedVaultOperationOnItem>('Missing target shared vault uuid')
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok<SharedVaultOperationOnItem>(new SharedVaultOperationOnItem(props))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
|
import { Item } from '../Item/Item'
|
||||||
|
import { ItemHash } from '../Item/ItemHash'
|
||||||
|
|
||||||
|
export interface SharedVaultOperationOnItemProps {
|
||||||
|
incomingItemHash: ItemHash
|
||||||
|
userUuid: Uuid
|
||||||
|
type: string
|
||||||
|
sharedVaultUuid: Uuid
|
||||||
|
targetSharedVaultUuid?: Uuid
|
||||||
|
existingItem?: Item
|
||||||
|
}
|
||||||
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { SharedVaultInvite } from './SharedVaultInvite'
|
import { SharedVaultInvite } from './SharedVaultInvite'
|
||||||
import { SharedVaultUserPermission } from '../SharedVaultUserPermission'
|
|
||||||
|
|
||||||
describe('SharedVaultInvite', () => {
|
describe('SharedVaultInvite', () => {
|
||||||
it('should create an entity', () => {
|
it('should create an entity', () => {
|
||||||
|
|||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||||
import { SharedVaultUserPermission } from '../SharedVaultUserPermission'
|
|
||||||
|
|
||||||
export interface SharedVaultInviteProps {
|
export interface SharedVaultInviteProps {
|
||||||
sharedVaultUuid: Uuid
|
sharedVaultUuid: Uuid
|
||||||
|
|||||||
+1
@@ -8,6 +8,7 @@ export interface SharedVaultInviteRepositoryInterface {
|
|||||||
remove(sharedVaultInvite: SharedVaultInvite): Promise<void>
|
remove(sharedVaultInvite: SharedVaultInvite): Promise<void>
|
||||||
removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void>
|
removeBySharedVaultUuid(sharedVaultUuid: Uuid): Promise<void>
|
||||||
findByUserUuid(userUuid: Uuid): Promise<SharedVaultInvite[]>
|
findByUserUuid(userUuid: Uuid): Promise<SharedVaultInvite[]>
|
||||||
|
findByUserUuidUpdatedAfter(userUuid: Uuid, updatedAtTimestamp: number): Promise<SharedVaultInvite[]>
|
||||||
findBySenderUuid(senderUuid: Uuid): Promise<SharedVaultInvite[]>
|
findBySenderUuid(senderUuid: Uuid): Promise<SharedVaultInvite[]>
|
||||||
findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultInvite | null>
|
findByUserUuidAndSharedVaultUuid(dto: { userUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultInvite | null>
|
||||||
findBySenderUuidAndSharedVaultUuid(dto: { senderUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultInvite[]>
|
findBySenderUuidAndSharedVaultUuid(dto: { senderUuid: Uuid; sharedVaultUuid: Uuid }): Promise<SharedVaultInvite[]>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { SharedVaultUser } from './SharedVaultUser'
|
import { SharedVaultUser } from './SharedVaultUser'
|
||||||
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
|
|
||||||
|
|
||||||
describe('SharedVaultUser', () => {
|
describe('SharedVaultUser', () => {
|
||||||
it('should create an entity', () => {
|
it('should create an entity', () => {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { SharedVaultUserPermission } from './SharedVaultUserPermission'
|
|
||||||
|
|
||||||
export interface SharedVaultUserProps {
|
export interface SharedVaultUserProps {
|
||||||
sharedVaultUuid: Uuid
|
sharedVaultUuid: Uuid
|
||||||
|
|||||||
+12
-19
@@ -1,14 +1,14 @@
|
|||||||
import { TimerInterface } from '@standardnotes/time'
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
import { Result } from '@standardnotes/domain-core'
|
import { NotificationPayload, NotificationType, Result, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
|
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
|
||||||
import { Notification } from '../../../Notifications/Notification'
|
import { Notification } from '../../../Notifications/Notification'
|
||||||
import { AddNotificationForUser } from './AddNotificationForUser'
|
import { AddNotificationForUser } from './AddNotificationForUser'
|
||||||
import { NotificationType } from '../../../Notifications/NotificationType'
|
|
||||||
|
|
||||||
describe('AddNotificationForUser', () => {
|
describe('AddNotificationForUser', () => {
|
||||||
let notificationRepository: NotificationRepositoryInterface
|
let notificationRepository: NotificationRepositoryInterface
|
||||||
let timer: TimerInterface
|
let timer: TimerInterface
|
||||||
|
let payload: NotificationPayload
|
||||||
|
|
||||||
const createUseCase = () => new AddNotificationForUser(notificationRepository, timer)
|
const createUseCase = () => new AddNotificationForUser(notificationRepository, timer)
|
||||||
|
|
||||||
@@ -18,6 +18,12 @@ describe('AddNotificationForUser', () => {
|
|||||||
|
|
||||||
timer = {} as jest.Mocked<TimerInterface>
|
timer = {} as jest.Mocked<TimerInterface>
|
||||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789)
|
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789)
|
||||||
|
|
||||||
|
payload = NotificationPayload.create({
|
||||||
|
sharedVaultUuid: Uuid.create('0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e').getValue(),
|
||||||
|
type: NotificationType.create(NotificationType.TYPES.RemovedFromSharedVault).getValue(),
|
||||||
|
version: '1.0',
|
||||||
|
}).getValue()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should save notification', async () => {
|
it('should save notification', async () => {
|
||||||
@@ -26,7 +32,7 @@ describe('AddNotificationForUser', () => {
|
|||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
|
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
|
||||||
type: NotificationType.TYPES.RemovedFromSharedVault,
|
type: NotificationType.TYPES.RemovedFromSharedVault,
|
||||||
payload: 'payload',
|
payload,
|
||||||
version: '1.0',
|
version: '1.0',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -39,7 +45,7 @@ describe('AddNotificationForUser', () => {
|
|||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
userUuid: 'invalid',
|
userUuid: 'invalid',
|
||||||
type: NotificationType.TYPES.RemovedFromSharedVault,
|
type: NotificationType.TYPES.RemovedFromSharedVault,
|
||||||
payload: 'payload',
|
payload,
|
||||||
version: '1.0',
|
version: '1.0',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -52,20 +58,7 @@ describe('AddNotificationForUser', () => {
|
|||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
|
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
|
||||||
type: 'invalid',
|
type: 'invalid',
|
||||||
payload: 'payload',
|
payload,
|
||||||
version: '1.0',
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(result.isFailed()).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should return error if notification payload is invalid', async () => {
|
|
||||||
const useCase = createUseCase()
|
|
||||||
|
|
||||||
const result = await useCase.execute({
|
|
||||||
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
|
|
||||||
type: NotificationType.TYPES.RemovedFromSharedVault,
|
|
||||||
payload: '',
|
|
||||||
version: '1.0',
|
version: '1.0',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -83,7 +76,7 @@ describe('AddNotificationForUser', () => {
|
|||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
|
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
|
||||||
type: NotificationType.TYPES.RemovedFromSharedVault,
|
type: NotificationType.TYPES.RemovedFromSharedVault,
|
||||||
payload: 'payload',
|
payload,
|
||||||
version: '1.0',
|
version: '1.0',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
+1
-7
@@ -1,10 +1,9 @@
|
|||||||
import { Result, Timestamps, UseCaseInterface, Uuid, Validator } from '@standardnotes/domain-core'
|
import { NotificationType, Result, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||||
import { TimerInterface } from '@standardnotes/time'
|
import { TimerInterface } from '@standardnotes/time'
|
||||||
|
|
||||||
import { AddNotificationForUserDTO } from './AddNotificationForUserDTO'
|
import { AddNotificationForUserDTO } from './AddNotificationForUserDTO'
|
||||||
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
|
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
|
||||||
import { Notification } from '../../../Notifications/Notification'
|
import { Notification } from '../../../Notifications/Notification'
|
||||||
import { NotificationType } from '../../../Notifications/NotificationType'
|
|
||||||
|
|
||||||
export class AddNotificationForUser implements UseCaseInterface<Notification> {
|
export class AddNotificationForUser implements UseCaseInterface<Notification> {
|
||||||
constructor(private notificationRepository: NotificationRepositoryInterface, private timer: TimerInterface) {}
|
constructor(private notificationRepository: NotificationRepositoryInterface, private timer: TimerInterface) {}
|
||||||
@@ -22,11 +21,6 @@ export class AddNotificationForUser implements UseCaseInterface<Notification> {
|
|||||||
}
|
}
|
||||||
const type = typeOrError.getValue()
|
const type = typeOrError.getValue()
|
||||||
|
|
||||||
const paylodNotEmptyValidationResult = Validator.isNotEmpty(dto.payload)
|
|
||||||
if (paylodNotEmptyValidationResult.isFailed()) {
|
|
||||||
return Result.fail(paylodNotEmptyValidationResult.getError())
|
|
||||||
}
|
|
||||||
|
|
||||||
const notificationOrError = Notification.create({
|
const notificationOrError = Notification.create({
|
||||||
userUuid,
|
userUuid,
|
||||||
type,
|
type,
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,8 @@
|
|||||||
|
import { NotificationPayload } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
export interface AddNotificationForUserDTO {
|
export interface AddNotificationForUserDTO {
|
||||||
version: string
|
version: string
|
||||||
type: string
|
type: string
|
||||||
userUuid: string
|
userUuid: string
|
||||||
payload: string
|
payload: NotificationPayload
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -9,6 +9,7 @@ describe('GetMessagesSentToUser', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
messageRepository = {} as jest.Mocked<MessageRepositoryInterface>
|
messageRepository = {} as jest.Mocked<MessageRepositoryInterface>
|
||||||
messageRepository.findByRecipientUuid = jest.fn().mockReturnValue([])
|
messageRepository.findByRecipientUuid = jest.fn().mockReturnValue([])
|
||||||
|
messageRepository.findByRecipientUuidUpdatedAfter = jest.fn().mockReturnValue([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return messages sent to user', async () => {
|
it('should return messages sent to user', async () => {
|
||||||
@@ -20,6 +21,16 @@ describe('GetMessagesSentToUser', () => {
|
|||||||
expect(result.getValue()).toEqual([])
|
expect(result.getValue()).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should return messages sent to user updated after given time', async () => {
|
||||||
|
const useCase = createUseCase()
|
||||||
|
const result = await useCase.execute({
|
||||||
|
recipientUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
lastSyncTime: 123,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.getValue()).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
it('should return error when recipient uuid is invalid', async () => {
|
it('should return error when recipient uuid is invalid', async () => {
|
||||||
const useCase = createUseCase()
|
const useCase = createUseCase()
|
||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
|
|||||||
+4
-2
@@ -14,8 +14,10 @@ export class GetMessagesSentToUser implements UseCaseInterface<Message[]> {
|
|||||||
}
|
}
|
||||||
const recipientUuid = recipientUuidOrError.getValue()
|
const recipientUuid = recipientUuidOrError.getValue()
|
||||||
|
|
||||||
const messages = await this.messageRepository.findByRecipientUuid(recipientUuid)
|
if (dto.lastSyncTime) {
|
||||||
|
return Result.ok(await this.messageRepository.findByRecipientUuidUpdatedAfter(recipientUuid, dto.lastSyncTime))
|
||||||
|
}
|
||||||
|
|
||||||
return Result.ok(messages)
|
return Result.ok(await this.messageRepository.findByRecipientUuid(recipientUuid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
export interface GetMessagesSentToUserDTO {
|
export interface GetMessagesSentToUserDTO {
|
||||||
recipientUuid: string
|
recipientUuid: string
|
||||||
|
lastSyncTime?: number
|
||||||
}
|
}
|
||||||
|
|||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
|
||||||
|
import { GetUserNotifications } from './GetUserNotifications'
|
||||||
|
|
||||||
|
describe('GetUserNotifications', () => {
|
||||||
|
let notificationRepository: NotificationRepositoryInterface
|
||||||
|
|
||||||
|
const createUseCase = () => new GetUserNotifications(notificationRepository)
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
notificationRepository = {} as jest.Mocked<NotificationRepositoryInterface>
|
||||||
|
notificationRepository.findByUserUuid = jest.fn().mockReturnValue([])
|
||||||
|
notificationRepository.findByUserUuidUpdatedAfter = jest.fn().mockReturnValue([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return notification for user', async () => {
|
||||||
|
const useCase = createUseCase()
|
||||||
|
const result = await useCase.execute({
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.getValue()).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return notifications for user updated after given time', async () => {
|
||||||
|
const useCase = createUseCase()
|
||||||
|
const result = await useCase.execute({
|
||||||
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
|
lastSyncTime: 123,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.getValue()).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return error when user uuid is invalid', async () => {
|
||||||
|
const useCase = createUseCase()
|
||||||
|
const result = await useCase.execute({
|
||||||
|
userUuid: 'invalid',
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result.isFailed()).toBe(true)
|
||||||
|
expect(result.getError()).toBe('Given value is not a valid uuid: invalid')
|
||||||
|
})
|
||||||
|
})
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||||
|
import { Notification } from '../../../Notifications/Notification'
|
||||||
|
import { GetUserNotificationsDTO } from './GetUserNotificationsDTO'
|
||||||
|
import { NotificationRepositoryInterface } from '../../../Notifications/NotificationRepositoryInterface'
|
||||||
|
|
||||||
|
export class GetUserNotifications implements UseCaseInterface<Notification[]> {
|
||||||
|
constructor(private notificationRepository: NotificationRepositoryInterface) {}
|
||||||
|
|
||||||
|
async execute(dto: GetUserNotificationsDTO): Promise<Result<Notification[]>> {
|
||||||
|
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||||
|
if (userUuidOrError.isFailed()) {
|
||||||
|
return Result.fail(userUuidOrError.getError())
|
||||||
|
}
|
||||||
|
const userUuid = userUuidOrError.getValue()
|
||||||
|
|
||||||
|
if (dto.lastSyncTime) {
|
||||||
|
return Result.ok(await this.notificationRepository.findByUserUuidUpdatedAfter(userUuid, dto.lastSyncTime))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.ok(await this.notificationRepository.findByUserUuid(userUuid))
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
export interface GetUserNotificationsDTO {
|
||||||
|
userUuid: string
|
||||||
|
lastSyncTime?: number
|
||||||
|
}
|
||||||
+64
@@ -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()
|
||||||
|
})
|
||||||
|
})
|
||||||
+29
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
export interface RemoveNotificationsForUserDTO {
|
||||||
|
type: string
|
||||||
|
userUuid: string
|
||||||
|
}
|
||||||
+1
-2
@@ -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 { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
|
||||||
import { AddUserToSharedVault } from '../AddUserToSharedVault/AddUserToSharedVault'
|
import { AddUserToSharedVault } from '../AddUserToSharedVault/AddUserToSharedVault'
|
||||||
import { AcceptInviteToSharedVault } from './AcceptInviteToSharedVault'
|
import { AcceptInviteToSharedVault } from './AcceptInviteToSharedVault'
|
||||||
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
|
||||||
|
|
||||||
describe('AcceptInviteToSharedVault', () => {
|
describe('AcceptInviteToSharedVault', () => {
|
||||||
let addUserToSharedVault: AddUserToSharedVault
|
let addUserToSharedVault: AddUserToSharedVault
|
||||||
|
|||||||
+1
-2
@@ -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 { TimerInterface } from '@standardnotes/time'
|
||||||
|
|
||||||
import { AddUserToSharedVaultDTO } from './AddUserToSharedVaultDTO'
|
import { AddUserToSharedVaultDTO } from './AddUserToSharedVaultDTO'
|
||||||
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
|
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
|
||||||
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
|
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
|
||||||
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
|
||||||
|
|
||||||
export class AddUserToSharedVault implements UseCaseInterface<SharedVaultUser> {
|
export class AddUserToSharedVault implements UseCaseInterface<SharedVaultUser> {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
+1
-2
@@ -4,8 +4,7 @@ import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/Sh
|
|||||||
import { CreateSharedVaultFileValetToken } from './CreateSharedVaultFileValetToken'
|
import { CreateSharedVaultFileValetToken } from './CreateSharedVaultFileValetToken'
|
||||||
import { SharedVault } from '../../../SharedVault/SharedVault'
|
import { SharedVault } from '../../../SharedVault/SharedVault'
|
||||||
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
|
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
import { SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||||
import { Timestamps, Uuid } from '@standardnotes/domain-core'
|
|
||||||
|
|
||||||
describe('CreateSharedVaultFileValetToken', () => {
|
describe('CreateSharedVaultFileValetToken', () => {
|
||||||
let sharedVaultRepository: SharedVaultRepositoryInterface
|
let sharedVaultRepository: SharedVaultRepositoryInterface
|
||||||
|
|||||||
+1
-2
@@ -1,10 +1,9 @@
|
|||||||
import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
|
import { SharedVaultValetTokenData, TokenEncoderInterface, ValetTokenOperation } from '@standardnotes/security'
|
||||||
|
import { Result, SharedVaultUserPermission, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
|
import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
|
||||||
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
|
||||||
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||||
import { CreateSharedVaultFileValetTokenDTO } from './CreateSharedVaultFileValetTokenDTO'
|
import { CreateSharedVaultFileValetTokenDTO } from './CreateSharedVaultFileValetTokenDTO'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
|
||||||
|
|
||||||
export class CreateSharedVaultFileValetToken implements UseCaseInterface<string> {
|
export class CreateSharedVaultFileValetToken implements UseCaseInterface<string> {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
+7
-8
@@ -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 { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
|
||||||
import { DeclineInviteToSharedVault } from './DeclineInviteToSharedVault'
|
import { DeclineInviteToSharedVault } from './DeclineInviteToSharedVault'
|
||||||
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
|
||||||
|
|
||||||
describe('DeclineInviteToSharedVault', () => {
|
describe('DeclineInviteToSharedVault', () => {
|
||||||
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
|
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
|
||||||
@@ -30,7 +29,7 @@ describe('DeclineInviteToSharedVault', () => {
|
|||||||
|
|
||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
inviteUuid: 'invalid',
|
inviteUuid: 'invalid',
|
||||||
originatorUuid: '00000000-0000-0000-0000-000000000000',
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result.isFailed()).toBe(true)
|
expect(result.isFailed()).toBe(true)
|
||||||
@@ -42,7 +41,7 @@ describe('DeclineInviteToSharedVault', () => {
|
|||||||
|
|
||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
originatorUuid: 'invalid',
|
userUuid: 'invalid',
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result.isFailed()).toBe(true)
|
expect(result.isFailed()).toBe(true)
|
||||||
@@ -56,7 +55,7 @@ describe('DeclineInviteToSharedVault', () => {
|
|||||||
|
|
||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
originatorUuid: '00000000-0000-0000-0000-000000000000',
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result.isFailed()).toBe(true)
|
expect(result.isFailed()).toBe(true)
|
||||||
@@ -68,11 +67,11 @@ describe('DeclineInviteToSharedVault', () => {
|
|||||||
|
|
||||||
const result = await useCase.execute({
|
const result = await useCase.execute({
|
||||||
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
originatorUuid: '00000000-0000-0000-0000-000000000001',
|
userUuid: '00000000-0000-0000-0000-000000000001',
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(result.isFailed()).toBe(true)
|
expect(result.isFailed()).toBe(true)
|
||||||
expect(result.getError()).toBe('Only the recipient of the invite can decline it')
|
expect(result.getError()).toBe('Only the recipient or the sender can decline the invite')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should delete invite', async () => {
|
it('should delete invite', async () => {
|
||||||
@@ -80,7 +79,7 @@ describe('DeclineInviteToSharedVault', () => {
|
|||||||
|
|
||||||
await useCase.execute({
|
await useCase.execute({
|
||||||
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
inviteUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
originatorUuid: '00000000-0000-0000-0000-000000000000',
|
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(sharedVaultInviteRepository.remove).toHaveBeenCalled()
|
expect(sharedVaultInviteRepository.remove).toHaveBeenCalled()
|
||||||
|
|||||||
+6
-6
@@ -12,19 +12,19 @@ export class DeclineInviteToSharedVault implements UseCaseInterface<void> {
|
|||||||
}
|
}
|
||||||
const inviteUuid = inviteUuidOrError.getValue()
|
const inviteUuid = inviteUuidOrError.getValue()
|
||||||
|
|
||||||
const originatorUuidOrError = Uuid.create(dto.originatorUuid)
|
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||||
if (originatorUuidOrError.isFailed()) {
|
if (userUuidOrError.isFailed()) {
|
||||||
return Result.fail(originatorUuidOrError.getError())
|
return Result.fail(userUuidOrError.getError())
|
||||||
}
|
}
|
||||||
const originatorUuid = originatorUuidOrError.getValue()
|
const userUuid = userUuidOrError.getValue()
|
||||||
|
|
||||||
const invite = await this.sharedVaultInviteRepository.findByUuid(inviteUuid)
|
const invite = await this.sharedVaultInviteRepository.findByUuid(inviteUuid)
|
||||||
if (!invite) {
|
if (!invite) {
|
||||||
return Result.fail('Invite not found')
|
return Result.fail('Invite not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!invite.props.userUuid.equals(originatorUuid)) {
|
if (!invite.props.userUuid.equals(userUuid) && !invite.props.senderUuid.equals(userUuid)) {
|
||||||
return Result.fail('Only the recipient of the invite can decline it')
|
return Result.fail('Only the recipient or the sender can decline the invite')
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.sharedVaultInviteRepository.remove(invite)
|
await this.sharedVaultInviteRepository.remove(invite)
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
export interface DeclineInviteToSharedVaultDTO {
|
export interface DeclineInviteToSharedVaultDTO {
|
||||||
inviteUuid: string
|
inviteUuid: string
|
||||||
originatorUuid: string
|
userUuid: string
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -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 { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
|
||||||
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
|
import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
|
||||||
@@ -6,7 +6,6 @@ import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/Sh
|
|||||||
import { DeleteSharedVault } from './DeleteSharedVault'
|
import { DeleteSharedVault } from './DeleteSharedVault'
|
||||||
import { SharedVault } from '../../../SharedVault/SharedVault'
|
import { SharedVault } from '../../../SharedVault/SharedVault'
|
||||||
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
|
import { SharedVaultUser } from '../../../SharedVault/User/SharedVaultUser'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
|
||||||
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
|
import { RemoveUserFromSharedVault } from '../RemoveUserFromSharedVault/RemoveUserFromSharedVault'
|
||||||
|
|
||||||
describe('DeleteSharedVault', () => {
|
describe('DeleteSharedVault', () => {
|
||||||
|
|||||||
+1
@@ -42,6 +42,7 @@ export class DeleteSharedVault implements UseCaseInterface<void> {
|
|||||||
originatorUuid: originatorUuid.value,
|
originatorUuid: originatorUuid.value,
|
||||||
sharedVaultUuid: sharedVaultUuid.value,
|
sharedVaultUuid: sharedVaultUuid.value,
|
||||||
userUuid: sharedVaultUser.props.userUuid.value,
|
userUuid: sharedVaultUser.props.userUuid.value,
|
||||||
|
forceRemoveOwner: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
|
|||||||
+1
-2
@@ -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 { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
|
||||||
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
|
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
|
||||||
import { DeleteSharedVaultInvitesSentByUser } from './DeleteSharedVaultInvitesSentByUser'
|
import { DeleteSharedVaultInvitesSentByUser } from './DeleteSharedVaultInvitesSentByUser'
|
||||||
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
|
||||||
|
|
||||||
describe('DeleteSharedVaultInvitesSentByUser', () => {
|
describe('DeleteSharedVaultInvitesSentByUser', () => {
|
||||||
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
|
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ export class DeleteSharedVaultInvitesSentByUser implements UseCaseInterface<void
|
|||||||
for (const invite of inboundInvites) {
|
for (const invite of inboundInvites) {
|
||||||
const result = await this.declineInviteToSharedVault.execute({
|
const result = await this.declineInviteToSharedVault.execute({
|
||||||
inviteUuid: invite.id.toString(),
|
inviteUuid: invite.id.toString(),
|
||||||
originatorUuid: userUuid.value,
|
userUuid: userUuid.value,
|
||||||
})
|
})
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
return Result.fail(result.getError())
|
return Result.fail(result.getError())
|
||||||
|
|||||||
+1
-2
@@ -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 { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
|
||||||
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
|
import { DeclineInviteToSharedVault } from '../DeclineInviteToSharedVault/DeclineInviteToSharedVault'
|
||||||
import { DeleteSharedVaultInvitesToUser } from './DeleteSharedVaultInvitesToUser'
|
import { DeleteSharedVaultInvitesToUser } from './DeleteSharedVaultInvitesToUser'
|
||||||
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
|
||||||
import { SharedVaultUserPermission } from '../../../SharedVault/User/SharedVaultUserPermission'
|
|
||||||
|
|
||||||
describe('DeleteSharedVaultInvitesToUser', () => {
|
describe('DeleteSharedVaultInvitesToUser', () => {
|
||||||
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
|
let sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ export class DeleteSharedVaultInvitesToUser implements UseCaseInterface<void> {
|
|||||||
for (const invite of inboundInvites) {
|
for (const invite of inboundInvites) {
|
||||||
const result = await this.declineInviteToSharedVault.execute({
|
const result = await this.declineInviteToSharedVault.execute({
|
||||||
inviteUuid: invite.id.toString(),
|
inviteUuid: invite.id.toString(),
|
||||||
originatorUuid: userUuid.value,
|
userUuid: userUuid.value,
|
||||||
})
|
})
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
return Result.fail(result.getError())
|
return Result.fail(result.getError())
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user