Compare commits

...

2 Commits

Author SHA1 Message Date
standardci
2606f6d929 chore(release): publish new version
- @standardnotes/analytics@2.24.8
 - @standardnotes/api-gateway@1.65.5
 - @standardnotes/auth-server@1.122.2
 - @standardnotes/domain-core@1.21.1
 - @standardnotes/domain-events-infra@1.12.9
 - @standardnotes/domain-events@2.113.1
 - @standardnotes/event-store@1.11.5
 - @standardnotes/files-server@1.19.5
 - @standardnotes/home-server@1.11.32
 - @standardnotes/revisions-server@1.23.9
 - @standardnotes/scheduler-server@1.20.7
 - @standardnotes/settings@1.21.12
 - @standardnotes/syncing-server@1.58.1
 - @standardnotes/websockets-server@1.9.8
2023-07-07 13:30:56 +00:00
Karol Sójko
c288e5d8dc fix: transfer notifications from auth to syncing-server. (#648)
* fix: transfer notifications from auth to syncing-server.

Co-authored-by: Mo <mo@standardnotes.com>

* fix: add notification to data source init

---------

Co-authored-by: Mo <mo@standardnotes.com>
2023-07-07 15:12:27 +02:00
56 changed files with 442 additions and 99 deletions

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.24.8](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.7...@standardnotes/analytics@2.24.8) (2023-07-07)
**Note:** Version bump only for package @standardnotes/analytics
## [2.24.7](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.24.6...@standardnotes/analytics@2.24.7) (2023-07-06)
**Note:** Version bump only for package @standardnotes/analytics

View File

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

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.65.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.4...@standardnotes/api-gateway@1.65.5) (2023-07-07)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.65.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.65.3...@standardnotes/api-gateway@1.65.4) (2023-07-06)
**Note:** Version bump only for package @standardnotes/api-gateway

View File

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

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.122.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.122.1...@standardnotes/auth-server@1.122.2) (2023-07-07)
### Bug Fixes
* transfer notifications from auth to syncing-server. ([#648](https://github.com/standardnotes/server/issues/648)) ([c288e5d](https://github.com/standardnotes/server/commit/c288e5d8dc54778a96a9fc33e3c9cae00583fade))
## [1.122.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.122.0...@standardnotes/auth-server@1.122.1) (2023-07-06)
**Note:** Version bump only for package @standardnotes/auth-server

View File

@@ -0,0 +1,16 @@
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',
)
}
}

View File

@@ -0,0 +1,17 @@
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") ')
}
}

View File

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

View File

