mirror of
https://github.com/standardnotes/server
synced 2026-01-23 05:01:45 -05:00
Compare commits
14 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5a0e88ab9 | ||
|
|
a59ba08339 | ||
|
|
2641056c51 | ||
|
|
5d812befc4 | ||
|
|
1c592d6f96 | ||
|
|
531f13fe1f | ||
|
|
4757cc8dae | ||
|
|
ecdfe9ecc0 | ||
|
|
d19cb08e9c | ||
|
|
f45320e5ed | ||
|
|
93ded34de9 | ||
|
|
dd13e2eaf7 | ||
|
|
1405c6f260 | ||
|
|
0dab31f993 |
109
.pnp.cjs
generated
109
.pnp.cjs
generated
@@ -2484,16 +2484,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/api", [\
|
||||
["npm:1.1.19", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-api-npm-1.1.19-6a6d650ec9-cca168245a.zip/node_modules/@standardnotes/api/",\
|
||||
["npm:1.7.2", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-api-npm-1.7.2-e68e7d4e63-bdfc414e6d.zip/node_modules/@standardnotes/api/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/api", "npm:1.1.19"],\
|
||||
["@standardnotes/auth", "npm:3.19.4"],\
|
||||
["@standardnotes/api", "npm:1.7.2"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/encryption", "npm:1.12.0"],\
|
||||
["@standardnotes/responses", "npm:1.6.39"],\
|
||||
["@standardnotes/services", "npm:1.15.0"],\
|
||||
["@standardnotes/utils", "npm:1.6.12"]\
|
||||
["@standardnotes/encryption", "npm:1.15.2"],\
|
||||
["@standardnotes/models", "npm:1.18.2"],\
|
||||
["@standardnotes/responses", "npm:1.10.1"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["@standardnotes/utils", "npm:1.9.0"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
@@ -2562,7 +2563,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@newrelic/winston-enricher", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.0.0"],\
|
||||
["@sentry/node", "npm:7.5.0"],\
|
||||
["@standardnotes/analytics", "workspace:packages/analytics"],\
|
||||
["@standardnotes/api", "npm:1.1.19"],\
|
||||
["@standardnotes/api", "npm:1.7.2"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/domain-events", "workspace:packages/domain-events"],\
|
||||
["@standardnotes/domain-events-infra", "workspace:packages/domain-events-infra"],\
|
||||
@@ -2687,16 +2688,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/encryption", [\
|
||||
["npm:1.12.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-encryption-npm-1.12.0-eb2342c675-1a28653b1e.zip/node_modules/@standardnotes/encryption/",\
|
||||
["npm:1.15.2", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-encryption-npm-1.15.2-ef86a8281d-6e8336f1e7.zip/node_modules/@standardnotes/encryption/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/encryption", "npm:1.12.0"],\
|
||||
["@standardnotes/encryption", "npm:1.15.2"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/models", "npm:1.14.0"],\
|
||||
["@standardnotes/responses", "npm:1.6.39"],\
|
||||
["@standardnotes/services", "npm:1.15.0"],\
|
||||
["@standardnotes/sncrypto-common", "npm:1.9.0"],\
|
||||
["@standardnotes/utils", "npm:1.6.12"],\
|
||||
["@standardnotes/models", "npm:1.18.2"],\
|
||||
["@standardnotes/responses", "npm:1.10.1"],\
|
||||
["@standardnotes/sncrypto-common", "npm:1.11.1"],\
|
||||
["@standardnotes/utils", "npm:1.9.0"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
@@ -2742,6 +2742,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.52.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-features-npm-1.52.0-8c1adf7881-3e6014272f.zip/node_modules/@standardnotes/features/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/features", "npm:1.52.0"],\
|
||||
["@standardnotes/auth", "npm:3.19.4"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/files-server", [\
|
||||
@@ -2797,14 +2808,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/models", [\
|
||||
["npm:1.14.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-models-npm-1.14.0-6f064d99e7-bfb9d517b6.zip/node_modules/@standardnotes/models/",\
|
||||
["npm:1.18.2", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-models-npm-1.18.2-56f35bb72d-88180a93e5.zip/node_modules/@standardnotes/models/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/models", "npm:1.14.0"],\
|
||||
["@standardnotes/models", "npm:1.18.2"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/features", "npm:1.50.0"],\
|
||||
["@standardnotes/responses", "npm:1.6.39"],\
|
||||
["@standardnotes/utils", "npm:1.6.12"],\
|
||||
["@standardnotes/features", "npm:1.52.0"],\
|
||||
["@standardnotes/responses", "npm:1.10.1"],\
|
||||
["@standardnotes/utils", "npm:1.9.0"],\
|
||||
["lodash", "npm:4.17.21"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
@@ -2840,6 +2851,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/responses", [\
|
||||
["npm:1.10.1", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-responses-npm-1.10.1-9f82fff6c1-b84fb3f71c.zip/node_modules/@standardnotes/responses/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/responses", "npm:1.10.1"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/features", "npm:1.52.0"],\
|
||||
["@standardnotes/security", "workspace:packages/security"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.6.39", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-responses-npm-1.6.39-395f4c2d65-0ea1d4d5b8.zip/node_modules/@standardnotes/responses/",\
|
||||
"packageDependencies": [\
|
||||
@@ -2932,21 +2954,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"linkType": "SOFT"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/services", [\
|
||||
["npm:1.15.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-services-npm-1.15.0-acab3bc6a3-1028a5b4c1.zip/node_modules/@standardnotes/services/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/services", "npm:1.15.0"],\
|
||||
["@standardnotes/auth", "npm:3.19.4"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["@standardnotes/models", "npm:1.14.0"],\
|
||||
["@standardnotes/responses", "npm:1.6.39"],\
|
||||
["@standardnotes/utils", "npm:1.6.12"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/settings", [\
|
||||
["workspace:packages/settings", {\
|
||||
"packageLocation": "./packages/settings/",\
|
||||
@@ -2960,6 +2967,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]\
|
||||
]],\
|
||||
["@standardnotes/sncrypto-common", [\
|
||||
["npm:1.11.1", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-sncrypto-common-npm-1.11.1-58d12d6912-69d698abb7.zip/node_modules/@standardnotes/sncrypto-common/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/sncrypto-common", "npm:1.11.1"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.9.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-sncrypto-common-npm-1.9.0-48773f745a-42252d7198.zip/node_modules/@standardnotes/sncrypto-common/",\
|
||||
"packageDependencies": [\
|
||||
@@ -3071,6 +3086,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["lodash", "npm:4.17.21"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.9.0", {\
|
||||
"packageLocation": "./.yarn/cache/@standardnotes-utils-npm-1.9.0-da939553f6-4591aff48d.zip/node_modules/@standardnotes/utils/",\
|
||||
"packageDependencies": [\
|
||||
["@standardnotes/utils", "npm:1.9.0"],\
|
||||
["@standardnotes/common", "workspace:packages/common"],\
|
||||
["dompurify", "npm:2.4.0"],\
|
||||
["lodash", "npm:4.17.21"],\
|
||||
["reflect-metadata", "npm:0.1.13"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@szmarczak/http-timer", [\
|
||||
@@ -5844,6 +5870,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["dompurify", "npm:2.3.8"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.4.0", {\
|
||||
"packageLocation": "./.yarn/cache/dompurify-npm-2.4.0-0ffecf22ef-c93ea73cf8.zip/node_modules/dompurify/",\
|
||||
"packageDependencies": [\
|
||||
["dompurify", "npm:2.4.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["dot-prop", [\
|
||||
|
||||
Binary file not shown.
BIN
.yarn/cache/@standardnotes-api-npm-1.7.2-e68e7d4e63-bdfc414e6d.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-api-npm-1.7.2-e68e7d4e63-bdfc414e6d.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@standardnotes-encryption-npm-1.15.2-ef86a8281d-6e8336f1e7.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-encryption-npm-1.15.2-ef86a8281d-6e8336f1e7.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@standardnotes-features-npm-1.52.0-8c1adf7881-3e6014272f.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-features-npm-1.52.0-8c1adf7881-3e6014272f.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@standardnotes-responses-npm-1.10.1-9f82fff6c1-b84fb3f71c.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-responses-npm-1.10.1-9f82fff6c1-b84fb3f71c.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@standardnotes-sncrypto-common-npm-1.11.1-58d12d6912-69d698abb7.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-sncrypto-common-npm-1.11.1-58d12d6912-69d698abb7.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@standardnotes-utils-npm-1.9.0-da939553f6-4591aff48d.zip
vendored
Normal file
BIN
.yarn/cache/@standardnotes-utils-npm-1.9.0-da939553f6-4591aff48d.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/dompurify-npm-2.4.0-0ffecf22ef-c93ea73cf8.zip
vendored
Normal file
BIN
.yarn/cache/dompurify-npm-2.4.0-0ffecf22ef-c93ea73cf8.zip
vendored
Normal file
Binary file not shown.
@@ -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/analytics@1.28.0...@standardnotes/analytics@1.29.0) (2022-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add remaining subscription time stats ([a59ba08](https://github.com/standardnotes/server/commit/a59ba083397c75960af0e8a102b617bf5baa287f))
|
||||
|
||||
# [1.28.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.27.0...@standardnotes/analytics@1.28.0) (2022-09-09)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "1.28.0",
|
||||
"version": "1.29.0",
|
||||
"engines": {
|
||||
"node": ">=14.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ export enum StatisticsMeasure {
|
||||
SubscriptionLength = 'subscription-length',
|
||||
RegistrationLength = 'registration-length',
|
||||
RegistrationToSubscriptionTime = 'registration-to-subscription-time',
|
||||
SubscriptionCancelToExpireTime = 'subscription-cancel-to-expire-time',
|
||||
Refunds = 'refunds',
|
||||
NotesCountFreeUsers = 'notes-count-free-users',
|
||||
NotesCountPaidUsers = 'notes-count-paid-users',
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.19.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.19.1...@standardnotes/api-gateway@1.19.2) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.19.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.19.0...@standardnotes/api-gateway@1.19.1) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.19.1",
|
||||
"version": "1.19.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,42 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.28.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.27.0...@standardnotes/auth-server@1.28.0) (2022-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add remaining subscription time stats ([a59ba08](https://github.com/standardnotes/server/commit/a59ba083397c75960af0e8a102b617bf5baa287f))
|
||||
|
||||
# [1.27.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.26.1...@standardnotes/auth-server@1.27.0) (2022-09-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** implement subscription server interface on server side ([5d812be](https://github.com/standardnotes/server/commit/5d812befc4733954919eef0d3718ae6f8eb81654))
|
||||
|
||||
## [1.26.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.26.0...@standardnotes/auth-server@1.26.1) (2022-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** disallow duplicating subscription invites ([531f13f](https://github.com/standardnotes/server/commit/531f13fe1f4bdfb8d27f5e3c07ec0b15d36ad413))
|
||||
|
||||
# [1.26.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.25.13...@standardnotes/auth-server@1.26.0) (2022-09-13)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add subscription sharing permission ([f45320e](https://github.com/standardnotes/server/commit/f45320e5ed8948a432029586c05284f4d640de5b))
|
||||
|
||||
## [1.25.13](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.25.12...@standardnotes/auth-server@1.25.13) (2022-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** add debug logs for canceling shared subscription invitations ([dd13e2e](https://github.com/standardnotes/server/commit/dd13e2eaf74de56a3c8c30c236c32c6dc0c560f2))
|
||||
|
||||
## [1.25.12](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.25.11...@standardnotes/auth-server@1.25.12) (2022-09-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** allow canceling shared subscription invitation before it was accepted ([0dab31f](https://github.com/standardnotes/server/commit/0dab31f9936bfd5081a87eef9701a268b8dec88c))
|
||||
|
||||
## [1.25.11](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.25.10...@standardnotes/auth-server@1.25.11) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
@@ -17,10 +17,10 @@ import '../src/Controller/SubscriptionTokensController'
|
||||
import '../src/Controller/OfflineController'
|
||||
import '../src/Controller/ValetTokenController'
|
||||
import '../src/Controller/ListedController'
|
||||
import '../src/Controller/SubscriptionInvitesController'
|
||||
import '../src/Controller/SubscriptionSettingsController'
|
||||
|
||||
import '../src/Infra/InversifyExpressUtils/InversifyExpressAuthController'
|
||||
import '../src/Infra/InversifyExpressUtils/InversifyExpressSubscriptionInvitesController'
|
||||
|
||||
import * as cors from 'cors'
|
||||
import { urlencoded, json, Request, Response, NextFunction, RequestHandler, ErrorRequestHandler } from 'express'
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class addSubscriptionSharingPermission1663073954000 implements MigrationInterface {
|
||||
name = 'addSubscriptionSharingPermission1663073954000'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'INSERT INTO `permissions` (uuid, name) VALUES ("3aeaf12e-380f-4f21-97b9-d862d63874f6", "server:subscription-sharing")',
|
||||
)
|
||||
|
||||
// Pro User Permissions
|
||||
await queryRunner.query(
|
||||
'INSERT INTO `role_permissions` (role_uuid, permission_uuid) VALUES \
|
||||
("8047edbb-a10a-4ff8-8d53-c2cae600a8e8", "3aeaf12e-380f-4f21-97b9-d862d63874f6") \
|
||||
',
|
||||
)
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.25.11",
|
||||
"version": "1.28.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -34,7 +34,7 @@
|
||||
"@newrelic/winston-enricher": "^4.0.0",
|
||||
"@sentry/node": "^7.3.0",
|
||||
"@standardnotes/analytics": "workspace:*",
|
||||
"@standardnotes/api": "^1.1.19",
|
||||
"@standardnotes/api": "^1.7.2",
|
||||
"@standardnotes/common": "workspace:*",
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
"@standardnotes/domain-events-infra": "workspace:*",
|
||||
|
||||
@@ -200,6 +200,7 @@ import { MuteMarketingEmails } from '../Domain/UseCase/MuteMarketingEmails/MuteM
|
||||
import { PaymentFailedEventHandler } from '../Domain/Handler/PaymentFailedEventHandler'
|
||||
import { PaymentSuccessEventHandler } from '../Domain/Handler/PaymentSuccessEventHandler'
|
||||
import { RefundProcessedEventHandler } from '../Domain/Handler/RefundProcessedEventHandler'
|
||||
import { SubscriptionInvitesController } from '../Controller/SubscriptionInvitesController'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const newrelicFormatter = require('@newrelic/winston-enricher')
|
||||
@@ -262,6 +263,7 @@ export class ContainerConfigLoader {
|
||||
|
||||
// Controller
|
||||
container.bind<AuthController>(TYPES.AuthController).to(AuthController)
|
||||
container.bind<SubscriptionInvitesController>(TYPES.SubscriptionInvitesController).to(SubscriptionInvitesController)
|
||||
|
||||
// Repositories
|
||||
container.bind<SessionRepositoryInterface>(TYPES.SessionRepository).to(MySQLSessionRepository)
|
||||
|
||||
@@ -5,6 +5,7 @@ const TYPES = {
|
||||
SQS: Symbol.for('SQS'),
|
||||
// Controller
|
||||
AuthController: Symbol.for('AuthController'),
|
||||
SubscriptionInvitesController: Symbol.for('SubscriptionInvitesController'),
|
||||
// Repositories
|
||||
UserRepository: Symbol.for('UserRepository'),
|
||||
SessionRepository: Symbol.for('SessionRepository'),
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import * as express from 'express'
|
||||
|
||||
import { SubscriptionInvitesController } from './SubscriptionInvitesController'
|
||||
import { results } from 'inversify-express-utils'
|
||||
import { User } from '../Domain/User/User'
|
||||
import { InviteToSharedSubscription } from '../Domain/UseCase/InviteToSharedSubscription/InviteToSharedSubscription'
|
||||
import { AcceptSharedSubscriptionInvitation } from '../Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation'
|
||||
import { DeclineSharedSubscriptionInvitation } from '../Domain/UseCase/DeclineSharedSubscriptionInvitation/DeclineSharedSubscriptionInvitation'
|
||||
import { CancelSharedSubscriptionInvitation } from '../Domain/UseCase/CancelSharedSubscriptionInvitation/CancelSharedSubscriptionInvitation'
|
||||
import { RoleName } from '@standardnotes/common'
|
||||
import { ListSharedSubscriptionInvitations } from '../Domain/UseCase/ListSharedSubscriptionInvitations/ListSharedSubscriptionInvitations'
|
||||
import { ApiVersion } from '@standardnotes/api'
|
||||
|
||||
describe('SubscriptionInvitesController', () => {
|
||||
let inviteToSharedSubscription: InviteToSharedSubscription
|
||||
@@ -19,8 +16,6 @@ describe('SubscriptionInvitesController', () => {
|
||||
let cancelSharedSubscriptionInvitation: CancelSharedSubscriptionInvitation
|
||||
let listSharedSubscriptionInvitations: ListSharedSubscriptionInvitations
|
||||
|
||||
let request: express.Request
|
||||
let response: express.Response
|
||||
let user: User
|
||||
|
||||
const createController = () =>
|
||||
@@ -51,25 +46,6 @@ describe('SubscriptionInvitesController', () => {
|
||||
|
||||
listSharedSubscriptionInvitations = {} as jest.Mocked<ListSharedSubscriptionInvitations>
|
||||
listSharedSubscriptionInvitations.execute = jest.fn()
|
||||
|
||||
request = {
|
||||
headers: {},
|
||||
body: {},
|
||||
params: {},
|
||||
} as jest.Mocked<express.Request>
|
||||
|
||||
response = {
|
||||
locals: {},
|
||||
} as jest.Mocked<express.Response>
|
||||
response.locals.user = {
|
||||
email: 'test@test.te',
|
||||
}
|
||||
response.locals.roles = [
|
||||
{
|
||||
uuid: '1-2-3',
|
||||
name: RoleName.CoreUser,
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
it('should get invitations to subscription sharing', async () => {
|
||||
@@ -77,128 +53,127 @@ describe('SubscriptionInvitesController', () => {
|
||||
invitations: [],
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().listInvites(request, response)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().listInvites({ api: ApiVersion.v0, inviterEmail: 'test@test.te' })
|
||||
|
||||
expect(listSharedSubscriptionInvitations.execute).toHaveBeenCalledWith({
|
||||
inviterEmail: 'test@test.te',
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(200)
|
||||
expect(result.status).toEqual(200)
|
||||
})
|
||||
|
||||
it('should cancel invitation to subscription sharing', async () => {
|
||||
request.params.inviteUuid = '1-2-3'
|
||||
|
||||
cancelSharedSubscriptionInvitation.execute = jest.fn().mockReturnValue({
|
||||
success: true,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().cancelSubscriptionSharing(request, response)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().cancelInvite({
|
||||
api: ApiVersion.v0,
|
||||
inviteUuid: '1-2-3',
|
||||
inviterEmail: 'test@test.te',
|
||||
})
|
||||
|
||||
expect(cancelSharedSubscriptionInvitation.execute).toHaveBeenCalledWith({
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
inviterEmail: 'test@test.te',
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(200)
|
||||
expect(result.status).toEqual(200)
|
||||
})
|
||||
|
||||
it('should not cancel invitation to subscription sharing if the workflow fails', async () => {
|
||||
request.params.inviteUuid = '1-2-3'
|
||||
|
||||
cancelSharedSubscriptionInvitation.execute = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().cancelSubscriptionSharing(request, response)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().cancelInvite({
|
||||
api: ApiVersion.v0,
|
||||
inviteUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(400)
|
||||
expect(result.status).toEqual(400)
|
||||
})
|
||||
|
||||
it('should decline invitation to subscription sharing', async () => {
|
||||
request.params.inviteUuid = '1-2-3'
|
||||
|
||||
declineSharedSubscriptionInvitation.execute = jest.fn().mockReturnValue({
|
||||
success: true,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().declineInvite(request)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().declineInvite({
|
||||
api: ApiVersion.v0,
|
||||
inviteUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(declineSharedSubscriptionInvitation.execute).toHaveBeenCalledWith({
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(200)
|
||||
expect(result.status).toEqual(200)
|
||||
})
|
||||
|
||||
it('should not decline invitation to subscription sharing if the workflow fails', async () => {
|
||||
request.params.inviteUuid = '1-2-3'
|
||||
|
||||
declineSharedSubscriptionInvitation.execute = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().declineInvite(request)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().declineInvite({
|
||||
api: ApiVersion.v0,
|
||||
inviteUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(declineSharedSubscriptionInvitation.execute).toHaveBeenCalledWith({
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(400)
|
||||
expect(result.status).toEqual(400)
|
||||
})
|
||||
|
||||
it('should accept invitation to subscription sharing', async () => {
|
||||
request.params.inviteUuid = '1-2-3'
|
||||
|
||||
acceptSharedSubscriptionInvitation.execute = jest.fn().mockReturnValue({
|
||||
success: true,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().acceptInvite(request)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().acceptInvite({
|
||||
api: ApiVersion.v0,
|
||||
inviteUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(acceptSharedSubscriptionInvitation.execute).toHaveBeenCalledWith({
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(200)
|
||||
expect(result.status).toEqual(200)
|
||||
})
|
||||
|
||||
it('should not accept invitation to subscription sharing if the workflow fails', async () => {
|
||||
request.params.inviteUuid = '1-2-3'
|
||||
|
||||
acceptSharedSubscriptionInvitation.execute = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().acceptInvite(request)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().acceptInvite({
|
||||
api: ApiVersion.v0,
|
||||
inviteUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(acceptSharedSubscriptionInvitation.execute).toHaveBeenCalledWith({
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(400)
|
||||
expect(result.status).toEqual(400)
|
||||
})
|
||||
|
||||
it('should invite to user subscription', async () => {
|
||||
request.body.identifier = 'invitee@test.te'
|
||||
response.locals.user = {
|
||||
uuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
}
|
||||
|
||||
inviteToSharedSubscription.execute = jest.fn().mockReturnValue({
|
||||
success: true,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().inviteToSubscriptionSharing(request, response)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().invite({
|
||||
api: ApiVersion.v0,
|
||||
identifier: 'invitee@test.te',
|
||||
inviterUuid: '1-2-3',
|
||||
inviterEmail: 'test@test.te',
|
||||
inviterRoles: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(inviteToSharedSubscription.execute).toHaveBeenCalledWith({
|
||||
inviterEmail: 'test@test.te',
|
||||
@@ -207,37 +182,36 @@ describe('SubscriptionInvitesController', () => {
|
||||
inviterRoles: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(200)
|
||||
expect(result.status).toEqual(200)
|
||||
})
|
||||
|
||||
it('should not invite to user subscription if the identifier is missing in request', async () => {
|
||||
response.locals.user = {
|
||||
uuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
}
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().inviteToSubscriptionSharing(request, response)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().invite({
|
||||
api: ApiVersion.v0,
|
||||
identifier: '',
|
||||
inviterUuid: '1-2-3',
|
||||
inviterEmail: 'test@test.te',
|
||||
inviterRoles: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(inviteToSharedSubscription.execute).not.toHaveBeenCalled()
|
||||
|
||||
expect(result.statusCode).toEqual(400)
|
||||
expect(result.status).toEqual(400)
|
||||
})
|
||||
|
||||
it('should not invite to user subscription if the workflow does not run', async () => {
|
||||
request.body.identifier = 'invitee@test.te'
|
||||
response.locals.user = {
|
||||
uuid: '1-2-3',
|
||||
email: 'test@test.te',
|
||||
}
|
||||
|
||||
inviteToSharedSubscription.execute = jest.fn().mockReturnValue({
|
||||
success: false,
|
||||
})
|
||||
|
||||
const httpResponse = <results.JsonResult>await createController().inviteToSubscriptionSharing(request, response)
|
||||
const result = await httpResponse.executeAsync()
|
||||
const result = await createController().invite({
|
||||
api: ApiVersion.v0,
|
||||
identifier: 'invitee@test.te',
|
||||
inviterUuid: '1-2-3',
|
||||
inviterEmail: 'test@test.te',
|
||||
inviterRoles: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(result.statusCode).toEqual(400)
|
||||
expect(result.status).toEqual(400)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { Role } from '@standardnotes/security'
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import {
|
||||
BaseHttpController,
|
||||
controller,
|
||||
httpDelete,
|
||||
httpGet,
|
||||
httpPost,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
results,
|
||||
} from 'inversify-express-utils'
|
||||
HttpStatusCode,
|
||||
SubscriptionInviteAcceptRequestParams,
|
||||
SubscriptionInviteAcceptResponse,
|
||||
SubscriptionInviteCancelRequestParams,
|
||||
SubscriptionInviteCancelResponse,
|
||||
SubscriptionInviteDeclineRequestParams,
|
||||
SubscriptionInviteDeclineResponse,
|
||||
SubscriptionInviteListRequestParams,
|
||||
SubscriptionInviteListResponse,
|
||||
SubscriptionInviteRequestParams,
|
||||
SubscriptionInviteResponse,
|
||||
SubscriptionServerInterface,
|
||||
} from '@standardnotes/api'
|
||||
import { RoleName } from '@standardnotes/common'
|
||||
import { inject } from 'inversify'
|
||||
|
||||
import TYPES from '../Bootstrap/Types'
|
||||
import { AcceptSharedSubscriptionInvitation } from '../Domain/UseCase/AcceptSharedSubscriptionInvitation/AcceptSharedSubscriptionInvitation'
|
||||
@@ -18,8 +22,7 @@ import { DeclineSharedSubscriptionInvitation } from '../Domain/UseCase/DeclineSh
|
||||
import { InviteToSharedSubscription } from '../Domain/UseCase/InviteToSharedSubscription/InviteToSharedSubscription'
|
||||
import { ListSharedSubscriptionInvitations } from '../Domain/UseCase/ListSharedSubscriptionInvitations/ListSharedSubscriptionInvitations'
|
||||
|
||||
@controller('/subscription-invites')
|
||||
export class SubscriptionInvitesController extends BaseHttpController {
|
||||
export class SubscriptionInvitesController implements SubscriptionServerInterface {
|
||||
constructor(
|
||||
@inject(TYPES.InviteToSharedSubscription) private inviteToSharedSubscription: InviteToSharedSubscription,
|
||||
@inject(TYPES.AcceptSharedSubscriptionInvitation)
|
||||
@@ -30,75 +33,103 @@ export class SubscriptionInvitesController extends BaseHttpController {
|
||||
private cancelSharedSubscriptionInvitation: CancelSharedSubscriptionInvitation,
|
||||
@inject(TYPES.ListSharedSubscriptionInvitations)
|
||||
private listSharedSubscriptionInvitations: ListSharedSubscriptionInvitations,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
) {}
|
||||
|
||||
@httpGet('/:inviteUuid/accept')
|
||||
async acceptInvite(request: Request): Promise<results.JsonResult> {
|
||||
async acceptInvite(params: SubscriptionInviteAcceptRequestParams): Promise<SubscriptionInviteAcceptResponse> {
|
||||
const result = await this.acceptSharedSubscriptionInvitation.execute({
|
||||
sharedSubscriptionInvitationUuid: request.params.inviteUuid,
|
||||
sharedSubscriptionInvitationUuid: params.inviteUuid,
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
return this.json(result)
|
||||
return {
|
||||
status: HttpStatusCode.Success,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
return this.json(result, 400)
|
||||
return {
|
||||
status: HttpStatusCode.BadRequest,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
@httpGet('/:inviteUuid/decline')
|
||||
async declineInvite(request: Request): Promise<results.JsonResult> {
|
||||
async declineInvite(params: SubscriptionInviteDeclineRequestParams): Promise<SubscriptionInviteDeclineResponse> {
|
||||
const result = await this.declineSharedSubscriptionInvitation.execute({
|
||||
sharedSubscriptionInvitationUuid: request.params.inviteUuid,
|
||||
sharedSubscriptionInvitationUuid: params.inviteUuid,
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
return this.json(result)
|
||||
return {
|
||||
status: HttpStatusCode.Success,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
return this.json(result, 400)
|
||||
return {
|
||||
status: HttpStatusCode.BadRequest,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
@httpPost('/', TYPES.ApiGatewayAuthMiddleware)
|
||||
async inviteToSubscriptionSharing(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
if (!request.body.identifier) {
|
||||
return this.json({ error: { message: 'Missing invitee identifier' } }, 400)
|
||||
async invite(params: SubscriptionInviteRequestParams): Promise<SubscriptionInviteResponse> {
|
||||
if (!params.identifier) {
|
||||
return {
|
||||
status: HttpStatusCode.BadRequest,
|
||||
data: {
|
||||
error: {
|
||||
message: 'Missing invitee identifier',
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const result = await this.inviteToSharedSubscription.execute({
|
||||
inviterEmail: response.locals.user.email,
|
||||
inviterUuid: response.locals.user.uuid,
|
||||
inviteeIdentifier: request.body.identifier,
|
||||
inviterRoles: response.locals.roles.map((role: Role) => role.name),
|
||||
inviterEmail: params.inviterEmail as string,
|
||||
inviterUuid: params.inviterUuid as string,
|
||||
inviteeIdentifier: params.identifier,
|
||||
inviterRoles: params.inviterRoles as RoleName[],
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
return this.json(result)
|
||||
return {
|
||||
status: HttpStatusCode.Success,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
return this.json(result, 400)
|
||||
return {
|
||||
status: HttpStatusCode.BadRequest,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
@httpDelete('/:inviteUuid', TYPES.ApiGatewayAuthMiddleware)
|
||||
async cancelSubscriptionSharing(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
async cancelInvite(params: SubscriptionInviteCancelRequestParams): Promise<SubscriptionInviteCancelResponse> {
|
||||
const result = await this.cancelSharedSubscriptionInvitation.execute({
|
||||
sharedSubscriptionInvitationUuid: request.params.inviteUuid,
|
||||
inviterEmail: response.locals.user.email,
|
||||
sharedSubscriptionInvitationUuid: params.inviteUuid,
|
||||
inviterEmail: params.inviterEmail as string,
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
return this.json(result)
|
||||
return {
|
||||
status: HttpStatusCode.Success,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
return this.json(result, 400)
|
||||
return {
|
||||
status: HttpStatusCode.BadRequest,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
|
||||
@httpGet('/', TYPES.ApiGatewayAuthMiddleware)
|
||||
async listInvites(_request: Request, response: Response): Promise<results.JsonResult> {
|
||||
async listInvites(params: SubscriptionInviteListRequestParams): Promise<SubscriptionInviteListResponse> {
|
||||
const result = await this.listSharedSubscriptionInvitations.execute({
|
||||
inviterEmail: response.locals.user.email,
|
||||
inviterEmail: params.inviterEmail as string,
|
||||
})
|
||||
|
||||
return this.json(result)
|
||||
return {
|
||||
status: HttpStatusCode.Success,
|
||||
data: result,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyti
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { User } from '../User/User'
|
||||
import { UserSubscription } from '../Subscription/UserSubscription'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
describe('SubscriptionCancelledEventHandler', () => {
|
||||
let userSubscriptionRepository: UserSubscriptionRepositoryInterface
|
||||
@@ -24,7 +23,6 @@ describe('SubscriptionCancelledEventHandler', () => {
|
||||
let analyticsStore: AnalyticsStoreInterface
|
||||
let statisticsStore: StatisticsStoreInterface
|
||||
let timestamp: number
|
||||
let logger: Logger
|
||||
|
||||
const createHandler = () =>
|
||||
new SubscriptionCancelledEventHandler(
|
||||
@@ -34,7 +32,6 @@ describe('SubscriptionCancelledEventHandler', () => {
|
||||
getUserAnalyticsId,
|
||||
analyticsStore,
|
||||
statisticsStore,
|
||||
logger,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -75,9 +72,6 @@ describe('SubscriptionCancelledEventHandler', () => {
|
||||
offline: false,
|
||||
replaced: false,
|
||||
}
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.info = jest.fn()
|
||||
})
|
||||
|
||||
it('should update subscription cancelled', async () => {
|
||||
|
||||
@@ -14,7 +14,6 @@ import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/Offl
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { UserSubscription } from '../Subscription/UserSubscription'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
@injectable()
|
||||
export class SubscriptionCancelledEventHandler implements DomainEventHandlerInterface {
|
||||
@@ -26,7 +25,6 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
|
||||
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
|
||||
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
|
||||
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {}
|
||||
async handle(event: SubscriptionCancelledEvent): Promise<void> {
|
||||
if (event.payload.offline) {
|
||||
@@ -50,14 +48,18 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
|
||||
if (subscriptions.length !== 0) {
|
||||
const lastSubscription = subscriptions.shift() as UserSubscription
|
||||
const subscriptionLength = event.payload.timestamp - lastSubscription.createdAt
|
||||
this.logger.info(
|
||||
`Canceling subscription ${lastSubscription.uuid} - lasted for ${subscriptionLength} microseconds`,
|
||||
)
|
||||
await this.statisticsStore.incrementMeasure(StatisticsMeasure.SubscriptionLength, subscriptionLength, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
|
||||
const remainingSubscriptionTime = lastSubscription.endsAt - event.payload.timestamp
|
||||
await this.statisticsStore.incrementMeasure(
|
||||
StatisticsMeasure.SubscriptionCancelToExpireTime,
|
||||
remainingSubscriptionTime,
|
||||
[Period.Today, Period.ThisWeek, Period.ThisMonth],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,9 @@ export interface SharedSubscriptionInvitationRepositoryInterface {
|
||||
findOneByUuidAndStatus(uuid: Uuid, status: InvitationStatus): Promise<SharedSubscriptionInvitation | null>
|
||||
findOneByUuid(uuid: Uuid): Promise<SharedSubscriptionInvitation | null>
|
||||
findByInviterEmail(inviterEmail: string): Promise<SharedSubscriptionInvitation[]>
|
||||
findOneByInviteeAndInviterEmail(
|
||||
inviteeEmail: string,
|
||||
inviterEmail: string,
|
||||
): Promise<SharedSubscriptionInvitation | null>
|
||||
countByInviterEmailAndStatus(inviterEmail: Uuid, statuses: InvitationStatus[]): Promise<number>
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { DomainEventPublisherInterface, SharedSubscriptionInvitationCanceledEven
|
||||
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||
import { InviterIdentifierType } from '../../SharedSubscription/InviterIdentifierType'
|
||||
import { InviteeIdentifierType } from '../../SharedSubscription/InviteeIdentifierType'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
describe('CancelSharedSubscriptionInvitation', () => {
|
||||
let sharedSubscriptionInvitationRepository: SharedSubscriptionInvitationRepositoryInterface
|
||||
@@ -28,6 +29,7 @@ describe('CancelSharedSubscriptionInvitation', () => {
|
||||
let invitation: SharedSubscriptionInvitation
|
||||
let domainEventPublisher: DomainEventPublisherInterface
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
let logger: Logger
|
||||
|
||||
const createUseCase = () =>
|
||||
new CancelSharedSubscriptionInvitation(
|
||||
@@ -38,6 +40,7 @@ describe('CancelSharedSubscriptionInvitation', () => {
|
||||
domainEventPublisher,
|
||||
domainEventFactory,
|
||||
timer,
|
||||
logger,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -60,6 +63,9 @@ describe('CancelSharedSubscriptionInvitation', () => {
|
||||
inviteeIdentifierType: InviteeIdentifierType.Email,
|
||||
} as jest.Mocked<SharedSubscriptionInvitation>
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.debug = jest.fn()
|
||||
|
||||
sharedSubscriptionInvitationRepository = {} as jest.Mocked<SharedSubscriptionInvitationRepositoryInterface>
|
||||
sharedSubscriptionInvitationRepository.findOneByUuid = jest.fn().mockReturnValue(invitation)
|
||||
sharedSubscriptionInvitationRepository.save = jest.fn()
|
||||
@@ -126,7 +132,7 @@ describe('CancelSharedSubscriptionInvitation', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should cancel a shared subscription invitation without subscription removal is subscription is not found', async () => {
|
||||
it('should cancel a shared subscription invitation without subscription removal if subscription is not found', async () => {
|
||||
userSubscriptionRepository.findOneByUserUuidAndSubscriptionId = jest.fn().mockReturnValue(null)
|
||||
|
||||
expect(
|
||||
@@ -175,7 +181,7 @@ describe('CancelSharedSubscriptionInvitation', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should not cancel a shared subscription invitation if invitee is not found', async () => {
|
||||
it('should cancel a shared subscription invitation without subscription removal if invitee is not found', async () => {
|
||||
userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
@@ -183,20 +189,21 @@ describe('CancelSharedSubscriptionInvitation', () => {
|
||||
inviterEmail: 'test@test.te',
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
success: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('should not cancel a shared subscription invitation if invitee is not found', async () => {
|
||||
userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
inviterEmail: 'test@test.te',
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
expect(sharedSubscriptionInvitationRepository.save).toHaveBeenCalledWith({
|
||||
status: 'canceled',
|
||||
subscriptionId: 3,
|
||||
updatedAt: 1,
|
||||
inviterIdentifier: 'test@test.te',
|
||||
uuid: '1-2-3',
|
||||
inviterIdentifierType: 'email',
|
||||
inviteeIdentifier: 'invitee@test.te',
|
||||
inviteeIdentifierType: 'email',
|
||||
})
|
||||
expect(userSubscriptionRepository.save).not.toHaveBeenCalled()
|
||||
expect(roleService.removeUserRole).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not cancel a shared subscription invitation if inviter subscription is not found', async () => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { SubscriptionName } from '@standardnotes/common'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||
@@ -29,6 +30,7 @@ export class CancelSharedSubscriptionInvitation implements UseCaseInterface {
|
||||
@inject(TYPES.DomainEventPublisher) private domainEventPublisher: DomainEventPublisherInterface,
|
||||
@inject(TYPES.DomainEventFactory) private domainEventFactory: DomainEventFactoryInterface,
|
||||
@inject(TYPES.Timer) private timer: TimerInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {}
|
||||
|
||||
async execute(dto: CancelSharedSubscriptionInvitationDTO): Promise<CancelSharedSubscriptionInvitationResponse> {
|
||||
@@ -36,29 +38,34 @@ export class CancelSharedSubscriptionInvitation implements UseCaseInterface {
|
||||
dto.sharedSubscriptionInvitationUuid,
|
||||
)
|
||||
if (sharedSubscriptionInvitation === null) {
|
||||
this.logger.debug(
|
||||
`Could not find a shared subscription invitation with uuid ${dto.sharedSubscriptionInvitationUuid}`,
|
||||
)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
|
||||
if (dto.inviterEmail !== sharedSubscriptionInvitation.inviterIdentifier) {
|
||||
this.logger.debug(
|
||||
`Subscription belongs to a different inviter (${sharedSubscriptionInvitation.inviterIdentifier}). Modifier: ${dto.inviterEmail}`,
|
||||
)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
|
||||
const invitee = await this.userRepository.findOneByEmail(sharedSubscriptionInvitation.inviteeIdentifier)
|
||||
if (invitee === null) {
|
||||
return {
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
|
||||
const inviterUserSubscriptions = await this.userSubscriptionRepository.findBySubscriptionIdAndType(
|
||||
sharedSubscriptionInvitation.subscriptionId,
|
||||
UserSubscriptionType.Regular,
|
||||
)
|
||||
if (inviterUserSubscriptions.length !== 1) {
|
||||
if (inviterUserSubscriptions.length === 0) {
|
||||
this.logger.debug(`Could not find a regular subscription with id ${sharedSubscriptionInvitation.subscriptionId}`)
|
||||
|
||||
return {
|
||||
success: false,
|
||||
}
|
||||
@@ -70,20 +77,22 @@ export class CancelSharedSubscriptionInvitation implements UseCaseInterface {
|
||||
|
||||
await this.sharedSubscriptionInvitationRepository.save(sharedSubscriptionInvitation)
|
||||
|
||||
await this.removeSharedSubscription(sharedSubscriptionInvitation.subscriptionId, invitee)
|
||||
if (invitee !== null) {
|
||||
await this.removeSharedSubscription(sharedSubscriptionInvitation.subscriptionId, invitee)
|
||||
|
||||
await this.roleService.removeUserRole(invitee, inviterUserSubscription.planName as SubscriptionName)
|
||||
await this.roleService.removeUserRole(invitee, inviterUserSubscription.planName as SubscriptionName)
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createSharedSubscriptionInvitationCanceledEvent({
|
||||
inviteeIdentifier: invitee.uuid,
|
||||
inviteeIdentifierType: InviteeIdentifierType.Uuid,
|
||||
inviterEmail: sharedSubscriptionInvitation.inviterIdentifier,
|
||||
inviterSubscriptionId: sharedSubscriptionInvitation.subscriptionId,
|
||||
inviterSubscriptionUuid: inviterUserSubscription.uuid,
|
||||
sharedSubscriptionInvitationUuid: sharedSubscriptionInvitation.uuid,
|
||||
}),
|
||||
)
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createSharedSubscriptionInvitationCanceledEvent({
|
||||
inviteeIdentifier: invitee.uuid,
|
||||
inviteeIdentifierType: InviteeIdentifierType.Uuid,
|
||||
inviterEmail: sharedSubscriptionInvitation.inviterIdentifier,
|
||||
inviterSubscriptionId: sharedSubscriptionInvitation.subscriptionId,
|
||||
inviterSubscriptionUuid: inviterUserSubscription.uuid,
|
||||
sharedSubscriptionInvitationUuid: sharedSubscriptionInvitation.uuid,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -10,6 +10,7 @@ import { UserSubscriptionRepositoryInterface } from '../../Subscription/UserSubs
|
||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||
import { RoleName } from '@standardnotes/common'
|
||||
import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType'
|
||||
import { SharedSubscriptionInvitation } from '../../SharedSubscription/SharedSubscriptionInvitation'
|
||||
|
||||
describe('InviteToSharedSubscription', () => {
|
||||
let userSubscriptionRepository: UserSubscriptionRepositoryInterface
|
||||
@@ -40,6 +41,7 @@ describe('InviteToSharedSubscription', () => {
|
||||
sharedSubscriptionInvitationRepository = {} as jest.Mocked<SharedSubscriptionInvitationRepositoryInterface>
|
||||
sharedSubscriptionInvitationRepository.save = jest.fn().mockImplementation((same) => ({ ...same, uuid: '1-2-3' }))
|
||||
sharedSubscriptionInvitationRepository.countByInviterEmailAndStatus = jest.fn().mockReturnValue(2)
|
||||
sharedSubscriptionInvitationRepository.findOneByInviteeAndInviterEmail = jest.fn().mockReturnValue(null)
|
||||
|
||||
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||
domainEventPublisher.publish = jest.fn()
|
||||
@@ -181,4 +183,26 @@ describe('InviteToSharedSubscription', () => {
|
||||
|
||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not create an invitation if it already exists', async () => {
|
||||
sharedSubscriptionInvitationRepository.findOneByInviteeAndInviterEmail = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<SharedSubscriptionInvitation>)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
inviteeIdentifier: 'invitee@test.te',
|
||||
inviterUuid: '1-2-3',
|
||||
inviterEmail: 'inviter@test.te',
|
||||
inviterRoles: [RoleName.ProUser],
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
})
|
||||
|
||||
expect(sharedSubscriptionInvitationRepository.save).not.toHaveBeenCalled()
|
||||
|
||||
expect(domainEventFactory.createSharedSubscriptionInvitationCreatedEvent).not.toHaveBeenCalled()
|
||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -53,6 +53,16 @@ export class InviteToSharedSubscription implements UseCaseInterface {
|
||||
}
|
||||
}
|
||||
|
||||
const existingInvitation = await this.sharedSubscriptionInvitationRepository.findOneByInviteeAndInviterEmail(
|
||||
dto.inviteeIdentifier,
|
||||
dto.inviterEmail,
|
||||
)
|
||||
if (existingInvitation !== null) {
|
||||
return {
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
|
||||
const sharedSubscriptionInvition = new SharedSubscriptionInvitation()
|
||||
sharedSubscriptionInvition.inviterIdentifier = dto.inviterEmail
|
||||
sharedSubscriptionInvition.inviterIdentifierType = InviterIdentifierType.Email
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { ApiVersion } from '@standardnotes/api'
|
||||
import { Role } from '@standardnotes/security'
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import {
|
||||
BaseHttpController,
|
||||
controller,
|
||||
httpDelete,
|
||||
httpGet,
|
||||
httpPost,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
results,
|
||||
} from 'inversify-express-utils'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { SubscriptionInvitesController } from '../../Controller/SubscriptionInvitesController'
|
||||
|
||||
@controller('/subscription-invites')
|
||||
export class InversifyExpressSubscriptionInvitesController extends BaseHttpController {
|
||||
constructor(
|
||||
@inject(TYPES.SubscriptionInvitesController) private subscriptionInvitesController: SubscriptionInvitesController,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpGet('/:inviteUuid/accept')
|
||||
async acceptInvite(request: Request): Promise<results.JsonResult> {
|
||||
const response = await this.subscriptionInvitesController.acceptInvite({
|
||||
api: request.query.api as ApiVersion,
|
||||
inviteUuid: request.params.inviteUuid,
|
||||
})
|
||||
|
||||
return this.json(response.data, response.status)
|
||||
}
|
||||
|
||||
@httpGet('/:inviteUuid/decline')
|
||||
async declineInvite(request: Request): Promise<results.JsonResult> {
|
||||
const response = await this.subscriptionInvitesController.declineInvite({
|
||||
api: request.query.api as ApiVersion,
|
||||
inviteUuid: request.params.inviteUuid,
|
||||
})
|
||||
|
||||
return this.json(response.data, response.status)
|
||||
}
|
||||
|
||||
@httpPost('/', TYPES.ApiGatewayAuthMiddleware)
|
||||
async inviteToSubscriptionSharing(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
const result = await this.subscriptionInvitesController.invite({
|
||||
...request.body,
|
||||
inviterEmail: response.locals.user.email,
|
||||
inviterUuid: response.locals.user.uuid,
|
||||
inviterRoles: response.locals.roles.map((role: Role) => role.name),
|
||||
})
|
||||
|
||||
return this.json(result.data, result.status)
|
||||
}
|
||||
|
||||
@httpDelete('/:inviteUuid', TYPES.ApiGatewayAuthMiddleware)
|
||||
async cancelSubscriptionSharing(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
const result = await this.subscriptionInvitesController.cancelInvite({
|
||||
...request.body,
|
||||
inviteUuid: request.params.inviteUuid,
|
||||
inviterEmail: response.locals.user.email,
|
||||
})
|
||||
|
||||
return this.json(result.data, result.status)
|
||||
}
|
||||
|
||||
@httpGet('/', TYPES.ApiGatewayAuthMiddleware)
|
||||
async listInvites(request: Request, response: Response): Promise<results.JsonResult> {
|
||||
const result = await this.subscriptionInvitesController.listInvites({
|
||||
...request.body,
|
||||
inviterEmail: response.locals.user.email,
|
||||
})
|
||||
|
||||
return this.json(result.data, result.status)
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,23 @@ describe('MySQLSharedSubscriptionInvitationRepository', () => {
|
||||
expect(result).toEqual(invitation)
|
||||
})
|
||||
|
||||
it('should find one invitation by invitee and inviter email', async () => {
|
||||
queryBuilder.where = jest.fn().mockReturnThis()
|
||||
queryBuilder.getOne = jest.fn().mockReturnValue(invitation)
|
||||
|
||||
const result = await createRepository().findOneByInviteeAndInviterEmail('invitee@test.te', 'inviter@test.te')
|
||||
|
||||
expect(queryBuilder.where).toHaveBeenCalledWith(
|
||||
'invitation.inviter_identifier = :inviterEmail AND invitation.invitee_identifier = :inviteeEmail',
|
||||
{
|
||||
inviterEmail: 'inviter@test.te',
|
||||
inviteeEmail: 'invitee@test.te',
|
||||
},
|
||||
)
|
||||
|
||||
expect(result).toEqual(invitation)
|
||||
})
|
||||
|
||||
it('should find one invitation by uuid', async () => {
|
||||
queryBuilder.where = jest.fn().mockReturnThis()
|
||||
queryBuilder.getOne = jest.fn().mockReturnValue(invitation)
|
||||
|
||||
@@ -13,6 +13,19 @@ export class MySQLSharedSubscriptionInvitationRepository implements SharedSubscr
|
||||
private ormRepository: Repository<SharedSubscriptionInvitation>,
|
||||
) {}
|
||||
|
||||
async findOneByInviteeAndInviterEmail(
|
||||
inviteeEmail: string,
|
||||
inviterEmail: string,
|
||||
): Promise<SharedSubscriptionInvitation | null> {
|
||||
return this.ormRepository
|
||||
.createQueryBuilder('invitation')
|
||||
.where('invitation.inviter_identifier = :inviterEmail AND invitation.invitee_identifier = :inviteeEmail', {
|
||||
inviterEmail,
|
||||
inviteeEmail,
|
||||
})
|
||||
.getOne()
|
||||
}
|
||||
|
||||
async save(sharedSubscriptionInvitation: SharedSubscriptionInvitation): Promise<SharedSubscriptionInvitation> {
|
||||
return this.ormRepository.save(sharedSubscriptionInvitation)
|
||||
}
|
||||
|
||||
@@ -189,6 +189,7 @@ describe('MySQLUserSubscriptionRepository', () => {
|
||||
ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => selectQueryBuilder)
|
||||
|
||||
selectQueryBuilder.where = jest.fn().mockReturnThis()
|
||||
selectQueryBuilder.orderBy = jest.fn().mockReturnThis()
|
||||
selectQueryBuilder.getMany = jest.fn().mockReturnValue([subscription])
|
||||
|
||||
const result = await createRepository().findBySubscriptionIdAndType(123, UserSubscriptionType.Regular)
|
||||
@@ -200,6 +201,7 @@ describe('MySQLUserSubscriptionRepository', () => {
|
||||
type: 'regular',
|
||||
},
|
||||
)
|
||||
expect(selectQueryBuilder.orderBy).toHaveBeenCalledWith('created_at', 'DESC')
|
||||
expect(selectQueryBuilder.getMany).toHaveBeenCalled()
|
||||
expect(result).toEqual([subscription])
|
||||
})
|
||||
|
||||
@@ -44,6 +44,7 @@ export class MySQLUserSubscriptionRepository implements UserSubscriptionReposito
|
||||
subscriptionId,
|
||||
type,
|
||||
})
|
||||
.orderBy('created_at', 'DESC')
|
||||
.getMany()
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.8.3](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.2...@standardnotes/syncing-server@1.8.3) (2022-09-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.8.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.1...@standardnotes/syncing-server@1.8.2) (2022-09-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **syncing-server:** files count stats ([ecdfe9e](https://github.com/standardnotes/syncing-server-js/commit/ecdfe9ecc0bce882c1e3c6984f67b76862d76836))
|
||||
|
||||
## [1.8.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.8.0...@standardnotes/syncing-server@1.8.1) (2022-09-09)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.8.1",
|
||||
"version": "1.8.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -112,10 +112,12 @@ export class CheckIntegrity implements UseCaseInterface {
|
||||
[Period.Today, Period.ThisMonth],
|
||||
)
|
||||
|
||||
await this.statisticsStore.incrementMeasure(StatisticsMeasure.FilesCount, counts.files, [
|
||||
Period.Today,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
if (!freeUser) {
|
||||
await this.statisticsStore.incrementMeasure(StatisticsMeasure.FilesCount, counts.files, [
|
||||
Period.Today,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
132
yarn.lock
132
yarn.lock
@@ -1803,17 +1803,18 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/api@npm:^1.1.19":
|
||||
version: 1.1.19
|
||||
resolution: "@standardnotes/api@npm:1.1.19"
|
||||
"@standardnotes/api@npm:^1.7.2":
|
||||
version: 1.7.2
|
||||
resolution: "@standardnotes/api@npm:1.7.2"
|
||||
dependencies:
|
||||
"@standardnotes/auth": ^3.19.4
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@standardnotes/encryption": ^1.8.23
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/services": ^1.13.23
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
checksum: cca168245a80d333ca6433799a7cbe4a233956cace92b9e9ec45b3f67e4e907ef4f08a9573008bdf2b11a09100dc0381cff820ee5bea384407c2107c494913ba
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/encryption": 1.15.2
|
||||
"@standardnotes/models": 1.18.2
|
||||
"@standardnotes/responses": 1.10.1
|
||||
"@standardnotes/security": ^1.1.0
|
||||
"@standardnotes/utils": 1.9.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: bdfc414e6d01620fd047979255a43eb447afbb69d1bb694015b162ad236431273cd234bba4129d13ba94791271aaff71895d726357491d6ab984c7d5a7a8a3f7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1824,7 +1825,7 @@ __metadata:
|
||||
"@newrelic/winston-enricher": ^4.0.0
|
||||
"@sentry/node": ^7.3.0
|
||||
"@standardnotes/analytics": "workspace:*"
|
||||
"@standardnotes/api": ^1.1.19
|
||||
"@standardnotes/api": ^1.7.2
|
||||
"@standardnotes/common": "workspace:*"
|
||||
"@standardnotes/domain-events": "workspace:*"
|
||||
"@standardnotes/domain-events-infra": "workspace:*"
|
||||
@@ -1885,7 +1886,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/common@^1.19.1, @standardnotes/common@^1.23.1, @standardnotes/common@workspace:*, @standardnotes/common@workspace:^, @standardnotes/common@workspace:packages/common":
|
||||
"@standardnotes/common@^1.19.1, @standardnotes/common@^1.23.1, @standardnotes/common@^1.32.0, @standardnotes/common@workspace:*, @standardnotes/common@workspace:^, @standardnotes/common@workspace:packages/common":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/common@workspace:packages/common"
|
||||
dependencies:
|
||||
@@ -1950,18 +1951,17 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/encryption@npm:^1.8.23":
|
||||
version: 1.12.0
|
||||
resolution: "@standardnotes/encryption@npm:1.12.0"
|
||||
"@standardnotes/encryption@npm:1.15.2":
|
||||
version: 1.15.2
|
||||
resolution: "@standardnotes/encryption@npm:1.15.2"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@standardnotes/models": 1.14.0
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/services": 1.15.0
|
||||
"@standardnotes/sncrypto-common": ^1.9.0
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/models": 1.18.2
|
||||
"@standardnotes/responses": 1.10.1
|
||||
"@standardnotes/sncrypto-common": 1.11.1
|
||||
"@standardnotes/utils": 1.9.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 1a28653b1e75c8c728fc7e68a64950eea2a291b339c7cd9f8672061ab9768ae7895fb75184b98e9046c296a96bb40d835dda7706ace973a948232f0f0655fcf7
|
||||
checksum: 6e8336f1e7e961fbd42c4890458dca877da62dcc1987f7e9a7fb6ca230821276fce6a33652669bcc1752a80ffc55e4cf82b8631f7902d9714f4a07a7956092b0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1993,7 +1993,19 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/features@npm:1.50.0, @standardnotes/features@npm:^1.36.3, @standardnotes/features@npm:^1.47.0":
|
||||
"@standardnotes/features@npm:1.52.0":
|
||||
version: 1.52.0
|
||||
resolution: "@standardnotes/features@npm:1.52.0"
|
||||
dependencies:
|
||||
"@standardnotes/auth": ^3.19.4
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/security": ^1.2.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 3e6014272f72ed33bc7de3cefb33a63a02866c01bfd4a54bc95426e2719f4997940de382cfd83982eaeafdbdf9afac558aecb9139117facfe9c7479089e2952d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/features@npm:^1.36.3, @standardnotes/features@npm:^1.47.0":
|
||||
version: 1.50.0
|
||||
resolution: "@standardnotes/features@npm:1.50.0"
|
||||
dependencies:
|
||||
@@ -2054,17 +2066,17 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/models@npm:1.14.0":
|
||||
version: 1.14.0
|
||||
resolution: "@standardnotes/models@npm:1.14.0"
|
||||
"@standardnotes/models@npm:1.18.2":
|
||||
version: 1.18.2
|
||||
resolution: "@standardnotes/models@npm:1.18.2"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@standardnotes/features": 1.50.0
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/features": 1.52.0
|
||||
"@standardnotes/responses": 1.10.1
|
||||
"@standardnotes/utils": 1.9.0
|
||||
lodash: ^4.17.21
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: bfb9d517b6569d39e3f7bb700a644e430c7c88a2ce84c24d649efd8aac1fa94f222258fe08e1afa2614ffd73ac414911bbe39a597c1f6e9bfce6852a2c7ac776
|
||||
checksum: 88180a93e5acdc349e1f96159c40610d7f52d49f0566386d9d6db8767d5ac4ba73af3131c8e433afa253557349e3f96238f6b2060e94df51ceedb5d378b3dd1f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2093,6 +2105,18 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/responses@npm:1.10.1":
|
||||
version: 1.10.1
|
||||
resolution: "@standardnotes/responses@npm:1.10.1"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.32.0
|
||||
"@standardnotes/features": 1.52.0
|
||||
"@standardnotes/security": ^1.1.0
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: b84fb3f71cc32286fc757280e01c2da7fd0576e96455bfd53c5e55f807875d7201a23e727a7c702277b90f1959837a9a0cbda94ca6a4f4ad6a4896e306ed851c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/responses@npm:^1.6.39":
|
||||
version: 1.6.39
|
||||
resolution: "@standardnotes/responses@npm:1.6.39"
|
||||
@@ -2138,7 +2162,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/security@workspace:*, @standardnotes/security@workspace:packages/security":
|
||||
"@standardnotes/security@^1.1.0, @standardnotes/security@^1.2.0, @standardnotes/security@workspace:*, @standardnotes/security@workspace:packages/security":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/security@workspace:packages/security"
|
||||
dependencies:
|
||||
@@ -2179,20 +2203,6 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/services@npm:1.15.0, @standardnotes/services@npm:^1.13.23":
|
||||
version: 1.15.0
|
||||
resolution: "@standardnotes/services@npm:1.15.0"
|
||||
dependencies:
|
||||
"@standardnotes/auth": ^3.19.4
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@standardnotes/models": 1.14.0
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 1028a5b4c1372f13044115b3dea510a7e32479567161007472116f8a6168570735beeb32a5e795259f461bc983e75c4a4be72b8a927c60225c4057594ce139b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/settings@workspace:*, @standardnotes/settings@workspace:packages/settings":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/settings@workspace:packages/settings"
|
||||
@@ -2203,6 +2213,15 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/sncrypto-common@npm:1.11.1":
|
||||
version: 1.11.1
|
||||
resolution: "@standardnotes/sncrypto-common@npm:1.11.1"
|
||||
dependencies:
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 69d698abb7ffc2aecfffd9ccf3e023adca73e5b27cfa1106dfdf10a13d6455b9581c9bf854b333f00255317ec62c384c516b218f40a55ee84fd4f659b8aef16b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/sncrypto-common@npm:^1.9.0":
|
||||
version: 1.9.0
|
||||
resolution: "@standardnotes/sncrypto-common@npm:1.9.0"
|
||||
@@ -2297,7 +2316,19 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/utils@npm:^1.4.6, @standardnotes/utils@npm:^1.6.12":
|
||||
"@standardnotes/utils@npm:1.9.0":
|
||||
version: 1.9.0
|
||||
resolution: "@standardnotes/utils@npm:1.9.0"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.32.0
|
||||
dompurify: ^2.3.8
|
||||
lodash: ^4.17.21
|
||||
reflect-metadata: ^0.1.13
|
||||
checksum: 4591aff48d074b30b911f96c63eaaf521ab49563507672fbd4d7fe460e51f88a45effb002d1c82cca3513d2199c0cdb720556b03ec3e0266f593317c8efa764a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/utils@npm:^1.4.6":
|
||||
version: 1.6.12
|
||||
resolution: "@standardnotes/utils@npm:1.6.12"
|
||||
dependencies:
|
||||
@@ -4471,6 +4502,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dompurify@npm:^2.3.8":
|
||||
version: 2.4.0
|
||||
resolution: "dompurify@npm:2.4.0"
|
||||
checksum: c93ea73cf8e3ba044588450198563e56ce6902e36d0e16e3699df2fa59e82c4fdd11d4ad04ef5024569ce96a35b46f29d0bbea522516add33cd39a7f56a8a675
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dot-prop@npm:^5.1.0":
|
||||
version: 5.3.0
|
||||
resolution: "dot-prop@npm:5.3.0"
|
||||
|
||||
Reference in New Issue
Block a user