Compare commits

...

8 Commits

Author SHA1 Message Date
standardci
2e82be47ed chore(release): publish new version
- @standardnotes/analytics@2.10.2
2022-11-14 13:01:32 +00:00
Karol Sójko
15dfd6dcba fix(analytics): imports from domain-core 2022-11-14 13:59:06 +01:00
standardci
dfd38943b0 chore(release): publish new version
- @standardnotes/syncing-server@1.13.11
2022-11-14 12:51:16 +00:00
Karol Sójko
500756d582 fix(syncing-server): decrease logs severity for content recalculation 2022-11-14 13:49:28 +01:00
standardci
f855f541d8 chore(release): publish new version
- @standardnotes/auth-server@1.60.0
2022-11-14 12:48:49 +00:00
Karol Sójko
590ec6643d feat(auth): add content size recalculation procedure trigger 2022-11-14 13:46:40 +01:00
standardci
b9efd35b50 chore(release): publish new version
- @standardnotes/syncing-server@1.13.10
2022-11-14 12:32:48 +00:00
Karol Sójko
3be1bfe58a fix(syncing-server): linter issues 2022-11-14 13:30:41 +01:00
14 changed files with 140 additions and 415 deletions

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.10.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.10.1...@standardnotes/analytics@2.10.2) (2022-11-14)
### Bug Fixes
* **analytics:** imports from domain-core ([15dfd6d](https://github.com/standardnotes/server/commit/15dfd6dcba75a772000eeb01b78a532067b01d5b))
## [2.10.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.10.0...@standardnotes/analytics@2.10.1) (2022-11-14)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "2.10.1",
"version": "2.10.2",
"engines": {
"node": ">=18.0.0 <19.0.0"
},

View File

@@ -7,6 +7,7 @@ import {
DomainEventMessageHandlerInterface,
DomainEventSubscriberFactoryInterface,
} from '@standardnotes/domain-events'
import { MapInterface } from '@standardnotes/domain-core'
import { Env } from './Env'
import TYPES from './Types'
@@ -47,7 +48,6 @@ import { RefundProcessedEventHandler } from '../Domain/Handler/RefundProcessedEv
import { RevenueModificationRepositoryInterface } from '../Domain/Revenue/RevenueModificationRepositoryInterface'
import { MySQLRevenueModificationRepository } from '../Infra/MySQL/MySQLRevenueModificationRepository'
import { TypeORMRevenueModification } from '../Infra/TypeORM/TypeORMRevenueModification'
import { MapInterface } from '@standardnotes/domain-core/src/Domain/Map/MapInterface'
import { RevenueModification } from '../Domain/Revenue/RevenueModification'
import { RevenueModificationMap } from '../Domain/Map/RevenueModificationMap'
import { SaveRevenueModification } from '../Domain/UseCase/SaveRevenueModification/SaveRevenueModification'

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.60.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.59.11...@standardnotes/auth-server@1.60.0) (2022-11-14)
### Features
* **auth:** add content size recalculation procedure trigger ([590ec66](https://github.com/standardnotes/server/commit/590ec6643db57adf3e202c6ccab4bac36aae8b59))
## [1.59.11](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.59.10...@standardnotes/auth-server@1.59.11) (2022-11-14)
**Note:** Version bump only for package @standardnotes/auth-server

View File

@@ -0,0 +1,74 @@
import 'reflect-metadata'
import 'newrelic'
import { Logger } from 'winston'
import * as dayjs from 'dayjs'
import * as utc from 'dayjs/plugin/utc'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
import { Stream } from 'stream'
const requestRecalculation = async (
userRepository: UserRepositoryInterface,
domainEventFactory: DomainEventFactoryInterface,
domainEventPublisher: DomainEventPublisherInterface,
logger: Logger,
): Promise<void> => {
const stream = await userRepository.streamAll()
return new Promise((resolve, reject) => {
stream
.pipe(
new Stream.Transform({
objectMode: true,
transform: async (rawUserData, _encoding, callback) => {
try {
await domainEventPublisher.publish(
domainEventFactory.createUserContentSizeRecalculationRequestedEvent(rawUserData.user_uuid),
)
} catch (error) {
logger.error(`Could not process user ${rawUserData.user_uuid}: ${(error as Error).message}`)
}
callback()
},
}),
)
.on('finish', resolve)
.on('error', reject)
})
}
const container = new ContainerConfigLoader()
void container.load().then((container) => {
dayjs.extend(utc)
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Logger)
logger.info('Starting content size recalculation requests ...')
const userRepository: UserRepositoryInterface = container.get(TYPES.UserRepository)
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.DomainEventFactory)
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.DomainEventPublisher)
Promise.resolve(requestRecalculation(userRepository, domainEventFactory, domainEventPublisher, logger))
.then(() => {
logger.info('content size recalculation requesting complete')
process.exit(0)
})
.catch((error) => {
logger.error(`Could not finish content size recalculation requesting : ${error.message}`)
process.exit(1)
})
})