@@ -18,7 +18,6 @@ import { TypeORMEmergencyAccessInvitation } from '../Infra/TypeORM/TypeORMEmerge
import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace'
import { Env } from './Env'
import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
import { TypeORMNotification } from '../Infra/TypeORM/TypeORMNotification'
export class AppDataSource {
private _dataSource: DataSource | undefined
@@ -65,7 +64,6 @@ export class AppDataSource {
TypeORMAuthenticatorChallenge,
TypeORMEmergencyAccessInvitation,
TypeORMCacheEntry,
TypeORMNotification,
],
migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
migrationsRun: true,

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.21.0...@standardnotes/domain-core@1.21.1) (2023-07-07)
### Bug Fixes
* transfer notifications from auth to syncing-server. ([#648](https://github.com/standardnotes/server/issues/648)) ([c288e5d](https://github.com/standardnotes/server/commit/c288e5d8dc54778a96a9fc33e3c9cae00583fade))
# [1.21.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.20.0...@standardnotes/domain-core@1.21.0) (2023-07-06)
### Features

View File

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

View File

@@ -43,9 +43,6 @@ export * from './Env/AbstractEnv'
export * from './Mapping/MapperInterface'
export * from './Notification/NotificationType'
export * from './Notification/NotificationTypeProps'
export * from './Service/ServiceConfiguration'
export * from './Service/ServiceContainer'
export * from './Service/ServiceContainerInterface'

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.12.9](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.8...@standardnotes/domain-events-infra@1.12.9) (2023-07-07)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.12.8](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.7...@standardnotes/domain-events-infra@1.12.8) (2023-07-05)
**Note:** Version bump only for package @standardnotes/domain-events-infra

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events-infra",
"version": "1.12.8",
"version": "1.12.9",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.113.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.113.0...@standardnotes/domain-events@2.113.1) (2023-07-07)
### Bug Fixes
* transfer notifications from auth to syncing-server. ([#648](https://github.com/standardnotes/server/issues/648)) ([c288e5d](https://github.com/standardnotes/server/commit/c288e5d8dc54778a96a9fc33e3c9cae00583fade))
# [2.113.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.112.1...@standardnotes/domain-events@2.113.0) (2023-07-05)
### Features

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events",
"version": "2.113.0",
"version": "2.113.1",
"engines": {
"node": ">=18.0.0 <21.0.0"
},

View File

@@ -1,7 +0,0 @@
import { DomainEventInterface } from './DomainEventInterface'
import { NotificationRequestedEventPayload } from './NotificationRequestedEventPayload'
export interface NotificationRequestedEvent extends DomainEventInterface {
type: 'NOTIFICATION_REQUESTED'
payload: NotificationRequestedEventPayload
}

View File

@@ -1,5 +0,0 @@
export interface NotificationRequestedEventPayload {
userUuid: string
type: string
payload: string
}

View File

@@ -42,8 +42,6 @@ export * from './Event/ListedAccountRequestedEvent'
export * from './Event/ListedAccountRequestedEventPayload'
export * from './Event/MuteEmailsSettingChangedEvent'
export * from './Event/MuteEmailsSettingChangedEventPayload'
export * from './Event/NotificationRequestedEvent'
export * from './Event/NotificationRequestedEventPayload'
export * from './Event/PaymentFailedEvent'
export * from './Event/PaymentFailedEventPayload'
export * from './Event/PaymentSuccessEvent'

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.5](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.4...@standardnotes/event-store@1.11.5) (2023-07-07)
**Note:** Version bump only for package @standardnotes/event-store
## [1.11.4](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.3...@standardnotes/event-store@1.11.4) (2023-07-06)
**Note:** Version bump only for package @standardnotes/event-store

View File

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

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.19.5](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.4...@standardnotes/files-server@1.19.5) (2023-07-07)
**Note:** Version bump only for package @standardnotes/files-server
## [1.19.4](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.19.3...@standardnotes/files-server@1.19.4) (2023-07-06)
**Note:** Version bump only for package @standardnotes/files-server

View File

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

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.11.32](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.31...@standardnotes/home-server@1.11.32) (2023-07-07)
**Note:** Version bump only for package @standardnotes/home-server
## [1.11.31](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.11.30...@standardnotes/home-server@1.11.31) (2023-07-07)
**Note:** Version bump only for package @standardnotes/home-server

View File

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

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.23.9](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.23.8...@standardnotes/revisions-server@1.23.9) (2023-07-07)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.23.8](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.23.7...@standardnotes/revisions-server@1.23.8) (2023-07-06)
**Note:** Version bump only for package @standardnotes/revisions-server

View File

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

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.20.7](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.6...@standardnotes/scheduler-server@1.20.7) (2023-07-07)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.20.6](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.5...@standardnotes/scheduler-server@1.20.6) (2023-07-06)
**Note:** Version bump only for package @standardnotes/scheduler-server

View File

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

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.21.12](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.11...@standardnotes/settings@1.21.12) (2023-07-07)
**Note:** Version bump only for package @standardnotes/settings
## [1.21.11](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.10...@standardnotes/settings@1.21.11) (2023-07-06)
**Note:** Version bump only for package @standardnotes/settings

View File

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

View File

