mirror of
https://github.com/standardnotes/server
synced 2026-04-21 05:02:25 -04:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 25b1f3e9ea | |||
| f94c8fc26e | |||
| d149f46cf6 | |||
| 6a24ba5d56 | |||
| db8333a858 | |||
| 3af254d7c7 | |||
| 8151bb108a | |||
| 3b18769c2d | |||
| 2883cac6d4 | |||
| d7ae2f0625 | |||
| 318f6d0986 | |||
| 2ca430f40c | |||
| fd65060a8e | |||
| cb81f819ba | |||
| 61c7040e4b | |||
| fa10827443 | |||
| bcee779e74 | |||
| 34315c91d7 | |||
| 8d3bf6c4a5 | |||
| 0c176b70f8 | |||
| 87a5854357 | |||
| 9c2d51d718 | |||
| e618f046ea | |||
| a36cb925ff | |||
| 9e2aea2793 | |||
| ef1e2bb5ed | |||
| 6a457281ea | |||
| 41c512798d | |||
| ffa0f51305 | |||
| e0cec9e24a | |||
| f6b359a772 | |||
| 648eb89c7c | |||
| ba22e085b8 | |||
| 35373db1d3 | |||
| 932cfa7200 | |||
| 932ef933fc | |||
| 4f1293525c | |||
| dd6bec8a0c | |||
| 1abca64765 | |||
| dbe55d89ec | |||
| dcb3ad661c | |||
| 1e1f6cb4a3 | |||
| 83d96fd71d | |||
| 7dc4670028 | |||
| dc88e2413b | |||
| b7f7c3f164 | |||
| f7def38e20 | |||
| cf49e1ff74 | |||
| 38de2d6b30 | |||
| 4b3de264ef | |||
| 4bb785c7f0 | |||
| 2fb904d2cb | |||
| ee79347e27 | |||
| 3477c81d37 | |||
| 930789316c | |||
| 01a08eae58 | |||
| d73c9833ab | |||
| 1841597405 | |||
| 8003e5ce43 | |||
| d0023a6c92 | |||
| a9293f6ce1 | |||
| 58c5b586a9 | |||
| 21d224da22 | |||
| 43d957c8d3 | |||
| 917fad510a | |||
| 269eef7ef3 | |||
| b811f4527b | |||
| 67378e4535 | |||
| dad9033482 | |||
| 32c8333564 | |||
| 4d074e7f9a | |||
| c61b615da6 |
@@ -9,134 +9,83 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/analytics"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/api-gateway"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/auth"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/common"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/domain-events"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/domain-events-infra"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/event-store"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/files"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/predicates"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/scheduler"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/security"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/settings"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/sncrypto-node"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/syncing-server"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/time"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
reviewers:
|
||||
- "moughxyz"
|
||||
- "karolsojko"
|
||||
|
||||
@@ -60,6 +60,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Configure AWS credentials
|
||||
@@ -90,6 +95,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Login to Docker Hub
|
||||
|
||||
@@ -63,6 +63,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Configure AWS credentials
|
||||
@@ -93,6 +98,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Login to Docker Hub
|
||||
|
||||
@@ -32,6 +32,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Configure AWS credentials
|
||||
@@ -62,6 +67,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Login to Docker Hub
|
||||
|
||||
@@ -63,6 +63,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Configure AWS credentials
|
||||
@@ -93,6 +98,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Login to Docker Hub
|
||||
|
||||
@@ -11,6 +11,11 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: ESLint
|
||||
run: yarn lint
|
||||
- name: Build
|
||||
|
||||
@@ -32,6 +32,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Configure AWS credentials
|
||||
@@ -62,6 +67,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Login to Docker Hub
|
||||
|
||||
@@ -14,9 +14,11 @@ jobs:
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ secrets.CI_PAT_TOKEN }}
|
||||
- uses: actions/setup-node@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Setup git config
|
||||
run: |
|
||||
git config --global user.name "standardci"
|
||||
@@ -43,4 +45,4 @@ jobs:
|
||||
commit-message: "${{ 'chore(deps): upgrade snjs' }}"
|
||||
delete-branch: true
|
||||
committer: standardci <ci@standardnotes.com>
|
||||
author: standardci <ci@standardnotes.com>
|
||||
author: standardci <ci@standardnotes.com>
|
||||
|
||||
@@ -63,6 +63,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Configure AWS credentials
|
||||
@@ -93,6 +98,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
node-version-file: '.nvmrc'
|
||||
- name: Build locally
|
||||
run: yarn build
|
||||
- name: Login to Docker Hub
|
||||
|
||||
@@ -124,7 +124,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["newrelic", "npm:9.0.0"],\
|
||||
["npm-check-updates", "npm:16.0.1"],\
|
||||
["prettier", "npm:2.7.1"],\
|
||||
["ts-node", "virtual:c0eab07e71af57f5501e97e7ca7a2a4f4965035bd2455ad124a8b09fa55780657c55fe3df41019fa6c2c44487c897668c842a0939e380b3c1f13b3756d128543#npm:10.8.2"],\
|
||||
["ts-node", "virtual:8859b278716fedf3e7458b5628625f7e35678c418626878559a0b816445001b7e24c55546f4677ba4c20b521aa0cf52cc33ac07deff171e383ada6eeab69933f#npm:10.9.1"],\
|
||||
["typescript", "patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=7ad353"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -2607,7 +2607,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
|
||||
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.7"],\
|
||||
["ua-parser-js", "npm:1.0.2"],\
|
||||
["uuid", "npm:8.3.2"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["winston", "npm:3.8.1"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -2788,8 +2788,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["prettyjson", "npm:1.2.5"],\
|
||||
["reflect-metadata", "npm:0.1.13"],\
|
||||
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
|
||||
["ts-node", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:10.8.2"],\
|
||||
["uuid", "npm:8.3.2"],\
|
||||
["ts-node", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:10.9.1"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["winston", "npm:3.8.1"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -2866,11 +2866,12 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["@types/jest", "npm:28.1.4"],\
|
||||
["@types/newrelic", "npm:7.0.3"],\
|
||||
["@types/node", "npm:18.0.3"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:5.30.5"],\
|
||||
["@typescript-eslint/eslint-plugin", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:5.30.5"],\
|
||||
["aws-sdk", "npm:2.1168.0"],\
|
||||
["dayjs", "npm:1.11.3"],\
|
||||
["dotenv", "npm:16.0.1"],\
|
||||
["eslint-plugin-prettier", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:4.2.1"],\
|
||||
["eslint", "npm:8.19.0"],\
|
||||
["eslint-plugin-prettier", "virtual:04783e12400851b8a3d76e71495851cc94959db6e62f04cb0a31190080629440b182d8c8eb4d7f2b04e281912f2783a5fd4d2c3c6ab68d38b7097246c93f4c19#npm:4.2.1"],\
|
||||
["inversify", "npm:6.0.1"],\
|
||||
["ioredis", "npm:5.2.0"],\
|
||||
["jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.1.2"],\
|
||||
@@ -2924,7 +2925,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["newrelic", "npm:9.0.0"],\
|
||||
["npm-check-updates", "npm:16.0.1"],\
|
||||
["prettier", "npm:2.7.1"],\
|
||||
["ts-node", "virtual:c0eab07e71af57f5501e97e7ca7a2a4f4965035bd2455ad124a8b09fa55780657c55fe3df41019fa6c2c44487c897668c842a0939e380b3c1f13b3756d128543#npm:10.8.2"],\
|
||||
["ts-node", "virtual:8859b278716fedf3e7458b5628625f7e35678c418626878559a0b816445001b7e24c55546f4677ba4c20b521aa0cf52cc33ac07deff171e383ada6eeab69933f#npm:10.9.1"],\
|
||||
["typescript", "patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=7ad353"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -3035,7 +3036,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["ts-jest", "virtual:c66bf20e88479ada0172094776519a9f51acc4731d22079b60a295bcec7ea42d5545cbce58a77a50d932bf953298799135e99707486e343da6d99ba1d167bdbd#npm:28.0.5"],\
|
||||
["typeorm", "virtual:31b5a94a105c89c9294c3d524a7f8929fe63ee5a2efadf21951ca4c0cfd2ecf02e8f4ef5a066bbda091f1e3a56e57c6749069a080618c96b22e51131a330fc4a#npm:0.3.7"],\
|
||||
["ua-parser-js", "npm:1.0.2"],\
|
||||
["uuid", "npm:8.3.2"],\
|
||||
["uuid", "npm:9.0.0"],\
|
||||
["winston", "npm:3.8.1"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
@@ -12187,10 +12188,53 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:10.8.2", {\
|
||||
"packageLocation": "./.yarn/__virtual__/ts-node-virtual-8a01a45377/0/cache/ts-node-npm-10.8.2-f3c0c9eaee-1eede939be.zip/node_modules/ts-node/",\
|
||||
["npm:10.9.1", {\
|
||||
"packageLocation": "./.yarn/cache/ts-node-npm-10.9.1-6c268be7f4-090adff130.zip/node_modules/ts-node/",\
|
||||
"packageDependencies": [\
|
||||
["ts-node", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:10.8.2"],\
|
||||
["ts-node", "npm:10.9.1"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:8859b278716fedf3e7458b5628625f7e35678c418626878559a0b816445001b7e24c55546f4677ba4c20b521aa0cf52cc33ac07deff171e383ada6eeab69933f#npm:10.9.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/ts-node-virtual-ac01688ebc/0/cache/ts-node-npm-10.9.1-6c268be7f4-090adff130.zip/node_modules/ts-node/",\
|
||||
"packageDependencies": [\
|
||||
["ts-node", "virtual:8859b278716fedf3e7458b5628625f7e35678c418626878559a0b816445001b7e24c55546f4677ba4c20b521aa0cf52cc33ac07deff171e383ada6eeab69933f#npm:10.9.1"],\
|
||||
["@cspotcode/source-map-support", "npm:0.8.1"],\
|
||||
["@swc/core", null],\
|
||||
["@swc/wasm", null],\
|
||||
["@tsconfig/node10", "npm:1.0.9"],\
|
||||
["@tsconfig/node12", "npm:1.0.11"],\
|
||||
["@tsconfig/node14", "npm:1.0.3"],\
|
||||
["@tsconfig/node16", "npm:1.0.3"],\
|
||||
["@types/node", "npm:18.0.3"],\
|
||||
["@types/swc__core", null],\
|
||||
["@types/swc__wasm", null],\
|
||||
["@types/typescript", null],\
|
||||
["acorn", "npm:8.7.1"],\
|
||||
["acorn-walk", "npm:8.2.0"],\
|
||||
["arg", "npm:4.1.3"],\
|
||||
["create-require", "npm:1.1.1"],\
|
||||
["diff", "npm:4.0.2"],\
|
||||
["make-error", "npm:1.3.6"],\
|
||||
["typescript", "patch:typescript@npm%3A4.7.4#~builtin<compat/typescript>::version=4.7.4&hash=7ad353"],\
|
||||
["v8-compile-cache-lib", "npm:3.0.1"],\
|
||||
["yn", "npm:3.1.1"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@swc/core",\
|
||||
"@swc/wasm",\
|
||||
"@types/node",\
|
||||
"@types/swc__core",\
|
||||
"@types/swc__wasm",\
|
||||
"@types/typescript",\
|
||||
"typescript"\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:10.9.1", {\
|
||||
"packageLocation": "./.yarn/__virtual__/ts-node-virtual-c4e9951caa/0/cache/ts-node-npm-10.9.1-6c268be7f4-090adff130.zip/node_modules/ts-node/",\
|
||||
"packageDependencies": [\
|
||||
["ts-node", "virtual:b442cf0427cc365d1c137f7340f9b81f9b204561afe791a8564ae9590c3a7fc4b5f793aaf8817b946f75a3cb64d03ef8790eb847f8b576b41e700da7b00c240c#npm:10.9.1"],\
|
||||
["@cspotcode/source-map-support", "npm:0.8.1"],\
|
||||
["@swc/core", null],\
|
||||
["@swc/wasm", null],\
|
||||
@@ -12735,6 +12779,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["uuid", "npm:8.3.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:9.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/uuid-npm-9.0.0-46c41e3e43-8dd2c83c43.zip/node_modules/uuid/",\
|
||||
"packageDependencies": [\
|
||||
["uuid", "npm:9.0.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["v8-compile-cache", [\
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Generated
Vendored
+1
-1
@@ -327,7 +327,7 @@ endif
|
||||
|
||||
quiet_cmd_regen_makefile = ACTION Regenerating $@
|
||||
cmd_regen_makefile = cd $(srcdir); /Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/Users/karolsojko/Library/Caches/node-gyp/16.15.1" "-Dnode_gyp_dir=/Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp" "-Dnode_lib_file=/Users/karolsojko/Library/Caches/node-gyp/16.15.1/<(target_arch)/node.lib" "-Dmodule_root_dir=/Users/karolsojko/workspace/server/.yarn/unplugged/@newrelic-native-metrics-npm-9.0.0-590d2e713a/node_modules/@newrelic/native-metrics" "-Dnode_engine=v8" "--depth=." "-Goutput_dir=." "--generator-output=build" -I/Users/karolsojko/workspace/server/.yarn/unplugged/@newrelic-native-metrics-npm-9.0.0-590d2e713a/node_modules/@newrelic/native-metrics/build/config.gypi -I/Users/karolsojko/workspace/server/.yarn/unplugged/node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/addon.gypi -I/Users/karolsojko/Library/Caches/node-gyp/16.15.1/include/node/common.gypi "--toplevel-dir=." binding.gyp
|
||||
Makefile: $(srcdir)/binding.gyp $(srcdir)/../../../../../../../../Library/Caches/node-gyp/16.15.1/include/node/common.gypi $(srcdir)/build/config.gypi $(srcdir)/../../../../node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/addon.gypi
|
||||
Makefile: $(srcdir)/binding.gyp $(srcdir)/../../../../node-gyp-npm-9.0.0-0eccfca4d1/node_modules/node-gyp/addon.gypi $(srcdir)/../../../../../../../../Library/Caches/node-gyp/16.15.1/include/node/common.gypi $(srcdir)/build/config.gypi
|
||||
$(call do_cmd,regen_makefile)
|
||||
|
||||
# "all" is a concatenation of the "all" targets from all the included
|
||||
|
||||
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
+1
-1
@@ -60,7 +60,7 @@
|
||||
"ini": "^3.0.0",
|
||||
"npm-check-updates": "^16.0.1",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-node": "^10.8.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"packageManager": "yarn@3.2.1",
|
||||
|
||||
@@ -3,6 +3,72 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [1.22.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.21.1...@standardnotes/analytics@1.22.0) (2022-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add statistics for refunds and account deletions ([d7ae2f0](https://github.com/standardnotes/server/commit/d7ae2f06255b19eb5d3403a4989610390064754e))
|
||||
|
||||
## [1.21.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.21.0...@standardnotes/analytics@1.21.1) (2022-09-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** increment by float instead of integer on measures ([cb81f81](https://github.com/standardnotes/server/commit/cb81f819ba30a45f27ec344480b5ef22e5a0a50d))
|
||||
|
||||
# [1.21.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.20.0...@standardnotes/analytics@1.21.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add measuring subscription length ([fa10827](https://github.com/standardnotes/server/commit/fa108274430d8dff1016ddcba5bbcb2778eb781b))
|
||||
|
||||
# [1.20.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.19.0...@standardnotes/analytics@1.20.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add keeping stats on payments ([0c176b7](https://github.com/standardnotes/server/commit/0c176b70f8281e1e490224b9c7ab85f272a3d4e9))
|
||||
|
||||
# [1.19.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.18.1...@standardnotes/analytics@1.19.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add statistics measurements tracking ([a36cb92](https://github.com/standardnotes/server/commit/a36cb925ff3bd8396a53f58c3e954549e904d694))
|
||||
|
||||
## [1.18.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.18.0...@standardnotes/analytics@1.18.1) (2022-08-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** add payment success activity ([9307893](https://github.com/standardnotes/server/commit/930789316c2eec8227f26e75d4917796168f2d08))
|
||||
|
||||
# [1.18.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.17.2...@standardnotes/analytics@1.18.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add payment failed event handler ([58c5b58](https://github.com/standardnotes/server/commit/58c5b586a904cf1fd179cc28783a6ae7da688063))
|
||||
|
||||
## [1.17.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.17.1...@standardnotes/analytics@1.17.2) (2022-08-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** quarterly calculations over time ([43d957c](https://github.com/standardnotes/server/commit/43d957c8d382b501e8101b51e30b33f18a4dd871))
|
||||
|
||||
## [1.17.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.17.0...@standardnotes/analytics@1.17.1) (2022-08-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** expire bitop keys ([269eef7](https://github.com/standardnotes/server/commit/269eef7ef31343390c6909350bf1bfede94c24b3))
|
||||
|
||||
# [1.17.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.16.0...@standardnotes/analytics@1.17.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add quarterly analytics ([67378e4](https://github.com/standardnotes/server/commit/67378e4535ef2760cfe3fe27256ffe117ee11a71))
|
||||
|
||||
# [1.16.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.15.0...@standardnotes/analytics@1.16.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add calculating quarterly stats ([32c8333](https://github.com/standardnotes/server/commit/32c8333564dea742b28ccc6f09e5fa33dd1f7af2))
|
||||
|
||||
# [1.15.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@1.14.0...@standardnotes/analytics@1.15.0) (2022-08-11)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "1.15.0",
|
||||
"version": "1.22.0",
|
||||
"engines": {
|
||||
"node": ">=14.0.0 <17.0.0"
|
||||
},
|
||||
@@ -23,7 +23,7 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test:unit": "jest spec --coverage"
|
||||
"test": "jest spec --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/ioredis": "^4.28.10",
|
||||
|
||||
@@ -11,4 +11,6 @@ export enum AnalyticsActivity {
|
||||
EmailUnbackedUpData = 'email-unbacked-up-data',
|
||||
EmailBackup = 'email-backup',
|
||||
LimitedDiscountOfferPurchased = 'limited-discount-offer-purchased',
|
||||
PaymentFailed = 'payment-failed',
|
||||
PaymentSuccess = 'payment-success',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum StatisticsMeasure {
|
||||
Income = 'income',
|
||||
SubscriptionLength = 'subscription-length',
|
||||
RegistrationLength = 'registration-length',
|
||||
Refunds = 'refunds',
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
import { Period } from '../Time/Period'
|
||||
import { StatisticsMeasure } from './StatisticsMeasure'
|
||||
|
||||
export interface StatisticsStoreInterface {
|
||||
incrementSNJSVersionUsage(snjsVersion: string): Promise<void>
|
||||
incrementApplicationVersionUsage(applicationVersion: string): Promise<void>
|
||||
@@ -5,4 +8,7 @@ export interface StatisticsStoreInterface {
|
||||
getYesterdaySNJSUsage(): Promise<Array<{ version: string; count: number }>>
|
||||
getYesterdayApplicationUsage(): Promise<Array<{ version: string; count: number }>>
|
||||
getYesterdayOutOfSyncIncidents(): Promise<number>
|
||||
incrementMeasure(measure: StatisticsMeasure, value: number, periods: Period[]): Promise<void>
|
||||
getMeasureAverage(measure: StatisticsMeasure, period: Period): Promise<number>
|
||||
getMeasureTotal(measure: StatisticsMeasure, period: Period): Promise<number>
|
||||
}
|
||||
|
||||
@@ -8,4 +8,8 @@ export enum Period {
|
||||
ThisMonth,
|
||||
LastMonth,
|
||||
Last30Days,
|
||||
Q1ThisYear,
|
||||
Q2ThisYear,
|
||||
Q3ThisYear,
|
||||
Q4ThisYear,
|
||||
}
|
||||
|
||||
@@ -48,6 +48,22 @@ describe('PeriodKeyGenerator', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('should generate period keys for Q1', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Q1ThisYear)).toEqual(['2022-1', '2022-2', '2022-3'])
|
||||
})
|
||||
|
||||
it('should generate period keys for Q2', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Q2ThisYear)).toEqual(['2022-4', '2022-5', '2022-6'])
|
||||
})
|
||||
|
||||
it('should generate period keys for Q3', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Q3ThisYear)).toEqual(['2022-7', '2022-8', '2022-9'])
|
||||
})
|
||||
|
||||
it('should generate period keys for Q4', () => {
|
||||
expect(createGenerator().getDiscretePeriodKeys(Period.Q4ThisYear)).toEqual(['2022-10', '2022-11', '2022-12'])
|
||||
})
|
||||
|
||||
it('should generate a period key for today', () => {
|
||||
expect(createGenerator().getPeriodKey(Period.Today)).toEqual('2022-5-24')
|
||||
})
|
||||
|
||||
@@ -12,6 +12,14 @@ export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
}
|
||||
|
||||
return periodKeys
|
||||
case Period.Q1ThisYear:
|
||||
return this.generateMonthlyKeysRange(0, 3)
|
||||
case Period.Q2ThisYear:
|
||||
return this.generateMonthlyKeysRange(3, 6)
|
||||
case Period.Q3ThisYear:
|
||||
return this.generateMonthlyKeysRange(6, 9)
|
||||
case Period.Q4ThisYear:
|
||||
return this.generateMonthlyKeysRange(9, 12)
|
||||
default:
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
@@ -115,4 +123,16 @@ export class PeriodKeyGenerator implements PeriodKeyGeneratorInterface {
|
||||
|
||||
return yesterday
|
||||
}
|
||||
|
||||
private generateMonthlyKeysRange(startingMonthIndex: number, endingMonthIndex: number): string[] {
|
||||
const today = new Date()
|
||||
const keys = []
|
||||
for (let i = startingMonthIndex; i < endingMonthIndex; i++) {
|
||||
today.setMonth(i)
|
||||
today.setDate(1)
|
||||
keys.push(this.getMonthlyKey(today))
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './Analytics/AnalyticsActivity'
|
||||
export * from './Analytics/AnalyticsStoreInterface'
|
||||
export * from './Statistics/StatisticsMeasure'
|
||||
export * from './Statistics/StatisticsStoreInterface'
|
||||
export * from './Time/Period'
|
||||
export * from './Time/PeriodKeyGenerator'
|
||||
|
||||
@@ -24,6 +24,7 @@ describe('RedisAnalyticsStore', () => {
|
||||
redisClient.setbit = jest.fn()
|
||||
redisClient.getbit = jest.fn().mockReturnValue(1)
|
||||
redisClient.bitop = jest.fn()
|
||||
redisClient.expire = jest.fn()
|
||||
|
||||
periodKeyGenerator = {} as jest.Mocked<PeriodKeyGeneratorInterface>
|
||||
periodKeyGenerator.getPeriodKey = jest.fn().mockReturnValue('period-key')
|
||||
@@ -48,6 +49,17 @@ describe('RedisAnalyticsStore', () => {
|
||||
expect(redisClient.bitcount).toHaveBeenCalledWith('bitmap:action:editing-items:timespan:2022-4-24-2022-4-26')
|
||||
})
|
||||
|
||||
it('should not calculate total count over time of activities if period is unsupported', async () => {
|
||||
let caughtError = null
|
||||
try {
|
||||
await createStore().calculateActivityTotalCountOverTime(AnalyticsActivity.EditingItems, Period.LastWeek)
|
||||
} catch (error) {
|
||||
caughtError = error
|
||||
}
|
||||
|
||||
expect(caughtError).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should calculate total count changes of activities', async () => {
|
||||
periodKeyGenerator.getDiscretePeriodKeys = jest.fn().mockReturnValue(['2022-4-24', '2022-4-25', '2022-4-26'])
|
||||
|
||||
|
||||
@@ -9,17 +9,24 @@ export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
|
||||
|
||||
async calculateActivityTotalCountOverTime(activity: AnalyticsActivity, period: Period): Promise<number> {
|
||||
if (period !== Period.Last30Days) {
|
||||
if (
|
||||
![Period.Last30Days, Period.Q1ThisYear, Period.Q2ThisYear, Period.Q3ThisYear, Period.Q4ThisYear].includes(period)
|
||||
) {
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
|
||||
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(Period.Last30Days)
|
||||
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(period)
|
||||
await this.redisClient.bitop(
|
||||
'OR',
|
||||
`bitmap:action:${activity}:timespan:${periodKeys[0]}-${periodKeys[periodKeys.length - 1]}`,
|
||||
...periodKeys.map((p) => `bitmap:action:${activity}:timespan:${p}`),
|
||||
)
|
||||
|
||||
await this.redisClient.expire(
|
||||
`bitmap:action:${activity}:timespan:${periodKeys[0]}-${periodKeys[periodKeys.length - 1]}`,
|
||||
3600,
|
||||
)
|
||||
|
||||
return this.redisClient.bitcount(
|
||||
`bitmap:action:${activity}:timespan:${periodKeys[0]}-${periodKeys[periodKeys.length - 1]}`,
|
||||
)
|
||||
@@ -29,11 +36,13 @@ export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||
activity: AnalyticsActivity,
|
||||
period: Period,
|
||||
): Promise<Array<{ periodKey: string; totalCount: number }>> {
|
||||
if (period !== Period.Last30Days) {
|
||||
if (
|
||||
![Period.Last30Days, Period.Q1ThisYear, Period.Q2ThisYear, Period.Q3ThisYear, Period.Q4ThisYear].includes(period)
|
||||
) {
|
||||
throw new Error(`Unsuporrted period: ${period}`)
|
||||
}
|
||||
|
||||
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(Period.Last30Days)
|
||||
const periodKeys = this.periodKeyGenerator.getDiscretePeriodKeys(period)
|
||||
const counts = []
|
||||
for (const periodKey of periodKeys) {
|
||||
counts.push({
|
||||
@@ -103,6 +112,8 @@ export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||
`bitmap:action:${activity}:timespan:${subsequentPeriodKey}`,
|
||||
)
|
||||
|
||||
await this.redisClient.expire(diffKey, 3600)
|
||||
|
||||
const retainedTotalInActivity = await this.redisClient.bitcount(diffKey)
|
||||
|
||||
const initialTotalInActivity = await this.redisClient.bitcount(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import * as IORedis from 'ioredis'
|
||||
import { PeriodKeyGeneratorInterface } from '../../Domain'
|
||||
|
||||
import { Period, PeriodKeyGeneratorInterface } from '../../Domain'
|
||||
import { StatisticsMeasure } from '../../Domain/Statistics/StatisticsMeasure'
|
||||
|
||||
import { RedisStatisticsStore } from './RedisStatisticsStore'
|
||||
|
||||
@@ -13,6 +15,7 @@ describe('RedisStatisticsStore', () => {
|
||||
beforeEach(() => {
|
||||
pipeline = {} as jest.Mocked<IORedis.Pipeline>
|
||||
pipeline.incr = jest.fn()
|
||||
pipeline.incrbyfloat = jest.fn()
|
||||
pipeline.setbit = jest.fn()
|
||||
pipeline.exec = jest.fn()
|
||||
|
||||
@@ -88,4 +91,30 @@ describe('RedisStatisticsStore', () => {
|
||||
expect(pipeline.incr).toHaveBeenCalled()
|
||||
expect(pipeline.exec).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should increment measure by a value', async () => {
|
||||
await createStore().incrementMeasure(StatisticsMeasure.PaymentSuccess, 2, [Period.Today, Period.ThisMonth])
|
||||
|
||||
expect(pipeline.incr).toHaveBeenCalledTimes(2)
|
||||
expect(pipeline.incrbyfloat).toHaveBeenCalledTimes(2)
|
||||
expect(pipeline.exec).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should count a measurement average', async () => {
|
||||
redisClient.get = jest.fn().mockReturnValueOnce('5').mockReturnValueOnce('2')
|
||||
|
||||
expect(await createStore().getMeasureAverage(StatisticsMeasure.PaymentSuccess, Period.Today)).toEqual(2 / 5)
|
||||
})
|
||||
|
||||
it('should count a measurement average - 0 increments', async () => {
|
||||
redisClient.get = jest.fn().mockReturnValueOnce(null).mockReturnValueOnce(null)
|
||||
|
||||
expect(await createStore().getMeasureAverage(StatisticsMeasure.PaymentSuccess, Period.Today)).toEqual(0)
|
||||
})
|
||||
|
||||
it('should count a measurement average - 0 total value', async () => {
|
||||
redisClient.get = jest.fn().mockReturnValueOnce(5).mockReturnValueOnce(null)
|
||||
|
||||
expect(await createStore().getMeasureAverage(StatisticsMeasure.PaymentSuccess, Period.Today)).toEqual(0)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,12 +1,49 @@
|
||||
import * as IORedis from 'ioredis'
|
||||
|
||||
import { Period, PeriodKeyGeneratorInterface } from '../../Domain'
|
||||
import { StatisticsMeasure } from '../../Domain/Statistics/StatisticsMeasure'
|
||||
|
||||
import { StatisticsStoreInterface } from '../../Domain/Statistics/StatisticsStoreInterface'
|
||||
|
||||
export class RedisStatisticsStore implements StatisticsStoreInterface {
|
||||
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
|
||||
|
||||
async getMeasureTotal(measure: StatisticsMeasure, period: Period): Promise<number> {
|
||||
const totalValue = await this.redisClient.get(
|
||||
`count:measure:${measure}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
|
||||
)
|
||||
|
||||
if (totalValue === null) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return +totalValue
|
||||
}
|
||||
|
||||
async incrementMeasure(measure: StatisticsMeasure, value: number, periods: Period[]): Promise<void> {
|
||||
const pipeline = this.redisClient.pipeline()
|
||||
|
||||
for (const period of periods) {
|
||||
pipeline.incrbyfloat(`count:measure:${measure}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`, value)
|
||||
pipeline.incr(`count:increments:${measure}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`)
|
||||
}
|
||||
|
||||
await pipeline.exec()
|
||||
}
|
||||
|
||||
async getMeasureAverage(measure: StatisticsMeasure, period: Period): Promise<number> {
|
||||
const increments = await this.redisClient.get(
|
||||
`count:increments:${measure}:timespan:${this.periodKeyGenerator.getPeriodKey(period)}`,
|
||||
)
|
||||
if (increments === null) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const totalValue = await this.getMeasureTotal(measure, period)
|
||||
|
||||
return totalValue / +increments
|
||||
}
|
||||
|
||||
async getYesterdayOutOfSyncIncidents(): Promise<number> {
|
||||
const count = await this.redisClient.get(
|
||||
`count:action:out-of-sync:timespan:${this.periodKeyGenerator.getPeriodKey(Period.Yesterday)}`,
|
||||
|
||||
@@ -3,6 +3,103 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.16.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.16.1...@standardnotes/api-gateway@1.16.2) (2022-09-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** include period key in statistics measures ([d149f46](https://github.com/standardnotes/api-gateway/commit/d149f46cf6456201dd8690977f64ed32a75f3459))
|
||||
* **api-gateway:** period types on analytics report ([f94c8fc](https://github.com/standardnotes/api-gateway/commit/f94c8fc26e684a07101cc5282ebb9cda3c8c6961))
|
||||
|
||||
## [1.16.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.16.0...@standardnotes/api-gateway@1.16.1) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.16.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.12...@standardnotes/api-gateway@1.16.0) (2022-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add statistics measures to report generation ([8151bb1](https://github.com/standardnotes/api-gateway/commit/8151bb108affb2b5cfa1ab365f99a9f0170a7795))
|
||||
|
||||
## [1.15.12](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.11...@standardnotes/api-gateway@1.15.12) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.11](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.10...@standardnotes/api-gateway@1.15.11) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.10](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.9...@standardnotes/api-gateway@1.15.10) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.9](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.8...@standardnotes/api-gateway@1.15.9) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.8](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.7...@standardnotes/api-gateway@1.15.8) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.7](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.6...@standardnotes/api-gateway@1.15.7) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.6](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.5...@standardnotes/api-gateway@1.15.6) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.5](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.4...@standardnotes/api-gateway@1.15.5) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.4](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.3...@standardnotes/api-gateway@1.15.4) (2022-08-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.15.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.2...@standardnotes/api-gateway@1.15.3) (2022-08-22)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** add error logs on missing connection id for websockets ([f7def38](https://github.com/standardnotes/api-gateway/commit/f7def38e20f87ae24ebc736a41bc7cac53b0c61f))
|
||||
|
||||
## [1.15.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.1...@standardnotes/api-gateway@1.15.2) (2022-08-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** add payment success events to report ([ee79347](https://github.com/standardnotes/api-gateway/commit/ee79347e27f5887def2cda57091a7c0a40570d33))
|
||||
|
||||
## [1.15.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.15.0...@standardnotes/api-gateway@1.15.1) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.15.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.14.3...@standardnotes/api-gateway@1.15.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add gathering analytics for failed payments ([d0023a6](https://github.com/standardnotes/api-gateway/commit/d0023a6c92756c81b8daa9089d38141b6cd4fe48))
|
||||
|
||||
## [1.14.3](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.14.2...@standardnotes/api-gateway@1.14.3) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.14.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.14.1...@standardnotes/api-gateway@1.14.2) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.14.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.14.0...@standardnotes/api-gateway@1.14.1) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.14.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.13.1...@standardnotes/api-gateway@1.14.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add quarterly analytics ([67378e4](https://github.com/standardnotes/api-gateway/commit/67378e4535ef2760cfe3fe27256ffe117ee11a71))
|
||||
|
||||
## [1.13.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.13.0...@standardnotes/api-gateway@1.13.1) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
# [1.13.0](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.12.0...@standardnotes/api-gateway@1.13.0) (2022-08-11)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -12,13 +12,96 @@ import {
|
||||
DailyAnalyticsReportGeneratedEvent,
|
||||
DomainEventService,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { AnalyticsActivity, AnalyticsStoreInterface, Period, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
import {
|
||||
AnalyticsActivity,
|
||||
AnalyticsStoreInterface,
|
||||
Period,
|
||||
StatisticsMeasure,
|
||||
StatisticsStoreInterface,
|
||||
} from '@standardnotes/analytics'
|
||||
|
||||
const requestReport = async (
|
||||
analyticsStore: AnalyticsStoreInterface,
|
||||
statisticsStore: StatisticsStoreInterface,
|
||||
domainEventPublisher: DomainEventPublisherInterface,
|
||||
): Promise<void> => {
|
||||
const analyticsOverTime = []
|
||||
|
||||
const thirtyDaysAnalyticsNames = [
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
AnalyticsActivity.EditingItems,
|
||||
AnalyticsActivity.SubscriptionPurchased,
|
||||
AnalyticsActivity.Register,
|
||||
AnalyticsActivity.SubscriptionRenewed,
|
||||
AnalyticsActivity.DeleteAccount,
|
||||
AnalyticsActivity.SubscriptionCancelled,
|
||||
AnalyticsActivity.SubscriptionRefunded,
|
||||
]
|
||||
|
||||
for (const analyticsName of thirtyDaysAnalyticsNames) {
|
||||
analyticsOverTime.push({
|
||||
name: analyticsName,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(analyticsName, Period.Last30Days),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(analyticsName, Period.Last30Days),
|
||||
})
|
||||
}
|
||||
|
||||
const quarterlyAnalyticsNames = [
|
||||
AnalyticsActivity.Register,
|
||||
AnalyticsActivity.SubscriptionPurchased,
|
||||
AnalyticsActivity.SubscriptionRenewed,
|
||||
]
|
||||
|
||||
for (const analyticsName of quarterlyAnalyticsNames) {
|
||||
for (const period of [Period.Q1ThisYear, Period.Q2ThisYear, Period.Q3ThisYear, Period.Q4ThisYear]) {
|
||||
analyticsOverTime.push({
|
||||
name: analyticsName,
|
||||
period: period,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(analyticsName, period),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(analyticsName, period),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const yesterdayActivityStatistics = []
|
||||
const yesterdayActivityNames = [
|
||||
AnalyticsActivity.LimitedDiscountOfferPurchased,
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
AnalyticsActivity.PaymentFailed,
|
||||
AnalyticsActivity.PaymentSuccess,
|
||||
]
|
||||
|
||||
for (const activityName of yesterdayActivityNames) {
|
||||
yesterdayActivityStatistics.push({
|
||||
name: activityName,
|
||||
retention: await analyticsStore.calculateActivityRetention(
|
||||
activityName,
|
||||
Period.DayBeforeYesterday,
|
||||
Period.Yesterday,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(activityName, Period.Yesterday),
|
||||
})
|
||||
}
|
||||
|
||||
const statisticMeasureNames = [
|
||||
StatisticsMeasure.Income,
|
||||
StatisticsMeasure.Refunds,
|
||||
StatisticsMeasure.RegistrationLength,
|
||||
StatisticsMeasure.SubscriptionLength,
|
||||
]
|
||||
const statisticMeasures = []
|
||||
for (const statisticMeasureName of statisticMeasureNames) {
|
||||
for (const period of [Period.Yesterday, Period.ThisMonth]) {
|
||||
statisticMeasures.push({
|
||||
name: statisticMeasureName,
|
||||
period,
|
||||
totalValue: await statisticsStore.getMeasureTotal(statisticMeasureName, period),
|
||||
average: await statisticsStore.getMeasureAverage(statisticMeasureName, period),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const event: DailyAnalyticsReportGeneratedEvent = {
|
||||
type: 'DAILY_ANALYTICS_REPORT_GENERATED',
|
||||
createdAt: new Date(),
|
||||
@@ -33,138 +116,9 @@ const requestReport = async (
|
||||
applicationStatistics: await statisticsStore.getYesterdayApplicationUsage(),
|
||||
snjsStatistics: await statisticsStore.getYesterdaySNJSUsage(),
|
||||
outOfSyncIncidents: await statisticsStore.getYesterdayOutOfSyncIncidents(),
|
||||
activityStatistics: [
|
||||
{
|
||||
name: AnalyticsActivity.EditingItems,
|
||||
retention: await analyticsStore.calculateActivityRetention(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.DayBeforeYesterday,
|
||||
Period.Yesterday,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.LimitedDiscountOfferPurchased,
|
||||
retention: 0,
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.LimitedDiscountOfferPurchased,
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.GeneralActivity,
|
||||
retention: await analyticsStore.calculateActivityRetention(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.DayBeforeYesterday,
|
||||
Period.Yesterday,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCount(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.Yesterday,
|
||||
),
|
||||
},
|
||||
],
|
||||
activityStatisticsOverTime: [
|
||||
{
|
||||
name: AnalyticsActivity.GeneralActivity,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.GeneralActivity,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.EditingItems,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.EditingItems,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.SubscriptionPurchased,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.SubscriptionPurchased,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.SubscriptionPurchased,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.Register,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.Register,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.Register,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.SubscriptionRenewed,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.SubscriptionRenewed,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.SubscriptionRenewed,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.DeleteAccount,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.DeleteAccount,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.DeleteAccount,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.SubscriptionCancelled,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.SubscriptionCancelled,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.SubscriptionCancelled,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: AnalyticsActivity.SubscriptionRefunded,
|
||||
period: Period.Last30Days,
|
||||
counts: await analyticsStore.calculateActivityChangesTotalCount(
|
||||
AnalyticsActivity.SubscriptionRefunded,
|
||||
Period.Last30Days,
|
||||
),
|
||||
totalCount: await analyticsStore.calculateActivityTotalCountOverTime(
|
||||
AnalyticsActivity.SubscriptionRefunded,
|
||||
Period.Last30Days,
|
||||
),
|
||||
},
|
||||
],
|
||||
activityStatistics: yesterdayActivityStatistics,
|
||||
activityStatisticsOverTime: analyticsOverTime,
|
||||
statisticMeasures,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.13.0",
|
||||
"version": "1.16.2",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import { Request, Response } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { BaseHttpController, controller, httpDelete, httpPost } from 'inversify-express-utils'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { HttpServiceInterface } from '../../Service/Http/HttpServiceInterface'
|
||||
|
||||
@controller('/v1/sockets')
|
||||
export class WebSocketsController extends BaseHttpController {
|
||||
constructor(@inject(TYPES.HTTPService) private httpService: HttpServiceInterface) {
|
||||
constructor(
|
||||
@inject(TYPES.HTTPService) private httpService: HttpServiceInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
@httpPost('/', TYPES.AuthMiddleware)
|
||||
async createWebSocketConnection(request: Request, response: Response): Promise<void> {
|
||||
if (!request.headers.connectionid) {
|
||||
this.logger.error('Could not create a websocket connection. Missing connection id header.')
|
||||
|
||||
response.status(400).send('Missing connection id in the request')
|
||||
|
||||
return
|
||||
@@ -24,6 +31,8 @@ export class WebSocketsController extends BaseHttpController {
|
||||
@httpDelete('/')
|
||||
async deleteWebSocketConnection(request: Request, response: Response): Promise<void> {
|
||||
if (!request.headers.connectionid) {
|
||||
this.logger.error('Could not delete a websocket connection. Missing connection id header.')
|
||||
|
||||
response.status(400).send('Missing connection id in the request')
|
||||
|
||||
return
|
||||
|
||||
@@ -3,6 +3,122 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.24.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.24.2...@standardnotes/auth-server@1.24.3) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.24.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.24.1...@standardnotes/auth-server@1.24.2) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.24.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.24.0...@standardnotes/auth-server@1.24.1) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.24.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.23.2...@standardnotes/auth-server@1.24.0) (2022-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add statistics for refunds and account deletions ([d7ae2f0](https://github.com/standardnotes/server/commit/d7ae2f06255b19eb5d3403a4989610390064754e))
|
||||
|
||||
## [1.23.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.23.1...@standardnotes/auth-server@1.23.2) (2022-09-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** add debug logs for subscription canceling ([2ca430f](https://github.com/standardnotes/server/commit/2ca430f40ce6a8d56aafa27e9c2d0b0dd561c650))
|
||||
|
||||
## [1.23.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.23.0...@standardnotes/auth-server@1.23.1) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.23.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.22.1...@standardnotes/auth-server@1.23.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add measuring subscription length ([fa10827](https://github.com/standardnotes/server/commit/fa108274430d8dff1016ddcba5bbcb2778eb781b))
|
||||
|
||||
## [1.22.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.22.0...@standardnotes/auth-server@1.22.1) (2022-09-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** StatisticsStore binding ([34315c9](https://github.com/standardnotes/server/commit/34315c91d7428bbe8297e50972aa7823e2a983b2))
|
||||
|
||||
# [1.22.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.21.5...@standardnotes/auth-server@1.22.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add keeping stats on payments ([0c176b7](https://github.com/standardnotes/server/commit/0c176b70f8281e1e490224b9c7ab85f272a3d4e9))
|
||||
|
||||
## [1.21.5](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.21.4...@standardnotes/auth-server@1.21.5) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.21.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.21.3...@standardnotes/auth-server@1.21.4) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.21.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.21.2...@standardnotes/auth-server@1.21.3) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.21.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.21.1...@standardnotes/auth-server@1.21.2) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.21.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.21.0...@standardnotes/auth-server@1.21.1) (2022-08-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.21.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.20.1...@standardnotes/auth-server@1.21.0) (2022-08-29)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** retain user agent, api version and received at on revoked sessions ([dc88e24](https://github.com/standardnotes/server/commit/dc88e2413b3be254b265d2874174eaac39d628ee))
|
||||
|
||||
## [1.20.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.20.0...@standardnotes/auth-server@1.20.1) (2022-08-17)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** change discount from 10% to 20% on a limited time offer ([4b3de26](https://github.com/standardnotes/server/commit/4b3de264efc4fffb2603181c158cddb25c4ed4a9))
|
||||
|
||||
# [1.20.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.19.1...@standardnotes/auth-server@1.20.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add payment success event handler ([01a08ea](https://github.com/standardnotes/server/commit/01a08eae582e070ec844f5e05f34260447b7d4c6))
|
||||
|
||||
## [1.19.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.19.0...@standardnotes/auth-server@1.19.1) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.19.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.18.4...@standardnotes/auth-server@1.19.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add payment failed event handler ([58c5b58](https://github.com/standardnotes/server/commit/58c5b586a904cf1fd179cc28783a6ae7da688063))
|
||||
|
||||
## [1.18.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.18.3...@standardnotes/auth-server@1.18.4) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.18.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.18.2...@standardnotes/auth-server@1.18.3) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.18.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.18.1...@standardnotes/auth-server@1.18.2) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
## [1.18.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.18.0...@standardnotes/auth-server@1.18.1) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
# [1.18.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.17.0...@standardnotes/auth-server@1.18.0) (2022-08-12)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add endpoint for generating offline subscription tokens for admin panel ([c61b615](https://github.com/standardnotes/server/commit/c61b615da6e1d4556e60e73d7414a80e8b331fca))
|
||||
|
||||
# [1.17.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.16.2...@standardnotes/auth-server@1.17.0) (2022-08-11)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm'
|
||||
|
||||
export class revokedSessionData1661771230400 implements MigrationInterface {
|
||||
name = 'revokedSessionData1661771230400'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('ALTER TABLE `revoked_sessions` ADD `received_at` datetime NULL')
|
||||
await queryRunner.query('ALTER TABLE `revoked_sessions` ADD `user_agent` text NULL')
|
||||
await queryRunner.query('ALTER TABLE `revoked_sessions` ADD `api_version` varchar(255) NULL')
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.17.0",
|
||||
"version": "1.24.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -63,7 +63,7 @@
|
||||
"reflect-metadata": "0.1.13",
|
||||
"typeorm": "^0.3.6",
|
||||
"ua-parser-js": "1.0.2",
|
||||
"uuid": "8.3.2",
|
||||
"uuid": "^9.0.0",
|
||||
"winston": "^3.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -9,7 +9,13 @@ import {
|
||||
} from '@standardnotes/domain-events'
|
||||
import { TimerInterface, Timer } from '@standardnotes/time'
|
||||
import { UAParser } from 'ua-parser-js'
|
||||
import { AnalyticsStoreInterface, PeriodKeyGenerator, RedisAnalyticsStore } from '@standardnotes/analytics'
|
||||
import {
|
||||
AnalyticsStoreInterface,
|
||||
PeriodKeyGenerator,
|
||||
RedisAnalyticsStore,
|
||||
RedisStatisticsStore,
|
||||
StatisticsStoreInterface,
|
||||
} from '@standardnotes/analytics'
|
||||
|
||||
import { Env } from './Env'
|
||||
import TYPES from './Types'
|
||||
@@ -191,6 +197,9 @@ import { AuthController } from '../Controller/AuthController'
|
||||
import { VerifyPredicate } from '../Domain/UseCase/VerifyPredicate/VerifyPredicate'
|
||||
import { PredicateVerificationRequestedEventHandler } from '../Domain/Handler/PredicateVerificationRequestedEventHandler'
|
||||
import { MuteMarketingEmails } from '../Domain/UseCase/MuteMarketingEmails/MuteMarketingEmails'
|
||||
import { PaymentFailedEventHandler } from '../Domain/Handler/PaymentFailedEventHandler'
|
||||
import { PaymentSuccessEventHandler } from '../Domain/Handler/PaymentSuccessEventHandler'
|
||||
import { RefundProcessedEventHandler } from '../Domain/Handler/RefundProcessedEventHandler'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const newrelicFormatter = require('@newrelic/winston-enricher')
|
||||
@@ -478,6 +487,9 @@ export class ContainerConfigLoader {
|
||||
container
|
||||
.bind<PredicateVerificationRequestedEventHandler>(TYPES.PredicateVerificationRequestedEventHandler)
|
||||
.to(PredicateVerificationRequestedEventHandler)
|
||||
container.bind<PaymentFailedEventHandler>(TYPES.PaymentFailedEventHandler).to(PaymentFailedEventHandler)
|
||||
container.bind<PaymentSuccessEventHandler>(TYPES.PaymentSuccessEventHandler).to(PaymentSuccessEventHandler)
|
||||
container.bind<RefundProcessedEventHandler>(TYPES.RefundProcessedEventHandler).to(RefundProcessedEventHandler)
|
||||
|
||||
// Services
|
||||
container.bind<UAParser>(TYPES.DeviceDetector).toConstantValue(new UAParser())
|
||||
@@ -538,9 +550,13 @@ export class ContainerConfigLoader {
|
||||
.bind<SelectorInterface<boolean>>(TYPES.BooleanSelector)
|
||||
.toConstantValue(new DeterministicSelector<boolean>())
|
||||
container.bind<UserSubscriptionServiceInterface>(TYPES.UserSubscriptionService).to(UserSubscriptionService)
|
||||
const periodKeyGenerator = new PeriodKeyGenerator()
|
||||
container
|
||||
.bind<AnalyticsStoreInterface>(TYPES.AnalyticsStore)
|
||||
.toConstantValue(new RedisAnalyticsStore(new PeriodKeyGenerator(), container.get(TYPES.Redis)))
|
||||
.toConstantValue(new RedisAnalyticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
|
||||
container
|
||||
.bind<StatisticsStoreInterface>(TYPES.StatisticsStore)
|
||||
.toConstantValue(new RedisStatisticsStore(periodKeyGenerator, container.get(TYPES.Redis)))
|
||||
|
||||
if (env.get('SNS_TOPIC_ARN', true)) {
|
||||
container
|
||||
@@ -576,6 +592,9 @@ export class ContainerConfigLoader {
|
||||
],
|
||||
['SHARED_SUBSCRIPTION_INVITATION_CREATED', container.get(TYPES.SharedSubscriptionInvitationCreatedEventHandler)],
|
||||
['PREDICATE_VERIFICATION_REQUESTED', container.get(TYPES.PredicateVerificationRequestedEventHandler)],
|
||||
['PAYMENT_FAILED', container.get(TYPES.PaymentFailedEventHandler)],
|
||||
['PAYMENT_SUCCESS', container.get(TYPES.PaymentSuccessEventHandler)],
|
||||
['REFUND_PROCESSED', container.get(TYPES.RefundProcessedEventHandler)],
|
||||
])
|
||||
|
||||
if (env.get('SQS_QUEUE_URL', true)) {
|
||||
|
||||
@@ -143,6 +143,9 @@ const TYPES = {
|
||||
UserDisabledSessionUserAgentLoggingEventHandler: Symbol.for('UserDisabledSessionUserAgentLoggingEventHandler'),
|
||||
SharedSubscriptionInvitationCreatedEventHandler: Symbol.for('SharedSubscriptionInvitationCreatedEventHandler'),
|
||||
PredicateVerificationRequestedEventHandler: Symbol.for('PredicateVerificationRequestedEventHandler'),
|
||||
PaymentFailedEventHandler: Symbol.for('PaymentFailedEventHandler'),
|
||||
PaymentSuccessEventHandler: Symbol.for('PaymentSuccessEventHandler'),
|
||||
RefundProcessedEventHandler: Symbol.for('RefundProcessedEventHandler'),
|
||||
// Services
|
||||
DeviceDetector: Symbol.for('DeviceDetector'),
|
||||
SessionService: Symbol.for('SessionService'),
|
||||
@@ -184,6 +187,7 @@ const TYPES = {
|
||||
BooleanSelector: Symbol.for('BooleanSelector'),
|
||||
UserSubscriptionService: Symbol.for('UserSubscriptionService'),
|
||||
AnalyticsStore: Symbol.for('AnalyticsStore'),
|
||||
StatisticsStore: Symbol.for('StatisticsStore'),
|
||||
}
|
||||
|
||||
export default TYPES
|
||||
|
||||
@@ -7,15 +7,18 @@ import { UserRepositoryInterface } from '../Domain/User/UserRepositoryInterface'
|
||||
import * as express from 'express'
|
||||
import { DeleteSetting } from '../Domain/UseCase/DeleteSetting/DeleteSetting'
|
||||
import { CreateSubscriptionToken } from '../Domain/UseCase/CreateSubscriptionToken/CreateSubscriptionToken'
|
||||
import { CreateOfflineSubscriptionToken } from '../Domain/UseCase/CreateOfflineSubscriptionToken/CreateOfflineSubscriptionToken'
|
||||
|
||||
describe('AdminController', () => {
|
||||
let deleteSetting: DeleteSetting
|
||||
let userRepository: UserRepositoryInterface
|
||||
let createSubscriptionToken: CreateSubscriptionToken
|
||||
let createOfflineSubscriptionToken: CreateOfflineSubscriptionToken
|
||||
let request: express.Request
|
||||
let user: User
|
||||
|
||||
const createController = () => new AdminController(deleteSetting, userRepository, createSubscriptionToken)
|
||||
const createController = () =>
|
||||
new AdminController(deleteSetting, userRepository, createSubscriptionToken, createOfflineSubscriptionToken)
|
||||
|
||||
beforeEach(() => {
|
||||
user = {} as jest.Mocked<User>
|
||||
@@ -34,6 +37,14 @@ describe('AdminController', () => {
|
||||
},
|
||||
})
|
||||
|
||||
createOfflineSubscriptionToken = {} as jest.Mocked<CreateOfflineSubscriptionToken>
|
||||
createOfflineSubscriptionToken.execute = jest.fn().mockReturnValue({
|
||||
success: true,
|
||||
offlineSubscriptionToken: {
|
||||
token: '123-sub-token',
|
||||
},
|
||||
})
|
||||
|
||||
request = {
|
||||
headers: {},
|
||||
body: {},
|
||||
@@ -125,6 +136,31 @@ describe('AdminController', () => {
|
||||
expect(await result.content.readAsStringAsync()).toEqual('{"token":"123-sub-token"}')
|
||||
})
|
||||
|
||||
it("should return a new offline subscription token for the user's email", async () => {
|
||||
request.params.email = 'test@test.te'
|
||||
|
||||
const httpResponse = await createController().createOfflineToken(request)
|
||||
const result = await httpResponse.executeAsync()
|
||||
|
||||
expect(httpResponse).toBeInstanceOf(results.JsonResult)
|
||||
|
||||
expect(result.statusCode).toBe(200)
|
||||
expect(await result.content.readAsStringAsync()).toEqual('{"token":"123-sub-token"}')
|
||||
})
|
||||
|
||||
it('should not return a new offline subscription token if the workflow fails', async () => {
|
||||
request.params.email = 'test@test.te'
|
||||
|
||||
createOfflineSubscriptionToken.execute = jest.fn().mockReturnValue({ success: false })
|
||||
|
||||
const httpResponse = await createController().createOfflineToken(request)
|
||||
const result = await httpResponse.executeAsync()
|
||||
|
||||
expect(httpResponse).toBeInstanceOf(results.BadRequestResult)
|
||||
|
||||
expect(result.statusCode).toBe(400)
|
||||
})
|
||||
|
||||
it('should not delete email backup setting if value is null', async () => {
|
||||
request.body = {}
|
||||
request.params = {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
results,
|
||||
} from 'inversify-express-utils'
|
||||
import TYPES from '../Bootstrap/Types'
|
||||
import { CreateOfflineSubscriptionToken } from '../Domain/UseCase/CreateOfflineSubscriptionToken/CreateOfflineSubscriptionToken'
|
||||
import { CreateSubscriptionToken } from '../Domain/UseCase/CreateSubscriptionToken/CreateSubscriptionToken'
|
||||
import { DeleteSetting } from '../Domain/UseCase/DeleteSetting/DeleteSetting'
|
||||
import { UserRepositoryInterface } from '../Domain/User/UserRepositoryInterface'
|
||||
@@ -21,6 +22,8 @@ export class AdminController extends BaseHttpController {
|
||||
@inject(TYPES.DeleteSetting) private doDeleteSetting: DeleteSetting,
|
||||
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
|
||||
@inject(TYPES.CreateSubscriptionToken) private createSubscriptionToken: CreateSubscriptionToken,
|
||||
@inject(TYPES.CreateOfflineSubscriptionToken)
|
||||
private createOfflineSubscriptionToken: CreateOfflineSubscriptionToken,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
@@ -90,6 +93,22 @@ export class AdminController extends BaseHttpController {
|
||||
})
|
||||
}
|
||||
|
||||
@httpPost('/users/:email/offline-subscription-token')
|
||||
async createOfflineToken(request: Request): Promise<results.JsonResult | results.BadRequestResult> {
|
||||
const { email } = request.params
|
||||
const result = await this.createOfflineSubscriptionToken.execute({
|
||||
userEmail: email,
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
return this.badRequest()
|
||||
}
|
||||
|
||||
return this.json({
|
||||
token: result.offlineSubscriptionToken.token,
|
||||
})
|
||||
}
|
||||
|
||||
@httpPost('/users/:userUuid/email-backups')
|
||||
async disableEmailBackups(request: Request): Promise<results.BadRequestErrorMessageResult | results.OkResult> {
|
||||
const { userUuid } = request.params
|
||||
|
||||
@@ -12,7 +12,8 @@ import { User } from '../User/User'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { AccountDeletionRequestedEventHandler } from './AccountDeletionRequestedEventHandler'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { AnalyticsStoreInterface } from '@standardnotes/analytics'
|
||||
import { AnalyticsStoreInterface, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
describe('AccountDeletionRequestedEventHandler', () => {
|
||||
let userRepository: UserRepositoryInterface
|
||||
@@ -27,6 +28,8 @@ describe('AccountDeletionRequestedEventHandler', () => {
|
||||
let event: AccountDeletionRequestedEvent
|
||||
let getUserAnalyticsId: GetUserAnalyticsId
|
||||
let analyticsStore: AnalyticsStoreInterface
|
||||
let statisticsStore: StatisticsStoreInterface
|
||||
let timer: TimerInterface
|
||||
|
||||
const createHandler = () =>
|
||||
new AccountDeletionRequestedEventHandler(
|
||||
@@ -36,6 +39,8 @@ describe('AccountDeletionRequestedEventHandler', () => {
|
||||
revokedSessionRepository,
|
||||
getUserAnalyticsId,
|
||||
analyticsStore,
|
||||
statisticsStore,
|
||||
timer,
|
||||
logger,
|
||||
)
|
||||
|
||||
@@ -87,6 +92,13 @@ describe('AccountDeletionRequestedEventHandler', () => {
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.info = jest.fn()
|
||||
logger.warn = jest.fn()
|
||||
|
||||
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
|
||||
statisticsStore.incrementMeasure = jest.fn()
|
||||
|
||||
timer = {} as jest.Mocked<TimerInterface>
|
||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123)
|
||||
timer.convertDateToMicroseconds = jest.fn().mockReturnValue(100)
|
||||
})
|
||||
|
||||
it('should remove a user', async () => {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
|
||||
import {
|
||||
AnalyticsActivity,
|
||||
AnalyticsStoreInterface,
|
||||
Period,
|
||||
StatisticsMeasure,
|
||||
StatisticsStoreInterface,
|
||||
} from '@standardnotes/analytics'
|
||||
import { AccountDeletionRequestedEvent, DomainEventHandlerInterface } from '@standardnotes/domain-events'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { Logger } from 'winston'
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
@@ -18,6 +25,8 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
@inject(TYPES.RevokedSessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
|
||||
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
|
||||
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
|
||||
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
|
||||
@inject(TYPES.Timer) private timer: TimerInterface,
|
||||
@inject(TYPES.Logger) private logger: Logger,
|
||||
) {}
|
||||
|
||||
@@ -39,6 +48,14 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
||||
Period.ThisMonth,
|
||||
])
|
||||
|
||||
const registrationLength =
|
||||
this.timer.getTimestampInMicroseconds() - this.timer.convertDateToMicroseconds(user.createdAt)
|
||||
await this.statisticsStore.incrementMeasure(StatisticsMeasure.RegistrationLength, registrationLength, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
|
||||
await this.userRepository.remove(user)
|
||||
|
||||
this.logger.info(`Finished account cleanup for user: ${event.payload.userUuid}`)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { PaymentFailedEvent } from '@standardnotes/domain-events'
|
||||
import { AnalyticsStoreInterface } from '@standardnotes/analytics'
|
||||
|
||||
import { PaymentFailedEventHandler } from './PaymentFailedEventHandler'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { User } from '../User/User'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
|
||||
describe('PaymentFailedEventHandler', () => {
|
||||
let userRepository: UserRepositoryInterface
|
||||
let event: PaymentFailedEvent
|
||||
let user: User
|
||||
let getUserAnalyticsId: GetUserAnalyticsId
|
||||
let analyticsStore: AnalyticsStoreInterface
|
||||
|
||||
const createHandler = () => new PaymentFailedEventHandler(userRepository, getUserAnalyticsId, analyticsStore)
|
||||
|
||||
beforeEach(() => {
|
||||
user = {} as jest.Mocked<User>
|
||||
|
||||
userRepository = {} as jest.Mocked<UserRepositoryInterface>
|
||||
userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
|
||||
|
||||
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
|
||||
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
|
||||
|
||||
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
|
||||
analyticsStore.markActivity = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<PaymentFailedEvent>
|
||||
event.payload = {
|
||||
userEmail: 'test@test.com',
|
||||
}
|
||||
})
|
||||
|
||||
it('should mark payment failed for analytics', async () => {
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(analyticsStore.markActivity).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not mark payment failed for analytics if user is not found', async () => {
|
||||
userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
|
||||
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(analyticsStore.markActivity).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
|
||||
import { DomainEventHandlerInterface, PaymentFailedEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
|
||||
@injectable()
|
||||
export class PaymentFailedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
|
||||
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
|
||||
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
|
||||
) {}
|
||||
|
||||
async handle(event: PaymentFailedEvent): Promise<void> {
|
||||
const user = await this.userRepository.findOneByEmail(event.payload.userEmail)
|
||||
if (user === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
|
||||
await this.analyticsStore.markActivity([AnalyticsActivity.PaymentFailed], analyticsId, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { PaymentSuccessEvent } from '@standardnotes/domain-events'
|
||||
import { AnalyticsStoreInterface, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
|
||||
import { PaymentSuccessEventHandler } from './PaymentSuccessEventHandler'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { User } from '../User/User'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
|
||||
describe('PaymentSuccessEventHandler', () => {
|
||||
let userRepository: UserRepositoryInterface
|
||||
let event: PaymentSuccessEvent
|
||||
let user: User
|
||||
let getUserAnalyticsId: GetUserAnalyticsId
|
||||
let analyticsStore: AnalyticsStoreInterface
|
||||
let statisticsStore: StatisticsStoreInterface
|
||||
|
||||
const createHandler = () =>
|
||||
new PaymentSuccessEventHandler(userRepository, getUserAnalyticsId, analyticsStore, statisticsStore)
|
||||
|
||||
beforeEach(() => {
|
||||
user = {} as jest.Mocked<User>
|
||||
|
||||
userRepository = {} as jest.Mocked<UserRepositoryInterface>
|
||||
userRepository.findOneByEmail = jest.fn().mockReturnValue(user)
|
||||
|
||||
getUserAnalyticsId = {} as jest.Mocked<GetUserAnalyticsId>
|
||||
getUserAnalyticsId.execute = jest.fn().mockReturnValue({ analyticsId: 3 })
|
||||
|
||||
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
|
||||
analyticsStore.markActivity = jest.fn()
|
||||
|
||||
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
|
||||
statisticsStore.incrementMeasure = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<PaymentSuccessEvent>
|
||||
event.payload = {
|
||||
userEmail: 'test@test.com',
|
||||
amount: 12.45,
|
||||
}
|
||||
})
|
||||
|
||||
it('should mark payment failed for analytics', async () => {
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(analyticsStore.markActivity).toHaveBeenCalled()
|
||||
expect(statisticsStore.incrementMeasure).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not mark payment failed for analytics if user is not found', async () => {
|
||||
userRepository.findOneByEmail = jest.fn().mockReturnValue(null)
|
||||
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(analyticsStore.markActivity).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
AnalyticsActivity,
|
||||
AnalyticsStoreInterface,
|
||||
Period,
|
||||
StatisticsMeasure,
|
||||
StatisticsStoreInterface,
|
||||
} from '@standardnotes/analytics'
|
||||
import { DomainEventHandlerInterface, PaymentSuccessEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
|
||||
@injectable()
|
||||
export class PaymentSuccessEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
|
||||
@inject(TYPES.GetUserAnalyticsId) private getUserAnalyticsId: GetUserAnalyticsId,
|
||||
@inject(TYPES.AnalyticsStore) private analyticsStore: AnalyticsStoreInterface,
|
||||
@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface,
|
||||
) {}
|
||||
|
||||
async handle(event: PaymentSuccessEvent): Promise<void> {
|
||||
const user = await this.userRepository.findOneByEmail(event.payload.userEmail)
|
||||
if (user === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: user.uuid })
|
||||
await this.analyticsStore.markActivity([AnalyticsActivity.PaymentSuccess], analyticsId, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
|
||||
await this.statisticsStore.incrementMeasure(StatisticsMeasure.Income, event.payload.amount, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { RefundProcessedEvent } from '@standardnotes/domain-events'
|
||||
import { Period, StatisticsMeasure, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
|
||||
import { RefundProcessedEventHandler } from './RefundProcessedEventHandler'
|
||||
|
||||
describe('RefundProcessedEventHandler', () => {
|
||||
let event: RefundProcessedEvent
|
||||
let statisticsStore: StatisticsStoreInterface
|
||||
|
||||
const createHandler = () => new RefundProcessedEventHandler(statisticsStore)
|
||||
|
||||
beforeEach(() => {
|
||||
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
|
||||
statisticsStore.incrementMeasure = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<RefundProcessedEvent>
|
||||
event.payload = {
|
||||
userEmail: 'test@test.com',
|
||||
amount: 12.45,
|
||||
}
|
||||
})
|
||||
|
||||
it('should mark refunds for statistics', async () => {
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(statisticsStore.incrementMeasure).toHaveBeenCalledWith(StatisticsMeasure.Refunds, 12.45, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Period, StatisticsMeasure, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
import { DomainEventHandlerInterface, RefundProcessedEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
|
||||
@injectable()
|
||||
export class RefundProcessedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(@inject(TYPES.StatisticsStore) private statisticsStore: StatisticsStoreInterface) {}
|
||||
|
||||
async handle(event: RefundProcessedEvent): Promise<void> {
|
||||
await this.statisticsStore.incrementMeasure(StatisticsMeasure.Refunds, event.payload.amount, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,12 @@ import * as dayjs from 'dayjs'
|
||||
import { SubscriptionCancelledEventHandler } from './SubscriptionCancelledEventHandler'
|
||||
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
|
||||
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
|
||||
import { AnalyticsStoreInterface } from '@standardnotes/analytics'
|
||||
import { AnalyticsStoreInterface, Period, StatisticsMeasure, StatisticsStoreInterface } from '@standardnotes/analytics'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { User } from '../User/User'
|
||||
import { UserSubscription } from '../Subscription/UserSubscription'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
describe('SubscriptionCancelledEventHandler', () => {
|
||||
let userSubscriptionRepository: UserSubscriptionRepositoryInterface
|
||||
@@ -20,7 +22,9 @@ describe('SubscriptionCancelledEventHandler', () => {
|
||||
let userRepository: UserRepositoryInterface
|
||||
let getUserAnalyticsId: GetUserAnalyticsId
|
||||
let analyticsStore: AnalyticsStoreInterface
|
||||
let statisticsStore: StatisticsStoreInterface
|
||||
let timestamp: number
|
||||
let logger: Logger
|
||||
|
||||
const createHandler = () =>
|
||||
new SubscriptionCancelledEventHandler(
|
||||
@@ -29,6 +33,8 @@ describe('SubscriptionCancelledEventHandler', () => {
|
||||
userRepository,
|
||||
getUserAnalyticsId,
|
||||
analyticsStore,
|
||||
statisticsStore,
|
||||
logger,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -43,8 +49,16 @@ describe('SubscriptionCancelledEventHandler', () => {
|
||||
analyticsStore = {} as jest.Mocked<AnalyticsStoreInterface>
|
||||
analyticsStore.markActivity = jest.fn()
|
||||
|
||||
statisticsStore = {} as jest.Mocked<StatisticsStoreInterface>
|
||||
statisticsStore.incrementMeasure = jest.fn()
|
||||
|
||||
const userSubscription = {
|
||||
createdAt: 1642395451515000,
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
|
||||
userSubscriptionRepository.updateCancelled = jest.fn()
|
||||
userSubscriptionRepository.findBySubscriptionId = jest.fn().mockReturnValue([userSubscription])
|
||||
|
||||
offlineUserSubscriptionRepository = {} as jest.Mocked<OfflineUserSubscriptionRepositoryInterface>
|
||||
offlineUserSubscriptionRepository.updateCancelled = jest.fn()
|
||||
@@ -59,14 +73,24 @@ describe('SubscriptionCancelledEventHandler', () => {
|
||||
subscriptionName: SubscriptionName.ProPlan,
|
||||
timestamp,
|
||||
offline: false,
|
||||
replaced: false,
|
||||
}
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.info = jest.fn()
|
||||
})
|
||||
|
||||
it('should update subscription cancelled', async () => {
|
||||
event.payload.timestamp = 1642395451516000
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(userSubscriptionRepository.updateCancelled).toHaveBeenCalledWith(1, true, timestamp)
|
||||
expect(userSubscriptionRepository.updateCancelled).toHaveBeenCalledWith(1, true, 1642395451516000)
|
||||
expect(analyticsStore.markActivity).toHaveBeenCalled()
|
||||
expect(statisticsStore.incrementMeasure).toHaveBeenCalledWith(StatisticsMeasure.SubscriptionLength, 1000, [
|
||||
Period.Today,
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
})
|
||||
|
||||
it('should update subscription cancelled - user not found', async () => {
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import { DomainEventHandlerInterface, SubscriptionCancelledEvent } from '@standardnotes/domain-events'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import {
|
||||
AnalyticsActivity,
|
||||
AnalyticsStoreInterface,
|
||||
Period,
|
||||
StatisticsMeasure,
|
||||
StatisticsStoreInterface,
|
||||
} from '@standardnotes/analytics'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { UserSubscriptionRepositoryInterface } from '../Subscription/UserSubscriptionRepositoryInterface'
|
||||
import { OfflineUserSubscriptionRepositoryInterface } from '../Subscription/OfflineUserSubscriptionRepositoryInterface'
|
||||
import { UserRepositoryInterface } from '../User/UserRepositoryInterface'
|
||||
import { GetUserAnalyticsId } from '../UseCase/GetUserAnalyticsId/GetUserAnalyticsId'
|
||||
import { AnalyticsActivity, AnalyticsStoreInterface, Period } from '@standardnotes/analytics'
|
||||
import { UserSubscription } from '../Subscription/UserSubscription'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
@injectable()
|
||||
export class SubscriptionCancelledEventHandler implements DomainEventHandlerInterface {
|
||||
@@ -17,6 +25,8 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
|
||||
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
|
||||
@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) {
|
||||
@@ -35,6 +45,20 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
|
||||
Period.ThisWeek,
|
||||
Period.ThisMonth,
|
||||
])
|
||||
|
||||
const subscriptions = await this.userSubscriptionRepository.findBySubscriptionId(event.payload.subscriptionId)
|
||||
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,
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
|
||||
Period.ThisMonth,
|
||||
])
|
||||
|
||||
const limitedDiscountPurchased = event.payload.discountCode === 'limited-10'
|
||||
const limitedDiscountPurchased = ['limited-10', 'limited-20'].includes(event.payload.discountCode as string)
|
||||
if (limitedDiscountPurchased) {
|
||||
await this.analyticsStore.markActivity([AnalyticsActivity.LimitedDiscountOfferPurchased], analyticsId, [
|
||||
Period.Today,
|
||||
|
||||
+8
-1
@@ -4,17 +4,23 @@ import { UserDisabledSessionUserAgentLoggingEvent } from '@standardnotes/domain-
|
||||
import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterface'
|
||||
|
||||
import { UserDisabledSessionUserAgentLoggingEventHandler } from './UserDisabledSessionUserAgentLoggingEventHandler'
|
||||
import { RevokedSessionRepositoryInterface } from '../Session/RevokedSessionRepositoryInterface'
|
||||
|
||||
describe('UserDisabledSessionUserAgentLoggingEventHandler', () => {
|
||||
let sessionRepository: SessionRepositoryInterface
|
||||
let revokedSessionRepository: RevokedSessionRepositoryInterface
|
||||
let event: UserDisabledSessionUserAgentLoggingEvent
|
||||
|
||||
const createHandler = () => new UserDisabledSessionUserAgentLoggingEventHandler(sessionRepository)
|
||||
const createHandler = () =>
|
||||
new UserDisabledSessionUserAgentLoggingEventHandler(sessionRepository, revokedSessionRepository)
|
||||
|
||||
beforeEach(() => {
|
||||
sessionRepository = {} as jest.Mocked<SessionRepositoryInterface>
|
||||
sessionRepository.clearUserAgentByUserUuid = jest.fn()
|
||||
|
||||
revokedSessionRepository = {} as jest.Mocked<RevokedSessionRepositoryInterface>
|
||||
revokedSessionRepository.clearUserAgentByUserUuid = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<UserDisabledSessionUserAgentLoggingEvent>
|
||||
event.payload = {
|
||||
userUuid: '1-2-3',
|
||||
@@ -26,5 +32,6 @@ describe('UserDisabledSessionUserAgentLoggingEventHandler', () => {
|
||||
await createHandler().handle(event)
|
||||
|
||||
expect(sessionRepository.clearUserAgentByUserUuid).toHaveBeenCalledWith('1-2-3')
|
||||
expect(revokedSessionRepository.clearUserAgentByUserUuid).toHaveBeenCalledWith('1-2-3')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,13 +2,18 @@ import { DomainEventHandlerInterface, UserDisabledSessionUserAgentLoggingEvent }
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import TYPES from '../../Bootstrap/Types'
|
||||
import { RevokedSessionRepositoryInterface } from '../Session/RevokedSessionRepositoryInterface'
|
||||
import { SessionRepositoryInterface } from '../Session/SessionRepositoryInterface'
|
||||
|
||||
@injectable()
|
||||
export class UserDisabledSessionUserAgentLoggingEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(@inject(TYPES.SessionRepository) private sessionRepository: SessionRepositoryInterface) {}
|
||||
constructor(
|
||||
@inject(TYPES.SessionRepository) private sessionRepository: SessionRepositoryInterface,
|
||||
@inject(TYPES.SessionRepository) private revokedSessionRepository: RevokedSessionRepositoryInterface,
|
||||
) {}
|
||||
|
||||
async handle(event: UserDisabledSessionUserAgentLoggingEvent): Promise<void> {
|
||||
await this.sessionRepository.clearUserAgentByUserUuid(event.payload.userUuid)
|
||||
await this.revokedSessionRepository.clearUserAgentByUserUuid(event.payload.userUuid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,4 +36,25 @@ export class RevokedSession {
|
||||
)
|
||||
@JoinColumn({ name: 'user_uuid', referencedColumnName: 'uuid' })
|
||||
declare user: Promise<User>
|
||||
|
||||
@Column({
|
||||
name: 'received_at',
|
||||
type: 'datetime',
|
||||
nullable: true,
|
||||
})
|
||||
declare receivedAt: Date
|
||||
|
||||
@Column({
|
||||
name: 'user_agent',
|
||||
type: 'text',
|
||||
nullable: true,
|
||||
})
|
||||
declare userAgent: string | null
|
||||
|
||||
@Column({
|
||||
name: 'api_version',
|
||||
length: 255,
|
||||
nullable: true,
|
||||
})
|
||||
declare apiVersion: string
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
import { RevokedSession } from './RevokedSession'
|
||||
|
||||
export interface RevokedSessionRepositoryInterface {
|
||||
@@ -5,4 +6,5 @@ export interface RevokedSessionRepositoryInterface {
|
||||
findAllByUserUuid(userUuid: string): Promise<Array<RevokedSession>>
|
||||
save(revokedSession: RevokedSession): Promise<RevokedSession>
|
||||
remove(revokedSession: RevokedSession): Promise<RevokedSession>
|
||||
clearUserAgentByUserUuid(userUuid: Uuid): Promise<void>
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'reflect-metadata'
|
||||
import * as winston from 'winston'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { ApiVersion } from '../Api/ApiVersion'
|
||||
import { Session } from './Session'
|
||||
import { SessionRepositoryInterface } from './SessionRepositoryInterface'
|
||||
import { SessionService } from './SessionService'
|
||||
@@ -47,6 +48,7 @@ describe('SessionService', () => {
|
||||
session.uuid = '2e1e43'
|
||||
session.userUuid = '1-2-3'
|
||||
session.userAgent = 'Chrome'
|
||||
session.apiVersion = ApiVersion.v20200115
|
||||
session.hashedAccessToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
|
||||
session.hashedRefreshToken = '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce'
|
||||
|
||||
@@ -80,6 +82,7 @@ describe('SessionService', () => {
|
||||
|
||||
timer = {} as jest.Mocked<TimerInterface>
|
||||
timer.convertStringDateToMilliseconds = jest.fn().mockReturnValue(123)
|
||||
timer.getUTCDate = jest.fn().mockReturnValue(new Date(1))
|
||||
|
||||
deviceDetector = {} as jest.Mocked<UAParser>
|
||||
deviceDetector.setUA = jest.fn().mockReturnThis()
|
||||
@@ -111,6 +114,7 @@ describe('SessionService', () => {
|
||||
expect(revokedSessionRepository.save).toHaveBeenCalledWith({
|
||||
uuid: '2e1e43',
|
||||
received: true,
|
||||
receivedAt: new Date(1),
|
||||
})
|
||||
})
|
||||
|
||||
@@ -476,6 +480,8 @@ describe('SessionService', () => {
|
||||
expect(revokedSessionRepository.save).toHaveBeenCalledWith({
|
||||
uuid: '2e1e43',
|
||||
userUuid: '1-2-3',
|
||||
userAgent: 'Chrome',
|
||||
apiVersion: '20200115',
|
||||
createdAt: expect.any(Date),
|
||||
})
|
||||
})
|
||||
|
||||
@@ -203,6 +203,7 @@ export class SessionService implements SessionServiceInterface {
|
||||
|
||||
async markRevokedSessionAsReceived(revokedSession: RevokedSession): Promise<RevokedSession> {
|
||||
revokedSession.received = true
|
||||
revokedSession.receivedAt = this.timer.getUTCDate()
|
||||
|
||||
return this.revokedSessionRepository.save(revokedSession)
|
||||
}
|
||||
@@ -224,7 +225,9 @@ export class SessionService implements SessionServiceInterface {
|
||||
const revokedSession = new RevokedSession()
|
||||
revokedSession.uuid = session.uuid
|
||||
revokedSession.userUuid = session.userUuid
|
||||
revokedSession.createdAt = dayjs.utc().toDate()
|
||||
revokedSession.createdAt = this.timer.getUTCDate()
|
||||
revokedSession.apiVersion = session.apiVersion
|
||||
revokedSession.userAgent = session.userAgent
|
||||
|
||||
return this.revokedSessionRepository.save(revokedSession)
|
||||
}
|
||||
@@ -246,8 +249,8 @@ export class SessionService implements SessionServiceInterface {
|
||||
}
|
||||
session.userUuid = dto.user.uuid
|
||||
session.apiVersion = dto.apiVersion
|
||||
session.createdAt = dayjs.utc().toDate()
|
||||
session.updatedAt = dayjs.utc().toDate()
|
||||
session.createdAt = this.timer.getUTCDate()
|
||||
session.updatedAt = this.timer.getUTCDate()
|
||||
session.readonlyAccess = dto.readonlyAccess
|
||||
|
||||
return session
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { Repository, SelectQueryBuilder } from 'typeorm'
|
||||
import { Repository, SelectQueryBuilder, UpdateQueryBuilder } from 'typeorm'
|
||||
|
||||
import { RevokedSession } from '../../Domain/Session/RevokedSession'
|
||||
|
||||
@@ -9,12 +9,14 @@ import { MySQLRevokedSessionRepository } from './MySQLRevokedSessionRepository'
|
||||
describe('MySQLRevokedSessionRepository', () => {
|
||||
let ormRepository: Repository<RevokedSession>
|
||||
let queryBuilder: SelectQueryBuilder<RevokedSession>
|
||||
let updateQueryBuilder: UpdateQueryBuilder<RevokedSession>
|
||||
let session: RevokedSession
|
||||
|
||||
const createRepository = () => new MySQLRevokedSessionRepository(ormRepository)
|
||||
|
||||
beforeEach(() => {
|
||||
queryBuilder = {} as jest.Mocked<SelectQueryBuilder<RevokedSession>>
|
||||
updateQueryBuilder = {} as jest.Mocked<UpdateQueryBuilder<RevokedSession>>
|
||||
|
||||
session = {} as jest.Mocked<RevokedSession>
|
||||
|
||||
@@ -36,6 +38,24 @@ describe('MySQLRevokedSessionRepository', () => {
|
||||
expect(ormRepository.remove).toHaveBeenCalledWith(session)
|
||||
})
|
||||
|
||||
it('should clear user agent data on all user sessions', async () => {
|
||||
ormRepository.createQueryBuilder = jest.fn().mockImplementation(() => updateQueryBuilder)
|
||||
|
||||
updateQueryBuilder.update = jest.fn().mockReturnThis()
|
||||
updateQueryBuilder.set = jest.fn().mockReturnThis()
|
||||
updateQueryBuilder.where = jest.fn().mockReturnThis()
|
||||
updateQueryBuilder.execute = jest.fn()
|
||||
|
||||
await createRepository().clearUserAgentByUserUuid('1-2-3')
|
||||
|
||||
expect(updateQueryBuilder.update).toHaveBeenCalled()
|
||||
expect(updateQueryBuilder.set).toHaveBeenCalledWith({
|
||||
userAgent: null,
|
||||
})
|
||||
expect(updateQueryBuilder.where).toHaveBeenCalledWith('user_uuid = :userUuid', { userUuid: '1-2-3' })
|
||||
expect(updateQueryBuilder.execute).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should find one session by id', async () => {
|
||||
queryBuilder.where = jest.fn().mockReturnThis()
|
||||
queryBuilder.getOne = jest.fn().mockReturnValue(session)
|
||||
|
||||
@@ -20,6 +20,17 @@ export class MySQLRevokedSessionRepository implements RevokedSessionRepositoryIn
|
||||
return this.ormRepository.remove(revokedSession)
|
||||
}
|
||||
|
||||
async clearUserAgentByUserUuid(userUuid: string): Promise<void> {
|
||||
await this.ormRepository
|
||||
.createQueryBuilder('revoked_session')
|
||||
.update()
|
||||
.set({
|
||||
userAgent: null,
|
||||
})
|
||||
.where('user_uuid = :userUuid', { userUuid })
|
||||
.execute()
|
||||
}
|
||||
|
||||
async findAllByUserUuid(userUuid: string): Promise<RevokedSession[]> {
|
||||
return this.ormRepository
|
||||
.createQueryBuilder('revoked_session')
|
||||
|
||||
@@ -157,6 +157,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().findBySubscriptionId(123)
|
||||
@@ -164,6 +165,7 @@ describe('MySQLUserSubscriptionRepository', () => {
|
||||
expect(selectQueryBuilder.where).toHaveBeenCalledWith('subscription_id = :subscriptionId', {
|
||||
subscriptionId: 123,
|
||||
})
|
||||
expect(selectQueryBuilder.orderBy).toHaveBeenCalledWith('created_at', 'DESC')
|
||||
expect(selectQueryBuilder.getMany).toHaveBeenCalled()
|
||||
expect(result).toEqual([subscription])
|
||||
})
|
||||
|
||||
@@ -44,6 +44,7 @@ export class MySQLUserSubscriptionRepository implements UserSubscriptionReposito
|
||||
.where('subscription_id = :subscriptionId', {
|
||||
subscriptionId,
|
||||
})
|
||||
.orderBy('created_at', 'DESC')
|
||||
.getMany()
|
||||
}
|
||||
|
||||
|
||||
@@ -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.31.0](https://github.com/standardnotes/server/compare/@standardnotes/common@1.30.0...@standardnotes/common@1.31.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add keeping stats on payments ([0c176b7](https://github.com/standardnotes/server/commit/0c176b70f8281e1e490224b9c7ab85f272a3d4e9))
|
||||
|
||||
# [1.30.0](https://github.com/standardnotes/server/compare/@standardnotes/common@1.29.0...@standardnotes/common@1.30.0) (2022-07-14)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/common",
|
||||
"version": "1.30.0",
|
||||
"version": "1.31.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -23,7 +23,7 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test:unit": "jest spec --coverage"
|
||||
"test": "jest spec --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^28.1.4",
|
||||
|
||||
@@ -3,6 +3,48 @@
|
||||
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/server/compare/@standardnotes/domain-events-infra@1.8.2...@standardnotes/domain-events-infra@1.8.3) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.8.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.1...@standardnotes/domain-events-infra@1.8.2) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.8.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.8.0...@standardnotes/domain-events-infra@1.8.1) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
# [1.8.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.37...@standardnotes/domain-events-infra@1.8.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add keeping stats on payments ([0c176b7](https://github.com/standardnotes/server/commit/0c176b70f8281e1e490224b9c7ab85f272a3d4e9))
|
||||
|
||||
## [1.7.37](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.36...@standardnotes/domain-events-infra@1.7.37) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.36](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.35...@standardnotes/domain-events-infra@1.7.36) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.35](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.34...@standardnotes/domain-events-infra@1.7.35) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.34](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.33...@standardnotes/domain-events-infra@1.7.34) (2022-08-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.33](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.32...@standardnotes/domain-events-infra@1.7.33) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.32](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.31...@standardnotes/domain-events-infra@1.7.32) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.7.31](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.7.30...@standardnotes/domain-events-infra@1.7.31) (2022-08-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.7.31",
|
||||
"version": "1.8.3",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -21,7 +21,7 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test:unit": "jest spec --coverage"
|
||||
"test": "jest spec --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/domain-events": "workspace:*",
|
||||
|
||||
@@ -3,6 +3,67 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.59.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.59.0...@standardnotes/domain-events@2.59.1) (2022-09-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api-gateway:** include period key in statistics measures ([d149f46](https://github.com/standardnotes/server/commit/d149f46cf6456201dd8690977f64ed32a75f3459))
|
||||
* **api-gateway:** period types on analytics report ([f94c8fc](https://github.com/standardnotes/server/commit/f94c8fc26e684a07101cc5282ebb9cda3c8c6961))
|
||||
|
||||
# [2.59.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.58.0...@standardnotes/domain-events@2.59.0) (2022-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* **api-gateway:** add statistics measures to report generation ([8151bb1](https://github.com/standardnotes/server/commit/8151bb108affb2b5cfa1ab365f99a9f0170a7795))
|
||||
|
||||
# [2.58.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.57.0...@standardnotes/domain-events@2.58.0) (2022-09-06)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add statistics for refunds and account deletions ([d7ae2f0](https://github.com/standardnotes/server/commit/d7ae2f06255b19eb5d3403a4989610390064754e))
|
||||
|
||||
# [2.57.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.56.0...@standardnotes/domain-events@2.57.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add keeping stats on payments ([0c176b7](https://github.com/standardnotes/server/commit/0c176b70f8281e1e490224b9c7ab85f272a3d4e9))
|
||||
|
||||
# [2.56.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.55.1...@standardnotes/domain-events@2.56.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-events:** add amount of dollars to payment success event ([9c2d51d](https://github.com/standardnotes/server/commit/9c2d51d718516b550c23637b00a3edead0749425))
|
||||
|
||||
## [2.55.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.55.0...@standardnotes/domain-events@2.55.1) (2022-09-01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **domain-events:** add admin-panel as event source option ([41c5127](https://github.com/standardnotes/server/commit/41c512798d932859b5d46c6e62fccb89fa288891))
|
||||
|
||||
# [2.55.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.54.2...@standardnotes/domain-events@2.55.0) (2022-09-01)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-events:** add subscription revert requested event ([e0cec9e](https://github.com/standardnotes/server/commit/e0cec9e24ab9954868fb428062c9a82d0f0f85d5))
|
||||
|
||||
## [2.54.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.54.1...@standardnotes/domain-events@2.54.2) (2022-08-30)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **domain-events:** add replaced boolean to subscription canceled event ([932ef93](https://github.com/standardnotes/server/commit/932ef933fce71aabdddca33da4eec6ce8fe686ef))
|
||||
|
||||
## [2.54.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.54.0...@standardnotes/domain-events@2.54.1) (2022-08-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **domain-events:** missing exports ([2fb904d](https://github.com/standardnotes/server/commit/2fb904d2cbff040ba9a6b2b323eab1591309b174))
|
||||
|
||||
# [2.54.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.53.0...@standardnotes/domain-events@2.54.0) (2022-08-15)
|
||||
|
||||
### Features
|
||||
|
||||
* **domain-events:** add payment success event ([1841597](https://github.com/standardnotes/server/commit/1841597405461981c7b6eb4ee8ada079c77a8fc5))
|
||||
|
||||
# [2.53.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.52.0...@standardnotes/domain-events@2.53.0) (2022-08-09)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.53.0",
|
||||
"version": "2.59.1",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -21,7 +21,7 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test:unit": "jest spec --coverage --passWithNoTests"
|
||||
"test": "jest spec --coverage --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "workspace:*",
|
||||
|
||||
@@ -12,6 +12,12 @@ export interface DailyAnalyticsReportGeneratedEventPayload {
|
||||
retention: number
|
||||
totalCount: number
|
||||
}>
|
||||
statisticMeasures: Array<{
|
||||
name: string
|
||||
totalValue: number
|
||||
average: number
|
||||
period: number
|
||||
}>
|
||||
activityStatisticsOverTime: Array<{
|
||||
name: string
|
||||
period: number
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum DomainEventService {
|
||||
AdminPanel = 'admin-panel',
|
||||
Auth = 'auth',
|
||||
SyncingServer = 'syncing-server',
|
||||
Payments = 'payments',
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
|
||||
import { PaymentSuccessEventPayload } from './PaymentSuccessEventPayload'
|
||||
|
||||
export interface PaymentSuccessEvent extends DomainEventInterface {
|
||||
type: 'PAYMENT_SUCCESS'
|
||||
payload: PaymentSuccessEventPayload
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface PaymentSuccessEventPayload {
|
||||
userEmail: string
|
||||
amount: number
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export interface RefundProcessedEventPayload {
|
||||
userEmail: string
|
||||
amount: number
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ export interface SubscriptionCancelledEventPayload {
|
||||
subscriptionName: SubscriptionName
|
||||
timestamp: number
|
||||
offline: boolean
|
||||
replaced: boolean
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
|
||||
import { SubscriptionRevertRequestedEventPayload } from './SubscriptionRevertRequestedEventPayload'
|
||||
|
||||
export interface SubscriptionRevertRequestedEvent extends DomainEventInterface {
|
||||
type: 'SUBSCRIPTION_REVERT_REQUESTED'
|
||||
payload: SubscriptionRevertRequestedEventPayload
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface SubscriptionRevertRequestedEventPayload {
|
||||
userEmail: string
|
||||
}
|
||||
@@ -54,6 +54,8 @@ export * from './Event/OneDriveBackupFailedEvent'
|
||||
export * from './Event/OneDriveBackupFailedEventPayload'
|
||||
export * from './Event/PaymentFailedEvent'
|
||||
export * from './Event/PaymentFailedEventPayload'
|
||||
export * from './Event/PaymentSuccessEvent'
|
||||
export * from './Event/PaymentSuccessEventPayload'
|
||||
export * from './Event/PredicateVerificationRequestedEvent'
|
||||
export * from './Event/PredicateVerificationRequestedEventPayload'
|
||||
export * from './Event/PredicateVerifiedEvent'
|
||||
@@ -84,6 +86,8 @@ export * from './Event/SubscriptionRenewedEvent'
|
||||
export * from './Event/SubscriptionRenewedEventPayload'
|
||||
export * from './Event/SubscriptionExpiredEvent'
|
||||
export * from './Event/SubscriptionExpiredEventPayload'
|
||||
export * from './Event/SubscriptionRevertRequestedEvent'
|
||||
export * from './Event/SubscriptionRevertRequestedEventPayload'
|
||||
export * from './Event/SubscriptionSyncRequestedEvent'
|
||||
export * from './Event/SubscriptionSyncRequestedEventPayload'
|
||||
export * from './Event/UserDisabledSessionUserAgentLoggingEvent'
|
||||
|
||||
@@ -3,6 +3,64 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.6](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.5...@standardnotes/event-store@1.3.6) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.5](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.4...@standardnotes/event-store@1.3.5) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.4](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.3...@standardnotes/event-store@1.3.4) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.3](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.2...@standardnotes/event-store@1.3.3) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.2](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.1...@standardnotes/event-store@1.3.2) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.3.1](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.3.0...@standardnotes/event-store@1.3.1) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.2.3...@standardnotes/event-store@1.3.0) (2022-09-02)
|
||||
|
||||
### Features
|
||||
|
||||
* **event-store:** add listening to subscription reverts ([ef1e2bb](https://github.com/standardnotes/server/commit/ef1e2bb5edb6df191d22a676e365aed3511b3960))
|
||||
|
||||
## [1.2.3](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.2.2...@standardnotes/event-store@1.2.3) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.2.2](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.2.1...@standardnotes/event-store@1.2.2) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.2.1](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.2.0...@standardnotes/event-store@1.2.1) (2022-08-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
# [1.2.0](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.33...@standardnotes/event-store@1.2.0) (2022-08-30)
|
||||
|
||||
### Features
|
||||
|
||||
* **event-store:** add account claim events subscription ([dd6bec8](https://github.com/standardnotes/server/commit/dd6bec8a0c957b87ccf4d1fb0636fa3f56a4525e))
|
||||
|
||||
## [1.1.33](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.32...@standardnotes/event-store@1.1.33) (2022-08-15)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **event-store:** add payment events handling ([3477c81](https://github.com/standardnotes/server/commit/3477c81d37e6cb92e76d59b1128daac702a4a7ae))
|
||||
|
||||
## [1.1.32](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.31...@standardnotes/event-store@1.1.32) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.1.31](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.1.30...@standardnotes/event-store@1.1.31) (2022-08-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.1.31",
|
||||
"version": "1.3.6",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -76,6 +76,10 @@ export class ContainerConfigLoader {
|
||||
['EMAIL_BACKUP_ATTACHMENT_CREATED', container.get(TYPES.EventHandler)],
|
||||
['EMAIL_BACKUP_REQUESTED', container.get(TYPES.EventHandler)],
|
||||
['OFFLINE_SUBSCRIPTION_TOKEN_CREATED', container.get(TYPES.EventHandler)],
|
||||
['PAYMENT_FAILED', container.get(TYPES.EventHandler)],
|
||||
['PAYMENT_SUCCESS', container.get(TYPES.EventHandler)],
|
||||
['ACCOUNT_CLAIM_REQUESTED', container.get(TYPES.EventHandler)],
|
||||
['SUBSCRIPTION_REVERT_REQUESTED', container.get(TYPES.EventHandler)],
|
||||
])
|
||||
|
||||
container
|
||||
|
||||
@@ -3,6 +3,54 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.5.45](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.44...@standardnotes/files-server@1.5.45) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.44](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.43...@standardnotes/files-server@1.5.44) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.43](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.42...@standardnotes/files-server@1.5.43) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.42](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.41...@standardnotes/files-server@1.5.42) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.41](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.40...@standardnotes/files-server@1.5.41) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.40](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.39...@standardnotes/files-server@1.5.40) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.39](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.38...@standardnotes/files-server@1.5.39) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.38](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.37...@standardnotes/files-server@1.5.38) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.37](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.36...@standardnotes/files-server@1.5.37) (2022-08-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.36](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.35...@standardnotes/files-server@1.5.36) (2022-08-29)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.35](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.34...@standardnotes/files-server@1.5.35) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.34](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.33...@standardnotes/files-server@1.5.34) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.5.33](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.5.32...@standardnotes/files-server@1.5.33) (2022-08-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.5.33",
|
||||
"version": "1.5.45",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -50,7 +50,7 @@
|
||||
"nodemon": "^2.0.19",
|
||||
"prettyjson": "^1.2.5",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"ts-node": "^10.4.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"winston": "^3.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -71,6 +71,6 @@
|
||||
"nodemon": "^2.0.19",
|
||||
"npm-check-updates": "^16.0.1",
|
||||
"ts-jest": "^28.0.5",
|
||||
"uuid": "^8.3.2"
|
||||
"uuid": "^9.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.
|
||||
|
||||
# [1.4.0](https://github.com/standardnotes/server/compare/@standardnotes/predicates@1.3.0...@standardnotes/predicates@1.4.0) (2022-09-05)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add keeping stats on payments ([0c176b7](https://github.com/standardnotes/server/commit/0c176b70f8281e1e490224b9c7ab85f272a3d4e9))
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/server/compare/@standardnotes/predicates@1.2.6...@standardnotes/predicates@1.3.0) (2022-07-25)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/predicates",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -23,7 +23,7 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test:unit": "jest spec --coverage --passWithNoTests"
|
||||
"test": "jest spec --coverage --passWithNoTests"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^28.1.4",
|
||||
|
||||
@@ -3,6 +3,74 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.22](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.21...@standardnotes/scheduler-server@1.10.22) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.21](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.20...@standardnotes/scheduler-server@1.10.21) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.20](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.19...@standardnotes/scheduler-server@1.10.20) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.19](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.18...@standardnotes/scheduler-server@1.10.19) (2022-09-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.18](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.17...@standardnotes/scheduler-server@1.10.18) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.17](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.16...@standardnotes/scheduler-server@1.10.17) (2022-09-05)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.16](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.15...@standardnotes/scheduler-server@1.10.16) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.15](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.14...@standardnotes/scheduler-server@1.10.15) (2022-09-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.14](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.13...@standardnotes/scheduler-server@1.10.14) (2022-08-30)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** linter issues ([648eb89](https://github.com/standardnotes/server/commit/648eb89c7c7b95cfb6235e38180958c3d332825d))
|
||||
|
||||
## [1.10.13](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.12...@standardnotes/scheduler-server@1.10.13) (2022-08-30)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** skip sending exit survery when a subscription is replaced ([35373db](https://github.com/standardnotes/server/commit/35373db1d3d25ae5878ef7f7cfc8594a6623da8a))
|
||||
|
||||
## [1.10.12](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.11...@standardnotes/scheduler-server@1.10.12) (2022-08-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.11](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.10...@standardnotes/scheduler-server@1.10.11) (2022-08-29)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** change logs severity to reduce noise ([dbe55d8](https://github.com/standardnotes/server/commit/dbe55d89ec33a4c69cae350793bc4c5dd6589a2b))
|
||||
|
||||
## [1.10.10](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.9...@standardnotes/scheduler-server@1.10.10) (2022-08-17)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **scheduler:** change discount from 10% to 20% on a limited time offer ([4b3de26](https://github.com/standardnotes/server/commit/4b3de264efc4fffb2603181c158cddb25c4ed4a9))
|
||||
|
||||
## [1.10.9](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.8...@standardnotes/scheduler-server@1.10.9) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.8](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.7...@standardnotes/scheduler-server@1.10.8) (2022-08-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.10.7](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.10.6...@standardnotes/scheduler-server@1.10.7) (2022-08-10)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.10.7",
|
||||
"version": "1.10.22",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
@@ -15,6 +15,7 @@
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc --rootDir ./",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"pretest": "yarn lint && yarn build",
|
||||
"test": "jest --coverage --config=./jest.config.js --maxWorkers=50%",
|
||||
"worker": "yarn node dist/bin/worker.js",
|
||||
@@ -48,6 +49,7 @@
|
||||
"@types/newrelic": "^7.0.3",
|
||||
"@types/node": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
||||
"eslint": "^8.14.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "^28.1.2",
|
||||
"npm-check-updates": "^16.0.1",
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('PredicateVerifiedEventHandler', () => {
|
||||
updatePredicateStatus.execute = jest.fn()
|
||||
|
||||
logger = {} as jest.Mocked<Logger>
|
||||
logger.info = jest.fn()
|
||||
logger.debug = jest.fn()
|
||||
|
||||
event = {} as jest.Mocked<PredicateVerifiedEvent>
|
||||
event.payload = {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user