View File

@@ -56,6 +56,11 @@ case "$COMMAND" in
yarn workspace @standardnotes/auth-server email-campaign $MESSAGE_IDENTIFIER
;;
'content-recalculation' )
echo "Starting Content Size Recalculation..."
yarn workspace @standardnotes/auth-server content-recalculation
;;
* )
echo "Unknown command"
;;

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.59.11",
"version": "1.60.0",
"engines": {
"node": ">=18.0.0 <19.0.0"
},
@@ -25,6 +25,7 @@
"daily-backup:google_drive": "yarn node dist/bin/backup.js google_drive daily",
"daily-backup:one_drive": "yarn node dist/bin/backup.js one_drive daily",
"weekly-backup:email": "yarn node dist/bin/backup.js email weekly",
"content-recalculation": "yarn node dist/bin/content.js",
"email-campaign": "yarn node dist/bin/email.js",
"typeorm": "typeorm-ts-node-commonjs",
"upgrade:snjs": "yarn ncu -u '@standardnotes/*'"

View File

@@ -1,406 +0,0 @@
import 'reflect-metadata'
import { EmailMessageIdentifier, ProtocolVersion, RoleName } from '@standardnotes/common'
import { PredicateName, PredicateAuthority, PredicateVerificationResult } from '@standardnotes/predicates'
import { TimerInterface } from '@standardnotes/time'
import { DomainEventFactory } from './DomainEventFactory'
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
describe('DomainEventFactory', () => {
let timer: TimerInterface
const createFactory = () => new DomainEventFactory(timer)
beforeEach(() => {
timer = {} as jest.Mocked<TimerInterface>
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(1)
timer.getUTCDate = jest.fn().mockReturnValue(new Date(1))
})
it('should create a EXIT_DISCOUNT_APPLY_REQUESTED event', () => {
expect(
createFactory().createExitDiscountApplyRequestedEvent({
userEmail: 'test@test.te',
discountCode: 'exit-20',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: 'test@test.te',
userIdentifierType: 'email',
},
origin: 'auth',
},
payload: {
userEmail: 'test@test.te',
discountCode: 'exit-20',
},
type: 'EXIT_DISCOUNT_APPLY_REQUESTED',
})
})
it('should create a WEB_SOCKET_MESSAGE_REQUESTED event', () => {
expect(
createFactory().createWebSocketMessageRequestedEvent({
userUuid: '1-2-3',
message: 'foobar',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
message: 'foobar',
},
type: 'WEB_SOCKET_MESSAGE_REQUESTED',
})
})
it('should create a EMAIL_MESSAGE_REQUESTED event', () => {
expect(
createFactory().createEmailMessageRequestedEvent({
userEmail: 'test@test.te',
messageIdentifier: EmailMessageIdentifier.ENCOURAGE_EMAIL_BACKUPS,
context: {
foo: 'bar',
},
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: 'test@test.te',
userIdentifierType: 'email',
},
origin: 'auth',
},
payload: {
messageIdentifier: 'ENCOURAGE_EMAIL_BACKUPS',
userEmail: 'test@test.te',
context: {
foo: 'bar',
},
},
type: 'EMAIL_MESSAGE_REQUESTED',
})
})
it('should create a PREDICATE_VERIFIED event', () => {
expect(
createFactory().createPredicateVerifiedEvent({
predicate: {
authority: PredicateAuthority.Auth,
jobUuid: '1-2-3',
name: PredicateName.EmailBackupsEnabled,
},
predicateVerificationResult: PredicateVerificationResult.Affirmed,
userUuid: '2-3-4',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '2-3-4',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
predicate: {
authority: 'auth',
jobUuid: '1-2-3',
name: 'email-backups-enabled',
},
predicateVerificationResult: 'affirmed',
},
type: 'PREDICATE_VERIFIED',
})
})
it('should create a SHARED_SUBSCRIPTION_INVITATION_CANCELED event', () => {
expect(
createFactory().createSharedSubscriptionInvitationCanceledEvent({
inviterEmail: 'test@test.te',
inviterSubscriptionId: 1,
inviterSubscriptionUuid: '2-3-4',
inviteeIdentifier: 'invitee@test.te',
inviteeIdentifierType: InviteeIdentifierType.Email,
sharedSubscriptionInvitationUuid: '1-2-3',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: 'test@test.te',
userIdentifierType: 'email',
},
origin: 'auth',
},
payload: {
inviterEmail: 'test@test.te',
inviterSubscriptionId: 1,
inviterSubscriptionUuid: '2-3-4',
inviteeIdentifier: 'invitee@test.te',
inviteeIdentifierType: InviteeIdentifierType.Email,
sharedSubscriptionInvitationUuid: '1-2-3',
},
type: 'SHARED_SUBSCRIPTION_INVITATION_CANCELED',
})
})
it('should create a SHARED_SUBSCRIPTION_INVITATION_CREATED event', () => {
expect(
createFactory().createSharedSubscriptionInvitationCreatedEvent({
inviterEmail: 'test@test.te',
inviterSubscriptionId: 1,
inviteeIdentifier: 'invitee@test.te',
inviteeIdentifierType: InviteeIdentifierType.Email,
sharedSubscriptionInvitationUuid: '1-2-3',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: 'test@test.te',
userIdentifierType: 'email',
},
origin: 'auth',
},
payload: {
inviterEmail: 'test@test.te',
inviterSubscriptionId: 1,
inviteeIdentifier: 'invitee@test.te',
inviteeIdentifierType: InviteeIdentifierType.Email,
sharedSubscriptionInvitationUuid: '1-2-3',
},
type: 'SHARED_SUBSCRIPTION_INVITATION_CREATED',
})
})
it('should create a USER_DISABLED_SESSION_USER_AGENT_LOGGING event', () => {
expect(
createFactory().createUserDisabledSessionUserAgentLoggingEvent({
email: 'test@test.te',
userUuid: '1-2-3',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
email: 'test@test.te',
},
type: 'USER_DISABLED_SESSION_USER_AGENT_LOGGING',
})
})
it('should create a USER_SIGNED_IN event', () => {
expect(
createFactory().createUserSignedInEvent({
browser: 'Firefox 1',
device: 'iOS 1',
userEmail: 'test@test.te',
userUuid: '1-2-3',
signInAlertEnabled: true,
muteSignInEmailsSettingUuid: '2-3-4',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
userEmail: 'test@test.te',
browser: 'Firefox 1',
device: 'iOS 1',
signInAlertEnabled: true,
muteSignInEmailsSettingUuid: '2-3-4',
},
type: 'USER_SIGNED_IN',
})
})
it('should create a LISTED_ACCOUNT_REQUESTED event', () => {
expect(createFactory().createListedAccountRequestedEvent('1-2-3', 'test@test.te')).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
userEmail: 'test@test.te',
},
type: 'LISTED_ACCOUNT_REQUESTED',
})
})
it('should create a USER_REGISTERED event', () => {
expect(
createFactory().createUserRegisteredEvent({
userUuid: '1-2-3',
email: 'test@test.te',
protocolVersion: ProtocolVersion.V004,
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
email: 'test@test.te',
protocolVersion: '004',
},
type: 'USER_REGISTERED',
})
})
it('should create a OFFLINE_SUBSCRIPTION_TOKEN_CREATED event', () => {
expect(createFactory().createOfflineSubscriptionTokenCreatedEvent('1-2-3', 'test@test.te')).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: 'test@test.te',
userIdentifierType: 'email',
},
origin: 'auth',
},
payload: {
token: '1-2-3',
email: 'test@test.te',
},
type: 'OFFLINE_SUBSCRIPTION_TOKEN_CREATED',
})
})
it('should create a USER_CHANGED_EMAIL event', () => {
expect(createFactory().createUserEmailChangedEvent('1-2-3', 'test@test.te', 'test2@test.te')).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
fromEmail: 'test@test.te',
toEmail: 'test2@test.te',
},
type: 'USER_EMAIL_CHANGED',
})
})
it('should create a CLOUD_BACKUP_REQUESTED event', () => {
expect(createFactory().createCloudBackupRequestedEvent('GOOGLE_DRIVE', 'test', '1-2-3', '2-3-4', true)).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
cloudProvider: 'GOOGLE_DRIVE',
cloudProviderToken: 'test',
userUuid: '1-2-3',
muteEmailsSettingUuid: '2-3-4',
userHasEmailsMuted: true,
},
type: 'CLOUD_BACKUP_REQUESTED',
})
})
it('should create a EMAIL_BACKUP_REQUESTED event', () => {
expect(createFactory().createEmailBackupRequestedEvent('1-2-3', '2-3-4', true)).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
muteEmailsSettingUuid: '2-3-4',
userHasEmailsMuted: true,
},
type: 'EMAIL_BACKUP_REQUESTED',
})
})
it('should create a ACCOUNT_DELETION_REQUESTED event', () => {
expect(
createFactory().createAccountDeletionRequestedEvent({
userUuid: '1-2-3',
userCreatedAtTimestamp: 123,
regularSubscriptionUuid: '2-3-4',
}),
).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
userCreatedAtTimestamp: 123,
regularSubscriptionUuid: '2-3-4',
},
type: 'ACCOUNT_DELETION_REQUESTED',
})
})
it('should create a USER_ROLE_CHANGED event', () => {
expect(createFactory().createUserRolesChangedEvent('1-2-3', 'test@test.com', [RoleName.ProUser])).toEqual({
createdAt: expect.any(Date),
meta: {
correlation: {
userIdentifier: '1-2-3',
userIdentifierType: 'uuid',
},
origin: 'auth',
},
payload: {
userUuid: '1-2-3',
email: 'test@test.com',
currentRoles: [RoleName.ProUser],
timestamp: expect.any(Number),
},
type: 'USER_ROLES_CHANGED',
})
})
})

