mirror of
https://github.com/standardnotes/server
synced 2026-05-10 09:57:17 -04:00
Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 74b4312928 | |||
| e91a832152 | |||
| 4f95bbee3f | |||
| b9c9f74d0c | |||
| e535cd504c | |||
| db0360860a | |||
| aa2b5f3b74 | |||
| 6241661e27 | |||
| 25047bf46d | |||
| a1820ed212 | |||
| 0a1d1624e8 | |||
| 7367de6832 | |||
| f0abfe89fc | |||
| d1244d165a | |||
| 106d8f9192 | |||
| 1d86ba8fcb | |||
| f20a947f8a | |||
| 19b9de05ae | |||
| 1d751c0fbe | |||
| fa2564e164 | |||
| 330bff0124 | |||
| ca57c8e7b5 | |||
| a82b9a0c8a | |||
| ea7e9d73c4 | |||
| 117b7b4b99 | |||
| b4bf11d9da | |||
| 0306e10469 | |||
| 0ab47013f2 | |||
| 836883b82d | |||
| ed671be9c5 | |||
| 9676a2586c | |||
| e95ba61c7f | |||
| a0718aea26 | |||
| 156fa7a618 | |||
| 8d006ece30 | |||
| 037c994040 | |||
| a164ba291d | |||
| 610fba2601 | |||
| 398338c8f8 | |||
| 34be157d8e | |||
| 76372fe357 | |||
| 46879c336b | |||
| aef9e936bd | |||
| 8cb92d9678 | |||
| 52db89de81 | |||
| c5af8dfc05 | |||
| 27ad8e6959 | |||
| c4a1502f70 | |||
| d1d6c753c4 | |||
| 3bd63f7674 | |||
| 376466d9b2 | |||
| e100c52bbc | |||
| d4830dec01 | |||
| 7e11821021 | |||
| 4715e019a2 | |||
| 794cd8734a | |||
| 14d42b26bb | |||
| 6bb44afd91 | |||
| c82345aeeb | |||
| 72ab08a0d0 | |||
| f2d1b47e40 | |||
| d9ee2c5be2 | |||
| eb59902cf7 | |||
| 002074e4d1 | |||
| 45b55068f9 | |||
| 157eee5d93 | |||
| d5f2b4f6eb | |||
| a7a93497e8 | |||
| 8f96f0ed7a | |||
| 3f064176f2 | |||
| c7b0c7dfa8 | |||
| df20dd46db | |||
| 6dfd09989e | |||
| fc821709e2 | |||
| e986abaab5 | |||
| a006fb3119 | |||
| 2af812eaf1 | |||
| d13c975f94 | |||
| 1f7e4dd184 | |||
| 8b04216998 | |||
| 27ff25b70e | |||
| dc3a41e4bb | |||
| 94448bb5d8 | |||
| 9a568b0f73 | |||
| a1ee491dc5 | |||
| e5c118c262 | |||
| 1bef1279e6 | |||
| c511f259c7 | |||
| f77ed8ef94 | |||
| a4929af2ee | |||
| 095811dda9 |
@@ -4,6 +4,7 @@ DB_USERNAME=std_notes_user
|
|||||||
DB_PASSWORD=changeme123
|
DB_PASSWORD=changeme123
|
||||||
DB_DATABASE=standard_notes_db
|
DB_DATABASE=standard_notes_db
|
||||||
DB_PORT=3306
|
DB_PORT=3306
|
||||||
|
DB_DEBUG_LEVEL=all
|
||||||
DB_SQLITE_DATABASE_PATH=standard_notes_db
|
DB_SQLITE_DATABASE_PATH=standard_notes_db
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
REDIS_HOST=cache
|
REDIS_HOST=cache
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Configure AWS credentials
|
- name: Configure AWS credentials
|
||||||
uses: aws-actions/configure-aws-credentials@v2
|
uses: aws-actions/configure-aws-credentials@v3
|
||||||
with:
|
with:
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
- name: Configure AWS credentials
|
- name: Configure AWS credentials
|
||||||
uses: aws-actions/configure-aws-credentials@v2
|
uses: aws-actions/configure-aws-credentials@v3
|
||||||
with:
|
with:
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@master
|
uses: docker/setup-buildx-action@master
|
||||||
|
|
||||||
- name: Publish Docker image
|
- name: Publish Docker image
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
context: ${{ steps.bundle-dir.outputs.temp_dir }}
|
context: ${{ steps.bundle-dir.outputs.temp_dir }}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
run: docker/is-available.sh http://localhost:3123 $(pwd)/logs
|
||||||
|
|
||||||
- name: Run E2E Test Suite
|
- name: Run E2E Test Suite
|
||||||
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html
|
run: yarn dlx mocha-headless-chrome --timeout 3600000 -f http://localhost:9001/mocha/test.html
|
||||||
|
|
||||||
- name: Show logs on failure
|
- name: Show logs on failure
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
@@ -141,6 +141,7 @@ jobs:
|
|||||||
echo "DB_USERNAME=standardnotes" >> packages/home-server/.env
|
echo "DB_USERNAME=standardnotes" >> packages/home-server/.env
|
||||||
echo "DB_PASSWORD=standardnotes" >> packages/home-server/.env
|
echo "DB_PASSWORD=standardnotes" >> packages/home-server/.env
|
||||||
echo "DB_TYPE=${{ matrix.db_type }}" >> packages/home-server/.env
|
echo "DB_TYPE=${{ matrix.db_type }}" >> packages/home-server/.env
|
||||||
|
echo "DB_DEBUG_LEVEL=all" >> packages/home-server/.env
|
||||||
echo "REDIS_URL=redis://localhost:6379" >> packages/home-server/.env
|
echo "REDIS_URL=redis://localhost:6379" >> packages/home-server/.env
|
||||||
echo "CACHE_TYPE=${{ matrix.cache_type }}" >> packages/home-server/.env
|
echo "CACHE_TYPE=${{ matrix.cache_type }}" >> packages/home-server/.env
|
||||||
echo "SECONDARY_DB_ENABLED=${{ matrix.secondary_db_enabled }}" >> packages/home-server/.env
|
echo "SECONDARY_DB_ENABLED=${{ matrix.secondary_db_enabled }}" >> packages/home-server/.env
|
||||||
@@ -162,7 +163,7 @@ jobs:
|
|||||||
run: for i in {1..30}; do curl -s http://localhost:3123/healthcheck && break || sleep 1; done
|
run: for i in {1..30}; do curl -s http://localhost:3123/healthcheck && break || sleep 1; done
|
||||||
|
|
||||||
- name: Run E2E Test Suite
|
- name: Run E2E Test Suite
|
||||||
run: yarn dlx mocha-headless-chrome --timeout 1800000 -f http://localhost:9001/mocha/test.html
|
run: yarn dlx mocha-headless-chrome --timeout 3600000 -f http://localhost:9001/mocha/test.html
|
||||||
|
|
||||||
- name: Show logs on failure
|
- name: Show logs on failure
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@master
|
uses: docker/setup-buildx-action@master
|
||||||
|
|
||||||
- name: Publish Docker image
|
- name: Publish Docker image
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v4
|
||||||
with:
|
with:
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
name: E2E Test Suite On Self Hosted Server
|
name: E2E Test Suite On Self Hosted Server
|
||||||
|
|
||||||
|
run-name: E2E Test Suite against ${{ inputs.ref_name }} by ${{ inputs.author }}
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 */12 * * *'
|
- cron: '0 */12 * * *'
|
||||||
@@ -9,6 +11,14 @@ on:
|
|||||||
type: string
|
type: string
|
||||||
default: latest
|
default: latest
|
||||||
description: The Docker image tag used for SNJS container
|
description: The Docker image tag used for SNJS container
|
||||||
|
author:
|
||||||
|
type: string
|
||||||
|
default: unknown
|
||||||
|
description: The author that triggered the workflow
|
||||||
|
ref_name:
|
||||||
|
type: string
|
||||||
|
default: unknown
|
||||||
|
description: The ref name from which the workflow was triggered
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
e2e:
|
e2e:
|
||||||
|
|||||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -53,7 +53,7 @@ services:
|
|||||||
image: mysql:8
|
image: mysql:8
|
||||||
container_name: db-ci
|
container_name: db-ci
|
||||||
env_file: .github/ci.env
|
env_file: .github/ci.env
|
||||||
expose:
|
ports:
|
||||||
- 3306
|
- 3306
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
|
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
|
||||||
@@ -66,7 +66,7 @@ services:
|
|||||||
secondary_db:
|
secondary_db:
|
||||||
image: mongo:5.0
|
image: mongo:5.0
|
||||||
container_name: secondary_db-ci
|
container_name: secondary_db-ci
|
||||||
expose:
|
ports:
|
||||||
- 27017
|
- 27017
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
@@ -83,7 +83,7 @@ services:
|
|||||||
container_name: cache-ci
|
container_name: cache-ci
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/redis/:/data
|
- ./data/redis/:/data
|
||||||
expose:
|
ports:
|
||||||
- 6379
|
- 6379
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -3,6 +3,63 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.26.11](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.10...@standardnotes/analytics@2.26.11) (2023-09-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.10](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.9...@standardnotes/analytics@2.26.10) (2023-09-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.9](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.8...@standardnotes/analytics@2.26.9) (2023-09-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.8](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.7...@standardnotes/analytics@2.26.8) (2023-09-12)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.7](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.6...@standardnotes/analytics@2.26.7) (2023-09-08)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.6](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.5...@standardnotes/analytics@2.26.6) (2023-09-07)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.4...@standardnotes/analytics@2.26.5) (2023-09-07)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.3...@standardnotes/analytics@2.26.4) (2023-09-06)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.2...@standardnotes/analytics@2.26.3) (2023-09-04)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.1...@standardnotes/analytics@2.26.2) (2023-09-01)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|
||||||
|
## [2.26.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.26.0...@standardnotes/analytics@2.26.1) (2023-09-01)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* inserting revisions instead of upsert ([#803](https://github.com/standardnotes/server/issues/803)) ([27ff25b](https://github.com/standardnotes/server/commit/27ff25b70e6b65dfe89aa35582422dce682a4105))
|
||||||
|
|
||||||
|
# [2.26.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.21...@standardnotes/analytics@2.26.0) (2023-09-01)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **analytics:** throwing errors on unexisting users ([c511f25](https://github.com/standardnotes/server/commit/c511f259c765fe5cb5b022213d2a59d67390a3c4))
|
||||||
|
* remove the alive and kicking info logs on workers ([1bef127](https://github.com/standardnotes/server/commit/1bef1279e6dbf3cbdfa87e44aa9108ed6dbb3b0f))
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* send websocket event to user when a message is sent ([#802](https://github.com/standardnotes/server/issues/802)) ([9a568b0](https://github.com/standardnotes/server/commit/9a568b0f73078ab74d4771bac469903a124e67da))
|
||||||
|
|
||||||
## [2.25.21](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.20...@standardnotes/analytics@2.25.21) (2023-08-31)
|
## [2.25.21](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.25.20...@standardnotes/analytics@2.25.21) (2023-08-31)
|
||||||
|
|
||||||
**Note:** Version bump only for package @standardnotes/analytics
|
**Note:** Version bump only for package @standardnotes/analytics
|
||||||
|
|||||||
@@ -22,6 +22,4 @@ void container.load().then((container) => {
|
|||||||
|
|
||||||
const subscriberFactory: DomainEventSubscriberFactoryInterface = container.get(TYPES.DomainEventSubscriberFactory)
|
const subscriberFactory: DomainEventSubscriberFactoryInterface = container.get(TYPES.DomainEventSubscriberFactory)
|
||||||
subscriberFactory.create().start()
|
subscriberFactory.create().start()
|
||||||
|
|
||||||
setInterval(() => logger.info('Alive and kicking!'), 20 * 60 * 1000)
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@standardnotes/analytics",
|
"name": "@standardnotes/analytics",
|
||||||
"version": "2.25.21",
|
"version": "2.26.11",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0 <21.0.0"
|
"node": ">=18.0.0 <21.0.0"
|
||||||
},
|
},
|
||||||
@@ -29,12 +29,12 @@
|
|||||||
"@types/jest": "^29.5.1",
|
"@types/jest": "^29.5.1",
|
||||||
"@types/mixpanel": "^2.14.4",
|
"@types/mixpanel": "^2.14.4",
|
||||||
"@types/node": "^20.5.7",
|
"@types/node": "^20.5.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
||||||
"@typescript-eslint/parser": "^5.59.2",
|
"@typescript-eslint/parser": "^6.5.0",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.39.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^3.0.3",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.0.4"
|
||||||
},
|
},
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
"mixpanel": "^0.17.0",
|
"mixpanel": "^0.17.0",
|
||||||
"mysql2": "^3.0.1",
|
"mysql2": "^3.0.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"typeorm": "^0.3.15",
|
"typeorm": "^0.3.17",
|
||||||
"winston": "^3.8.1"
|
"winston": "^3.8.1"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ export class AccountDeletionRequestedEventHandler implements DomainEventHandlerI
|
|||||||
Period.ThisMonth,
|
Period.ThisMonth,
|
||||||
])
|
])
|
||||||
|
|
||||||
await this.analyticsEntityRepository.remove(analyticsEntity)
|
|
||||||
|
|
||||||
if (this.mixpanelClient !== null) {
|
if (this.mixpanelClient !== null) {
|
||||||
this.mixpanelClient.track(event.type, {
|
this.mixpanelClient.track(event.type, {
|
||||||
distinct_id: analyticsEntity.id.toString(),
|
distinct_id: analyticsEntity.id.toString(),
|
||||||
user_created_at: this.timer.convertMicrosecondsToDate(event.payload.userCreatedAtTimestamp),
|
user_created_at: this.timer.convertMicrosecondsToDate(event.payload.userCreatedAtTimestamp),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.analyticsEntityRepository.remove(analyticsEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ export class PaymentFailedEventHandler implements DomainEventHandlerInterface {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: PaymentFailedEvent): Promise<void> {
|
async handle(event: PaymentFailedEvent): Promise<void> {
|
||||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity([AnalyticsActivity.PaymentFailed], analyticsId, [
|
await this.analyticsStore.markActivity([AnalyticsActivity.PaymentFailed], analyticsId, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -88,7 +88,11 @@ export class PaymentSuccessEventHandler implements DomainEventHandlerInterface {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: PaymentSuccessEvent): Promise<void> {
|
async handle(event: PaymentSuccessEvent): Promise<void> {
|
||||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity([AnalyticsActivity.PaymentSuccess], analyticsId, [
|
await this.analyticsStore.markActivity([AnalyticsActivity.PaymentSuccess], analyticsId, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ export class RefundProcessedEventHandler implements DomainEventHandlerInterface
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: RefundProcessedEvent): Promise<void> {
|
async handle(event: RefundProcessedEvent): Promise<void> {
|
||||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId } = analyticsMetadataOrError.getValue()
|
||||||
await this.statisticsStore.incrementMeasure(StatisticMeasureName.NAMES.Refunds, event.payload.amount, [
|
await this.statisticsStore.incrementMeasure(StatisticMeasureName.NAMES.Refunds, event.payload.amount, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ export class SessionCreatedEventHandler implements DomainEventHandlerInterface {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SessionCreatedEvent): Promise<void> {
|
async handle(event: SessionCreatedEvent): Promise<void> {
|
||||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: event.payload.userUuid })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userUuid: event.payload.userUuid })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId } = analyticsMetadataOrError.getValue()
|
||||||
|
|
||||||
if (this.mixpanelClient !== null) {
|
if (this.mixpanelClient !== null) {
|
||||||
this.mixpanelClient.track(event.type, {
|
this.mixpanelClient.track(event.type, {
|
||||||
|
|||||||
@@ -13,7 +13,11 @@ export class SessionRefreshedEventHandler implements DomainEventHandlerInterface
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SessionRefreshedEvent): Promise<void> {
|
async handle(event: SessionRefreshedEvent): Promise<void> {
|
||||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userUuid: event.payload.userUuid })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userUuid: event.payload.userUuid })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId } = analyticsMetadataOrError.getValue()
|
||||||
|
|
||||||
if (this.mixpanelClient !== null) {
|
if (this.mixpanelClient !== null) {
|
||||||
this.mixpanelClient.track(event.type, {
|
this.mixpanelClient.track(event.type, {
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ export class SubscriptionCancelledEventHandler implements DomainEventHandlerInte
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SubscriptionCancelledEvent): Promise<void> {
|
async handle(event: SubscriptionCancelledEvent): Promise<void> {
|
||||||
const { analyticsId, userUuid } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId, userUuid } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionCancelled], analyticsId, [
|
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionCancelled], analyticsId, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ export class SubscriptionExpiredEventHandler implements DomainEventHandlerInterf
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SubscriptionExpiredEvent): Promise<void> {
|
async handle(event: SubscriptionExpiredEvent): Promise<void> {
|
||||||
const { analyticsId, userUuid } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId, userUuid } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity(
|
await this.analyticsStore.markActivity(
|
||||||
[AnalyticsActivity.SubscriptionExpired, AnalyticsActivity.ExistingCustomersChurn],
|
[AnalyticsActivity.SubscriptionExpired, AnalyticsActivity.ExistingCustomersChurn],
|
||||||
analyticsId,
|
analyticsId,
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ export class SubscriptionPurchasedEventHandler implements DomainEventHandlerInte
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SubscriptionPurchasedEvent): Promise<void> {
|
async handle(event: SubscriptionPurchasedEvent): Promise<void> {
|
||||||
const { analyticsId, userUuid } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId, userUuid } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionPurchased], analyticsId, [
|
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionPurchased], analyticsId, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ export class SubscriptionReactivatedEventHandler implements DomainEventHandlerIn
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SubscriptionReactivatedEvent): Promise<void> {
|
async handle(event: SubscriptionReactivatedEvent): Promise<void> {
|
||||||
const { analyticsId } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionReactivated], analyticsId, [
|
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionReactivated], analyticsId, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ export class SubscriptionRefundedEventHandler implements DomainEventHandlerInter
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SubscriptionRefundedEvent): Promise<void> {
|
async handle(event: SubscriptionRefundedEvent): Promise<void> {
|
||||||
const { analyticsId, userUuid } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId, userUuid } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRefunded], analyticsId, [
|
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRefunded], analyticsId, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -26,7 +26,11 @@ export class SubscriptionRenewedEventHandler implements DomainEventHandlerInterf
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async handle(event: SubscriptionRenewedEvent): Promise<void> {
|
async handle(event: SubscriptionRenewedEvent): Promise<void> {
|
||||||
const { analyticsId, userUuid } = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
const analyticsMetadataOrError = await this.getUserAnalyticsId.execute({ userEmail: event.payload.userEmail })
|
||||||
|
if (analyticsMetadataOrError.isFailed()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { analyticsId, userUuid } = analyticsMetadataOrError.getValue()
|
||||||
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRenewed], analyticsId, [
|
await this.analyticsStore.markActivity([AnalyticsActivity.SubscriptionRenewed], analyticsId, [
|
||||||
Period.Today,
|
Period.Today,
|
||||||
Period.ThisWeek,
|
Period.ThisWeek,
|
||||||
|
|||||||
@@ -24,23 +24,18 @@ describe('GetUserAnalyticsId', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should return analytics id for a user by uuid', async () => {
|
it('should return analytics id for a user by uuid', async () => {
|
||||||
expect((await createUseCase().execute({ userUuid: '1-2-3' })).analyticsId).toEqual(123)
|
expect((await createUseCase().execute({ userUuid: '1-2-3' })).getValue().analyticsId).toEqual(123)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return analytics id for a user by email', async () => {
|
it('should return analytics id for a user by email', async () => {
|
||||||
expect((await createUseCase().execute({ userEmail: 'test@test.te' })).analyticsId).toEqual(123)
|
expect((await createUseCase().execute({ userEmail: 'test@test.te' })).getValue().analyticsId).toEqual(123)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw error if user is missing analytics entity', async () => {
|
it('should throw error if user is missing analytics entity', async () => {
|
||||||
analyticsEntityRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
|
analyticsEntityRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
|
||||||
let error = null
|
|
||||||
|
|
||||||
try {
|
const result = await createUseCase().execute({ userUuid: '1-2-3' })
|
||||||
await createUseCase().execute({ userUuid: '1-2-3' })
|
|
||||||
} catch (caughtError) {
|
|
||||||
error = caughtError
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error).not.toBeNull()
|
expect(result.isFailed()).toEqual(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import { inject, injectable } from 'inversify'
|
import { inject, injectable } from 'inversify'
|
||||||
import { Username, Uuid } from '@standardnotes/domain-core'
|
import { Result, UseCaseInterface, Username, Uuid } from '@standardnotes/domain-core'
|
||||||
|
|
||||||
import TYPES from '../../../Bootstrap/Types'
|
import TYPES from '../../../Bootstrap/Types'
|
||||||
import { AnalyticsEntityRepositoryInterface } from '../../Entity/AnalyticsEntityRepositoryInterface'
|
import { AnalyticsEntityRepositoryInterface } from '../../Entity/AnalyticsEntityRepositoryInterface'
|
||||||
import { UseCaseInterface } from '../UseCaseInterface'
|
|
||||||
import { GetUserAnalyticsIdDTO } from './GetUserAnalyticsIdDTO'
|
import { GetUserAnalyticsIdDTO } from './GetUserAnalyticsIdDTO'
|
||||||
import { GetUserAnalyticsIdResponse } from './GetUserAnalyticsIdResponse'
|
import { GetUserAnalyticsIdResponse } from './GetUserAnalyticsIdResponse'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class GetUserAnalyticsId implements UseCaseInterface {
|
export class GetUserAnalyticsId implements UseCaseInterface<GetUserAnalyticsIdResponse> {
|
||||||
constructor(
|
constructor(
|
||||||
@inject(TYPES.AnalyticsEntityRepository) private analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
|
@inject(TYPES.AnalyticsEntityRepository) private analyticsEntityRepository: AnalyticsEntityRepositoryInterface,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(dto: GetUserAnalyticsIdDTO): Promise<GetUserAnalyticsIdResponse> {
|
async execute(dto: GetUserAnalyticsIdDTO): Promise<Result<GetUserAnalyticsIdResponse>> {
|
||||||
let analyticsEntity = null
|
let analyticsEntity = null
|
||||||
if (dto.userUuid) {
|
if (dto.userUuid) {
|
||||||
analyticsEntity = await this.analyticsEntityRepository.findOneByUserUuid(dto.userUuid)
|
analyticsEntity = await this.analyticsEntityRepository.findOneByUserUuid(dto.userUuid)
|
||||||
@@ -22,13 +21,13 @@ export class GetUserAnalyticsId implements UseCaseInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (analyticsEntity === null) {
|
if (analyticsEntity === null) {
|
||||||
throw new Error(`Could not find analytics entity for user ${dto.userUuid}`)
|
return Result.fail(`Could not find analytics entity ${dto.userUuid}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return Result.ok({
|
||||||
analyticsId: analyticsEntity.id,
|
analyticsId: analyticsEntity.id,
|
||||||
userUuid: Uuid.create(analyticsEntity.userUuid).getValue(),
|
userUuid: Uuid.create(analyticsEntity.userUuid).getValue(),
|
||||||
username: Username.create(analyticsEntity.username).getValue(),
|
username: Username.create(analyticsEntity.username).getValue(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import { AnalyticsActivity } from '../../Domain/Analytics/AnalyticsActivity'
|
|||||||
import { AnalyticsStoreInterface } from '../../Domain/Analytics/AnalyticsStoreInterface'
|
import { AnalyticsStoreInterface } from '../../Domain/Analytics/AnalyticsStoreInterface'
|
||||||
|
|
||||||
export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
export class RedisAnalyticsStore implements AnalyticsStoreInterface {
|
||||||
constructor(private periodKeyGenerator: PeriodKeyGeneratorInterface, private redisClient: IORedis.Redis) {}
|
constructor(
|
||||||
|
private periodKeyGenerator: PeriodKeyGeneratorInterface,
|
||||||
|
private redisClient: IORedis.Redis,
|
||||||
|
) {}
|
||||||
|
|
||||||
async calculateActivityTotalCountOverTime(activity: AnalyticsActivity, period: Period): Promise<number> {
|
async calculateActivityTotalCountOverTime(activity: AnalyticsActivity, period: Period): Promise<number> {
|
||||||
if (
|
if (
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user