mirror of
https://github.com/standardnotes/server
synced 2026-04-28 00:01:24 -04:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6778a80f21 | |||
| d4d49454a6 | |||
| 04b52e6773 | |||
| 2a1859e4be | |||
| dd9a9c68cb | |||
| 9147ff5d49 | |||
| 503b84531b | |||
| fe8ca828fb | |||
| 03a4a3f2ab | |||
| 3a8607d146 |
@@ -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,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [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.13",
|
||||
"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.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.11",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [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
|
||||
|
||||
* **auth:** set ttl for started and not picked up transitions to 10h ([fe8ca82](https://github.com/standardnotes/server/commit/fe8ca828fb37306e0e5056627e67366885e86861))
|
||||
|
||||
## [1.141.12](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.141.11...@standardnotes/auth-server@1.141.12) (2023-09-13)
|
||||
|
||||
### 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 } 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,6 +39,19 @@ const requestTransition = async (
|
||||
|
||||
let usersTriggered = 0
|
||||
for (const user of users) {
|
||||
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 === 'VERIFIED' && revisionsTransitionStatus === 'VERIFIED'
|
||||
|
||||
if (userHasTransitionRole && bothTransitionStatusesAreVerified) {
|
||||
continue
|
||||
}
|
||||
|
||||
const transitionRequestedEvent = domainEventFactory.createTransitionRequestedEvent({
|
||||
userUuid: user.uuid,
|
||||
type: 'items',
|
||||
@@ -67,8 +83,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.12",
|
||||
"version": "1.142.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'
|
||||
@@ -943,15 +942,6 @@ export class ContainerConfigLoader {
|
||||
new UpdateTransitionStatus(
|
||||
container.get<TransitionStatusRepositoryInterface>(TYPES.Auth_TransitionStatusRepository),
|
||||
container.get<RoleServiceInterface>(TYPES.Auth_RoleService),
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,14 +2,10 @@ export interface TransitionStatusRepositoryInterface {
|
||||
updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED',
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED' | 'VERIFIED',
|
||||
): 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' }>>
|
||||
): Promise<'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED' | 'VERIFIED' | null>
|
||||
}
|
||||
|
||||
+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'
|
||||
}
|
||||
+3
-45
@@ -3,80 +3,38 @@ import { RoleName, Uuid } from '@standardnotes/domain-core'
|
||||
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { UpdateTransitionStatus } from './UpdateTransitionStatus'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
describe('UpdateTransitionStatus', () => {
|
||||
let transitionStatusRepository: TransitionStatusRepositoryInterface
|
||||
let roleService: RoleServiceInterface
|
||||
let logger: Logger
|
||||
|
||||
const createUseCase = () => new UpdateTransitionStatus(transitionStatusRepository, roleService, logger)
|
||||
const createUseCase = () => new UpdateTransitionStatus(transitionStatusRepository, roleService)
|
||||
|
||||
beforeEach(() => {
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
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',
|
||||
},
|
||||
])
|
||||
|
||||
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()
|
||||
|
||||
|
||||
@@ -2,13 +2,11 @@ import { Result, RoleName, UseCaseInterface, Uuid } from '@standardnotes/domain-
|
||||
import { TransitionStatusRepositoryInterface } from '../../Transition/TransitionStatusRepositoryInterface'
|
||||
import { UpdateTransitionStatusDTO } from './UpdateTransitionStatusDTO'
|
||||
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
export class UpdateTransitionStatus implements UseCaseInterface<void> {
|
||||
constructor(
|
||||
private transitionStatusRepository: TransitionStatusRepositoryInterface,
|
||||
private roleService: RoleServiceInterface,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async execute(dto: UpdateTransitionStatusDTO): Promise<Result<void>> {
|
||||
@@ -18,42 +16,12 @@ export class UpdateTransitionStatus implements UseCaseInterface<void> {
|
||||
}
|
||||
const userUuid = userUuidOrError.getValue()
|
||||
|
||||
if (dto.status !== 'FINISHED') {
|
||||
await this.transitionStatusRepository.updateStatus(dto.userUuid, dto.transitionType, dto.status)
|
||||
await this.transitionStatusRepository.updateStatus(dto.userUuid, dto.transitionType, dto.status)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
|
||||
await this.transitionStatusRepository.removeStatus(dto.userUuid, dto.transitionType)
|
||||
|
||||
if (dto.transitionType === 'items') {
|
||||
if (dto.transitionType === 'items' && dto.status === '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: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED' | 'VERIFIED'
|
||||
}
|
||||
|
||||
@@ -4,24 +4,6 @@ export class InMemoryTransitionStatusRepository implements TransitionStatusRepos
|
||||
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' }[] = []
|
||||
|
||||
if (transitionType === 'items') {
|
||||
for (const [userUuid, status] of this.itemStatuses) {
|
||||
statuses.push({ userUuid, status })
|
||||
}
|
||||
} else {
|
||||
for (const [userUuid, status] of this.revisionStatuses) {
|
||||
statuses.push({ userUuid, status })
|
||||
}
|
||||
}
|
||||
|
||||
return statuses
|
||||
}
|
||||
|
||||
async updateStatus(
|
||||
userUuid: string,
|
||||
transitionType: 'items' | 'revisions',
|
||||
|
||||
@@ -7,47 +7,35 @@ export class RedisTransitionStatusRepository implements TransitionStatusReposito
|
||||
|
||||
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',
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED' | 'VERIFIED',
|
||||
): Promise<void> {
|
||||
if (status === 'IN_PROGRESS') {
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, 7200, status)
|
||||
} else {
|
||||
await this.redisClient.set(`${this.PREFIX}:${transitionType}:${userUuid}`, status)
|
||||
switch (status) {
|
||||
case 'FAILED':
|
||||
case 'VERIFIED':
|
||||
await this.redisClient.set(`${this.PREFIX}:${transitionType}:${userUuid}`, status)
|
||||
break
|
||||
case 'IN_PROGRESS': {
|
||||
const ttl2Hourse = 7_200
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, ttl2Hourse, status)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
const ttl10Hours = 36_000
|
||||
await this.redisClient.setex(`${this.PREFIX}:${transitionType}:${userUuid}`, ttl10Hours, status)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async removeStatus(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
|
||||
): Promise<'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED' | 'VERIFIED' | null> {
|
||||
const status = await this.redisClient.get(`${this.PREFIX}:${transitionType}:${userUuid}`)
|
||||
|
||||
return status
|
||||
return status as 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED' | 'VERIFIED' | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.12.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.29",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [2.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.126.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: 'STARTED' | 'IN_PROGRESS' | 'FINISHED' | 'FAILED' | 'VERIFIED'
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.11.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.41",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.22.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.20",
|
||||
"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.
|
||||
|
||||
## [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.15.53](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.15.52...@standardnotes/home-server@1.15.53) (2023-09-13)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/home-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/home-server",
|
||||
"version": "1.15.53",
|
||||
"version": "1.15.56",
|
||||
"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.
|
||||
|
||||
# [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
|
||||
|
||||
* skip already updated items and revisions in integrity check ([#825](https://github.com/standardnotes/server/issues/825)) ([03a4a3f](https://github.com/standardnotes/server/commit/03a4a3f2abc0b4e09942ba39dbd227524068dfb6))
|
||||
|
||||
## [1.33.20](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.33.19...@standardnotes/revisions-server@1.33.20) (2023-09-13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/revisions-server",
|
||||
"version": "1.33.20",
|
||||
"version": "1.34.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'FAILED' | 'FINISHED'
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' | 'FINISHED' | 'VERIFIED'
|
||||
}): 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: 'STARTED' | 'IN_PROGRESS' | 'FAILED' | 'FINISHED' | 'VERIFIED'
|
||||
}): TransitionStatusUpdatedEvent
|
||||
}
|
||||
|
||||
@@ -33,24 +33,12 @@ export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerIn
|
||||
}
|
||||
|
||||
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,
|
||||
}),
|
||||
)
|
||||
|
||||
const userUuid = await this.getUserUuidFromEvent(event)
|
||||
if (userUuid === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuidOrError.getValue())) {
|
||||
if (await this.isAlreadyMigrated(userUuid)) {
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
@@ -102,6 +90,22 @@ export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerIn
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (event.payload.status === 'FINISHED' && event.payload.transitionType === 'revisions') {
|
||||
const userUuid = await this.getUserUuidFromEvent(event)
|
||||
if (userUuid === null) {
|
||||
return
|
||||
}
|
||||
|
||||
if (await this.isAlreadyMigrated(userUuid)) {
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'VERIFIED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async isAlreadyMigrated(userUuid: Uuid): Promise<boolean> {
|
||||
@@ -115,4 +119,25 @@ export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerIn
|
||||
|
||||
return totalRevisionsCountForUserInPrimary === 0
|
||||
}
|
||||
|
||||
private async getUserUuidFromEvent(event: TransitionStatusUpdatedEvent): 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: 'FAILED',
|
||||
transitionType: 'revisions',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return userUuidOrError.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -87,6 +87,7 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
const integrityCheckResult = await this.checkIntegrityBetweenPrimaryAndSecondaryDatabase(
|
||||
userUuid,
|
||||
newRevisionsInSecondaryCount,
|
||||
updatedRevisionsInSecondary,
|
||||
)
|
||||
if (integrityCheckResult.isFailed()) {
|
||||
if (newRevisionsInSecondaryCount === 0 && updatedRevisionsInSecondaryCount === 0) {
|
||||
@@ -144,6 +145,10 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
(updatedRevision) => updatedRevision.id.toString() === revision.id.toString(),
|
||||
)
|
||||
) {
|
||||
this.logger.info(
|
||||
`Skipping saving revision ${revision.id.toString()} as it was updated in secondary database`,
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -285,6 +290,7 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
private async checkIntegrityBetweenPrimaryAndSecondaryDatabase(
|
||||
userUuid: Uuid,
|
||||
newRevisionsInSecondaryCount: number,
|
||||
updatedRevisionsInSecondary: Revision[],
|
||||
): Promise<Result<boolean>> {
|
||||
try {
|
||||
const totalRevisionsCountForUserInPrimary = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
|
||||
@@ -314,6 +320,17 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
|
||||
return Result.fail(`Revision ${revision.id.toString()} not found in secondary database`)
|
||||
}
|
||||
|
||||
if (
|
||||
updatedRevisionsInSecondary.find(
|
||||
(updatedRevision) => updatedRevision.id.toString() === revision.id.toString(),
|
||||
)
|
||||
) {
|
||||
this.logger.info(
|
||||
`Skipping integrity check for revision ${revision.id.toString()} as it was updated in secondary database`,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!revision.isIdenticalTo(revisionInSecondary)) {
|
||||
return Result.fail(
|
||||
`Revision ${revision.id.toString()} is not identical in primary and secondary database. Revision in primary database: ${JSON.stringify(
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.20.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.45",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,25 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [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
|
||||
|
||||
* skip already updated items and revisions in integrity check ([#825](https://github.com/standardnotes/syncing-server-js/issues/825)) ([03a4a3f](https://github.com/standardnotes/syncing-server-js/commit/03a4a3f2abc0b4e09942ba39dbd227524068dfb6))
|
||||
* **syncing-server:** updating with missing creation date ([#824](https://github.com/standardnotes/syncing-server-js/issues/824)) ([3a8607d](https://github.com/standardnotes/syncing-server-js/commit/3a8607d1465cabedad68b84c753e407342e60d20))
|
||||
|
||||
## [1.95.17](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.95.16...@standardnotes/syncing-server@1.95.17) (2023-09-13)
|
||||
|
||||
### 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.17",
|
||||
"version": "1.96.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <21.0.0"
|
||||
},
|
||||
|
||||
@@ -173,7 +173,7 @@ export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
userUuid: string
|
||||
transitionType: 'items' | 'revisions'
|
||||
transitionTimestamp: number
|
||||
status: 'STARTED' | 'FAILED' | 'FINISHED'
|
||||
status: 'STARTED' | 'IN_PROGRESS' | 'FAILED' | 'FINISHED' | 'VERIFIED'
|
||||
}): 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: 'STARTED' | 'IN_PROGRESS' | 'FAILED' | 'FINISHED' | 'VERIFIED'
|
||||
}): TransitionStatusUpdatedEvent
|
||||
createEmailRequestedEvent(dto: {
|
||||
userEmail: string
|
||||
|
||||
@@ -18,7 +18,11 @@ export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerIn
|
||||
) {}
|
||||
|
||||
async handle(event: TransitionStatusUpdatedEvent): Promise<void> {
|
||||
if (event.payload.status === 'STARTED' && event.payload.transitionType === 'items') {
|
||||
if (event.payload.transitionType !== 'items') {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.payload.status === 'STARTED') {
|
||||
if (await this.isAlreadyMigrated(event.payload.userUuid)) {
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
@@ -68,6 +72,15 @@ export class TransitionStatusUpdatedEventHandler implements DomainEventHandlerIn
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
}),
|
||||
)
|
||||
} else if (event.payload.status === 'FINISHED') {
|
||||
if (await this.isAlreadyMigrated(event.payload.userUuid)) {
|
||||
this.domainEventFactory.createTransitionStatusUpdatedEvent({
|
||||
userUuid: event.payload.userUuid,
|
||||
status: 'VERIFIED',
|
||||
transitionType: 'items',
|
||||
transitionTimestamp: event.payload.transitionTimestamp,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+48
-2
@@ -298,7 +298,7 @@ describe('UpdateExistingItem', () => {
|
||||
expect(itemRepository.save).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return error if created at time is not give in any form', async () => {
|
||||
it('should fallback to updated at timestamp if created at time is not give in any form', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
@@ -308,13 +308,59 @@ describe('UpdateExistingItem', () => {
|
||||
...itemHash1.props,
|
||||
created_at: undefined,
|
||||
created_at_timestamp: undefined,
|
||||
updated_at_timestamp: 123,
|
||||
}).getValue(),
|
||||
sessionUuid: '00000000-0000-0000-0000-000000000000',
|
||||
performingUserUuid: '00000000-0000-0000-0000-000000000000',
|
||||
roleNames: [RoleName.NAMES.CoreUser],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeTruthy()
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(itemRepository.save).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fallback to updated at date if created at time is not give in any form', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
existingItem: item1,
|
||||
onGoingRevisionsTransition: false,
|
||||
itemHash: ItemHash.create({
|
||||
...itemHash1.props,
|
||||
created_at: undefined,
|
||||
created_at_timestamp: undefined,
|
||||
updated_at_timestamp: undefined,
|
||||
updated_at: '2020-01-01T00:00:00.000Z',
|
||||
}).getValue(),
|
||||
sessionUuid: '00000000-0000-0000-0000-000000000000',
|
||||
performingUserUuid: '00000000-0000-0000-0000-000000000000',
|
||||
roleNames: [RoleName.NAMES.CoreUser],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(itemRepository.save).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should fallback to 0 if created at and update at time is not give in any form', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
existingItem: item1,
|
||||
onGoingRevisionsTransition: false,
|
||||
itemHash: ItemHash.create({
|
||||
...itemHash1.props,
|
||||
created_at: undefined,
|
||||
created_at_timestamp: undefined,
|
||||
updated_at_timestamp: undefined,
|
||||
updated_at: undefined,
|
||||
}).getValue(),
|
||||
sessionUuid: '00000000-0000-0000-0000-000000000000',
|
||||
performingUserUuid: '00000000-0000-0000-0000-000000000000',
|
||||
roleNames: [RoleName.NAMES.CoreUser],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
expect(itemRepository.save).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return error if dates could not be created from timestamps', async () => {
|
||||
|
||||
+25
-11
@@ -23,6 +23,7 @@ import { SharedVaultOperationOnItem } from '../../../SharedVault/SharedVaultOper
|
||||
import { AddNotificationForUser } from '../../Messaging/AddNotificationForUser/AddNotificationForUser'
|
||||
import { RemoveNotificationsForUser } from '../../Messaging/RemoveNotificationsForUser/RemoveNotificationsForUser'
|
||||
import { ItemRepositoryResolverInterface } from '../../../Item/ItemRepositoryResolverInterface'
|
||||
import { ItemHash } from '../../../Item/ItemHash'
|
||||
|
||||
export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
constructor(
|
||||
@@ -115,17 +116,7 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
)
|
||||
const updatedAtDate = this.timer.convertMicrosecondsToDate(updatedAtTimestamp)
|
||||
|
||||
let createdAtTimestamp: number
|
||||
let createdAtDate: Date
|
||||
if (dto.itemHash.props.created_at_timestamp) {
|
||||
createdAtTimestamp = dto.itemHash.props.created_at_timestamp
|
||||
createdAtDate = this.timer.convertMicrosecondsToDate(createdAtTimestamp)
|
||||
} else if (dto.itemHash.props.created_at) {
|
||||
createdAtTimestamp = this.timer.convertStringDateToMicroseconds(dto.itemHash.props.created_at)
|
||||
createdAtDate = this.timer.convertStringDateToDate(dto.itemHash.props.created_at)
|
||||
} else {
|
||||
return Result.fail('Created at timestamp is required.')
|
||||
}
|
||||
const { createdAtDate, createdAtTimestamp } = this.determineCreatedAt(dto.itemHash)
|
||||
|
||||
const datesOrError = Dates.create(createdAtDate, updatedAtDate)
|
||||
if (datesOrError.isFailed()) {
|
||||
@@ -221,6 +212,29 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
return Result.ok(dto.existingItem)
|
||||
}
|
||||
|
||||
private determineCreatedAt(itemHash: ItemHash): { createdAtDate: Date; createdAtTimestamp: number } {
|
||||
let createdAtTimestamp: number
|
||||
let createdAtDate: Date
|
||||
if (itemHash.props.created_at_timestamp) {
|
||||
createdAtTimestamp = itemHash.props.created_at_timestamp
|
||||
createdAtDate = this.timer.convertMicrosecondsToDate(createdAtTimestamp)
|
||||
} else if (itemHash.props.created_at) {
|
||||
createdAtTimestamp = this.timer.convertStringDateToMicroseconds(itemHash.props.created_at)
|
||||
createdAtDate = this.timer.convertStringDateToDate(itemHash.props.created_at)
|
||||
} else if (itemHash.props.updated_at_timestamp) {
|
||||
createdAtTimestamp = itemHash.props.updated_at_timestamp
|
||||
createdAtDate = this.timer.convertMicrosecondsToDate(itemHash.props.updated_at_timestamp)
|
||||
} else if (itemHash.props.updated_at) {
|
||||
createdAtTimestamp = this.timer.convertStringDateToMicroseconds(itemHash.props.updated_at)
|
||||
createdAtDate = this.timer.convertStringDateToDate(itemHash.props.updated_at)
|
||||
} else {
|
||||
createdAtTimestamp = 0
|
||||
createdAtDate = new Date(0)
|
||||
}
|
||||
|
||||
return { createdAtDate, createdAtTimestamp }
|
||||
}
|
||||
|
||||
private async addNotificationsAndPublishEvents(
|
||||
userUuid: Uuid,
|
||||
sharedVaultOperation: SharedVaultOperationOnItem | null,
|
||||
|
||||
+11
@@ -82,6 +82,7 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use
|
||||
const integrityCheckResult = await this.checkIntegrityBetweenPrimaryAndSecondaryDatabase(
|
||||
userUuid,
|
||||
newItemsInSecondaryCount,
|
||||
updatedItemsInSecondary,
|
||||
)
|
||||
if (integrityCheckResult.isFailed()) {
|
||||
if (newItemsInSecondaryCount === 0 && updatedItemsInSecondaryCount === 0) {
|
||||
@@ -209,6 +210,8 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use
|
||||
|
||||
for (const item of items) {
|
||||
if (updatedItemsInSecondary.find((updatedItem) => updatedItem.uuid.equals(item.uuid))) {
|
||||
this.logger.info(`Skipping saving item ${item.uuid.value} as it was updated in secondary database`)
|
||||
|
||||
continue
|
||||
}
|
||||
await (this.secondaryItemRepository as ItemRepositoryInterface).save(item)
|
||||
@@ -234,6 +237,7 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use
|
||||
private async checkIntegrityBetweenPrimaryAndSecondaryDatabase(
|
||||
userUuid: Uuid,
|
||||
newItemsInSecondaryCount: number,
|
||||
updatedItemsInSecondary: Item[],
|
||||
): Promise<Result<boolean>> {
|
||||
try {
|
||||
const totalItemsCountForUserInPrimary = await this.primaryItemRepository.countAll({ userUuid: userUuid.value })
|
||||
@@ -265,6 +269,13 @@ export class TransitionItemsFromPrimaryToSecondaryDatabaseForUser implements Use
|
||||
return Result.fail(`Item ${item.uuid.value} not found in secondary database`)
|
||||
}
|
||||
|
||||
if (updatedItemsInSecondary.find((updatedItem) => updatedItem.uuid.equals(item.uuid))) {
|
||||
this.logger.info(
|
||||
`Skipping integrity check for item ${item.uuid.value} as it was updated in secondary database`,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!item.isIdenticalTo(itemInSecondary)) {
|
||||
return Result.fail(
|
||||
`Item ${
|
||||
|
||||
@@ -18,7 +18,6 @@ export class MongoDBItem {
|
||||
declare content: string | null
|
||||
|
||||
@Column()
|
||||
@Index('index_items_on_content_type')
|
||||
declare contentType: string | null
|
||||
|
||||
@Column()
|
||||
|
||||
@@ -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.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.42",
|
||||
"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