View File

@@ -1,3 +1,5 @@
/* istanbul ignore file */
import { EmailMessageIdentifier, JSONString, ProtocolVersion, RoleName, Uuid } from '@standardnotes/common'
import {
AccountDeletionRequestedEvent,
@@ -17,6 +19,7 @@ import {
EmailMessageRequestedEvent,
WebSocketMessageRequestedEvent,
ExitDiscountApplyRequestedEvent,
UserContentSizeRecalculationRequestedEvent,
} from '@standardnotes/domain-events'
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
import { TimerInterface } from '@standardnotes/time'
@@ -29,6 +32,23 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
export class DomainEventFactory implements DomainEventFactoryInterface {
constructor(@inject(TYPES.Timer) private timer: TimerInterface) {}
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent {
return {
type: 'USER_CONTENT_SIZE_RECALCULATION_REQUESTED',
createdAt: this.timer.getUTCDate(),
meta: {
correlation: {
userIdentifier: userUuid,
userIdentifierType: 'uuid',
},
origin: DomainEventService.Auth,
},
payload: {
userUuid,
},
}
}
createExitDiscountApplyRequestedEvent(dto: {
userEmail: string
discountCode: string

View File

@@ -17,10 +17,12 @@ import {
EmailMessageRequestedEvent,
WebSocketMessageRequestedEvent,
ExitDiscountApplyRequestedEvent,
UserContentSizeRecalculationRequestedEvent,
} from '@standardnotes/domain-events'
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
export interface DomainEventFactoryInterface {
createUserContentSizeRecalculationRequestedEvent(userUuid: string): UserContentSizeRecalculationRequestedEvent
createWebSocketMessageRequestedEvent(dto: { userUuid: Uuid; message: JSONString }): WebSocketMessageRequestedEvent
createEmailMessageRequestedEvent(dto: {
userEmail: string

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.13.11](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.13.10...@standardnotes/syncing-server@1.13.11) (2022-11-14)
### Bug Fixes
* **syncing-server:** decrease logs severity for content recalculation ([500756d](https://github.com/standardnotes/syncing-server-js/commit/500756d58239ea4f639362542476827f9faaa88b))
## [1.13.10](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.13.9...@standardnotes/syncing-server@1.13.10) (2022-11-14)
### Bug Fixes
* **syncing-server:** linter issues ([3be1bfe](https://github.com/standardnotes/syncing-server-js/commit/3be1bfe58a0dcdda4f593cf5327426cbdcee7c45))
## [1.13.9](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.13.8...@standardnotes/syncing-server@1.13.9) (2022-11-14)
### Bug Fixes

View File

@@ -1,6 +1,6 @@
{
"name": "@standardnotes/syncing-server",
"version": "1.13.9",
"version": "1.13.11",
"engines": {
"node": ">=18.0.0 <19.0.0"
},
@@ -16,6 +16,7 @@
"setup:env": "cp .env.sample .env",
"build": "tsc --build",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"pretest": "yarn lint && yarn build",
"test": "jest --coverage --config=./jest.config.js --maxWorkers=50%",
"start": "yarn node dist/bin/server.js",

View File

@@ -19,7 +19,7 @@ export class UserContentSizeRecalculationRequestedEventHandler implements Domain
) {}
async handle(event: UserContentSizeRecalculationRequestedEvent): Promise<void> {
this.logger.info(`Starting content size recalculation for user: ${event.payload.userUuid}`)
this.logger.debug(`Starting content size recalculation for user: ${event.payload.userUuid}`)
const stream = await this.itemRepository.streamAll({
deleted: false,
@@ -41,7 +41,7 @@ export class UserContentSizeRecalculationRequestedEventHandler implements Domain
return
}
loggerHandle.info(`Fixing content size for item ${item.item_uuid}`)
loggerHandle.debug(`Fixing content size for item ${item.item_uuid}`)
const modelItem = await this.itemRepository.findByUuid(item.item_uuid)
if (modelItem !== null) {
@@ -49,7 +49,7 @@ export class UserContentSizeRecalculationRequestedEventHandler implements Domain
JSON.stringify(await this.itemProjector.projectFull(modelItem)),
)
if (modelItem.contentSize !== fixedContentSize) {
loggerHandle.info(`Fixing content size from ${modelItem.contentSize} to ${fixedContentSize}`)
loggerHandle.debug(`Fixing content size from ${modelItem.contentSize} to ${fixedContentSize}`)
modelItem.contentSize = fixedContentSize

View File

@@ -13,10 +13,14 @@ export class RevisionMetadata extends Entity<RevisionMetadataProps> {
static create(props: RevisionMetadataProps, id?: UniqueEntityId): Result<RevisionMetadata> {
if (!(props.createdAt instanceof Date)) {
return Result.fail<RevisionMetadata>(`Could not create Revision Metadata. Creation date should be a date object, given: ${props.createdAt}`)
return Result.fail<RevisionMetadata>(
`Could not create Revision Metadata. Creation date should be a date object, given: ${props.createdAt}`,
)
}
if (!(props.updatedAt instanceof Date)) {
return Result.fail<RevisionMetadata>(`Could not create Revision Metadata. Update date should be a date object, given: ${props.updatedAt}`)
return Result.fail<RevisionMetadata>(
`Could not create Revision Metadata. Update date should be a date object, given: ${props.updatedAt}`,
)
}
return Result.ok<RevisionMetadata>(new RevisionMetadata(props, id))