mirror of
https://github.com/standardnotes/server
synced 2026-06-02 05:38:53 -04:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5d0d63ddd | |||
| 36f07c691a | |||
| ac0390e7c3 | |||
| 0477507a6a | |||
| 3e7856c895 | |||
| 6778a80f21 | |||
| d4d49454a6 | |||
| 04b52e6773 | |||
| 2a1859e4be | |||
| dd9a9c68cb | |||
| 9147ff5d49 |
@@ -3326,10 +3326,10 @@ const RAW_RUNTIME_STATE =
|
||||
}]\
|
||||
]],\
|
||||
["@hexagon/base64", [\
|
||||
["npm:1.1.26", {\
|
||||
"packageLocation": "./.yarn/cache/@hexagon-base64-npm-1.1.26-dbfda05df8-e42582ed12.zip/node_modules/@hexagon/base64/",\
|
||||
["npm:1.1.27", {\
|
||||
"packageLocation": "./.yarn/cache/@hexagon-base64-npm-1.1.27-df6f264962-899fffaf54.zip/node_modules/@hexagon/base64/",\
|
||||
"packageDependencies": [\
|
||||
["@hexagon/base64", "npm:1.1.26"]\
|
||||
["@hexagon/base64", "npm:1.1.27"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
@@ -5067,44 +5067,29 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@simplewebauthn/iso-webcrypto", [\
|
||||
["npm:7.2.0", {\
|
||||
"packageLocation": "./.yarn/cache/@simplewebauthn-iso-webcrypto-npm-7.2.0-db7b12b859-b57899d0ad.zip/node_modules/@simplewebauthn/iso-webcrypto/",\
|
||||
"packageDependencies": [\
|
||||
["@simplewebauthn/iso-webcrypto", "npm:7.2.0"],\
|
||||
["@simplewebauthn/typescript-types", "npm:7.0.0"],\
|
||||
["@types/node", "npm:18.16.16"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@simplewebauthn/server", [\
|
||||
["npm:7.2.0", {\
|
||||
"packageLocation": "./.yarn/cache/@simplewebauthn-server-npm-7.2.0-f1ed5fde8a-2e37c87edd.zip/node_modules/@simplewebauthn/server/",\
|
||||
["npm:8.1.1", {\
|
||||
"packageLocation": "./.yarn/cache/@simplewebauthn-server-npm-8.1.1-106d3bd108-a07c2a067b.zip/node_modules/@simplewebauthn/server/",\
|
||||
"packageDependencies": [\
|
||||
["@simplewebauthn/server", "npm:7.2.0"],\
|
||||
["@hexagon/base64", "npm:1.1.26"],\
|
||||
["@simplewebauthn/server", "npm:8.1.1"],\
|
||||
["@hexagon/base64", "npm:1.1.27"],\
|
||||
["@peculiar/asn1-android", "npm:2.3.6"],\
|
||||
["@peculiar/asn1-ecc", "npm:2.3.6"],\
|
||||
["@peculiar/asn1-rsa", "npm:2.3.6"],\
|
||||
["@peculiar/asn1-schema", "npm:2.3.6"],\
|
||||
["@peculiar/asn1-x509", "npm:2.3.6"],\
|
||||
["@simplewebauthn/iso-webcrypto", "npm:7.2.0"],\
|
||||
["@simplewebauthn/typescript-types", "npm:7.0.0"],\
|
||||
["@types/debug", "npm:4.1.8"],\
|
||||
["@types/node", "npm:18.16.16"],\
|
||||
["cbor-x", "npm:1.5.3"],\
|
||||
["cross-fetch", "npm:3.1.6"],\
|
||||
["debug", "virtual:ac3d8e680759ce54399273724d44e041d6c9b73454d191d411a8c44bb27e22f02aaf6ed9d3ad0ac1c298eac4833cff369c9c7b84c573016112c4f84be2cd8543#npm:4.3.4"]\
|
||||
["@simplewebauthn/typescript-types", "npm:8.0.0"],\
|
||||
["cbor-x", "npm:1.5.4"],\
|
||||
["cross-fetch", "npm:4.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@simplewebauthn/typescript-types", [\
|
||||
["npm:7.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/@simplewebauthn-typescript-types-npm-7.0.0-cc6ca20415-124238ea18.zip/node_modules/@simplewebauthn/typescript-types/",\
|
||||
["npm:8.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/@simplewebauthn-typescript-types-npm-8.0.0-f3b313c27b-21e0b13268.zip/node_modules/@simplewebauthn/typescript-types/",\
|
||||
"packageDependencies": [\
|
||||
["@simplewebauthn/typescript-types", "npm:7.0.0"]\
|
||||
["@simplewebauthn/typescript-types", "npm:8.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
@@ -5864,8 +5849,8 @@ const RAW_RUNTIME_STATE =
|
||||
["@cbor-extract/cbor-extract-linux-arm64", "npm:2.1.1"],\
|
||||
["@cbor-extract/cbor-extract-linux-x64", "npm:2.1.1"],\
|
||||
["@newrelic/winston-enricher", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.0.1"],\
|
||||
["@simplewebauthn/server", "npm:7.2.0"],\
|
||||
["@simplewebauthn/typescript-types", "npm:7.0.0"],\
|
||||
["@simplewebauthn/server", "npm:8.1.1"],\
|
||||
["@simplewebauthn/typescript-types", "npm:8.0.0"],\
|
||||
["@standardnotes/api", "npm:1.26.26"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/domain-core", "workspace:packages/domain-core"],\
|
||||
@@ -6720,16 +6705,6 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/debug", [\
|
||||
["npm:4.1.8", {\
|
||||
"packageLocation": "./.yarn/cache/@types-debug-npm-4.1.8-a04e2ca136-9c190e8129.zip/node_modules/@types/debug/",\
|
||||
"packageDependencies": [\
|
||||
["@types/debug", "npm:4.1.8"],\
|
||||
["@types/ms", "npm:0.7.31"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/dotenv", [\
|
||||
["npm:8.2.0", {\
|
||||
"packageLocation": "./.yarn/cache/@types-dotenv-npm-8.2.0-f4d0e3d65b-13f90a36f7.zip/node_modules/@types/dotenv/",\
|
||||
@@ -6956,15 +6931,6 @@ const RAW_RUNTIME_STATE =
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/ms", [\
|
||||
["npm:0.7.31", {\
|
||||
"packageLocation": "./.yarn/cache/@types-ms-npm-0.7.31-ea3b89342b-cccb52777b.zip/node_modules/@types/ms/",\
|
||||
"packageDependencies": [\
|
||||
["@types/ms", "npm:0.7.31"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@types/newrelic", [\
|
||||
["npm:9.14.0", {\
|
||||
"packageLocation": "./.yarn/cache/@types-newrelic-npm-9.14.0-4668da51a1-2ec951bd8f.zip/node_modules/@types/newrelic/",\
|
||||
@@ -6982,13 +6948,6 @@ const RAW_RUNTIME_STATE =
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:18.16.16", {\
|
||||
"packageLocation": "./.yarn/cache/@types-node-npm-18.16.16-8a41330dc3-946bd4d8e6.zip/node_modules/@types/node/",\
|
||||
"packageDependencies": [\
|
||||
["@types/node", "npm:18.16.16"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:20.2.5", {\
|
||||
"packageLocation": "./.yarn/cache/@types-node-npm-20.2.5-0014d2d9ce-55e4f8d08e.zip/node_modules/@types/node/",\
|
||||
"packageDependencies": [\
|
||||
@@ -8706,10 +8665,10 @@ const RAW_RUNTIME_STATE =
|
||||
}]\
|
||||
]],\
|
||||
["cbor-x", [\
|
||||
["npm:1.5.3", {\
|
||||
"packageLocation": "./.yarn/cache/cbor-x-npm-1.5.3-1d452dd267-d4df85b339.zip/node_modules/cbor-x/",\
|
||||
["npm:1.5.4", {\
|
||||
"packageLocation": "./.yarn/cache/cbor-x-npm-1.5.4-2d5a649a4b-742aea498a.zip/node_modules/cbor-x/",\
|
||||
"packageDependencies": [\
|
||||
["cbor-x", "npm:1.5.3"],\
|
||||
["cbor-x", "npm:1.5.4"],\
|
||||
["cbor-extract", "npm:2.1.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
@@ -9434,11 +9393,11 @@ const RAW_RUNTIME_STATE =
|
||||
}]\
|
||||
]],\
|
||||
["cross-fetch", [\
|
||||
["npm:3.1.6", {\
|
||||
"packageLocation": "./.yarn/cache/cross-fetch-npm-3.1.6-cdb982d446-a8989fca82.zip/node_modules/cross-fetch/",\
|
||||
["npm:4.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/cross-fetch-npm-4.0.0-9c67668db4-30e86b703a.zip/node_modules/cross-fetch/",\
|
||||
"packageDependencies": [\
|
||||
["cross-fetch", "npm:3.1.6"],\
|
||||
["node-fetch", "virtual:0f92dfe7f9dc4fd492639d4a5b7805c2b27442bf599fd4f370b22a7966ba078f5d4525e2a8e8af29369f20e1833ed084bd52be59679efaa6c1c6c10cdbcd8baa#npm:2.6.11"]\
|
||||
["cross-fetch", "npm:4.0.0"],\
|
||||
["node-fetch", "virtual:9c67668db478e95ba4d6a763bc55027eeff0d22eaf59478017ea07386fc33a3c7b7b625af78aa86a33991a9a500a7aa216e28632de568f02adefd662ef53a42d#npm:2.7.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
@@ -14174,6 +14133,13 @@ const RAW_RUNTIME_STATE =
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["npm:2.7.0", {\
|
||||
"packageLocation": "./.yarn/cache/node-fetch-npm-2.7.0-587d57004e-a3ad788903.zip/node_modules/node-fetch/",\
|
||||
"packageDependencies": [\
|
||||
["node-fetch", "npm:2.7.0"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["npm:3.3.1", {\
|
||||
"packageLocation": "./.yarn/cache/node-fetch-npm-3.3.1-576511fc5a-1d0c635bdf.zip/node_modules/node-fetch/",\
|
||||
"packageDependencies": [\
|
||||
@@ -14197,6 +14163,20 @@ const RAW_RUNTIME_STATE =
|
||||
"encoding"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:9c67668db478e95ba4d6a763bc55027eeff0d22eaf59478017ea07386fc33a3c7b7b625af78aa86a33991a9a500a7aa216e28632de568f02adefd662ef53a42d#npm:2.7.0", {\
|
||||
"packageLocation": "./.yarn/__virtual__/node-fetch-virtual-0ec1497d1c/0/cache/node-fetch-npm-2.7.0-587d57004e-a3ad788903.zip/node_modules/node-fetch/",\
|
||||
"packageDependencies": [\
|
||||
["node-fetch", "virtual:9c67668db478e95ba4d6a763bc55027eeff0d22eaf59478017ea07386fc33a3c7b7b625af78aa86a33991a9a500a7aa216e28632de568f02adefd662ef53a42d#npm:2.7.0"],\
|
||||
["@types/encoding", null],\
|
||||
["encoding", null],\
|
||||
["whatwg-url", "npm:5.0.0"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/encoding",\
|
||||
"encoding"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["node-gyp", [\
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.26.14](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.13...@standardnotes/analytics@2.26.14) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.13](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.12...@standardnotes/analytics@2.26.13) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.26.12](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.11...@standardnotes/analytics@2.26.12) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "2.26.12",
|
||||
"version": "2.26.14",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.74.12](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.11...@standardnotes/api-gateway@1.74.12) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.11](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.10...@standardnotes/api-gateway@1.74.11) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.74.10](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.74.9...@standardnotes/api-gateway@1.74.10) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.74.10",
|
||||
"version": "1.74.12",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -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.143.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.142.1...@standardnotes/auth-server@1.143.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* refactor transition to minimize status changes ([#828](https://github.com/standardnotes/server/issues/828)) ([36f07c6](https://github.com/standardnotes/server/commit/36f07c691afc213ecf817d6e98f885ddb19a6ed6))
|
||||
|
||||
## [1.142.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.142.0...@standardnotes/auth-server@1.142.1) (2023-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add debug logs for updating transition status on auth ([0477507](https://github.com/standardnotes/server/commit/0477507a6a951dc2bb904711c870e2c40a0664bd))
|
||||
|
||||
# [1.142.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.14...@standardnotes/auth-server@1.142.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* add skipping verified transitions ([#827](https://github.com/standardnotes/server/issues/827)) ([d4d4945](https://github.com/standardnotes/server/commit/d4d49454a68de0acdf440dc202fa14b9743905f6))
|
||||
|
||||
## [1.141.14](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.13...@standardnotes/auth-server@1.141.14) (2023-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** remove extensive logs from updating transitions ([2a1859e](https://github.com/standardnotes/server/commit/2a1859e4beff4cc7c4348ebbff8357a8e061bf5e))
|
||||
* **auth:** upgrade simplewebauthn dependency ([#826](https://github.com/standardnotes/server/issues/826)) ([dd9a9c6](https://github.com/standardnotes/server/commit/dd9a9c68cb431a61700a8e5d8247eb1b505a9d62))
|
||||
|
||||
## [1.141.13](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.12...@standardnotes/auth-server@1.141.13) (2023-09-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -11,12 +11,15 @@ import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
|
||||
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { TransitionStatusRepositoryInterface } from '../src/Domain/Transition/TransitionStatusRepositoryInterface'
|
||||
import { RoleName, TransitionStatus } from '@standardnotes/domain-core'
|
||||
|
||||
const inputArgs = process.argv.slice(2)
|
||||
const startDateString = inputArgs[0]
|
||||
const endDateString = inputArgs[1]
|
||||
|
||||
const requestTransition = async (
|
||||
transitionStatusRepository: TransitionStatusRepositoryInterface,
|
||||
userRepository: UserRepositoryInterface,
|
||||
logger: Logger,
|
||||
domainEventFactory: DomainEventFactoryInterface,
|
||||
@@ -36,15 +39,45 @@ const requestTransition = async (
|
||||
|
||||
let usersTriggered = 0
|
||||
for (const user of users) {
|
||||
const transitionRequestedEvent = domainEventFactory.createTransitionRequestedEvent({
|
||||
userUuid: user.uuid,
|
||||
type: 'items',
|
||||
timestamp,
|
||||
})
|
||||
const itemsTransitionStatus = await transitionStatusRepository.getStatus(user.uuid, 'items')
|
||||
const revisionsTransitionStatus = await transitionStatusRepository.getStatus(user.uuid, 'revisions')
|
||||
|
||||
const userRoles = await user.roles
|
||||
|
||||
const userHasTransitionRole = userRoles.some((role) => role.name === RoleName.NAMES.TransitionUser)
|
||||
const bothTransitionStatusesAreVerified =
|
||||
itemsTransitionStatus?.value === TransitionStatus.STATUSES.Verified &&
|
||||
revisionsTransitionStatus?.value === TransitionStatus.STATUSES.Verified
|
||||
|
||||
if (userHasTransitionRole && bothTransitionStatusesAreVerified) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (itemsTransitionStatus?.value !== TransitionStatus.STATUSES.Verified) {
|
||||
await transitionStatusRepository.remove(user.uuid, 'items')
|
||||
|
||||
await domainEventPublisher.publish(
|
||||
domainEventFactory.createTransitionRequestedEvent({
|
||||
userUuid: user.uuid,
|
||||
type: 'items',
|
||||
timestamp,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (revisionsTransitionStatus?.value !== TransitionStatus.STATUSES.Verified) {
|
||||
await transitionStatusRepository.remove(user.uuid, 'revisions')
|
||||
|
||||
await domainEventPublisher.publish(
|
||||
domainEventFactory.createTransitionRequestedEvent({
|
||||
userUuid: user.uuid,
|
||||
type: 'revisions',
|
||||
timestamp,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
usersTriggered += 1
|
||||
|
||||
await domainEventPublisher.publish(transitionRequestedEvent)
|
||||
}
|
||||
|
||||
logger.info(
|
||||
@@ -67,8 +100,20 @@ void container.load().then((container) => {
|
||||
const domainEventFactory: DomainEventFactoryInterface = container.get(TYPES.Auth_DomainEventFactory)
|
||||
const domainEventPublisher: DomainEventPublisherInterface = container.get(TYPES.Auth_DomainEventPublisher)
|
||||
const timer = container.get<TimerInterface>(TYPES.Auth_Timer)
|
||||
const transitionStatusRepository = container.get<TransitionStatusRepositoryInterface>(
|
||||
TYPES.Auth_TransitionStatusRepository,
|
||||
)
|
||||
|
||||
Promise.resolve(requestTransition(userRepository, logger, domainEventFactory, domainEventPublisher, timer))
|
||||
Promise.resolve(
|
||||
requestTransition(
|
||||
transitionStatusRepository,
|
||||
userRepository,
|
||||
logger,
|
||||
domainEventFactory,
|
||||
domainEventPublisher,
|
||||
timer,
|
||||
),
|
||||
)
|
||||
.then(() => {
|
||||
logger.info(`Finished transition request for users created between ${startDateString} and ${endDateString}`)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.141.13",
|
||||
"version": "1.143.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
@@ -40,8 +40,8 @@
|
||||
"@aws-sdk/client-sqs": "^3.332.0",
|
||||
"@cbor-extract/cbor-extract-linux-arm64": "^2.1.1",
|
||||
"@cbor-extract/cbor-extract-linux-x64": "^2.1.1",
|
||||
"@simplewebauthn/server": "^7.2.0",
|
||||
"@simplewebauthn/typescript-types": "^7.0.0",
|
||||
"@simplewebauthn/server": "^8.1.1",
|
||||
"@simplewebauthn/typescript-types": "^8.0.0",
|
||||
"@standardnotes/api": "^1.26.26",
|
||||
"@standardnotes/common": "workspace:*",
|
||||
"@standardnotes/domain-core": "workspace:^",
|
||||
|
||||
@@ -263,7 +263,6 @@ import { RedisTransitionStatusRepository } from '../Infra/Redis/RedisTransitionS
|
||||
import { InMemoryTransitionStatusRepository } from '../Infra/InMemory/InMemoryTransitionStatusRepository'
|
||||
import { TransitionStatusUpdatedEventHandler } from '../Domain/Handler/TransitionStatusUpdatedEventHandler'
|
||||
import { UpdateTransitionStatus } from '../Domain/UseCase/UpdateTransitionStatus/UpdateTransitionStatus'
|
||||
import { GetTransitionStatus } from '../Domain/UseCase/GetTransitionStatus/GetTransitionStatus'
|
||||
import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
|
||||
import { SharedVaultUserPersistenceMapper } from '../Mapping/SharedVaultUserPersistenceMapper'
|
||||
import { SharedVaultUserRepositoryInterface } from '../Domain/SharedVault/SharedVaultUserRepositoryInterface'
|
||||
@@ -946,14 +945,6 @@ export class ContainerConfigLoader {
|
||||
container.get<winston.Logger>(TYPES.Auth_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<GetTransitionStatus>(TYPES.Auth_GetTransitionStatus)
|
||||
.toConstantValue(
|
||||
new GetTransitionStatus(
|
||||
container.get<TransitionStatusRepositoryInterface>(TYPES.Auth_TransitionStatusRepository),
|
||||
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<AddSharedVaultUser>(TYPES.Auth_AddSharedVaultUser)
|
||||
.toConstantValue(
|
||||
|
||||
@@ -159,7 +159,6 @@ const TYPES = {
|
||||
Auth_GetUserKeyParamsRecovery: Symbol.for('Auth_GetUserKeyParamsRecovery'),
|
||||
Auth_UpdateStorageQuotaUsedForUser: Symbol.for('Auth_UpdateStorageQuotaUsedForUser'),
|
||||
Auth_UpdateTransitionStatus: Symbol.for('Auth_UpdateTransitionStatus'),
|
||||
Auth_GetTransitionStatus: Symbol.for('Auth_GetTransitionStatus'),
|
||||
Auth_AddSharedVaultUser: Symbol.for('Auth_AddSharedVaultUser'),
|
||||
Auth_RemoveSharedVaultUser: Symbol.for('Auth_RemoveSharedVaultUser'),
|
||||
// Handlers
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
import { TransitionStatus } from '@standardnotes/domain-core'
|
||||
|
||||
export interface TransitionStatusRepositoryInterface {
|
||||
updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED',
|
||||
): Promise<void>
|
||||
removeStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void>
|
||||
getStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<'STARTED' | 'IN_PROGRESS' | 'FAILED' | null>
|
||||
getStatuses(
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<Array<{ userUuid: string; status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' }>>
|
||||
updateStatus(userUuid: string, transitionType: 'items' | 'revisions', status: TransitionStatus): Promise<void>
|
||||
getStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<TransitionStatus | null>
|
||||
remove(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void>
|
||||
}
|
||||
|
||||
+14
-3
@@ -9,7 +9,14 @@ import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
|
||||
import { CreateCrossServiceToken } from './CreateCrossServiceToken'
|
||||
import { GetSetting } from '../GetSetting/GetSetting'
|
||||
import { Result, SharedVaultUser, SharedVaultUserPermission, Timestamps, Uuid } from '@standardnotes/domain-core'
|
||||
import {
|
||||
Result,
|
||||
SharedVaultUser,
|
||||
SharedVaultUserPermission,
|
||||
Timestamps,
|
||||
TransitionStatus,
|
||||
Uuid,
|
||||
} from '@standardnotes/domain-core'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { SharedVaultUserRepositoryInterface } from '../../SharedVault/SharedVaultUserRepositoryInterface'
|
||||
|
||||
@@ -72,7 +79,9 @@ describe('CreateCrossServiceToken', () => {
|
||||
getSettingUseCase.execute = jest.fn().mockReturnValue(Result.ok({ setting: { value: '100' } }))
|
||||
|
||||
transitionStatusRepository = {} as jest.Mocked<TransitionStatusRepositoryInterface>
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('TO-DO')
|
||||
transitionStatusRepository.getStatus = jest
|
||||
.fn()
|
||||
.mockReturnValue(TransitionStatus.create(TransitionStatus.STATUSES.Verified).getValue())
|
||||
|
||||
sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
|
||||
sharedVaultUserRepository.findByUserUuid = jest.fn().mockReturnValue([
|
||||
@@ -120,7 +129,9 @@ describe('CreateCrossServiceToken', () => {
|
||||
})
|
||||
|
||||
it('should create a cross service token for user that has an ongoing transaction', async () => {
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('IN_PROGRESS')
|
||||
transitionStatusRepository.getStatus = jest
|
||||
.fn()
|
||||
.mockReturnValue(TransitionStatus.create(TransitionStatus.STATUSES.InProgress).getValue())
|
||||
|
||||
await createUseCase().execute({
|
||||
user,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TokenEncoderInterface, CrossServiceTokenData } from '@standardnotes/security'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Result, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { Result, TransitionStatus, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { ProjectorInterface } from '../../../Projection/ProjectorInterface'
|
||||
@@ -60,9 +60,8 @@ export class CreateCrossServiceToken implements UseCaseInterface<string> {
|
||||
user: this.projectUser(user),
|
||||
roles: this.projectRoles(roles),
|
||||
shared_vault_owner_context: undefined,
|
||||
ongoing_transition: transitionStatus === 'IN_PROGRESS',
|
||||
ongoing_revisions_transition:
|
||||
revisionsTransitionStatus === 'STARTED' || revisionsTransitionStatus === 'IN_PROGRESS',
|
||||
ongoing_transition: transitionStatus?.value === TransitionStatus.STATUSES.InProgress,
|
||||
ongoing_revisions_transition: revisionsTransitionStatus?.value === TransitionStatus.STATUSES.InProgress,
|
||||
belongs_to_shared_vaults: sharedVaultAssociations.map((association) => ({
|
||||
shared_vault_uuid: association.props.sharedVaultUuid.value,
|
||||
permission: association.props.permission.value,
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ export class GenerateAuthenticatorAuthenticationOptions
|
||||
.update(`u2f-selector-${dto.username}${this.pseudoKeyParamsKey}`)
|
||||
.digest('base64url')
|
||||
|
||||
const options = generateAuthenticationOptions({
|
||||
const options = await generateAuthenticationOptions({
|
||||
allowCredentials: [
|
||||
{
|
||||
id: Buffer.from(credentialIdHash),
|
||||
@@ -56,7 +56,7 @@ export class GenerateAuthenticatorAuthenticationOptions
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const authenticators = await this.authenticatorRepository.findByUserUuid(userUuid)
|
||||
const options = generateAuthenticationOptions({
|
||||
const options = await generateAuthenticationOptions({
|
||||
allowCredentials: authenticators.map((authenticator) => ({
|
||||
id: authenticator.props.credentialId,
|
||||
type: 'public-key',
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ export class GenerateAuthenticatorRegistrationOptions
|
||||
}
|
||||
|
||||
const authenticators = await this.authenticatorRepository.findByUserUuid(userUuid)
|
||||
const options = generateRegistrationOptions({
|
||||
const options = await generateRegistrationOptions({
|
||||
rpID: this.relyingPartyId,
|
||||
rpName: this.relyingPartyName,
|
||||
userID: userUuid.value,
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
import { RoleName } from '@standardnotes/domain-core'
|
||||
import { Role } from '../../Role/Role'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { User } from '../../User/User'
|
||||
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
import { GetTransitionStatus } from './GetTransitionStatus'
|
||||
|
||||
describe('GetTransitionStatus', () => {
|
||||
let transitionStatusRepository: TransitionStatusRepositoryInterface
|
||||
let userRepository: UserRepositoryInterface
|
||||
let user: User
|
||||
let role: Role
|
||||
|
||||
const createUseCase = () => new GetTransitionStatus(transitionStatusRepository, userRepository)
|
||||
|
||||
beforeEach(() => {
|
||||
transitionStatusRepository = {} as jest.Mocked<TransitionStatusRepositoryInterface>
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue(null)
|
||||
|
||||
role = {} as jest.Mocked<Role>
|
||||
role.name = RoleName.NAMES.CoreUser
|
||||
|
||||
user = {
|
||||
uuid: '00000000-0000-0000-0000-000000000000',
|
||||
email: 'test@test.te',
|
||||
} as jest.Mocked<User>
|
||||
user.roles = Promise.resolve([role])
|
||||
|
||||
userRepository = {} as jest.Mocked<UserRepositoryInterface>
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(user)
|
||||
})
|
||||
|
||||
it('returns transition status FINISHED', async () => {
|
||||
role.name = RoleName.NAMES.TransitionUser
|
||||
user.roles = Promise.resolve([role])
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(user)
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
transitionType: 'items',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(result.getValue()).toEqual('FINISHED')
|
||||
})
|
||||
|
||||
it('returns transition status STARTED', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('STARTED')
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
transitionType: 'items',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(result.getValue()).toEqual('STARTED')
|
||||
})
|
||||
|
||||
it('returns transition status TO-DO', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
transitionType: 'items',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(result.getValue()).toEqual('TO-DO')
|
||||
})
|
||||
|
||||
it('returns transition status FAILED', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
transitionStatusRepository.getStatus = jest.fn().mockReturnValue('FAILED')
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
transitionType: 'items',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(result.getValue()).toEqual('FAILED')
|
||||
})
|
||||
|
||||
it('return error if user uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: 'invalid',
|
||||
transitionType: 'items',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toEqual('Given value is not a valid uuid: invalid')
|
||||
})
|
||||
|
||||
it('return error if user not found', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
transitionType: 'items',
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toEqual('User not found.')
|
||||
})
|
||||
})
|
||||
@@ -1,43 +0,0 @@
|
||||
import { Result, RoleName, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { GetTransitionStatusDTO } from './GetTransitionStatusDTO'
|
||||
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
|
||||
export class GetTransitionStatus
|
||||
implements UseCaseInterface<'TO-DO' | 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'>
|
||||
{
|
||||
constructor(
|
||||
private transitionStatusRepository: TransitionStatusRepositoryInterface,
|
||||
private userRepository: UserRepositoryInterface,
|
||||
) {}
|
||||
|
||||
async execute(
|
||||
dto: GetTransitionStatusDTO,
|
||||
): Promise<Result<'TO-DO' | 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'>> {
|
||||
const userUuidOrError = Uuid.create(dto.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return Result.fail(userUuidOrError.getError())
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
const user = await this.userRepository.findOneByUuid(userUuid)
|
||||
if (user === null) {
|
||||
return Result.fail('User not found.')
|
||||
}
|
||||
|
||||
const roles = await user.roles
|
||||
for (const role of roles) {
|
||||
if (role.name === RoleName.NAMES.TransitionUser) {
|
||||
return Result.ok('FINISHED')
|
||||
}
|
||||
}
|
||||
|
||||
const transitionStatus = await this.transitionStatusRepository.getStatus(userUuid.value, dto.transitionType)
|
||||
if (transitionStatus === null) {
|
||||
return Result.ok('TO-DO')
|
||||
}
|
||||
|
||||
return Result.ok(transitionStatus)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface GetTransitionStatusDTO {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
}
|
||||
+42
-46
@@ -1,4 +1,4 @@
|
||||
import { RoleName, Uuid } from '@standardnotes/domain-core'
|
||||
import { RoleName, TransitionStatus, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
@@ -17,82 +17,42 @@ describe('UpdateTransitionStatus', () => {
|
||||
logger.info = jest.fn()
|
||||
|
||||
transitionStatusRepository = {} as jest.Mocked<TransitionStatusRepositoryInterface>
|
||||
transitionStatusRepository.removeStatus = jest.fn()
|
||||
transitionStatusRepository.updateStatus = jest.fn()
|
||||
transitionStatusRepository.getStatuses = jest.fn().mockResolvedValue([
|
||||
{
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'STARTED',
|
||||
},
|
||||
{
|
||||
userUuid: '00000000-0000-0000-0000-000000000001',
|
||||
status: 'IN_PROGRESS',
|
||||
},
|
||||
{
|
||||
userUuid: '00000000-0000-0000-0000-000000000002',
|
||||
status: 'FAILED',
|
||||
},
|
||||
])
|
||||
transitionStatusRepository.getStatus = jest.fn().mockResolvedValue(null)
|
||||
|
||||
roleService = {} as jest.Mocked<RoleServiceInterface>
|
||||
roleService.addRoleToUser = jest.fn()
|
||||
})
|
||||
|
||||
it('should remove transition status and add TransitionUser role', async () => {
|
||||
it('should add TRANSITION_USER role', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'FINISHED',
|
||||
status: 'VERIFIED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(transitionStatusRepository.removeStatus).toHaveBeenCalledWith(
|
||||
'00000000-0000-0000-0000-000000000000',
|
||||
'items',
|
||||
)
|
||||
expect(roleService.addRoleToUser).toHaveBeenCalledWith(
|
||||
Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
RoleName.create(RoleName.NAMES.TransitionUser).getValue(),
|
||||
)
|
||||
})
|
||||
|
||||
it('should remove transition status', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'FINISHED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(transitionStatusRepository.removeStatus).toHaveBeenCalledWith(
|
||||
'00000000-0000-0000-0000-000000000000',
|
||||
'revisions',
|
||||
)
|
||||
expect(roleService.addRoleToUser).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should update transition status', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: 'STARTED',
|
||||
status: TransitionStatus.STATUSES.InProgress,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(transitionStatusRepository.updateStatus).toHaveBeenCalledWith(
|
||||
'00000000-0000-0000-0000-000000000000',
|
||||
'items',
|
||||
'STARTED',
|
||||
)
|
||||
expect(transitionStatusRepository.updateStatus).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return error when user uuid is invalid', async () => {
|
||||
@@ -108,4 +68,40 @@ describe('UpdateTransitionStatus', () => {
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.getError()).toEqual('Given value is not a valid uuid: invalid')
|
||||
})
|
||||
|
||||
it('should not update status if transition is already verified', async () => {
|
||||
transitionStatusRepository.getStatus = jest
|
||||
.fn()
|
||||
.mockResolvedValue(TransitionStatus.create(TransitionStatus.STATUSES.Verified).getValue())
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: TransitionStatus.STATUSES.InProgress,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(transitionStatusRepository.updateStatus).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not update status if transition is already failed', async () => {
|
||||
transitionStatusRepository.getStatus = jest
|
||||
.fn()
|
||||
.mockResolvedValue(TransitionStatus.create(TransitionStatus.STATUSES.Failed).getValue())
|
||||
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
status: TransitionStatus.STATUSES.InProgress,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(transitionStatusRepository.updateStatus).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Result, RoleName, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { Result, RoleName, TransitionStatus, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { UpdateTransitionStatusDTO } from './UpdateTransitionStatusDTO'
|
||||
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||
@@ -18,42 +18,23 @@ export class UpdateTransitionStatus implements UseCaseInterface<void> {
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
if (dto.status !== 'FINISHED') {
|
||||
await this.transitionStatusRepository.updateStatus(dto.userUuid, dto.transitionType, dto.status)
|
||||
const currentStatus = await this.transitionStatusRepository.getStatus(dto.userUuid, dto.transitionType)
|
||||
if (
|
||||
[TransitionStatus.STATUSES.Verified, TransitionStatus.STATUSES.Failed].includes(currentStatus?.value as string)
|
||||
) {
|
||||
this.logger.info(`User ${dto.userUuid} transition already finished.`)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
await this.transitionStatusRepository.removeStatus(dto.userUuid, dto.transitionType)
|
||||
const transitionStatus = TransitionStatus.create(dto.status).getValue()
|
||||
|
||||
if (dto.transitionType === 'items') {
|
||||
await this.transitionStatusRepository.updateStatus(dto.userUuid, dto.transitionType, transitionStatus)
|
||||
|
||||
if (dto.transitionType === 'items' && transitionStatus.value === TransitionStatus.STATUSES.Verified) {
|
||||
await this.roleService.addRoleToUser(userUuid, RoleName.create(RoleName.NAMES.TransitionUser).getValue())
|
||||
}
|
||||
|
||||
if (dto.transitionType === 'items') {
|
||||
const itemStatuses = await this.transitionStatusRepository.getStatuses('items')
|
||||
const itemsStartedStatusesCount = itemStatuses.filter((status) => status.status === 'STARTED').length
|
||||
const itemsInProgressStatusesCount = itemStatuses.filter((status) => status.status === 'IN_PROGRESS').length
|
||||
const itemsFailedStatusesCount = itemStatuses.filter((status) => status.status === 'FAILED').length
|
||||
|
||||
this.logger.info(
|
||||
`[TRANSITION ${dto.transitionTimestamp}] Items transition statuses: ${itemsStartedStatusesCount} started, ${itemsInProgressStatusesCount} in progress, ${itemsFailedStatusesCount} failed`,
|
||||
)
|
||||
}
|
||||
|
||||
if (dto.transitionType === 'revisions') {
|
||||
const revisionStatuses = await this.transitionStatusRepository.getStatuses('revisions')
|
||||
const revisionsStartedStatusesCount = revisionStatuses.filter((status) => status.status === 'STARTED').length
|
||||
const revisionsInProgressStatusesCount = revisionStatuses.filter(
|
||||
(status) => status.status === 'IN_PROGRESS',
|
||||
).length
|
||||
const revisionsFailedStatusesCount = revisionStatuses.filter((status) => status.status === 'FAILED').length
|
||||
|
||||
this.logger.info(
|
||||
`[TRANSITION ${dto.transitionTimestamp}] Revisions transition statuses: ${revisionsStartedStatusesCount} started, ${revisionsInProgressStatusesCount} in progress, ${revisionsFailedStatusesCount} failed`,
|
||||
)
|
||||
}
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@ export interface UpdateTransitionStatusDTO {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'
|
||||
status: string
|
||||
}
|
||||
|
||||
@@ -1,40 +1,19 @@
|
||||
import { TransitionStatus } from '@standardnotes/domain-core'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Domain/Transition/TransitionStatusRepositoryInterface'
|
||||
|
||||
export class InMemoryTransitionStatusRepository implements TransitionStatusRepositoryInterface {
|
||||
private itemStatuses: Map<string, 'STARTED' | 'FAILED'> = new Map()
|
||||
private revisionStatuses: Map<string, 'STARTED' | 'FAILED'> = new Map()
|
||||
|
||||
async getStatuses(
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<{ userUuid: string; status: 'STARTED' | 'FAILED' | 'IN_PROGRESS' }[]> {
|
||||
const statuses: { userUuid: string; status: 'STARTED' | 'FAILED' | 'IN_PROGRESS' }[] = []
|
||||
private itemStatuses: Map<string, string> = new Map()
|
||||
private revisionStatuses: Map<string, string> = new Map()
|
||||
|
||||
async updateStatus(userUuid: string, transitionType: 'items' | 'revisions', status: TransitionStatus): Promise<void> {
|
||||
if (transitionType === 'items') {
|
||||
for (const [userUuid, status] of this.itemStatuses) {
|
||||
statuses.push({ userUuid, status })
|
||||
}
|
||||
this.itemStatuses.set(userUuid, status.value)
|
||||
} else {
|
||||
for (const [userUuid, status] of this.revisionStatuses) {
|
||||
statuses.push({ userUuid, status })
|
||||
}
|
||||
}
|
||||
|
||||
return statuses
|
||||
}
|
||||
|
||||
async updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
status: 'STARTED' | 'FAILED',
|
||||
): Promise<void> {
|
||||
if (transitionType === 'items') {
|
||||
this.itemStatuses.set(userUuid, status)
|
||||
} else {
|
||||
this.revisionStatuses.set(userUuid, status)
|
||||
this.revisionStatuses.set(userUuid, status.value)
|
||||
}
|
||||
}
|
||||
|
||||
async removeStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void> {
|
||||
async remove(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void> {
|
||||
if (transitionType === 'items') {
|
||||
this.itemStatuses.delete(userUuid)
|
||||
} else {
|
||||
@@ -42,8 +21,8 @@ export class InMemoryTransitionStatusRepository implements TransitionStatusRepos
|
||||
}
|
||||
}
|
||||
|
||||
async getStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<'STARTED' | 'FAILED' | null> {
|
||||
let status: 'STARTED' | 'FAILED' | null = null
|
||||
async getStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<TransitionStatus | null> {
|
||||
let status: string | null
|
||||
|
||||
if (transitionType === 'items') {
|
||||
status = this.itemStatuses.get(userUuid) ?? null
|
||||
@@ -51,6 +30,10 @@ export class InMemoryTransitionStatusRepository implements TransitionStatusRepos
|
||||
status = this.revisionStatuses.get(userUuid) ?? null
|
||||
}
|
||||
|
||||
return status
|
||||
if (status === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return TransitionStatus.create(status).getValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,38 @@
|
||||
import * as IORedis from 'ioredis'
|
||||
|
||||
import { TransitionStatusRepositoryInterface } from '../../Domain/Transition/TransitionStatusRepositoryInterface'
|
||||
import { TransitionStatus } from '@standardnotes/domain-core'
|
||||
|
||||
export class RedisTransitionStatusRepository implements TransitionStatusRepositoryInterface {
|
||||
private readonly PREFIX = 'transition'
|
||||
|
||||
constructor(private redisClient: IORedis.Redis) {}
|
||||
|
||||
async getStatuses(
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<{ userUuid: string; status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' }[]> {
|
||||
const keys = await this.redisClient.keys(`${this.PREFIX}:${transitionType}:*`)
|
||||
const statuses = await Promise.all(
|
||||
keys.map(async (key) => {
|
||||
const userUuid = key.split(':')[2]
|
||||
const status = (await this.redisClient.get(key)) as 'STARTED' | 'IN_PROGRESS' | 'FAILED'
|
||||
return { userUuid, status }
|
||||
}),
|
||||
)
|
||||
|
||||
return statuses
|
||||
}
|
||||
|
||||
async updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED',
|
||||
): Promise<void> {
|
||||
if (status === 'IN_PROGRESS') {
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, 7_200, status)
|
||||
} else if (status === 'STARTED') {
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, 36_000, status)
|
||||
} else {
|
||||
await this.redisClient.set(`${this.PREFIX}:${transitionType}:${userUuid}`, status)
|
||||
}
|
||||
}
|
||||
|
||||
async removeStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void> {
|
||||
async remove(userUuid: string, transitionType: 'items' | 'revisions'): Promise<void> {
|
||||
await this.redisClient.del(`${this.PREFIX}:${transitionType}:${userUuid}`)
|
||||
}
|
||||
|
||||
async getStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
): Promise<'STARTED' | 'IN_PROGRESS' | 'FAILED' | null> {
|
||||
const status = (await this.redisClient.get(`${this.PREFIX}:${transitionType}:${userUuid}`)) as
|
||||
| 'STARTED'
|
||||
| 'IN_PROGRESS'
|
||||
| 'FAILED'
|
||||
| null
|
||||
async updateStatus(userUuid: string, transitionType: 'items' | 'revisions', status: TransitionStatus): Promise<void> {
|
||||
switch (status.value) {
|
||||
case TransitionStatus.STATUSES.Failed:
|
||||
case TransitionStatus.STATUSES.Verified:
|
||||
await this.redisClient.set(`${this.PREFIX}:${transitionType}:${userUuid}`, status.value)
|
||||
break
|
||||
case TransitionStatus.STATUSES.InProgress: {
|
||||
const ttl2Hourse = 7_200
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, ttl2Hourse, status.value)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status
|
||||
async getStatus(userUuid: string, transitionType: 'items' | 'revisions'): Promise<TransitionStatus | null> {
|
||||
const status = await this.redisClient.get(`${this.PREFIX}:${transitionType}:${userUuid}`)
|
||||
|
||||
if (status === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return TransitionStatus.create(status).getValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.29.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.28.1...@standardnotes/domain-core@1.29.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* refactor transition to minimize status changes ([#828](https://github.com/standardnotes/server/issues/828)) ([36f07c6](https://github.com/standardnotes/server/commit/36f07c691afc213ecf817d6e98f885ddb19a6ed6))
|
||||
|
||||
## [1.28.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-core@1.28.0...@standardnotes/domain-core@1.28.1) (2023-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-core",
|
||||
"version": "1.28.1",
|
||||
"version": "1.29.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Result } from '../Core/Result'
|
||||
import { ValueObject } from '../Core/ValueObject'
|
||||
import { TransitionStatusProps } from './TransitionStatusProps'
|
||||
|
||||
export class TransitionStatus extends ValueObject<TransitionStatusProps> {
|
||||
static readonly STATUSES = {
|
||||
InProgress: 'IN_PROGRESS',
|
||||
Failed: 'FAILED',
|
||||
Verified: 'VERIFIED',
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
return this.props.value
|
||||
}
|
||||
|
||||
private constructor(props: TransitionStatusProps) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static create(name: string): Result<TransitionStatus> {
|
||||
const isValidName = Object.values(this.STATUSES).includes(name)
|
||||
if (!isValidName) {
|
||||
return Result.fail<TransitionStatus>('Invalid transition status name.')
|
||||
} else {
|
||||
return Result.ok<TransitionStatus>(new TransitionStatus({ value: name }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface TransitionStatusProps {
|
||||
value: string
|
||||
}
|
||||
@@ -67,5 +67,8 @@ export * from './SharedVault/SharedVaultUserProps'
|
||||
export * from './Subscription/SubscriptionPlanName'
|
||||
export * from './Subscription/SubscriptionPlanNameProps'
|
||||
|
||||
export * from './Transition/TransitionStatus'
|
||||
export * from './Transition/TransitionStatusProps'
|
||||
|
||||
export * from './UseCase/SyncUseCaseInterface'
|
||||
export * from './UseCase/UseCaseInterface'
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.12.30](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.29...@standardnotes/domain-events-infra@1.12.30) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.29](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.28...@standardnotes/domain-events-infra@1.12.29) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.12.28](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.12.27...@standardnotes/domain-events-infra@1.12.28) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.12.28",
|
||||
"version": "1.12.30",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [2.127.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.126.0...@standardnotes/domain-events@2.127.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* refactor transition to minimize status changes ([#828](https://github.com/standardnotes/server/issues/828)) ([36f07c6](https://github.com/standardnotes/server/commit/36f07c691afc213ecf817d6e98f885ddb19a6ed6))
|
||||
|
||||
# [2.126.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.125.4...@standardnotes/domain-events@2.126.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* add skipping verified transitions ([#827](https://github.com/standardnotes/server/issues/827)) ([d4d4945](https://github.com/standardnotes/server/commit/d4d49454a68de0acdf440dc202fa14b9743905f6))
|
||||
|
||||
## [2.125.4](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.125.3...@standardnotes/domain-events@2.125.4) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.125.4",
|
||||
"version": "2.127.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -2,5 +2,5 @@ export interface TransitionStatusUpdatedEventPayload {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED'
|
||||
status: string
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.11.42](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.41...@standardnotes/event-store@1.11.42) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.41](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.40...@standardnotes/event-store@1.11.41) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.11.40](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.11.39...@standardnotes/event-store@1.11.40) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.11.40",
|
||||
"version": "1.11.42",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.22.21](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.20...@standardnotes/files-server@1.22.21) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.22.20](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.19...@standardnotes/files-server@1.22.20) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.22.19](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.22.18...@standardnotes/files-server@1.22.19) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.22.19",
|
||||
"version": "1.22.21",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.15.58](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.57...@standardnotes/home-server@1.15.58) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.57](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.56...@standardnotes/home-server@1.15.57) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.56](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.55...@standardnotes/home-server@1.15.56) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.55](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.54...@standardnotes/home-server@1.15.55) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
## [1.15.54](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.53...@standardnotes/home-server@1.15.54) (2023-09-14)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/home-server",
|
||||
"version": "1.15.54",
|
||||
"version": "1.15.58",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,24 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.35.0](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.34.1...@standardnotes/revisions-server@1.35.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* refactor transition to minimize status changes ([#828](https://github.com/standardnotes/server/issues/828)) ([36f07c6](https://github.com/standardnotes/server/commit/36f07c691afc213ecf817d6e98f885ddb19a6ed6))
|
||||
|
||||
## [1.34.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.34.0...@standardnotes/revisions-server@1.34.1) (2023-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add debug logs for transition status updates ([3e7856c](https://github.com/standardnotes/server/commit/3e7856c895e73b775c8977c6c6e86dffd5755c00))
|
||||
|
||||
# [1.34.0](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.33.21...@standardnotes/revisions-server@1.34.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* add skipping verified transitions ([#827](https://github.com/standardnotes/server/issues/827)) ([d4d4945](https://github.com/standardnotes/server/commit/d4d49454a68de0acdf440dc202fa14b9743905f6))
|
||||
|
||||
## [1.33.21](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.33.20...@standardnotes/revisions-server@1.33.21) (2023-09-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/revisions-server",
|
||||
"version": "1.33.21",
|
||||
"version": "1.35.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -60,8 +60,6 @@ import { RevisionHttpRepresentation } from '../Mapping/Http/RevisionHttpRepresen
|
||||
import { TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser } from '../Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { DomainEventFactoryInterface } from '../Domain/Event/DomainEventFactoryInterface'
|
||||
import { DomainEventFactory } from '../Domain/Event/DomainEventFactory'
|
||||
import { TransitionStatusUpdatedEventHandler } from '../Domain/Handler/TransitionStatusUpdatedEventHandler'
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from '../Domain/UseCase/Transition/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { SQLRevision } from '../Infra/TypeORM/SQL/SQLRevision'
|
||||
import { SQLRevisionRepository } from '../Infra/TypeORM/SQL/SQLRevisionRepository'
|
||||
import { SQLRevisionMetadataPersistenceMapper } from '../Mapping/Persistence/SQL/SQLRevisionMetadataPersistenceMapper'
|
||||
@@ -354,16 +352,6 @@ export class ContainerConfigLoader {
|
||||
env.get('MIGRATION_BATCH_SIZE', true) ? +env.get('MIGRATION_BATCH_SIZE', true) : 100,
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<TriggerTransitionFromPrimaryToSecondaryDatabaseForUser>(
|
||||
TYPES.Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser,
|
||||
)
|
||||
.toConstantValue(
|
||||
new TriggerTransitionFromPrimaryToSecondaryDatabaseForUser(
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Revisions_DomainEventPublisher),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Revisions_DomainEventFactory),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<RemoveRevisionsFromSharedVault>(TYPES.Revisions_RemoveRevisionsFromSharedVault)
|
||||
.toConstantValue(
|
||||
@@ -439,19 +427,6 @@ export class ContainerConfigLoader {
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<TransitionStatusUpdatedEventHandler>(TYPES.Revisions_TransitionStatusUpdatedEventHandler)
|
||||
.toConstantValue(
|
||||
new TransitionStatusUpdatedEventHandler(
|
||||
container.get<RevisionRepositoryInterface>(TYPES.Revisions_SQLRevisionRepository),
|
||||
container.get<TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser>(
|
||||
TYPES.Revisions_TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser,
|
||||
),
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Revisions_DomainEventPublisher),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Revisions_DomainEventFactory),
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<ItemRemovedFromSharedVaultEventHandler>(TYPES.Revisions_ItemRemovedFromSharedVaultEventHandler)
|
||||
.toConstantValue(
|
||||
@@ -464,9 +439,12 @@ export class ContainerConfigLoader {
|
||||
.bind<TransitionRequestedEventHandler>(TYPES.Revisions_TransitionRequestedEventHandler)
|
||||
.toConstantValue(
|
||||
new TransitionRequestedEventHandler(
|
||||
container.get<TriggerTransitionFromPrimaryToSecondaryDatabaseForUser>(
|
||||
TYPES.Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser,
|
||||
container.get<TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser>(
|
||||
TYPES.Revisions_TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser,
|
||||
),
|
||||
container.get<RevisionRepositoryInterface>(TYPES.Revisions_SQLRevisionRepository),
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Revisions_DomainEventPublisher),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Revisions_DomainEventFactory),
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
@@ -475,7 +453,6 @@ export class ContainerConfigLoader {
|
||||
['ITEM_DUMPED', container.get(TYPES.Revisions_ItemDumpedEventHandler)],
|
||||
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Revisions_AccountDeletionRequestedEventHandler)],
|
||||
['REVISIONS_COPY_REQUESTED', container.get(TYPES.Revisions_RevisionsCopyRequestedEventHandler)],
|
||||
['TRANSITION_STATUS_UPDATED', container.get(TYPES.Revisions_TransitionStatusUpdatedEventHandler)],
|
||||
['ITEM_REMOVED_FROM_SHARED_VAULT', container.get(TYPES.Revisions_ItemRemovedFromSharedVaultEventHandler)],
|
||||
['TRANSITION_REQUESTED', container.get(TYPES.Revisions_TransitionRequestedEventHandler)],
|
||||
])
|
||||
|
||||
@@ -46,9 +46,6 @@ const TYPES = {
|
||||
Revisions_TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser: Symbol.for(
|
||||
'Revisions_TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser',
|
||||
),
|
||||
Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser: Symbol.for(
|
||||
'Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser',
|
||||
),
|
||||
Revisions_RemoveRevisionsFromSharedVault: Symbol.for('Revisions_RemoveRevisionsFromSharedVault'),
|
||||
// Controller
|
||||
Revisions_ControllerContainer: Symbol.for('Revisions_ControllerContainer'),
|
||||
@@ -58,7 +55,6 @@ const TYPES = {
|
||||
Revisions_ItemDumpedEventHandler: Symbol.for('Revisions_ItemDumpedEventHandler'),
|
||||
Revisions_AccountDeletionRequestedEventHandler: Symbol.for('Revisions_AccountDeletionRequestedEventHandler'),
|
||||
Revisions_RevisionsCopyRequestedEventHandler: Symbol.for('Revisions_RevisionsCopyRequestedEventHandler'),
|
||||
Revisions_TransitionStatusUpdatedEventHandler: Symbol.for('Revisions_TransitionStatusUpdatedEventHandler'),
|
||||
Revisions_ItemRemovedFromSharedVaultEventHandler: Symbol.for('Revisions_ItemRemovedFromSharedVaultEventHandler'),
|
||||
Revisions_TransitionRequestedEventHandler: Symbol.for('Revisions_TransitionRequestedEventHandler'),
|
||||
// Services
|
||||
|
||||
@@ -10,7 +10,7 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'FAILED' | 'FINISHED'
|
||||
status: string
|
||||
}): TransitionStatusUpdatedEvent {
|
||||
return {
|
||||
type: 'TRANSITION_STATUS_UPDATED',
|
||||
@@ -20,7 +20,7 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
userIdentifier: dto.userUuid,
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: DomainEventService.SyncingServer,
|
||||
origin: DomainEventService.Revisions,
|
||||
},
|
||||
payload: dto,
|
||||
}
|
||||
|
||||
@@ -5,6 +5,6 @@ export interface DomainEventFactoryInterface {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' | 'FINISHED'
|
||||
status: string
|
||||
}): TransitionStatusUpdatedEvent
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
import { DomainEventHandlerInterface, TransitionRequestedEvent } from '@standardnotes/domain-events'
|
||||
import {
|
||||
DomainEventHandlerInterface,
|
||||
DomainEventPublisherInterface,
|
||||
TransitionRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
||||
import { RevisionRepositoryInterface } from '../Revision/RevisionRepositoryInterface'
|
||||
import { TransitionStatus, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
export class TransitionRequestedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private triggerTransitionFromPrimaryToSecondaryDatabaseForUser: TriggerTransitionFromPrimaryToSecondaryDatabaseForUser,
|
||||
private transitionRevisionsFromPrimaryToSecondaryDatabaseForUser: TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser,
|
||||
private primaryRevisionsRepository: RevisionRepositoryInterface,
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
@@ -14,15 +23,96 @@ export class TransitionRequestedEventHandler implements DomainEventHandlerInterf
|
||||
return
|
||||
}
|
||||
|
||||
const userUuid = await this.getUserUuidFromEvent(event)
|
||||
if (!userUuid) {
|
||||
return
|
||||
}
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuid)) {
|
||||
this.logger.info(`User ${event.payload.userUuid} already migrated.`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Verified,
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.logger.info(`Handling transition requested event for user ${event.payload.userUuid}`)
|
||||
|
||||
const result = await this.triggerTransitionFromPrimaryToSecondaryDatabaseForUser.execute({
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.InProgress,
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
const result = await this.transitionRevisionsFromPrimaryToSecondaryDatabaseForUser.execute({
|
||||
userUuid: event.payload.userUuid,
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to trigger transition for user ${event.payload.userUuid}`)
|
||||
this.logger.error(`Failed to transition for user ${event.payload.userUuid}`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Failed,
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Verified,
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: Uuid): Promise<boolean> {
|
||||
const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
|
||||
|
||||
if (totalRevisionsCountForUserInPrimary > 0) {
|
||||
this.logger.info(
|
||||
`User ${userUuid.value} has ${totalRevisionsCountForUserInPrimary} revisions in primary database.`,
|
||||
)
|
||||
}
|
||||
|
||||
return totalRevisionsCountForUserInPrimary === 0
|
||||
}
|
||||
|
||||
private async getUserUuidFromEvent(event: TransitionRequestedEvent): Promise<Uuid | null> {
|
||||
const userUuidOrError = Uuid.create(event.payload.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
this.logger.error(
|
||||
`Failed to transition revisions for user ${event.payload.userUuid}: ${userUuidOrError.getError()}`,
|
||||
)
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Failed,
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return userUuidOrError.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
import {
|
||||
DomainEventHandlerInterface,
|
||||
DomainEventPublisherInterface,
|
||||
TransitionStatusUpdatedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { Logger } from 'winston'
|
||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
||||
import { TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
import { RevisionRepositoryInterface } from '../Revision/RevisionRepositoryInterface'
|
||||
|
||||
export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private primaryRevisionsRepository: RevisionRepositoryInterface,
|
||||
private transitionRevisionsFromPrimaryToSecondaryDatabaseForUser: TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser,
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async handle(event: TransitionStatusUpdatedEvent): Promise<void> {
|
||||
if (event.payload.status === 'STARTED' && event.payload.transitionType === 'items') {
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'STARTED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (event.payload.status === 'STARTED' && event.payload.transitionType === 'revisions') {
|
||||
const userUuidOrError = Uuid.create(event.payload.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
this.logger.error(
|
||||
`Failed to transition revisions for user ${event.payload.userUuid}: ${userUuidOrError.getError()}`,
|
||||
)
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'FAILED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuidOrError.getValue())) {
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'FINISHED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'IN_PROGRESS',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
const result = await this.transitionRevisionsFromPrimaryToSecondaryDatabaseForUser.execute({
|
||||
userUuid: event.payload.userUuid,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to transition revisions for user ${event.payload.userUuid}: ${result.getError()}`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'FAILED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'FINISHED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: Uuid): Promise<boolean> {
|
||||
const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
|
||||
|
||||
if (totalRevisionsCountForUserInPrimary > 0) {
|
||||
this.logger.info(
|
||||
`User ${userUuid.value} has ${totalRevisionsCountForUserInPrimary} revisions in primary database.`,
|
||||
)
|
||||
}
|
||||
|
||||
return totalRevisionsCountForUserInPrimary === 0
|
||||
}
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from './TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
|
||||
|
||||
describe('TriggerTransitionFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
let domainEventPubliser: DomainEventPublisherInterface
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
|
||||
const createUseCase = () =>
|
||||
new TriggerTransitionFromPrimaryToSecondaryDatabaseForUser(domainEventPubliser, domainEventFactory)
|
||||
|
||||
beforeEach(() => {
|
||||
domainEventPubliser = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||
domainEventPubliser.publish = jest.fn()
|
||||
|
||||
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
||||
domainEventFactory.createTransitionStatusUpdatedEvent = jest.fn()
|
||||
})
|
||||
|
||||
it('should publish transition status updated event', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(domainEventPubliser.publish).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO } from './TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO'
|
||||
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
|
||||
|
||||
export class TriggerTransitionFromPrimaryToSecondaryDatabaseForUser implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private domainEventPubliser: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO): Promise<Result<void>> {
|
||||
const event = this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: dto.userUuid,
|
||||
status: 'STARTED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: dto.transitionTimestamp,
|
||||
})
|
||||
|
||||
await this.domainEventPubliser.publish(event)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
export interface TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO {
|
||||
userUuid: string
|
||||
transitionTimestamp: number
|
||||
}
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.20.46](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.45...@standardnotes/scheduler-server@1.20.46) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.20.45](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.44...@standardnotes/scheduler-server@1.20.45) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.20.44](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.20.43...@standardnotes/scheduler-server@1.20.44) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.20.44",
|
||||
"version": "1.20.46",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -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.32](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.31...@standardnotes/settings@1.21.32) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/settings
|
||||
|
||||
## [1.21.31](https://github.com/standardnotes/server/compare/@standardnotes/settings@1.21.30...@standardnotes/settings@1.21.31) (2023-09-12)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/settings
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/settings",
|
||||
"version": "1.21.31",
|
||||
"version": "1.21.32",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -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.97.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.96.1...@standardnotes/syncing-server@1.97.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* refactor transition to minimize status changes ([#828](https://github.com/standardnotes/syncing-server-js/issues/828)) ([36f07c6](https://github.com/standardnotes/syncing-server-js/commit/36f07c691afc213ecf817d6e98f885ddb19a6ed6))
|
||||
|
||||
## [1.96.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.96.0...@standardnotes/syncing-server@1.96.1) (2023-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add debug logs for transition status updates ([3e7856c](https://github.com/standardnotes/syncing-server-js/commit/3e7856c895e73b775c8977c6c6e86dffd5755c00))
|
||||
|
||||
# [1.96.0](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.95.19...@standardnotes/syncing-server@1.96.0) (2023-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* add skipping verified transitions ([#827](https://github.com/standardnotes/syncing-server-js/issues/827)) ([d4d4945](https://github.com/standardnotes/syncing-server-js/commit/d4d49454a68de0acdf440dc202fa14b9743905f6))
|
||||
|
||||
## [1.95.19](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.95.18...@standardnotes/syncing-server@1.95.19) (2023-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** remove unused index in mongodb ([9147ff5](https://github.com/standardnotes/syncing-server-js/commit/9147ff5d49c507d943f4f8c6775f7c1fff878b0f))
|
||||
|
||||
## [1.95.18](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.95.17...@standardnotes/syncing-server@1.95.18) (2023-09-14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from '../src/Domain/UseCase/Transition/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
const inputArgs = process.argv.slice(2)
|
||||
const userUuid = inputArgs[0]
|
||||
|
||||
const requestTransition = async (
|
||||
triggerTransitionFromPrimaryToSecondaryDatabaseForUser: TriggerTransitionFromPrimaryToSecondaryDatabaseForUser,
|
||||
timer: TimerInterface,
|
||||
logger: Logger,
|
||||
): Promise<void> => {
|
||||
const result = await triggerTransitionFromPrimaryToSecondaryDatabaseForUser.execute({
|
||||
userUuid,
|
||||
transitionTimestamp: timer.getTimestampInMicroseconds(),
|
||||
})
|
||||
if (result.isFailed()) {
|
||||
logger.error(`Could not trigger transition for user ${userUuid}: ${result.getError()}`)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const container = new ContainerConfigLoader('worker')
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const logger: Logger = container.get(TYPES.Sync_Logger)
|
||||
|
||||
logger.info(`Starting transitiong for user ${userUuid} ...`)
|
||||
|
||||
const triggerTransitionFromPrimaryToSecondaryDatabaseForUser: TriggerTransitionFromPrimaryToSecondaryDatabaseForUser =
|
||||
container.get(TYPES.Sync_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser)
|
||||
const timer = container.get<TimerInterface>(TYPES.Sync_Timer)
|
||||
|
||||
Promise.resolve(requestTransition(triggerTransitionFromPrimaryToSecondaryDatabaseForUser, timer, logger))
|
||||
.then(() => {
|
||||
logger.info(`Transition triggered for user ${userUuid}`)
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`Could not trigger transition for user ${userUuid}: ${error.message}`)
|
||||
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
|
||||
|
||||
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/transition.js')))
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
|
||||
exports.default = index
|
||||
@@ -14,12 +14,6 @@ case "$COMMAND" in
|
||||
node docker/entrypoint-worker.js
|
||||
;;
|
||||
|
||||
'transition' )
|
||||
echo "[Docker] Starting transition Single User..."
|
||||
USER_UUID=$1 && shift 1
|
||||
node docker/entrypoint-transition.js $USER_UUID
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "[Docker] Unknown command"
|
||||
;;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.95.18",
|
||||
"version": "1.97.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -160,8 +160,6 @@ import { ItemRepositoryResolverInterface } from '../Domain/Item/ItemRepositoryRe
|
||||
import { TypeORMItemRepositoryResolver } from '../Infra/TypeORM/TypeORMItemRepositoryResolver'
|
||||
import { TransitionItemsFromPrimaryToSecondaryDatabaseForUser } from '../Domain/UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { SharedVaultFileMovedEventHandler } from '../Domain/Handler/SharedVaultFileMovedEventHandler'
|
||||
import { TransitionStatusUpdatedEventHandler } from '../Domain/Handler/TransitionStatusUpdatedEventHandler'
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from '../Domain/UseCase/Transition/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { SQLItem } from '../Infra/TypeORM/SQLItem'
|
||||
import { SQLItemPersistenceMapper } from '../Mapping/Persistence/SQLItemPersistenceMapper'
|
||||
import { SQLItemRepository } from '../Infra/TypeORM/SQLItemRepository'
|
||||
@@ -837,16 +835,6 @@ export class ContainerConfigLoader {
|
||||
env.get('MIGRATION_BATCH_SIZE', true) ? +env.get('MIGRATION_BATCH_SIZE', true) : 100,
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<TriggerTransitionFromPrimaryToSecondaryDatabaseForUser>(
|
||||
TYPES.Sync_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser,
|
||||
)
|
||||
.toConstantValue(
|
||||
new TriggerTransitionFromPrimaryToSecondaryDatabaseForUser(
|
||||
container.get<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher),
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory),
|
||||
),
|
||||
)
|
||||
|
||||
// Services
|
||||
container
|
||||
@@ -949,9 +937,9 @@ export class ContainerConfigLoader {
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<TransitionStatusUpdatedEventHandler>(TYPES.Sync_TransitionStatusUpdatedEventHandler)
|
||||
.bind<TransitionRequestedEventHandler>(TYPES.Sync_TransitionRequestedEventHandler)
|
||||
.toConstantValue(
|
||||
new TransitionStatusUpdatedEventHandler(
|
||||
new TransitionRequestedEventHandler(
|
||||
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
|
||||
container.get<TransitionItemsFromPrimaryToSecondaryDatabaseForUser>(
|
||||
TYPES.Sync_TransitionItemsFromPrimaryToSecondaryDatabaseForUser,
|
||||
@@ -961,16 +949,6 @@ export class ContainerConfigLoader {
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<TransitionRequestedEventHandler>(TYPES.Sync_TransitionRequestedEventHandler)
|
||||
.toConstantValue(
|
||||
new TransitionRequestedEventHandler(
|
||||
container.get<TriggerTransitionFromPrimaryToSecondaryDatabaseForUser>(
|
||||
TYPES.Sync_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser,
|
||||
),
|
||||
container.get<Logger>(TYPES.Sync_Logger),
|
||||
),
|
||||
)
|
||||
|
||||
// Services
|
||||
container.bind<ContentDecoder>(TYPES.Sync_ContentDecoder).toDynamicValue(() => new ContentDecoder())
|
||||
@@ -1005,10 +983,6 @@ export class ContainerConfigLoader {
|
||||
'SHARED_VAULT_FILE_MOVED',
|
||||
container.get<SharedVaultFileMovedEventHandler>(TYPES.Sync_SharedVaultFileMovedEventHandler),
|
||||
],
|
||||
[
|
||||
'TRANSITION_STATUS_UPDATED',
|
||||
container.get<TransitionStatusUpdatedEventHandler>(TYPES.Sync_TransitionStatusUpdatedEventHandler),
|
||||
],
|
||||
[
|
||||
'TRANSITION_REQUESTED',
|
||||
container.get<TransitionRequestedEventHandler>(TYPES.Sync_TransitionRequestedEventHandler),
|
||||
|
||||
@@ -84,9 +84,6 @@ const TYPES = {
|
||||
Sync_TransitionItemsFromPrimaryToSecondaryDatabaseForUser: Symbol.for(
|
||||
'Sync_TransitionItemsFromPrimaryToSecondaryDatabaseForUser',
|
||||
),
|
||||
Sync_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser: Symbol.for(
|
||||
'Sync_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser',
|
||||
),
|
||||
Sync_SendEventToClient: Symbol.for('Sync_SendEventToClient'),
|
||||
// Handlers
|
||||
Sync_AccountDeletionRequestedEventHandler: Symbol.for('Sync_AccountDeletionRequestedEventHandler'),
|
||||
@@ -96,7 +93,6 @@ const TYPES = {
|
||||
Sync_SharedVaultFileRemovedEventHandler: Symbol.for('Sync_SharedVaultFileRemovedEventHandler'),
|
||||
Sync_SharedVaultFileUploadedEventHandler: Symbol.for('Sync_SharedVaultFileUploadedEventHandler'),
|
||||
Sync_SharedVaultFileMovedEventHandler: Symbol.for('Sync_SharedVaultFileMovedEventHandler'),
|
||||
Sync_TransitionStatusUpdatedEventHandler: Symbol.for('Sync_TransitionStatusUpdatedEventHandler'),
|
||||
Sync_TransitionRequestedEventHandler: Symbol.for('Sync_TransitionRequestedEventHandler'),
|
||||
// Services
|
||||
Sync_ContentDecoder: Symbol.for('Sync_ContentDecoder'),
|
||||
|
||||
@@ -173,7 +173,7 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'FAILED' | 'FINISHED'
|
||||
status: string
|
||||
}): TransitionStatusUpdatedEvent {
|
||||
return {
|
||||
type: 'TRANSITION_STATUS_UPDATED',
|
||||
|
||||
@@ -53,7 +53,7 @@ export interface DomainEventFactoryInterface {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' | 'FINISHED'
|
||||
status: string
|
||||
}): TransitionStatusUpdatedEvent
|
||||
createEmailRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import { DomainEventHandlerInterface, TransitionRequestedEvent } from '@standardnotes/domain-events'
|
||||
import {
|
||||
DomainEventHandlerInterface,
|
||||
DomainEventPublisherInterface,
|
||||
TransitionRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { Logger } from 'winston'
|
||||
import { TransitionStatus, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser/TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { TransitionItemsFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { ItemRepositoryInterface } from '../Item/ItemRepositoryInterface'
|
||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
||||
|
||||
export class TransitionRequestedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private triggerTransitionFromPrimaryToSecondaryDatabaseForUser: TriggerTransitionFromPrimaryToSecondaryDatabaseForUser,
|
||||
private primaryItemRepository: ItemRepositoryInterface,
|
||||
private transitionItemsFromPrimaryToSecondaryDatabaseForUser: TransitionItemsFromPrimaryToSecondaryDatabaseForUser,
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
@@ -14,15 +24,95 @@ export class TransitionRequestedEventHandler implements DomainEventHandlerInterf
|
||||
return
|
||||
}
|
||||
|
||||
const userUuid = await this.getUserUuidFromEvent(event)
|
||||
if (!userUuid) {
|
||||
return
|
||||
}
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuid)) {
|
||||
this.logger.info(`User ${event.payload.userUuid} already migrated.`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Verified,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.logger.info(`Handling transition requested event for user ${event.payload.userUuid}`)
|
||||
|
||||
const result = await this.triggerTransitionFromPrimaryToSecondaryDatabaseForUser.execute({
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.InProgress,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
const result = await this.transitionItemsFromPrimaryToSecondaryDatabaseForUser.execute({
|
||||
userUuid: event.payload.userUuid,
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to trigger transition for user ${event.payload.userUuid}`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Failed,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Verified,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: Uuid): Promise<boolean> {
|
||||
const totalItemsCountForUserInPrimary = await this.primaryItemRepository.countAll({
|
||||
userUuid: userUuid.value,
|
||||
})
|
||||
|
||||
if (totalItemsCountForUserInPrimary > 0) {
|
||||
this.logger.info(`User ${userUuid.value} has ${totalItemsCountForUserInPrimary} items in primary database.`)
|
||||
}
|
||||
|
||||
return totalItemsCountForUserInPrimary === 0
|
||||
}
|
||||
|
||||
private async getUserUuidFromEvent(event: TransitionRequestedEvent): Promise<Uuid | null> {
|
||||
const userUuidOrError = Uuid.create(event.payload.userUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
this.logger.error(`Failed to transition items for user ${event.payload.userUuid}: ${userUuidOrError.getError()}`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: TransitionStatus.STATUSES.Failed,
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.timestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return userUuidOrError.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import {
|
||||
DomainEventHandlerInterface,
|
||||
DomainEventPublisherInterface,
|
||||
TransitionStatusUpdatedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { Logger } from 'winston'
|
||||
import { TransitionItemsFromPrimaryToSecondaryDatabaseForUser } from '../UseCase/Transition/TransitionItemsFromPrimaryToSecondaryDatabaseForUser/TransitionItemsFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
|
||||
import { ItemRepositoryInterface } from '../Item/ItemRepositoryInterface'
|
||||
|
||||
export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private primaryItemRepository: ItemRepositoryInterface,
|
||||
private transitionItemsFromPrimaryToSecondaryDatabaseForUser: TransitionItemsFromPrimaryToSecondaryDatabaseForUser,
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async handle(event: TransitionStatusUpdatedEvent): Promise<void> {
|
||||
if (event.payload.status === 'STARTED' && event.payload.transitionType === 'items') {
|
||||
if (await this.isAlreadyMigrated(event.payload.userUuid)) {
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'FINISHED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'IN_PROGRESS',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
const result = await this.transitionItemsFromPrimaryToSecondaryDatabaseForUser.execute({
|
||||
userUuid: event.payload.userUuid,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to transition items for user ${event.payload.userUuid}: ${result.getError()}`)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'FAILED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'FINISHED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: string): Promise<boolean> {
|
||||
const totalItemsCountForUser = await this.primaryItemRepository.countAll({ userUuid })
|
||||
|
||||
if (totalItemsCountForUser > 0) {
|
||||
this.logger.info(`User ${userUuid} has ${totalItemsCountForUser} items in primary database.`)
|
||||
}
|
||||
|
||||
return totalItemsCountForUser === 0
|
||||
}
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUser } from './TriggerTransitionFromPrimaryToSecondaryDatabaseForUser'
|
||||
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
|
||||
|
||||
describe('TriggerTransitionFromPrimaryToSecondaryDatabaseForUser', () => {
|
||||
let domainEventPubliser: DomainEventPublisherInterface
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
|
||||
const createUseCase = () =>
|
||||
new TriggerTransitionFromPrimaryToSecondaryDatabaseForUser(domainEventPubliser, domainEventFactory)
|
||||
|
||||
beforeEach(() => {
|
||||
domainEventPubliser = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||
domainEventPubliser.publish = jest.fn()
|
||||
|
||||
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
||||
domainEventFactory.createTransitionStatusUpdatedEvent = jest.fn()
|
||||
})
|
||||
|
||||
it('should publish transition status updated event', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
await useCase.execute({
|
||||
userUuid: '00000000-0000-0000-0000-000000000000',
|
||||
transitionTimestamp: 123,
|
||||
})
|
||||
|
||||
expect(domainEventPubliser.publish).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
|
||||
import { TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO } from './TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO'
|
||||
import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
|
||||
|
||||
export class TriggerTransitionFromPrimaryToSecondaryDatabaseForUser implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private domainEventPubliser: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO): Promise<Result<void>> {
|
||||
const event = this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: dto.userUuid,
|
||||
status: 'STARTED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: dto.transitionTimestamp,
|
||||
})
|
||||
|
||||
await this.domainEventPubliser.publish(event)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
export interface TriggerTransitionFromPrimaryToSecondaryDatabaseForUserDTO {
|
||||
userUuid: string
|
||||
transitionTimestamp: number
|
||||
}
|
||||
@@ -18,7 +18,6 @@ export class MongoDBItem {
|
||||
declare content: string | null
|
||||
|
||||
@Column()
|
||||
@Index('index_items_on_content_type')
|
||||
declare contentType: string | null
|
||||
|
||||
@Column()
|
||||
|
||||
@@ -89,7 +89,9 @@ export class SQLLegacyItemRepository implements ItemRepositoryInterface {
|
||||
|
||||
return item
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to find item ${uuid.value} by uuid: ${(error as Error).message}`)
|
||||
this.logger.error(
|
||||
`Failed to map item ${uuid.value} for user ${persistence.userUuid} by uuid: ${(error as Error).message}`,
|
||||
)
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -137,7 +139,9 @@ export class SQLLegacyItemRepository implements ItemRepositoryInterface {
|
||||
|
||||
return item
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to find item ${uuid} by uuid and userUuid: ${(error as Error).message}`)
|
||||
this.logger.error(
|
||||
`Failed to map item ${uuid} for user ${persistence.userUuid} by uuid and userUuid: ${(error as Error).message}`,
|
||||
)
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -151,7 +155,11 @@ export class SQLLegacyItemRepository implements ItemRepositoryInterface {
|
||||
try {
|
||||
domainItems.push(this.mapper.toDomain(persistencItem))
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to map item ${persistencItem.uuid} to domain: ${(error as Error).message}`)
|
||||
this.logger.error(
|
||||
`Failed to map item ${persistencItem.uuid} for user ${persistencItem.userUuid} to domain: ${
|
||||
(error as Error).message
|
||||
}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.43](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.42...@standardnotes/websockets-server@1.10.43) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
## [1.10.42](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.41...@standardnotes/websockets-server@1.10.42) (2023-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
## [1.10.41](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.10.40...@standardnotes/websockets-server@1.10.41) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/websockets-server",
|
||||
"version": "1.10.41",
|
||||
"version": "1.10.43",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -2659,10 +2659,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@hexagon/base64@npm:^1.1.25":
|
||||
version: 1.1.26
|
||||
resolution: "@hexagon/base64@npm:1.1.26"
|
||||
checksum: e42582ed12465bffaf96307c9d5b7dfd36166ec4dc41a1838b9a560c90c9d136d006099a205e1684fb0dc18002cc5af51a49dd7b81a7c4b86798372d6ee26af3
|
||||
"@hexagon/base64@npm:^1.1.27":
|
||||
version: 1.1.27
|
||||
resolution: "@hexagon/base64@npm:1.1.27"
|
||||
checksum: 899fffaf54b291e1df997bf33dbf6e068fcfbd83155adc114e14bcb9c1e36c5f820dfaaee3d0c2409f7e84efa4352f51655eac8bec4c2432fca443bf179bce8d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -3793,7 +3793,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@peculiar/asn1-android@npm:^2.3.3":
|
||||
"@peculiar/asn1-android@npm:^2.3.6":
|
||||
version: 2.3.6
|
||||
resolution: "@peculiar/asn1-android@npm:2.3.6"
|
||||
dependencies:
|
||||
@@ -3804,7 +3804,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@peculiar/asn1-ecc@npm:^2.3.4":
|
||||
"@peculiar/asn1-ecc@npm:^2.3.6":
|
||||
version: 2.3.6
|
||||
resolution: "@peculiar/asn1-ecc@npm:2.3.6"
|
||||
dependencies:
|
||||
@@ -3816,7 +3816,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@peculiar/asn1-rsa@npm:^2.3.4":
|
||||
"@peculiar/asn1-rsa@npm:^2.3.6":
|
||||
version: 2.3.6
|
||||
resolution: "@peculiar/asn1-rsa@npm:2.3.6"
|
||||
dependencies:
|
||||
@@ -3828,7 +3828,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@peculiar/asn1-schema@npm:^2.3.3, @peculiar/asn1-schema@npm:^2.3.6":
|
||||
"@peculiar/asn1-schema@npm:^2.3.6":
|
||||
version: 2.3.6
|
||||
resolution: "@peculiar/asn1-schema@npm:2.3.6"
|
||||
dependencies:
|
||||
@@ -3839,7 +3839,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@peculiar/asn1-x509@npm:^2.3.4, @peculiar/asn1-x509@npm:^2.3.6":
|
||||
"@peculiar/asn1-x509@npm:^2.3.6":
|
||||
version: 2.3.6
|
||||
resolution: "@peculiar/asn1-x509@npm:2.3.6"
|
||||
dependencies:
|
||||
@@ -3987,41 +3987,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@simplewebauthn/iso-webcrypto@npm:^7.2.0":
|
||||
version: 7.2.0
|
||||
resolution: "@simplewebauthn/iso-webcrypto@npm:7.2.0"
|
||||
"@simplewebauthn/server@npm:^8.1.1":
|
||||
version: 8.1.1
|
||||
resolution: "@simplewebauthn/server@npm:8.1.1"
|
||||
dependencies:
|
||||
"@simplewebauthn/typescript-types": "npm:*"
|
||||
"@types/node": "npm:^18.11.9"
|
||||
checksum: b57899d0ada391507ce8f4601328ed62df5d09f75f6e91b018278631270a96f37ceab95f9e824c9555dd05820e5a99ac386ed067db7902d37bdb6d995fbd7eaf
|
||||
"@hexagon/base64": "npm:^1.1.27"
|
||||
"@peculiar/asn1-android": "npm:^2.3.6"
|
||||
"@peculiar/asn1-ecc": "npm:^2.3.6"
|
||||
"@peculiar/asn1-rsa": "npm:^2.3.6"
|
||||
"@peculiar/asn1-schema": "npm:^2.3.6"
|
||||
"@peculiar/asn1-x509": "npm:^2.3.6"
|
||||
"@simplewebauthn/typescript-types": "npm:^8.0.0"
|
||||
cbor-x: "npm:^1.5.2"
|
||||
cross-fetch: "npm:^4.0.0"
|
||||
checksum: a07c2a067b25b7f4afe215dcf81e0280aa5c382f5eb3cb1ef9327c6dc84c9618ed5774fc61bbc5717b8633dd5b8b4c41c7800cb32e83c6a4b1d2d1e1e50f5250
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@simplewebauthn/server@npm:^7.2.0":
|
||||
version: 7.2.0
|
||||
resolution: "@simplewebauthn/server@npm:7.2.0"
|
||||
dependencies:
|
||||
"@hexagon/base64": "npm:^1.1.25"
|
||||
"@peculiar/asn1-android": "npm:^2.3.3"
|
||||
"@peculiar/asn1-ecc": "npm:^2.3.4"
|
||||
"@peculiar/asn1-rsa": "npm:^2.3.4"
|
||||
"@peculiar/asn1-schema": "npm:^2.3.3"
|
||||
"@peculiar/asn1-x509": "npm:^2.3.4"
|
||||
"@simplewebauthn/iso-webcrypto": "npm:^7.2.0"
|
||||
"@simplewebauthn/typescript-types": "npm:*"
|
||||
"@types/debug": "npm:^4.1.7"
|
||||
"@types/node": "npm:^18.11.9"
|
||||
cbor-x: "npm:^1.4.1"
|
||||
cross-fetch: "npm:^3.1.5"
|
||||
debug: "npm:^4.3.2"
|
||||
checksum: 2e37c87edd05abace8ba8c5b1f4e2cb4adb9ec4dcf0b237d25f375f35538d25e31cc0ae196029006cf5124c983216a3cf69127732942863d2960bd72ed5783c4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@simplewebauthn/typescript-types@npm:*, @simplewebauthn/typescript-types@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "@simplewebauthn/typescript-types@npm:7.0.0"
|
||||
checksum: 124238ea1859c80761c4cdbf19107e2e8e96fdefa64affb55fb4fc67d1ac5e3354c3098c908729d2de439a633115d98da77ded7289286fe576559306fa933815
|
||||
"@simplewebauthn/typescript-types@npm:^8.0.0":
|
||||
version: 8.0.0
|
||||
resolution: "@simplewebauthn/typescript-types@npm:8.0.0"
|
||||
checksum: 21e0b13268f237d7cd6ecdc6cdceb884ddcc85e18a3554b65d10da4f502056aefa810db94f504beaad96b4ac0c7861a022954dcc6aa8721d4215571c2c3dcdf5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4744,8 +4730,8 @@ __metadata:
|
||||
"@cbor-extract/cbor-extract-linux-arm64": "npm:^2.1.1"
|
||||
"@cbor-extract/cbor-extract-linux-x64": "npm:^2.1.1"
|
||||
"@newrelic/winston-enricher": "npm:^4.0.1"
|
||||
"@simplewebauthn/server": "npm:^7.2.0"
|
||||
"@simplewebauthn/typescript-types": "npm:^7.0.0"
|
||||
"@simplewebauthn/server": "npm:^8.1.1"
|
||||
"@simplewebauthn/typescript-types": "npm:^8.0.0"
|
||||
"@standardnotes/api": "npm:^1.26.26"
|
||||
"@standardnotes/common": "workspace:*"
|
||||
"@standardnotes/domain-core": "workspace:^"
|
||||
@@ -5589,15 +5575,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/debug@npm:^4.1.7":
|
||||
version: 4.1.8
|
||||
resolution: "@types/debug@npm:4.1.8"
|
||||
dependencies:
|
||||
"@types/ms": "npm:*"
|
||||
checksum: 9c190e812984e0f6e02dfdfb0c7a3081a55cf3fc712a4e059336bd9f8329db70211eb851ce409311520876549cff2c4785ce48dd4c9fef8e48549c87bec29ded
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/dotenv@npm:^8.2.0":
|
||||
version: 8.2.0
|
||||
resolution: "@types/dotenv@npm:8.2.0"
|
||||
@@ -5792,13 +5769,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/ms@npm:*":
|
||||
version: 0.7.31
|
||||
resolution: "@types/ms@npm:0.7.31"
|
||||
checksum: cccb52777bb683c65ac5bab61351cd3910c9ce3512b1d903a591fc9694bb83afad6e48bf0beee5b47b6a8b620a05f5d82f8febfd55de05e7d9eb93586cc196c8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/newrelic@npm:^9.14.0":
|
||||
version: 9.14.0
|
||||
resolution: "@types/newrelic@npm:9.14.0"
|
||||
@@ -5820,13 +5790,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^18.11.9":
|
||||
version: 18.16.16
|
||||
resolution: "@types/node@npm:18.16.16"
|
||||
checksum: 946bd4d8e6fa54220e4193bc594de8a2e138e6afebb6efb7d862d98e30ced25a19476a6f47c81e690b9ac77f616f64217e0bcf4811916ccd9b5935e5bea0e4a0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^20.5.7":
|
||||
version: 20.5.7
|
||||
resolution: "@types/node@npm:20.5.7"
|
||||
@@ -7208,15 +7171,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cbor-x@npm:^1.4.1":
|
||||
version: 1.5.3
|
||||
resolution: "cbor-x@npm:1.5.3"
|
||||
"cbor-x@npm:^1.5.2":
|
||||
version: 1.5.4
|
||||
resolution: "cbor-x@npm:1.5.4"
|
||||
dependencies:
|
||||
cbor-extract: "npm:^2.1.1"
|
||||
dependenciesMeta:
|
||||
cbor-extract:
|
||||
optional: true
|
||||
checksum: d4df85b33969826f4c96a4b4a8fbe03132fb0817fba876f16d41ad6d1a7d2668ec04c923f313220506029cc2b5ab212901ba24b4594d0115e0f527ef31506fbf
|
||||
checksum: 742aea498abfe004a7ff4db2a1c0e00d9e9c1d89db4ad9aa94a9b886cd2ce10a133f20e32788c83696eef368e18c2b5bc82e4b1480c5af91937816a5630989d6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7848,12 +7811,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-fetch@npm:^3.1.5":
|
||||
version: 3.1.6
|
||||
resolution: "cross-fetch@npm:3.1.6"
|
||||
"cross-fetch@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "cross-fetch@npm:4.0.0"
|
||||
dependencies:
|
||||
node-fetch: "npm:^2.6.11"
|
||||
checksum: a8989fca821cae97520976d00f85ce7c3ab8af7e00cc06c94fd94c49ada6847f4cdeabca8e0ebd4aa6c7343f70bea7e0c64d5910b846aab218136a450585aa61
|
||||
node-fetch: "npm:^2.6.12"
|
||||
checksum: 30e86b703a455baca17b7f2088fdd88b71193b39e7cb61f3385511dc6064b7741c816329c0abff8a74d306969455c8797131d056518a981fd4d2424ecd4ab451
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -12007,7 +11970,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-fetch@npm:^2.6.11, node-fetch@npm:^2.6.7":
|
||||
"node-fetch@npm:^2.6.12":
|
||||
version: 2.7.0
|
||||
resolution: "node-fetch@npm:2.7.0"
|
||||
dependencies:
|
||||
whatwg-url: "npm:^5.0.0"
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
checksum: a3ad7889038bf6c49046272515d4f0e3167088b40fd37e1cc6eeea745f5a68cec798d55ac3210e2bc51891cb745e3dc30a734cc5f4b4df764f45886881b198b1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-fetch@npm:^2.6.7":
|
||||
version: 2.6.11
|
||||
resolution: "node-fetch@npm:2.6.11"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user