mirror of
https://github.com/standardnotes/server
synced 2026-01-26 23:01:10 -05:00
Compare commits
18 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7d21b092d | ||
|
|
031fa71e7d | ||
|
|
948e843ad6 | ||
|
|
7b0ea0a069 | ||
|
|
8887b6e642 | ||
|
|
597ff13393 | ||
|
|
4ab61b94a4 | ||
|
|
e19652d62a | ||
|
|
a341e78909 | ||
|
|
48e52ac48c | ||
|
|
6dbb87708f | ||
|
|
d15d51eae6 | ||
|
|
0058368681 | ||
|
|
746c821698 | ||
|
|
3f2d8c902c | ||
|
|
3637db2563 | ||
|
|
8ac84c59af | ||
|
|
a2b1323568 |
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.34.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.5...@standardnotes/analytics@2.34.6) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.34.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.4...@standardnotes/analytics@2.34.5) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
|
||||
## [2.34.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.3...@standardnotes/analytics@2.34.4) (2023-12-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "2.34.4",
|
||||
"version": "2.34.6",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -84,6 +84,7 @@ export class ContainerConfigLoader {
|
||||
level: env.get('LOG_LEVEL', true) || 'info',
|
||||
format: winston.format.combine(...winstonFormatters),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||
defaultMeta: { service: 'analytics' },
|
||||
})
|
||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
||||
|
||||
|
||||
@@ -3,6 +3,29 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.88.4](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.88.3...@standardnotes/api-gateway@1.88.4) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.88.3](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.88.2...@standardnotes/api-gateway@1.88.3) (2023-12-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** add extra meta to logs ([a341e78](https://github.com/standardnotes/server/commit/a341e789093556f09c2a337e39a8053abdcf587b))
|
||||
|
||||
## [1.88.2](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.88.1...@standardnotes/api-gateway@1.88.2) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** add userId to logs in error handler if possible ([0058368](https://github.com/standardnotes/server/commit/005836868126ae5fa4c4468644704938aea0f4ec))
|
||||
|
||||
## [1.88.1](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.88.0...@standardnotes/api-gateway@1.88.1) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** response header on grpc websocket connection validation ([3637db2](https://github.com/standardnotes/server/commit/3637db2563255aaddd44700c039495c6b9a9e4aa))
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
|
||||
# [1.88.0](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.87.7...@standardnotes/api-gateway@1.88.0) (2023-12-07)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -96,6 +96,7 @@ void container.load().then((container) => {
|
||||
url: request.url,
|
||||
snjs: request.headers['x-snjs-version'],
|
||||
application: request.headers['x-application-version'],
|
||||
userId: response.locals.user ? response.locals.user.uuid : undefined,
|
||||
})
|
||||
logger.debug(
|
||||
`[URL: |${request.method}| ${request.url}][SNJS: ${request.headers['x-snjs-version']}][Application: ${
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.88.0",
|
||||
"version": "1.88.4",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -81,7 +81,7 @@ export class GRPCWebSocketAuthMiddleware extends BaseMiddleware {
|
||||
}
|
||||
|
||||
if (authResponse.status > 200) {
|
||||
response.setHeader('content-type', authResponse.headers['content-type'] as string)
|
||||
response.setHeader('content-type', 'application/json')
|
||||
response.status(authResponse.status).send(authResponse.data)
|
||||
|
||||
return
|
||||
|
||||
@@ -240,6 +240,9 @@ export class HttpServiceProxy implements ServiceProxyInterface {
|
||||
tooManyRetryAttempts
|
||||
? `Request to ${serverUrl}/${endpoint} timed out after ${retryAttempt} retries`
|
||||
: `Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
||||
{
|
||||
userId: response.locals.user ? response.locals.user.uuid : undefined,
|
||||
},
|
||||
)
|
||||
|
||||
this.logger.debug(`Response error: ${JSON.stringify(error)}`)
|
||||
|
||||
@@ -275,6 +275,9 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
|
||||
tooManyRetryAttempts
|
||||
? `Request to ${serverUrl}/${endpoint} timed out after ${retryAttempt} retries`
|
||||
: `Could not pass the request to ${serverUrl}/${endpoint} on underlying service: ${detailedErrorMessage}`,
|
||||
{
|
||||
userId: response.locals.user ? response.locals.user.uuid : undefined,
|
||||
},
|
||||
)
|
||||
|
||||
this.logger.debug(`Response error: ${JSON.stringify(error)}`)
|
||||
|
||||
@@ -43,11 +43,10 @@ export class GRPCSyncingServerServiceProxy {
|
||||
}
|
||||
|
||||
if (error.code === Status.INTERNAL) {
|
||||
this.logger.error(
|
||||
`[GRPCSyncingServerServiceProxy][${response.locals.user.uuid}] Internal gRPC error: ${
|
||||
error.message
|
||||
}. Payload: ${JSON.stringify(payload)}`,
|
||||
)
|
||||
this.logger.error(`Internal gRPC error: ${error.message}. Payload: ${JSON.stringify(payload)}`, {
|
||||
codeTag: 'GRPCSyncingServerServiceProxy',
|
||||
userId: response.locals.user.uuid,
|
||||
})
|
||||
}
|
||||
|
||||
return reject(error)
|
||||
@@ -60,11 +59,10 @@ export class GRPCSyncingServerServiceProxy {
|
||||
'code' in (error as Record<string, unknown>) &&
|
||||
(error as Record<string, unknown>).code === Status.INTERNAL
|
||||
) {
|
||||
this.logger.error(
|
||||
`[GRPCSyncingServerServiceProxy][${response.locals.user.uuid}] Internal gRPC error: ${JSON.stringify(
|
||||
error,
|
||||
)}. Payload: ${JSON.stringify(payload)}`,
|
||||
)
|
||||
this.logger.error(`Internal gRPC error: ${JSON.stringify(error)}. Payload: ${JSON.stringify(payload)}`, {
|
||||
codeTag: 'GRPCSyncingServerServiceProxy.catch',
|
||||
userId: response.locals.user.uuid,
|
||||
})
|
||||
}
|
||||
|
||||
reject(error)
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.176.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.176.3...@standardnotes/auth-server@1.176.4) (2023-12-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** generate new recovery codes when enabling mfa ([#964](https://github.com/standardnotes/server/issues/964)) ([031fa71](https://github.com/standardnotes/server/commit/031fa71e7d86221ec7fb0f4b21c62454646564e2))
|
||||
|
||||
## [1.176.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.176.2...@standardnotes/auth-server@1.176.3) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.176.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.176.1...@standardnotes/auth-server@1.176.2) (2023-12-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** error log meta on triggering email backups ([4ab61b9](https://github.com/standardnotes/server/commit/4ab61b94a4aee361399a76c9f2b6b977c4832b06))
|
||||
|
||||
## [1.176.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.176.0...@standardnotes/auth-server@1.176.1) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** logger meta on disabling settings ([3f2d8c9](https://github.com/standardnotes/server/commit/3f2d8c902c5331e07959f0b7b42684ef47346220))
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
* logs meta ([8ac84c5](https://github.com/standardnotes/server/commit/8ac84c59af886bb9c42de012fb1e7864e116ab55))
|
||||
|
||||
# [1.176.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.175.1...@standardnotes/auth-server@1.176.0) (2023-12-07)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.176.0",
|
||||
"version": "1.176.4",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -310,7 +310,7 @@ export class ContainerConfigLoader {
|
||||
level: env.get('LOG_LEVEL', true) || 'info',
|
||||
format: winston.format.combine(...winstonFormatters),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||
defaultMeta: { service: 'auth' },
|
||||
defaultMeta: { service: `auth:${this.mode}` },
|
||||
})
|
||||
}
|
||||
container.bind<winston.Logger>(TYPES.Auth_Logger).toConstantValue(logger)
|
||||
@@ -1269,6 +1269,7 @@ export class ContainerConfigLoader {
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
|
||||
container.get<TriggerEmailBackupForUser>(TYPES.Auth_TriggerEmailBackupForUser),
|
||||
container.get<GenerateRecoveryCodes>(TYPES.Auth_GenerateRecoveryCodes),
|
||||
),
|
||||
)
|
||||
container
|
||||
|
||||
@@ -19,7 +19,7 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
async handle(event: AccountDeletionRequestedEvent): Promise<void> {
|
||||
const userUuidOrError = Uuid.create(event.payload.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
this.logger.warn(`Could not find user with uuid: ${event.payload.userUuid}`)
|
||||
this.logger.warn('Could not find user.', { userId: event.payload.userUuid })
|
||||
|
||||
return
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
const user = await this.userRepository.findOneByUuid(userUuid)
|
||||
|
||||
if (user === null) {
|
||||
this.logger.warn(`Could not find user with uuid: ${userUuid.value}`)
|
||||
this.logger.warn('Could not find user.', { userId: userUuid.value })
|
||||
|
||||
return
|
||||
}
|
||||
@@ -37,7 +37,9 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
|
||||
await this.userRepository.remove(user)
|
||||
|
||||
this.logger.info(`Finished account cleanup for user: ${userUuid.value}`)
|
||||
this.logger.info('Finished account cleanup.', {
|
||||
userId: userUuid.value,
|
||||
})
|
||||
}
|
||||
|
||||
private async removeSessions(userUuid: string): Promise<void> {
|
||||
|
||||
@@ -15,7 +15,9 @@ export class EmailSubscriptionUnsubscribedEventHandler implements DomainEventHan
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to disable email setting for user ${event.payload.userEmail}: ${result.getError()}`)
|
||||
this.logger.error(`Failed to disable email setting for user: ${result.getError()}`, {
|
||||
userId: event.payload.userEmail,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ export class TriggerEmailBackupForAllUsers implements UseCaseInterface<void> {
|
||||
})
|
||||
/* istanbul ignore next */
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to trigger email backup for user ${setting.props.userUuid.value}`)
|
||||
this.logger.error(`Failed to trigger email backup for user: ${result.getError()}`, {
|
||||
userId: setting.props.userUuid.value,
|
||||
})
|
||||
failedUsers++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import { EmailBackupFrequency, LogSessionUserAgentOption, MuteMarketingEmailsOption } from '@standardnotes/settings'
|
||||
import { SettingName, Result } from '@standardnotes/domain-core'
|
||||
|
||||
import { GenerateRecoveryCodes } from '../GenerateRecoveryCodes/GenerateRecoveryCodes'
|
||||
import { TriggerPostSettingUpdateActions } from './TriggerPostSettingUpdateActions'
|
||||
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||
import { TriggerEmailBackupForUser } from '../TriggerEmailBackupForUser/TriggerEmailBackupForUser'
|
||||
@@ -15,11 +16,20 @@ describe('TriggerPostSettingUpdateActions', () => {
|
||||
let domainEventPublisher: DomainEventPublisherInterface
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
let triggerEmailBackupForUser: TriggerEmailBackupForUser
|
||||
let generateRecoveryCodes: GenerateRecoveryCodes
|
||||
|
||||
const createUseCase = () =>
|
||||
new TriggerPostSettingUpdateActions(domainEventPublisher, domainEventFactory, triggerEmailBackupForUser)
|
||||
new TriggerPostSettingUpdateActions(
|
||||
domainEventPublisher,
|
||||
domainEventFactory,
|
||||
triggerEmailBackupForUser,
|
||||
generateRecoveryCodes,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
generateRecoveryCodes = {} as jest.Mocked<GenerateRecoveryCodes>
|
||||
generateRecoveryCodes.execute = jest.fn().mockReturnValue(Result.ok())
|
||||
|
||||
triggerEmailBackupForUser = {} as jest.Mocked<TriggerEmailBackupForUser>
|
||||
triggerEmailBackupForUser.execute = jest.fn().mockReturnValue(Result.ok())
|
||||
|
||||
@@ -101,4 +111,15 @@ describe('TriggerPostSettingUpdateActions', () => {
|
||||
username: 'test@test.te',
|
||||
})
|
||||
})
|
||||
|
||||
it('should generate new recovery codes upon enabling mfa setting', async () => {
|
||||
await createUseCase().execute({
|
||||
updatedSettingName: SettingName.NAMES.MfaSecret,
|
||||
userUuid: '4-5-6',
|
||||
userEmail: 'test@test.te',
|
||||
unencryptedValue: '123',
|
||||
})
|
||||
|
||||
expect(generateRecoveryCodes.execute).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,6 +5,7 @@ import { EmailBackupFrequency, LogSessionUserAgentOption } from '@standardnotes/
|
||||
import { TriggerPostSettingUpdateActionsDTO } from './TriggerPostSettingUpdateActionsDTO'
|
||||
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||
import { TriggerEmailBackupForUser } from '../TriggerEmailBackupForUser/TriggerEmailBackupForUser'
|
||||
import { GenerateRecoveryCodes } from '../GenerateRecoveryCodes/GenerateRecoveryCodes'
|
||||
|
||||
export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
|
||||
private readonly emailSettingToSubscriptionRejectionLevelMap: Map<string, string> = new Map([
|
||||
@@ -18,6 +19,7 @@ export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private triggerEmailBackupForUser: TriggerEmailBackupForUser,
|
||||
private generateRecoveryCodes: GenerateRecoveryCodes,
|
||||
) {}
|
||||
|
||||
async execute(dto: TriggerPostSettingUpdateActionsDTO): Promise<Result<void>> {
|
||||
@@ -35,6 +37,12 @@ export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
|
||||
await this.triggerSessionUserAgentCleanup(dto.userEmail, dto.userUuid)
|
||||
}
|
||||
|
||||
if (this.isEnablingMFASetting(dto.updatedSettingName, dto.unencryptedValue)) {
|
||||
await this.generateRecoveryCodes.execute({
|
||||
userUuid: dto.userUuid,
|
||||
})
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
@@ -54,6 +62,10 @@ export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
|
||||
)
|
||||
}
|
||||
|
||||
private isEnablingMFASetting(settingName: string, newValue: string | null): boolean {
|
||||
return settingName === SettingName.NAMES.MfaSecret && newValue !== null
|
||||
}
|
||||
|
||||
private isDisablingSessionUserAgentLogging(settingName: string, newValue: string | null): boolean {
|
||||
return SettingName.NAMES.LogSessionUserAgent === settingName && LogSessionUserAgentOption.Disabled === newValue
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export class WebSocketsClientService implements ClientServiceInterface {
|
||||
(await user.roles).map((role) => role.name),
|
||||
)
|
||||
|
||||
this.logger.info(`[WebSockets] Requesting message ${event.type} to user ${user.uuid}`)
|
||||
this.logger.debug(`[WebSockets] Requesting message ${event.type} to user ${user.uuid}`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createWebSocketMessageRequestedEvent({
|
||||
|
||||
@@ -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.22.5](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.22.4...@standardnotes/domain-events-infra@1.22.5) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.22.4](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.22.3...@standardnotes/domain-events-infra@1.22.4) (2023-12-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.22.4",
|
||||
"version": "1.22.5",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.138.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.138.1...@standardnotes/domain-events@2.138.2) (2023-12-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** add user uuid for the emails requesting backup ([7b0ea0a](https://github.com/standardnotes/server/commit/7b0ea0a06975902e01951b13c84e941827dedd84))
|
||||
|
||||
## [2.138.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.138.0...@standardnotes/domain-events@2.138.1) (2023-11-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.138.1",
|
||||
"version": "2.138.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -12,4 +12,5 @@ export interface EmailRequestedEventPayload {
|
||||
attachmentFileName: string
|
||||
attachmentContentType: string
|
||||
}>
|
||||
userUuid?: string
|
||||
}
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.36.6](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.36.5...@standardnotes/files-server@1.36.6) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.36.5](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.36.4...@standardnotes/files-server@1.36.5) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
|
||||
## [1.36.4](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.36.3...@standardnotes/files-server@1.36.4) (2023-12-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -19,7 +19,7 @@ import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
const container = new ContainerConfigLoader('server')
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
@@ -9,7 +9,7 @@ import { DomainEventSubscriberInterface } from '@standardnotes/domain-events'
|
||||
import * as dayjs from 'dayjs'
|
||||
import * as utc from 'dayjs/plugin/utc'
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
dayjs.extend(utc)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.36.4",
|
||||
"version": "1.36.6",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -54,6 +54,8 @@ import { MoveFile } from '../Domain/UseCase/MoveFile/MoveFile'
|
||||
import { SharedVaultValetTokenAuthMiddleware } from '../Infra/InversifyExpress/Middleware/SharedVaultValetTokenAuthMiddleware'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
constructor(private mode: 'server' | 'worker' = 'server') {}
|
||||
|
||||
async load(configuration?: {
|
||||
directCallDomainEventPublisher?: DirectCallDomainEventPublisher
|
||||
logger?: Transform
|
||||
@@ -316,7 +318,7 @@ export class ContainerConfigLoader {
|
||||
level: env.get('LOG_LEVEL', true) || 'info',
|
||||
format: winston.format.combine(winston.format.splat(), winston.format.json()),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||
defaultMeta: { service: 'files' },
|
||||
defaultMeta: { service: `files:${this.mode}` },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,34 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.22.19](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.18...@standardnotes/home-server@1.22.19) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.22.18](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.17...@standardnotes/home-server@1.22.18) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.22.17](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.16...@standardnotes/home-server@1.22.17) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.22.16](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.15...@standardnotes/home-server@1.22.16) (2023-12-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.22.15](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.14...@standardnotes/home-server@1.22.15) (2023-12-08)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.22.14](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.13...@standardnotes/home-server@1.22.14) (2023-12-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.22.13](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.12...@standardnotes/home-server@1.22.13) (2023-12-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.22.12](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.11...@standardnotes/home-server@1.22.12) (2023-12-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/home-server",
|
||||
"version": "1.22.12",
|
||||
"version": "1.22.19",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.51.6](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.5...@standardnotes/revisions-server@1.51.6) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||
|
||||
## [1.51.5](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.4...@standardnotes/revisions-server@1.51.5) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
* logs meta ([8ac84c5](https://github.com/standardnotes/server/commit/8ac84c59af886bb9c42de012fb1e7864e116ab55))
|
||||
|
||||
## [1.51.4](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.3...@standardnotes/revisions-server@1.51.4) (2023-12-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/revisions-server",
|
||||
"version": "1.51.4",
|
||||
"version": "1.51.6",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -90,7 +90,7 @@ export class ContainerConfigLoader {
|
||||
level: env.get('LOG_LEVEL', true) || 'info',
|
||||
format: winston.format.combine(...winstonFormatters),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||
defaultMeta: { service: 'revisions' },
|
||||
defaultMeta: { service: `revisions:${this.mode}` },
|
||||
})
|
||||
}
|
||||
container.bind<winston.Logger>(TYPES.Revisions_Logger).toConstantValue(logger)
|
||||
|
||||
@@ -12,7 +12,7 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
async handle(event: AccountDeletionRequestedEvent): Promise<void> {
|
||||
const userUuidOrError = Uuid.create(event.payload.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
this.logger.warn(`Failed account cleanup: ${userUuidOrError.getError()}`)
|
||||
this.logger.warn(`Failed account cleanup: ${userUuidOrError.getError()}`, { userId: event.payload.userUuid })
|
||||
|
||||
return
|
||||
}
|
||||
@@ -20,6 +20,6 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
|
||||
await this.revisionRepository.removeByUserUuid(userUuid)
|
||||
|
||||
this.logger.info(`Finished account cleanup for user: ${event.payload.userUuid}`)
|
||||
this.logger.info('Finished account cleanup.', { userId: event.payload.userUuid })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.27.11](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.10...@standardnotes/scheduler-server@1.27.11) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.27.10](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.9...@standardnotes/scheduler-server@1.27.10) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
|
||||
## [1.27.9](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.8...@standardnotes/scheduler-server@1.27.9) (2023-12-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.27.9",
|
||||
"version": "1.27.11",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -62,6 +62,7 @@ export class ContainerConfigLoader {
|
||||
level: env.get('LOG_LEVEL', true) || 'info',
|
||||
format: winston.format.combine(...winstonFormatters),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||
defaultMeta: { service: 'scheduler' },
|
||||
})
|
||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
||||
|
||||
|
||||
@@ -3,6 +3,31 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.128.2](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.128.1...@standardnotes/syncing-server@1.128.2) (2023-12-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** add user uuid for the emails requesting backup ([7b0ea0a](https://github.com/standardnotes/server/commit/7b0ea0a06975902e01951b13c84e941827dedd84))
|
||||
|
||||
## [1.128.1](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.128.0...@standardnotes/syncing-server@1.128.1) (2023-12-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** logs meta for email with backup requested ([597ff13](https://github.com/standardnotes/server/commit/597ff13393965a6d6f3a35e12d41d648543d35b7))
|
||||
|
||||
# [1.128.0](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.127.9...@standardnotes/syncing-server@1.128.0) (2023-12-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **syncing-server:** send websocket event to shared vault members upon items change in shared vault ([#961](https://github.com/standardnotes/server/issues/961)) ([6dbb877](https://github.com/standardnotes/server/commit/6dbb87708faf6c6f4ec28b45570390b6c816a7a2))
|
||||
|
||||
## [1.127.9](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.127.8...@standardnotes/syncing-server@1.127.9) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
* logs meta ([8ac84c5](https://github.com/standardnotes/server/commit/8ac84c59af886bb9c42de012fb1e7864e116ab55))
|
||||
|
||||
## [1.127.8](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.127.7...@standardnotes/syncing-server@1.127.8) (2023-12-07)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.127.8",
|
||||
"version": "1.128.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -161,6 +161,7 @@ import { SyncResponse20200115 } from '../Domain/Item/SyncResponse/SyncResponse20
|
||||
import { SyncResponse } from '@standardnotes/grpc'
|
||||
import { SyncResponseGRPCMapper } from '../Mapping/gRPC/SyncResponseGRPCMapper'
|
||||
import { AccountDeletionVerificationRequestedEventHandler } from '../Domain/Handler/AccountDeletionVerificationRequestedEventHandler'
|
||||
import { SendEventToClients } from '../Domain/UseCase/Syncing/SendEventToClients/SendEventToClients'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
|
||||
@@ -195,7 +196,7 @@ export class ContainerConfigLoader {
|
||||
level: env.get('LOG_LEVEL', true) || 'info',
|
||||
format: winston.format.combine(...winstonFormatters),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||
defaultMeta: { service: 'syncing-server' },
|
||||
defaultMeta: { service: `syncing-server:${this.mode}` },
|
||||
})
|
||||
}
|
||||
container.bind<winston.Logger>(TYPES.Sync_Logger).toConstantValue(logger)
|
||||
@@ -561,6 +562,15 @@ export class ContainerConfigLoader {
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<SendEventToClients>(TYPES.Sync_SendEventToClients)
|
||||
.toConstantValue(
|
||||
new SendEventToClients(
|
||||
container.get<SharedVaultUserRepositoryInterface>(TYPES.Sync_SharedVaultUserRepository),
|
||||
container.get<SendEventToClient>(TYPES.Sync_SendEventToClient),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<AddNotificationForUser>(TYPES.Sync_AddNotificationForUser)
|
||||
.toConstantValue(
|
||||
@@ -607,6 +617,7 @@ export class ContainerConfigLoader {
|
||||
container.get<SaveNewItem>(TYPES.Sync_SaveNewItem),
|
||||
container.get<UpdateExistingItem>(TYPES.Sync_UpdateExistingItem),
|
||||
container.get<SendEventToClient>(TYPES.Sync_SendEventToClient),
|
||||
container.get<SendEventToClients>(TYPES.Sync_SendEventToClients),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
|
||||
@@ -77,6 +77,7 @@ const TYPES = {
|
||||
Sync_UpdateStorageQuotaUsedInSharedVault: Symbol.for('Sync_UpdateStorageQuotaUsedInSharedVault'),
|
||||
Sync_AddNotificationsForUsers: Symbol.for('Sync_AddNotificationsForUsers'),
|
||||
Sync_SendEventToClient: Symbol.for('Sync_SendEventToClient'),
|
||||
Sync_SendEventToClients: Symbol.for('Sync_SendEventToClients'),
|
||||
Sync_RemoveItemsFromSharedVault: Symbol.for('Sync_RemoveItemsFromSharedVault'),
|
||||
Sync_DesignateSurvivor: Symbol.for('Sync_DesignateSurvivor'),
|
||||
Sync_RemoveUserFromSharedVaults: Symbol.for('Sync_RemoveUserFromSharedVaults'),
|
||||
|
||||
@@ -329,6 +329,7 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
attachmentFileName: string
|
||||
attachmentContentType: string
|
||||
}>
|
||||
userUuid?: string
|
||||
}): EmailRequestedEvent {
|
||||
return {
|
||||
type: 'EMAIL_REQUESTED',
|
||||
|
||||
@@ -74,6 +74,7 @@ export interface DomainEventFactoryInterface {
|
||||
attachmentFileName: string
|
||||
attachmentContentType: string
|
||||
}>
|
||||
userUuid?: string
|
||||
}): EmailRequestedEvent
|
||||
createDuplicateItemSyncedEvent(dto: { itemUuid: string; userUuid: string }): DuplicateItemSyncedEvent
|
||||
createItemRevisionCreationRequested(dto: { itemUuid: string; userUuid: string }): ItemRevisionCreationRequestedEvent
|
||||
|
||||
@@ -17,7 +17,10 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
async handle(event: AccountDeletionRequestedEvent): Promise<void> {
|
||||
const userUuidOrError = Uuid.create(event.payload.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
this.logger.error(`AccountDeletionRequestedEventHandler failed: ${userUuidOrError.getError()}`)
|
||||
this.logger.error(userUuidOrError.getError(), {
|
||||
userId: event.payload.userUuid,
|
||||
codeTag: 'AccountDeletionRequestedEventHandler',
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
@@ -30,9 +33,9 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
allowSurviving: true,
|
||||
})
|
||||
if (deletingVaultsResult.isFailed()) {
|
||||
this.logger.error(
|
||||
`Failed to delete shared vaults for user: ${event.payload.userUuid}: ${deletingVaultsResult.getError()}`,
|
||||
)
|
||||
this.logger.error(`Failed to delete shared vaults: ${deletingVaultsResult.getError()}`, {
|
||||
userId: event.payload.userUuid,
|
||||
})
|
||||
}
|
||||
|
||||
const deletedSharedVaultUuids = Array.from(deletingVaultsResult.getValue().keys())
|
||||
@@ -49,13 +52,13 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
userUuid: event.payload.userUuid,
|
||||
})
|
||||
if (deletingUserFromOtherVaultsResult.isFailed()) {
|
||||
this.logger.error(
|
||||
`Failed to remove user: ${
|
||||
event.payload.userUuid
|
||||
} from shared vaults: ${deletingUserFromOtherVaultsResult.getError()}`,
|
||||
)
|
||||
this.logger.error(`Failed to remove user from shared vaults: ${deletingUserFromOtherVaultsResult.getError()}`, {
|
||||
userId: event.payload.userUuid,
|
||||
})
|
||||
}
|
||||
|
||||
this.logger.info(`Finished account cleanup for user: ${event.payload.userUuid}`)
|
||||
this.logger.info('Finished account cleanup', {
|
||||
userId: event.payload.userUuid,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,10 +81,13 @@ export class EmailBackupRequestedEventHandler implements DomainEventHandlerInter
|
||||
attachmentContentType: 'application/json',
|
||||
},
|
||||
],
|
||||
userUuid: event.payload.userUuid,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
this.logger.info(`Email with backup requested for user ${event.payload.userUuid}`)
|
||||
this.logger.info('Email with backup requested for user', {
|
||||
userId: event.payload.userUuid,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import { Item } from '../../../Item/Item'
|
||||
import { SendEventToClient } from '../SendEventToClient/SendEventToClient'
|
||||
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
|
||||
import { ItemsChangedOnServerEvent } from '@standardnotes/domain-events'
|
||||
import { SendEventToClients } from '../SendEventToClients/SendEventToClients'
|
||||
import { SharedVaultAssociation } from '../../../SharedVault/SharedVaultAssociation'
|
||||
|
||||
describe('SaveItems', () => {
|
||||
let itemSaveValidator: ItemSaveValidatorInterface
|
||||
@@ -22,6 +24,7 @@ describe('SaveItems', () => {
|
||||
let itemHash1: ItemHash
|
||||
let savedItem: Item
|
||||
let sendEventToClient: SendEventToClient
|
||||
let sendEventToClients: SendEventToClients
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
|
||||
const createUseCase = () =>
|
||||
@@ -32,6 +35,7 @@ describe('SaveItems', () => {
|
||||
saveNewItem,
|
||||
updateExistingItem,
|
||||
sendEventToClient,
|
||||
sendEventToClients,
|
||||
domainEventFactory,
|
||||
logger,
|
||||
)
|
||||
@@ -40,6 +44,9 @@ describe('SaveItems', () => {
|
||||
sendEventToClient = {} as jest.Mocked<SendEventToClient>
|
||||
sendEventToClient.execute = jest.fn().mockReturnValue(Result.ok())
|
||||
|
||||
sendEventToClients = {} as jest.Mocked<SendEventToClients>
|
||||
sendEventToClients.execute = jest.fn().mockReturnValue(Result.ok())
|
||||
|
||||
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
||||
domainEventFactory.createItemsChangedOnServerEvent = jest
|
||||
.fn()
|
||||
@@ -243,6 +250,51 @@ describe('SaveItems', () => {
|
||||
performingUserUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
expect(sendEventToClient.execute).toHaveBeenCalled()
|
||||
expect(sendEventToClients.execute).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should update existing shared vault items', async () => {
|
||||
savedItem = 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,
|
||||
sharedVaultAssociation: SharedVaultAssociation.create({
|
||||
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
}).getValue(),
|
||||
dates: Dates.create(new Date(123), new Date(123)).getValue(),
|
||||
timestamps: Timestamps.create(123, 123).getValue(),
|
||||
}).getValue()
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
itemRepository.findByUuid = jest.fn().mockResolvedValue(savedItem)
|
||||
updateExistingItem.execute = jest.fn().mockResolvedValue(Result.ok(savedItem))
|
||||
|
||||
const result = await useCase.execute({
|
||||
itemHashes: [itemHash1],
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
apiVersion: '1',
|
||||
readOnlyAccess: false,
|
||||
sessionUuid: 'session-uuid',
|
||||
snjsVersion: '2.200.0',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(updateExistingItem.execute).toHaveBeenCalledWith({
|
||||
itemHash: itemHash1,
|
||||
existingItem: savedItem,
|
||||
sessionUuid: 'session-uuid',
|
||||
performingUserUuid: '00000000-0000-0000-0000-000000000000',
|
||||
})
|
||||
expect(sendEventToClient.execute).toHaveBeenCalled()
|
||||
expect(sendEventToClients.execute).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should mark items as conflicts if updating existing item fails', async () => {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { UpdateExistingItem } from '../UpdateExistingItem/UpdateExistingItem'
|
||||
import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
|
||||
import { SendEventToClient } from '../SendEventToClient/SendEventToClient'
|
||||
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
|
||||
import { SendEventToClients } from '../SendEventToClients/SendEventToClients'
|
||||
|
||||
export class SaveItems implements UseCaseInterface<SaveItemsResult> {
|
||||
private readonly SYNC_TOKEN_VERSION = 2
|
||||
@@ -24,6 +25,7 @@ export class SaveItems implements UseCaseInterface<SaveItemsResult> {
|
||||
private saveNewItem: SaveNewItem,
|
||||
private updateExistingItem: UpdateExistingItem,
|
||||
private sendEventToClient: SendEventToClient,
|
||||
private sendEventToClients: SendEventToClients,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
@@ -167,7 +169,31 @@ export class SaveItems implements UseCaseInterface<SaveItemsResult> {
|
||||
})
|
||||
/* istanbul ignore next */
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`[${dto.userUuid}] Sending items changed event to client failed. Error: ${result.getError()}`)
|
||||
this.logger.error(`Sending items changed event to client failed. Error: ${result.getError()}`, {
|
||||
userId: dto.userUuid,
|
||||
})
|
||||
}
|
||||
|
||||
const sharedVaultUuidsMap = new Map<string, boolean>()
|
||||
for (const item of savedItems) {
|
||||
if (item.isAssociatedWithASharedVault()) {
|
||||
sharedVaultUuidsMap.set((item.sharedVaultUuid as Uuid).value, true)
|
||||
}
|
||||
}
|
||||
const sharedVaultUuids = Array.from(sharedVaultUuidsMap.keys())
|
||||
for (const sharedVaultUuid of sharedVaultUuids) {
|
||||
const result = await this.sendEventToClients.execute({
|
||||
sharedVaultUuid,
|
||||
event: itemsChangedEvent,
|
||||
originatingUserUuid: dto.userUuid,
|
||||
})
|
||||
/* istanbul ignore next */
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Sending items changed event to clients failed. Error: ${result.getError()}`, {
|
||||
userId: dto.userUuid,
|
||||
sharedVaultUuid,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import { Logger } from 'winston'
|
||||
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||
import { SendEventToClient } from '../SendEventToClient/SendEventToClient'
|
||||
import { SendEventToClients } from './SendEventToClients'
|
||||
import { Result, SharedVaultUser, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||
import { DomainEventInterface } from '@standardnotes/domain-events'
|
||||
|
||||
describe('SendEventToClients', () => {
|
||||
let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
|
||||
let sendEventToClient: SendEventToClient
|
||||
let logger: Logger
|
||||
|
||||
const createUseCase = () => new SendEventToClients(sharedVaultUserRepository, sendEventToClient, logger)
|
||||
|
||||
beforeEach(() => {
|
||||
const sharedVaultUser = SharedVaultUser.create({
|
||||
permission: SharedVaultUserPermission.create('read').getValue(),
|
||||
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
timestamps: Timestamps.create(123456789, 123456789).getValue(),
|
||||
userUuid: Uuid.create('00000000-0000-0000-0000-000000000001').getValue(),
|
||||
isDesignatedSurvivor: false,
|
||||
}).getValue()
|
||||
|
||||
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
|
||||
sharedVaultUserRepository.findBySharedVaultUuid = jest.fn().mockReturnValue([sharedVaultUser])
|
||||
|
||||
sendEventToClient = {} as jest.Mocked<SendEventToClient>
|
||||
sendEventToClient.execute = jest.fn().mockReturnValue(Result.ok())
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.error = jest.fn()
|
||||
})
|
||||
|
||||
it('should send event to all users', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
event: {
|
||||
type: 'test',
|
||||
} as jest.Mocked<DomainEventInterface>,
|
||||
originatingUserUuid: '00000000-0000-0000-0000-000000000003',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(sendEventToClient.execute).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should send event to all users except the originating one', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
event: {
|
||||
type: 'test',
|
||||
} as jest.Mocked<DomainEventInterface>,
|
||||
originatingUserUuid: '00000000-0000-0000-0000-000000000001',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(sendEventToClient.execute).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('should return error if shared vault uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
sharedVaultUuid: 'invalid',
|
||||
event: {
|
||||
type: 'test',
|
||||
} as jest.Mocked<DomainEventInterface>,
|
||||
originatingUserUuid: '00000000-0000-0000-0000-000000000001',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should return error if originating user uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
event: {
|
||||
type: 'test',
|
||||
} as jest.Mocked<DomainEventInterface>,
|
||||
originatingUserUuid: 'invalid',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should log error if sending event to client failed', async () => {
|
||||
sendEventToClient.execute = jest.fn().mockReturnValue(Result.fail('test error'))
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000000',
|
||||
event: {
|
||||
type: 'test',
|
||||
} as jest.Mocked<DomainEventInterface>,
|
||||
originatingUserUuid: '00000000-0000-0000-0000-000000000003',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(logger.error).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { SendEventToClientsDTO } from './SendEventToClientsDTO'
|
||||
import { SendEventToClient } from '../SendEventToClient/SendEventToClient'
|
||||
import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
|
||||
|
||||
export class SendEventToClients implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
|
||||
private sendEventToClient: SendEventToClient,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async execute(dto: SendEventToClientsDTO): Promise<Result<void>> {
|
||||
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultUuidOrError.getError())
|
||||
}
|
||||
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||
|
||||
const originatingUserUuidOrError = Uuid.create(dto.originatingUserUuid)
|
||||
if (originatingUserUuidOrError.isFailed()) {
|
||||
return Result.fail(originatingUserUuidOrError.getError())
|
||||
}
|
||||
const originatingUserUuid = originatingUserUuidOrError.getValue()
|
||||
|
||||
const sharedVaultUsers = await this.sharedVaultUserRepository.findBySharedVaultUuid(sharedVaultUuid)
|
||||
|
||||
for (const sharedVaultUser of sharedVaultUsers) {
|
||||
if (originatingUserUuid.equals(sharedVaultUser.props.userUuid)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const result = await this.sendEventToClient.execute({
|
||||
event: dto.event,
|
||||
userUuid: sharedVaultUser.props.userUuid.value,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to send event to client: ${result.getError()}`, {
|
||||
userId: sharedVaultUser.props.userUuid.value,
|
||||
sharedVaultUuid: sharedVaultUuid.value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { DomainEventInterface } from '@standardnotes/domain-events'
|
||||
|
||||
export interface SendEventToClientsDTO {
|
||||
sharedVaultUuid: string
|
||||
event: DomainEventInterface
|
||||
originatingUserUuid: string
|
||||
}
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.22.2](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.22.1...@standardnotes/websockets-server@1.22.2) (2023-12-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
## [1.22.1](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.22.0...@standardnotes/websockets-server@1.22.1) (2023-12-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* logger meta information ([a2b1323](https://github.com/standardnotes/server/commit/a2b1323568f5ced74b41aa4634340a6ca0668683))
|
||||
|
||||
# [1.22.0](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.21.4...@standardnotes/websockets-server@1.22.0) (2023-12-07)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/websockets-server",
|
||||
"version": "1.22.0",
|
||||
"version": "1.22.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -49,6 +49,7 @@ export class ContainerConfigLoader {
|
||||
level: env.get('LOG_LEVEL', true) || 'info',
|
||||
format: winston.format.combine(...winstonFormatters),
|
||||
transports: [new winston.transports.Console({ level: env.get('LOG_LEVEL', true) || 'info' })],
|
||||
defaultMeta: { service: `websockets:${this.mode}` },
|
||||
})
|
||||
container.bind<winston.Logger>(TYPES.Logger).toConstantValue(logger)
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ export class WebSocketMessageRequestedEventHandler implements DomainEventHandler
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Could not send message to user ${event.payload.userUuid}. Error: ${result.getError()}`)
|
||||
this.logger.error(`Could not send message to user. Error: ${result.getError()}`, {
|
||||
userId: event.payload.userUuid,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,10 @@ export class AddWebSocketsConnection implements UseCaseInterface<void> {
|
||||
|
||||
return Result.ok()
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Error persisting connection ${dto.connectionId} for user ${dto.userUuid}: ${(error as Error).message}`,
|
||||
)
|
||||
this.logger.error(`Error persisting connection for user: ${(error as Error).message}`, {
|
||||
userId: dto.userUuid,
|
||||
connectionId: dto.connectionId,
|
||||
})
|
||||
|
||||
return Result.fail((error as Error).message)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ export class RemoveWebSocketsConnection implements UseCaseInterface<void> {
|
||||
|
||||
return Result.ok()
|
||||
} catch (error) {
|
||||
this.logger.error(`Error removing connection ${dto.connectionId}: ${(error as Error).message}`)
|
||||
this.logger.error(`Error removing connection: ${(error as Error).message}`, {
|
||||
connectionId: dto.connectionId,
|
||||
})
|
||||
|
||||
return Result.fail((error as Error).message)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user