@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.58.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.58.0...@standardnotes/syncing-server@1.58.1) (2023-07-07)
### Bug Fixes
* transfer notifications from auth to syncing-server. ([#648](https://github.com/standardnotes/syncing-server-js/issues/648)) ([c288e5d](https://github.com/standardnotes/syncing-server-js/commit/c288e5d8dc54778a96a9fc33e3c9cae00583fade))
# [1.58.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.57.0...@standardnotes/syncing-server@1.58.0) (2023-07-07)
### Features

View File

@@ -0,0 +1,16 @@
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`')
}
}

View File

@@ -0,0 +1,17 @@
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"')
}
}

View File

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

View File

@@ -1,23 +1,28 @@
import { DataSource, EntityTarget, LoggerOptions, ObjectLiteral, Repository } from 'typeorm'
import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'
import { Item } from '../Domain/Item/Item'
import { Notification } from '../Domain/Notifications/Notification'
import { Env } from './Env'
import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
export class AppDataSource {
private dataSource: DataSource | undefined
private _dataSource: DataSource | undefined
constructor(private env: Env) {}
getRepository<Entity extends ObjectLiteral>(target: EntityTarget<Entity>): Repository<Entity> {
if (!this.dataSource) {
if (!this._dataSource) {
throw new Error('DataSource not initialized')
}
return this.dataSource.getRepository(target)
return this._dataSource.getRepository(target)
}
async initialize(): Promise<void> {
await this.dataSource.initialize()
}
get dataSource(): DataSource {
this.env.load()
const isConfiguredForMySQL = this.env.get('DB_TYPE') === 'mysql'
@@ -28,7 +33,7 @@ export class AppDataSource {
const commonDataSourceOptions = {
maxQueryExecutionTime,
entities: [Item],
entities: [Item, Notification],
migrations: [`${__dirname}/../../migrations/${isConfiguredForMySQL ? 'mysql' : 'sqlite'}/*.js`],
migrationsRun: true,
logging: <LoggerOptions>this.env.get('DB_DEBUG_LEVEL', true) ?? 'info',
@@ -72,7 +77,7 @@ export class AppDataSource {
database: inReplicaMode ? undefined : this.env.get('DB_DATABASE'),
}
this.dataSource = new DataSource(mySQLDataSourceOptions)
this._dataSource = new DataSource(mySQLDataSourceOptions)
} else {
const sqliteDataSourceOptions: SqliteConnectionOptions = {
...commonDataSourceOptions,
@@ -80,9 +85,9 @@ export class AppDataSource {
database: this.env.get('DB_SQLITE_DATABASE_PATH'),
}
this.dataSource = new DataSource(sqliteDataSourceOptions)
this._dataSource = new DataSource(sqliteDataSourceOptions)
}
await this.dataSource.initialize()
return this._dataSource
}
}

View File

@@ -0,0 +1,7 @@
import { AppDataSource } from './DataSource'
import { Env } from './Env'
const env: Env = new Env()
env.load()
export const MigrationsDataSource = new AppDataSource(env).dataSource

View File

@@ -5,7 +5,6 @@ import {
EmailRequestedEvent,
ItemDumpedEvent,
ItemRevisionCreationRequestedEvent,
NotificationRequestedEvent,
RevisionsCopyRequestedEvent,
} from '@standardnotes/domain-events'
import { TimerInterface } from '@standardnotes/time'
@@ -14,25 +13,6 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
export class DomainEventFactory implements DomainEventFactoryInterface {
constructor(private timer: TimerInterface) {}
createNotificationRequestedEvent(dto: {
userUuid: string
type: string
payload: string
}): NotificationRequestedEvent {
return {
type: 'NOTIFICATION_REQUESTED',
createdAt: this.timer.getUTCDate(),
meta: {
correlation: {
userIdentifier: dto.userUuid,
userIdentifierType: 'uuid',
},
origin: DomainEventService.SyncingServer,
},
payload: dto,
}
}
createRevisionsCopyRequestedEvent(
userUuid: string,
dto: {

View File

@@ -3,12 +3,10 @@ import {
EmailRequestedEvent,
ItemDumpedEvent,
ItemRevisionCreationRequestedEvent,
NotificationRequestedEvent,
RevisionsCopyRequestedEvent,
} from '@standardnotes/domain-events'
export interface DomainEventFactoryInterface {
createNotificationRequestedEvent(dto: { userUuid: string; type: string; payload: string }): NotificationRequestedEvent
createEmailRequestedEvent(dto: {
userEmail: string
messageIdentifier: string

View File

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

View File

@@ -1,4 +1,6 @@
import { NotificationType, Timestamps, Uuid } from '@standardnotes/domain-core'
import { Timestamps, Uuid } from '@standardnotes/domain-core'
import { NotificationType } from './NotificationType'
export interface NotificationProps {
userUuid: Uuid

View File

@@ -0,0 +1,5 @@
import { Notification } from './Notification'
export interface NotificationRepositoryInterface {
save(notification: Notification): Promise<void>
}

View File

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

View File

@@ -0,0 +1,94 @@
import { TimerInterface } from '@standardnotes/time'
import { Result } from '@standardnotes/domain-core'
import { NotificationRepositoryInterface } from '../../Notifications/NotificationRepositoryInterface'
import { Notification } from '../../Notifications/Notification'
import { AddNotificationForUser } from './AddNotificationForUser'
import { NotificationType } from '../../Notifications/NotificationType'
describe('AddNotificationForUser', () => {
let notificationRepository: NotificationRepositoryInterface
let timer: TimerInterface
const createUseCase = () => new AddNotificationForUser(notificationRepository, timer)
beforeEach(() => {
notificationRepository = {} as jest.Mocked<NotificationRepositoryInterface>
notificationRepository.save = jest.fn()
timer = {} as jest.Mocked<TimerInterface>
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789)
})
it('should save notification', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
type: NotificationType.TYPES.RemovedFromSharedVault,
payload: 'payload',
version: '1.0',
})
expect(result.isFailed()).toBeFalsy()
})
it('should return error if user uuid is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: 'invalid',
type: NotificationType.TYPES.RemovedFromSharedVault,
payload: 'payload',
version: '1.0',
})
expect(result.isFailed()).toBeTruthy()
})
it('should return error if notification type is invalid', async () => {
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
type: 'invalid',
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',
})
expect(result.isFailed()).toBeTruthy()
})
it('should return error if notification could not be created', async () => {
const mock = jest.spyOn(Notification, 'create')
mock.mockImplementation(() => {
return Result.fail('Oops')
})
const useCase = createUseCase()
const result = await useCase.execute({
userUuid: '0e8c3c7e-3f1a-4f7a-9b5a-5b2b0a7d4b1e',
type: NotificationType.TYPES.RemovedFromSharedVault,
payload: 'payload',
version: '1.0',
})
expect(result.isFailed()).toBeTruthy()
mock.mockRestore()
})
})

View File

@@ -0,0 +1,48 @@
import { Result, Timestamps, UseCaseInterface, Uuid, Validator } from '@standardnotes/domain-core'
import { TimerInterface } from '@standardnotes/time'
import { AddNotificationForUserDTO } from './AddNotificationForUserDTO'
import { NotificationRepositoryInterface } from '../../Notifications/NotificationRepositoryInterface'
import { Notification } from '../../Notifications/Notification'
import { NotificationType } from '../../Notifications/NotificationType'
export class AddNotificationForUser implements UseCaseInterface<Notification> {
constructor(private notificationRepository: NotificationRepositoryInterface, private timer: TimerInterface) {}
async execute(dto: AddNotificationForUserDTO): Promise<Result<Notification>> {
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 paylodNotEmptyValidationResult = Validator.isNotEmpty(dto.payload)
if (paylodNotEmptyValidationResult.isFailed()) {
return Result.fail(paylodNotEmptyValidationResult.getError())
}
const notificationOrError = Notification.create({
userUuid,
type,
payload: dto.payload,
timestamps: Timestamps.create(
this.timer.getTimestampInMicroseconds(),
this.timer.getTimestampInMicroseconds(),
).getValue(),
})
if (notificationOrError.isFailed()) {
return Result.fail(notificationOrError.getError())
}
const notification = notificationOrError.getValue()
await this.notificationRepository.save(notification)
return Result.ok(notification)
}
}

View File

@@ -0,0 +1,6 @@
export interface AddNotificationForUserDTO {
version: string
type: string
userUuid: string
payload: string
}

View File

@@ -1,29 +1,22 @@
import { Uuid, Timestamps } from '@standardnotes/domain-core'
import { DomainEventPublisherInterface, NotificationRequestedEvent } from '@standardnotes/domain-events'
import { Uuid, Timestamps, Result } from '@standardnotes/domain-core'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { SharedVault } from '../../SharedVault/SharedVault'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUser } from '../../SharedVault/User/SharedVaultUser'
import { SharedVaultUserPermission } from '../../SharedVault/User/SharedVaultUserPermission'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { RemoveUserFromSharedVault } from './RemoveUserFromSharedVault'
import { AddNotificationForUser } from '../AddNotificationForUser/AddNotificationForUser'
describe('RemoveUserFromSharedVault', () => {
let sharedVaultRepository: SharedVaultRepositoryInterface
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
let domainEventPublisher: DomainEventPublisherInterface
let domainEventFactory: DomainEventFactoryInterface
let addNotificationForUser: AddNotificationForUser
let sharedVault: SharedVault
let sharedVaultUser: SharedVaultUser
const createUseCase = () =>
new RemoveUserFromSharedVault(
sharedVaultUserRepository,
sharedVaultRepository,
domainEventFactory,
domainEventPublisher,
)
new RemoveUserFromSharedVault(sharedVaultUserRepository, sharedVaultRepository, addNotificationForUser)
beforeEach(() => {
sharedVault = SharedVault.create({
@@ -46,13 +39,8 @@ describe('RemoveUserFromSharedVault', () => {
sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid = jest.fn().mockResolvedValue(sharedVaultUser)
sharedVaultUserRepository.remove = jest.fn()
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
domainEventPublisher.publish = jest.fn()
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
domainEventFactory.createNotificationRequestedEvent = jest
.fn()
.mockReturnValue({} as jest.Mocked<NotificationRequestedEvent>)
addNotificationForUser = {} as jest.Mocked<AddNotificationForUser>
addNotificationForUser.execute = jest.fn().mockReturnValue(Result.ok())
})
it('should remove user from shared vault', async () => {
@@ -64,7 +52,6 @@ describe('RemoveUserFromSharedVault', () => {
})
expect(sharedVaultUserRepository.remove).toHaveBeenCalledWith(sharedVaultUser)
expect(domainEventPublisher.publish).toHaveBeenCalled()
})
it('should return error when shared vault is not found', async () => {
@@ -162,4 +149,28 @@ describe('RemoveUserFromSharedVault', () => {
expect(result.isFailed()).toBe(true)
expect(result.getError()).toBe('Given value is not a valid uuid: invalid')
})
it('should add notification for user', async () => {
const useCase = createUseCase()
await useCase.execute({
originatorUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
userUuid: '00000000-0000-0000-0000-000000000001',
})
expect(addNotificationForUser.execute).toHaveBeenCalled()
})
it('should return error if notification could not be added', async () => {
addNotificationForUser.execute = jest.fn().mockResolvedValue(Result.fail('Could not add notification'))
const useCase = createUseCase()
const result = await useCase.execute({
originatorUuid: '00000000-0000-0000-0000-000000000000',
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
userUuid: '00000000-0000-0000-0000-000000000001',
})
expect(result.isFailed()).toBe(true)
})
})

View File

@@ -1,17 +1,16 @@
import { NotificationType, Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
import { RemoveUserFromSharedVaultDTO } from './RemoveUserFromSharedVaultDTO'
import { SharedVaultRepositoryInterface } from '../../SharedVault/SharedVaultRepositoryInterface'
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/User/SharedVaultUserRepositoryInterface'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { AddNotificationForUser } from '../AddNotificationForUser/AddNotificationForUser'
import { NotificationType } from '../../Notifications/NotificationType'
export class RemoveUserFromSharedVault implements UseCaseInterface<void> {
constructor(
private sharedVaultUsersRepository: SharedVaultUserRepositoryInterface,
private sharedVaultRepository: SharedVaultRepositoryInterface,
private domainEventFactory: DomainEventFactoryInterface,
private domainEventPublisher: DomainEventPublisherInterface,
private addNotificationForUser: AddNotificationForUser,
) {}
async execute(dto: RemoveUserFromSharedVaultDTO): Promise<Result<void>> {
@@ -58,16 +57,17 @@ export class RemoveUserFromSharedVault implements UseCaseInterface<void> {
await this.sharedVaultUsersRepository.remove(sharedVaultUser)
await this.domainEventPublisher.publish(
this.domainEventFactory.createNotificationRequestedEvent({
type: NotificationType.TYPES.RemovedFromSharedVault,
userUuid: sharedVaultUser.props.userUuid.value,
payload: JSON.stringify({
sharedVaultUuid: sharedVault.id.toString(),
version: '1.0',
}),
const result = await this.addNotificationForUser.execute({
userUuid: sharedVaultUser.props.userUuid.value,
type: NotificationType.TYPES.RemovedFromSharedVault,
payload: JSON.stringify({
sharedVaultUuid: sharedVault.id.toString(),
}),
)
version: '1.0',
})
if (result.isFailed()) {
return Result.fail(result.getError())
}
return Result.ok()
}

View File

@@ -0,0 +1,19 @@
import { Repository } from 'typeorm'
import { MapperInterface } from '@standardnotes/domain-core'
import { NotificationRepositoryInterface } from '../../Domain/Notifications/NotificationRepositoryInterface'
import { TypeORMNotification } from './TypeORMNotification'
import { Notification } from '../../Domain/Notifications/Notification'
export class TypeORMNotificationRepository implements NotificationRepositoryInterface {
constructor(
private ormRepository: Repository<TypeORMNotification>,
private mapper: MapperInterface<Notification, TypeORMNotification>,
) {}
async save(sharedVault: Notification): Promise<void> {
const persistence = this.mapper.toProjection(sharedVault)
await this.ormRepository.save(persistence)
}
}

View File

@@ -0,0 +1,57 @@
import { Timestamps, MapperInterface, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
import { Notification } from '../../Domain/Notifications/Notification'
import { TypeORMNotification } from '../../Infra/TypeORM/TypeORMNotification'
import { NotificationType } from '../../Domain/Notifications/NotificationType'
export class NotificationPersistenceMapper implements MapperInterface<Notification, TypeORMNotification> {
toDomain(projection: TypeORMNotification): Notification {
const userUuidOrError = Uuid.create(projection.userUuid)
if (userUuidOrError.isFailed()) {
throw new Error(`Failed to create notification from projection: ${userUuidOrError.getError()}`)
}
const userUuid = userUuidOrError.getValue()
const timestampsOrError = Timestamps.create(projection.createdAtTimestamp, projection.updatedAtTimestamp)
if (timestampsOrError.isFailed()) {
throw new Error(`Failed to create notification from projection: ${timestampsOrError.getError()}`)
}
const timestamps = timestampsOrError.getValue()
const typeOrError = NotificationType.create(projection.type)
if (typeOrError.isFailed()) {
throw new Error(`Failed to create notification from projection: ${typeOrError.getError()}`)
}
const type = typeOrError.getValue()
const notificationOrError = Notification.create(
{
userUuid,
payload: projection.payload,
type,
timestamps,
},
new UniqueEntityId(projection.uuid),
)
if (notificationOrError.isFailed()) {
throw new Error(`Failed to create notification from projection: ${notificationOrError.getError()}`)
}
const notification = notificationOrError.getValue()
return notification
}
toProjection(domain: Notification): TypeORMNotification {
const typeorm = new TypeORMNotification()
typeorm.uuid = domain.id.toString()
typeorm.userUuid = domain.props.userUuid.value
typeorm.payload = domain.props.payload
typeorm.type = domain.props.type.value
typeorm.createdAtTimestamp = domain.props.timestamps.createdAt
typeorm.updatedAtTimestamp = domain.props.timestamps.updatedAt
return typeorm
}
}

View File

@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.9.8](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.9.7...@standardnotes/websockets-server@1.9.8) (2023-07-07)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.9.7](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.9.6...@standardnotes/websockets-server@1.9.7) (2023-07-06)
**Note:** Version bump only for package @standardnotes/websockets-server

View File

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