mirror of
https://github.com/standardnotes/server
synced 2026-01-18 08:04:28 -05:00
Compare commits
25 Commits
@standardn
...
@standardn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59fc4a089c | ||
|
|
ef26dc8cbb | ||
|
|
8a0fbb28b0 | ||
|
|
618d8d5b1a | ||
|
|
3a936dc9c1 | ||
|
|
031fcd75ee | ||
|
|
c8cd23cb32 | ||
|
|
a3049938a3 | ||
|
|
b23488e862 | ||
|
|
c8203cf04c | ||
|
|
4f2616ef0a | ||
|
|
04ffc69e00 | ||
|
|
5b4bb6e7a7 | ||
|
|
2e953ba998 | ||
|
|
ed5a4eb960 | ||
|
|
31b2c05084 | ||
|
|
6e1662038c | ||
|
|
df78d88f79 | ||
|
|
addedb3091 | ||
|
|
2ea17b2dea | ||
|
|
85d2f42f47 | ||
|
|
cdb655c1bd | ||
|
|
3064d03aa9 | ||
|
|
6af6417ca2 | ||
|
|
a35271fbb3 |
@@ -3,6 +3,59 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.17.5](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.4...@standardnotes/analytics@2.17.5) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** accessing analytics in report ([ef26dc8](https://github.com/standardnotes/server/commit/ef26dc8cbb967e088ae7387ff6dbec1e60dc3ee4))
|
||||
|
||||
## [2.17.4](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.3...@standardnotes/analytics@2.17.4) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/analytics
|
||||
|
||||
## [2.17.3](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.2...@standardnotes/analytics@2.17.3) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** add debug logs for the report ([031fcd7](https://github.com/standardnotes/server/commit/031fcd75eecdcf4c2f17257754a0ba3f24ba6d6e))
|
||||
|
||||
## [2.17.2](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.1...@standardnotes/analytics@2.17.2) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** calculating active users ([a304993](https://github.com/standardnotes/server/commit/a3049938a31e21a5867a314ac62bee6aa4990d57))
|
||||
|
||||
## [2.17.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.17.0...@standardnotes/analytics@2.17.1) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **analytics:** container binding ([04ffc69](https://github.com/standardnotes/server/commit/04ffc69e000803107d8834c286de97b3d213a842))
|
||||
* **auth:** replace date object with number timestamp ([5b4bb6e](https://github.com/standardnotes/server/commit/5b4bb6e7a78a1b0f4e663bb990619f65f6a5c757))
|
||||
|
||||
# [2.17.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.16.0...@standardnotes/analytics@2.17.0) (2022-12-20)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add users activit to the report email ([ed5a4eb](https://github.com/standardnotes/server/commit/ed5a4eb960a6c8fe9d0c77331f29dc3c7ffb9100))
|
||||
|
||||
# [2.16.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.15.1...@standardnotes/analytics@2.16.0) (2022-12-20)
|
||||
|
||||
### Features
|
||||
|
||||
* **analytics:** add active users stats to report ([6e16620](https://github.com/standardnotes/server/commit/6e1662038c3340fb60939464616789bab7639160))
|
||||
|
||||
## [2.15.1](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.15.0...@standardnotes/analytics@2.15.1) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** add persisting statistics for all subscription plans ([addedb3](https://github.com/standardnotes/server/commit/addedb3091ddae81618d56663e18f2ae76a43c4e))
|
||||
|
||||
# [2.15.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.14.0...@standardnotes/analytics@2.15.0) (2022-12-19)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add requesting persisting statistics ([a35271f](https://github.com/standardnotes/server/commit/a35271fbb399b68a3ac7021395d8063707fba222))
|
||||
|
||||
# [2.14.0](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.13.0...@standardnotes/analytics@2.14.0) (2022-12-19)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -121,6 +121,10 @@ const requestReport = async (
|
||||
StatisticMeasureName.NAMES.FiveYearPlansMRR,
|
||||
StatisticMeasureName.NAMES.PlusPlansMRR,
|
||||
StatisticMeasureName.NAMES.ProPlansMRR,
|
||||
StatisticMeasureName.NAMES.ActiveUsers,
|
||||
StatisticMeasureName.NAMES.ActiveFreeUsers,
|
||||
StatisticMeasureName.NAMES.ActivePlusUsers,
|
||||
StatisticMeasureName.NAMES.ActiveProUsers,
|
||||
]
|
||||
for (const statisticName of thirtyDaysStatisticsNames) {
|
||||
statisticsOverTime.push({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/analytics",
|
||||
"version": "2.14.0",
|
||||
"version": "2.17.5",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -218,6 +218,7 @@ export class ContainerConfigLoader {
|
||||
.toConstantValue(
|
||||
new StatisticPersistenceRequestedEventHandler(
|
||||
container.get(TYPES.PersistStatistic),
|
||||
container.get(TYPES.Timer),
|
||||
container.get(TYPES.Logger),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -5,6 +5,31 @@ import { AnalyticsActivity } from '../Analytics/AnalyticsActivity'
|
||||
import { StatisticMeasureName } from '../Statistics/StatisticMeasureName'
|
||||
import { Period } from '../Time/Period'
|
||||
|
||||
const countActiveUsers = (measureName: string, data: any): { yesterday: number; last30Days: number } => {
|
||||
const totalActiveUsersLast30DaysIncludingToday = data.statisticsOverTime.find(
|
||||
(a: { name: string; period: number }) => a.name === measureName && a.period === 27,
|
||||
)
|
||||
|
||||
const totalActiveUsersYesterday =
|
||||
totalActiveUsersLast30DaysIncludingToday.counts[totalActiveUsersLast30DaysIncludingToday.counts.length - 2]
|
||||
.totalCount
|
||||
|
||||
const filteredCounts = totalActiveUsersLast30DaysIncludingToday.counts.filter(
|
||||
(count: { totalCount: number }) => count.totalCount !== 0,
|
||||
)
|
||||
|
||||
const averageActiveUsersLast30Days = Math.floor(
|
||||
filteredCounts.reduce((previousValue: { totalCount: any }, currentValue: { totalCount: any }) => {
|
||||
return previousValue.totalCount + currentValue.totalCount
|
||||
}) / filteredCounts.length,
|
||||
)
|
||||
|
||||
return {
|
||||
yesterday: totalActiveUsersYesterday,
|
||||
last30Days: averageActiveUsersLast30Days,
|
||||
}
|
||||
}
|
||||
|
||||
const getChartUrls = (
|
||||
data: any,
|
||||
): {
|
||||
@@ -12,7 +37,6 @@ const getChartUrls = (
|
||||
users: string
|
||||
quarterlyPerformance: string
|
||||
churn: string
|
||||
mrr: string
|
||||
mrrMonthly: string
|
||||
} => {
|
||||
const subscriptionPurchasingOverTime = data.activityStatisticsOverTime.find(
|
||||
@@ -237,82 +261,6 @@ const getChartUrls = (
|
||||
},
|
||||
}
|
||||
|
||||
const mrrOverTime = data.statisticsOverTime.find(
|
||||
(a: { name: string; period: number }) => a.name === 'mrr' && a.period === 27,
|
||||
)
|
||||
const monthlyPlansMrrOverTime = data.statisticsOverTime.find(
|
||||
(a: { name: string; period: number }) => a.name === 'monthly-plans-mrr' && a.period === 27,
|
||||
)
|
||||
const annualPlansMrrOverTime = data.statisticsOverTime.find(
|
||||
(a: { name: string; period: number }) => a.name === 'annual-plans-mrr' && a.period === 27,
|
||||
)
|
||||
const fiveYearPlansMrrOverTime = data.statisticsOverTime.find(
|
||||
(a: { name: string; period: number }) => a.name === 'five-year-plans-mrr' && a.period === 27,
|
||||
)
|
||||
const proPlansMrrOverTime = data.statisticsOverTime.find(
|
||||
(a: { name: string; period: number }) => a.name === 'pro-plans-mrr' && a.period === 27,
|
||||
)
|
||||
const plusPlansMrrOverTime = data.statisticsOverTime.find(
|
||||
(a: { name: string; period: number }) => a.name === 'plus-plans-mrr' && a.period === 27,
|
||||
)
|
||||
|
||||
const mrrOverTimeConfig = {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: mrrOverTime?.counts.map((count: { periodKey: any }) => count.periodKey),
|
||||
datasets: [
|
||||
{
|
||||
label: 'MRR',
|
||||
backgroundColor: 'rgb(25, 255, 140)',
|
||||
borderColor: 'rgb(25, 255, 140)',
|
||||
data: mrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
|
||||
fill: false,
|
||||
pointRadius: 2,
|
||||
},
|
||||
{
|
||||
label: 'MRR - Monthly Plans',
|
||||
backgroundColor: 'rgb(54, 162, 235)',
|
||||
borderColor: 'rgb(54, 162, 235)',
|
||||
data: monthlyPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
|
||||
fill: false,
|
||||
pointRadius: 2,
|
||||
},
|
||||
{
|
||||
label: 'MRR - Annual Plans',
|
||||
backgroundColor: 'rgb(255, 221, 51)',
|
||||
borderColor: 'rgb(255, 221, 51)',
|
||||
data: annualPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
|
||||
fill: false,
|
||||
pointRadius: 2,
|
||||
},
|
||||
{
|
||||
label: 'MRR - Five Year Plans',
|
||||
backgroundColor: 'rgb(255, 120, 120)',
|
||||
borderColor: 'rgb(255, 120, 120)',
|
||||
data: fiveYearPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
|
||||
fill: false,
|
||||
pointRadius: 2,
|
||||
},
|
||||
{
|
||||
label: 'MRR - PRO Plans',
|
||||
backgroundColor: 'rgb(255, 99, 132)',
|
||||
borderColor: 'rgb(255, 99, 132)',
|
||||
data: proPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
|
||||
fill: false,
|
||||
pointRadius: 2,
|
||||
},
|
||||
{
|
||||
label: 'MRR - PLUS Plans',
|
||||
backgroundColor: 'rgb(221, 51, 255)',
|
||||
borderColor: 'rgb(221, 51, 255)',
|
||||
data: plusPlansMrrOverTime?.counts.map((count: { totalCount: any }) => count.totalCount),
|
||||
fill: false,
|
||||
pointRadius: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const mrrMonthlyOverTime = data.statisticsOverTime
|
||||
.find((a: { name: string; period: Period }) => a.name === 'mrr' && a.period === Period.ThisYear)
|
||||
?.counts.map((count: { totalCount: number }) => +count.totalCount.toFixed(2))
|
||||
@@ -371,7 +319,6 @@ const getChartUrls = (
|
||||
JSON.stringify(quarterlyConfig),
|
||||
)}`,
|
||||
churn: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(churnConfig))}`,
|
||||
mrr: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(mrrOverTimeConfig))}`,
|
||||
mrrMonthly: `https://quickchart.io/chart?width=800&c=${encodeURIComponent(JSON.stringify(mrrMonthlyConfig))}`,
|
||||
}
|
||||
}
|
||||
@@ -608,12 +555,39 @@ export const html = (data: any, timer: TimerInterface) => {
|
||||
(value: { periodKey: string }) => value.periodKey === thisMonthPeriodKey,
|
||||
)
|
||||
|
||||
const totalActiveUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveUsers, data)
|
||||
const totalActiveFreeUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveFreeUsers, data)
|
||||
const totalActivePlusUsers = countActiveUsers(StatisticMeasureName.NAMES.ActivePlusUsers, data)
|
||||
const totalActiveProUsers = countActiveUsers(StatisticMeasureName.NAMES.ActiveProUsers, data)
|
||||
|
||||
return ` <div>
|
||||
<p>Hello,</p>
|
||||
<p>
|
||||
<strong>Here are some statistics from yesterday:</strong>
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Active Users</b>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Total:</b> ${totalActiveUsers.yesterday.toLocaleString('en-US')}
|
||||
</li>
|
||||
<li>
|
||||
<b>By Subscription Type:</b>
|
||||
<ul>
|
||||
<li>
|
||||
<b>FREE:</b> ${totalActiveFreeUsers.yesterday.toLocaleString('en-US')}
|
||||
</li>
|
||||
<li>
|
||||
<b>PLUS:</b> ${totalActivePlusUsers.yesterday.toLocaleString('en-US')}
|
||||
</li>
|
||||
<li>
|
||||
<b>PRO:</b> ${totalActiveProUsers.yesterday.toLocaleString('en-US')}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<b>Payments</b>
|
||||
<ul>
|
||||
@@ -812,6 +786,28 @@ export const html = (data: any, timer: TimerInterface) => {
|
||||
<strong>Here are some statistics from last 30 days:</strong>
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Active Users (Average)</b>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Total:</b> ${totalActiveUsers.last30Days.toLocaleString('en-US')}
|
||||
</li>
|
||||
<li>
|
||||
<b>By Subscription Type:</b>
|
||||
<ul>
|
||||
<li>
|
||||
<b>FREE:</b> ${totalActiveFreeUsers.last30Days.toLocaleString('en-US')}
|
||||
</li>
|
||||
<li>
|
||||
<b>PLUS:</b> ${totalActivePlusUsers.last30Days.toLocaleString('en-US')}
|
||||
</li>
|
||||
<li>
|
||||
<b>PRO:</b> ${totalActiveProUsers.last30Days.toLocaleString('en-US')}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<b>Payments (This Month)</b>
|
||||
<ul>
|
||||
@@ -944,10 +940,6 @@ export const html = (data: any, timer: TimerInterface) => {
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
<strong>Here is the MRR chart over 30 days:</strong>
|
||||
</p>
|
||||
<img src=${chartUrls.mrr}></img>
|
||||
<p>
|
||||
<strong>Here is the MRR Monthly chart this year:</strong>
|
||||
</p>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { DomainEventHandlerInterface, StatisticPersistenceRequestedEvent } from '@standardnotes/domain-events'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { Logger } from 'winston'
|
||||
import { PersistStatistic } from '../UseCase/PersistStatistic/PersistStatistic'
|
||||
|
||||
export class StatisticPersistenceRequestedEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(private persistStatistic: PersistStatistic, private logger: Logger) {}
|
||||
constructor(private persistStatistic: PersistStatistic, private timer: TimerInterface, private logger: Logger) {}
|
||||
|
||||
async handle(event: StatisticPersistenceRequestedEvent): Promise<void> {
|
||||
const result = await this.persistStatistic.execute({
|
||||
date: event.payload.date,
|
||||
date: this.timer.convertMicrosecondsToDate(event.payload.date),
|
||||
statisticMeasureName: event.payload.statisticMeasureName,
|
||||
value: event.payload.value,
|
||||
})
|
||||
|
||||
@@ -26,6 +26,10 @@ export class StatisticMeasureName extends ValueObject<StatisticMeasureNameProps>
|
||||
FiveYearPlansMRR: 'five-year-plans-mrr',
|
||||
ProPlansMRR: 'pro-plans-mrr',
|
||||
PlusPlansMRR: 'plus-plans-mrr',
|
||||
ActiveUsers: 'active-users',
|
||||
ActiveProUsers: 'active-pro-users',
|
||||
ActivePlusUsers: 'active-plus-users',
|
||||
ActiveFreeUsers: 'active-free-users',
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.41.2](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.41.1...@standardnotes/api-gateway@1.41.2) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
## [1.41.1](https://github.com/standardnotes/api-gateway/compare/@standardnotes/api-gateway@1.41.0...@standardnotes/api-gateway@1.41.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/api-gateway
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/api-gateway",
|
||||
"version": "1.41.1",
|
||||
"version": "1.41.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,36 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.70.4](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.3...@standardnotes/auth-server@1.70.4) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** replace date object with number timestamp ([5b4bb6e](https://github.com/standardnotes/server/commit/5b4bb6e7a78a1b0f4e663bb990619f65f6a5c757))
|
||||
|
||||
## [1.70.3](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.2...@standardnotes/auth-server@1.70.3) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** add persisting statistics for all subscription plans ([addedb3](https://github.com/standardnotes/server/commit/addedb3091ddae81618d56663e18f2ae76a43c4e))
|
||||
|
||||
## [1.70.2](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.1...@standardnotes/auth-server@1.70.2) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** docker command ([85d2f42](https://github.com/standardnotes/server/commit/85d2f42f473110e8dfca975bfecc7a56823bdef4))
|
||||
|
||||
## [1.70.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.70.0...@standardnotes/auth-server@1.70.1) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** saving subscription plan name in session traces ([3064d03](https://github.com/standardnotes/server/commit/3064d03aa9a2ac9ca3acfff30480ea8629faeb14))
|
||||
|
||||
# [1.70.0](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.69.1...@standardnotes/auth-server@1.70.0) (2022-12-19)
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** add requesting persisting statistics ([a35271f](https://github.com/standardnotes/server/commit/a35271fbb399b68a3ac7021395d8063707fba222))
|
||||
|
||||
## [1.69.1](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.69.0...@standardnotes/auth-server@1.69.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/auth-server
|
||||
|
||||
40
packages/auth/bin/stats.ts
Normal file
40
packages/auth/bin/stats.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import 'newrelic'
|
||||
|
||||
import { Logger } from 'winston'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
|
||||
import TYPES from '../src/Bootstrap/Types'
|
||||
import { Env } from '../src/Bootstrap/Env'
|
||||
import { PersistStatistics } from '../src/Domain/UseCase/PersistStatistics/PersistStatistics'
|
||||
|
||||
const container = new ContainerConfigLoader()
|
||||
void container.load().then((container) => {
|
||||
const env: Env = new Env()
|
||||
env.load()
|
||||
|
||||
const logger: Logger = container.get(TYPES.Logger)
|
||||
|
||||
logger.info('Starting session traces cleanup')
|
||||
|
||||
const persistStats: PersistStatistics = container.get(TYPES.PersistStatistics)
|
||||
const timer: TimerInterface = container.get(TYPES.Timer)
|
||||
|
||||
Promise.resolve(
|
||||
persistStats.execute({
|
||||
sessionsInADay: timer.getUTCDateNDaysAgo(1),
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
logger.info('Stats persisted.')
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(`Could not persist stats: ${error.message}`)
|
||||
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
@@ -24,6 +24,11 @@ case "$COMMAND" in
|
||||
yarn workspace @standardnotes/auth-server cleanup
|
||||
;;
|
||||
|
||||
'stats' )
|
||||
echo "[Docker] Starting Persisting Stats..."
|
||||
yarn workspace @standardnotes/auth-server stats
|
||||
;;
|
||||
|
||||
'email-daily-backup' )
|
||||
echo "[Docker] Starting Email Daily Backup..."
|
||||
yarn workspace @standardnotes/auth-server daily-backup:email
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/auth-server",
|
||||
"version": "1.69.1",
|
||||
"version": "1.70.4",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
@@ -20,6 +20,7 @@
|
||||
"start": "yarn node dist/bin/server.js",
|
||||
"worker": "yarn node dist/bin/worker.js",
|
||||
"cleanup": "yarn node dist/bin/cleanup.js",
|
||||
"stats": "yarn node dist/bin/stats.js",
|
||||
"daily-backup:email": "yarn node dist/bin/backup.js email daily",
|
||||
"user-email-backup": "yarn node dist/bin/user_email_backup.js",
|
||||
"daily-backup:dropbox": "yarn node dist/bin/backup.js dropbox daily",
|
||||
|
||||
@@ -202,6 +202,7 @@ import { SessionTrace } from '../Domain/Session/SessionTrace'
|
||||
import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace'
|
||||
import { TraceSession } from '../Domain/UseCase/TraceSession/TraceSession'
|
||||
import { CleanupSessionTraces } from '../Domain/UseCase/CleanupSessionTraces/CleanupSessionTraces'
|
||||
import { PersistStatistics } from '../Domain/UseCase/PersistStatistics/PersistStatistics'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const newrelicFormatter = require('@newrelic/winston-enricher')
|
||||
@@ -500,6 +501,16 @@ export class ContainerConfigLoader {
|
||||
container.get(TYPES.SESSION_TRACE_DAYS_TTL),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<PersistStatistics>(TYPES.PersistStatistics)
|
||||
.toConstantValue(
|
||||
new PersistStatistics(
|
||||
container.get(TYPES.SessionTraceRepository),
|
||||
container.get(TYPES.DomainEventPublisher),
|
||||
container.get(TYPES.DomainEventFactory),
|
||||
container.get(TYPES.Timer),
|
||||
),
|
||||
)
|
||||
|
||||
container
|
||||
.bind<CleanupSessionTraces>(TYPES.CleanupSessionTraces)
|
||||
|
||||
@@ -126,6 +126,7 @@ const TYPES = {
|
||||
ProcessUserRequest: Symbol.for('ProcessUserRequest'),
|
||||
TraceSession: Symbol.for('TraceSession'),
|
||||
CleanupSessionTraces: Symbol.for('CleanupSessionTraces'),
|
||||
PersistStatistics: Symbol.for('PersistStatistics'),
|
||||
// Handlers
|
||||
UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'),
|
||||
AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'),
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
MuteEmailsSettingChangedEvent,
|
||||
EmailRequestedEvent,
|
||||
StatisticPersistenceRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
@@ -31,6 +32,25 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
|
||||
export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
constructor(@inject(TYPES.Timer) private timer: TimerInterface) {}
|
||||
|
||||
createStatisticPersistenceRequestedEvent(dto: {
|
||||
statisticMeasureName: string
|
||||
value: number
|
||||
date: number
|
||||
}): StatisticPersistenceRequestedEvent {
|
||||
return {
|
||||
type: 'STATISTIC_PERSISTENCE_REQUESTED',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: '-',
|
||||
userIdentifierType: 'email',
|
||||
},
|
||||
origin: DomainEventService.Auth,
|
||||
},
|
||||
payload: dto,
|
||||
}
|
||||
}
|
||||
|
||||
createMuteEmailsSettingChangedEvent(dto: {
|
||||
username: string
|
||||
mute: boolean
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
UserContentSizeRecalculationRequestedEvent,
|
||||
MuteEmailsSettingChangedEvent,
|
||||
EmailRequestedEvent,
|
||||
StatisticPersistenceRequestedEvent,
|
||||
} from '@standardnotes/domain-events'
|
||||
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
|
||||
|
||||
@@ -88,4 +89,9 @@ export interface DomainEventFactoryInterface {
|
||||
mute: boolean
|
||||
emailSubscriptionRejectionLevel: string
|
||||
}): MuteEmailsSettingChangedEvent
|
||||
createStatisticPersistenceRequestedEvent(dto: {
|
||||
statisticMeasureName: string
|
||||
value: number
|
||||
date: number
|
||||
}): StatisticPersistenceRequestedEvent
|
||||
}
|
||||
|
||||
@@ -41,4 +41,23 @@ describe('RoleToSubscriptionMap', () => {
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('should filter our subscription roles from an array of roles', () => {
|
||||
const roles = [
|
||||
{
|
||||
name: RoleName.CoreUser,
|
||||
} as jest.Mocked<Role>,
|
||||
{
|
||||
name: RoleName.FilesBetaUser,
|
||||
} as jest.Mocked<Role>,
|
||||
{
|
||||
name: RoleName.PlusUser,
|
||||
} as jest.Mocked<Role>,
|
||||
]
|
||||
expect(createMap().filterSubscriptionRoles(roles)).toEqual([
|
||||
{
|
||||
name: RoleName.PlusUser,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -17,6 +17,10 @@ export class RoleToSubscriptionMap implements RoleToSubscriptionMapInterface {
|
||||
return roles.filter((role) => this.nonSubscriptionRoles.includes(role.name as RoleName))
|
||||
}
|
||||
|
||||
filterSubscriptionRoles(roles: Role[]): Array<Role> {
|
||||
return roles.filter((role) => !this.nonSubscriptionRoles.includes(role.name as RoleName))
|
||||
}
|
||||
|
||||
getSubscriptionNameForRoleName(roleName: RoleName): SubscriptionName | undefined {
|
||||
return this.roleNameToSubscriptionNameMap.get(roleName)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Role } from './Role'
|
||||
|
||||
export interface RoleToSubscriptionMapInterface {
|
||||
filterNonSubscriptionRoles(roles: Role[]): Array<Role>
|
||||
filterSubscriptionRoles(roles: Role[]): Array<Role>
|
||||
getSubscriptionNameForRoleName(roleName: RoleName): SubscriptionName | undefined
|
||||
getRoleNameForSubscriptionName(subscriptionName: SubscriptionName): RoleName | undefined
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Uuid } from '@standardnotes/domain-core'
|
||||
import { SubscriptionPlanName, Uuid } from '@standardnotes/domain-core'
|
||||
|
||||
import { SessionTrace } from './SessionTrace'
|
||||
|
||||
@@ -6,4 +6,6 @@ export interface SessionTraceRepositoryInterface {
|
||||
save(sessionTrace: SessionTrace): Promise<void>
|
||||
removeExpiredBefore(date: Date): Promise<void>
|
||||
findOneByUserUuidAndDate(userUuid: Uuid, date: Date): Promise<SessionTrace | null>
|
||||
countByDate(date: Date): Promise<number>
|
||||
countByDateAndSubscriptionPlanName(date: Date, subscriptionPlanName: SubscriptionPlanName): Promise<number>
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('CreateCrossServiceToken', () => {
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(user)
|
||||
|
||||
roleToSubscriptionMap = {} as jest.Mocked<RoleToSubscriptionMapInterface>
|
||||
roleToSubscriptionMap.filterNonSubscriptionRoles = jest.fn().mockReturnValue([RoleName.NAMES.PlusUser])
|
||||
roleToSubscriptionMap.filterSubscriptionRoles = jest.fn().mockReturnValue([RoleName.NAMES.PlusUser])
|
||||
roleToSubscriptionMap.getSubscriptionNameForRoleName = jest
|
||||
.fn()
|
||||
.mockReturnValue(SubscriptionPlanName.NAMES.PlusPlan)
|
||||
@@ -170,7 +170,7 @@ describe('CreateCrossServiceToken', () => {
|
||||
})
|
||||
|
||||
it('should trace session without a subscription role', async () => {
|
||||
roleToSubscriptionMap.filterNonSubscriptionRoles = jest.fn().mockReturnValue([])
|
||||
roleToSubscriptionMap.filterSubscriptionRoles = jest.fn().mockReturnValue([])
|
||||
|
||||
await createUseCase().execute({
|
||||
user,
|
||||
|
||||
@@ -102,7 +102,7 @@ export class CreateCrossServiceToken implements UseCaseInterface {
|
||||
}
|
||||
|
||||
private getSubscriptionNameFromRoles(roles: Array<Role>): string | null {
|
||||
const nonSubscriptionRoles = this.roleToSubscriptionMap.filterNonSubscriptionRoles(roles)
|
||||
const nonSubscriptionRoles = this.roleToSubscriptionMap.filterSubscriptionRoles(roles)
|
||||
if (nonSubscriptionRoles.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { DomainEventPublisherInterface, StatisticPersistenceRequestedEvent } from '@standardnotes/domain-events'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||
import { SessionTraceRepositoryInterface } from '../../Session/SessionTraceRepositoryInterface'
|
||||
|
||||
import { PersistStatistics } from './PersistStatistics'
|
||||
|
||||
describe('PersistStatistics', () => {
|
||||
let sessionTracesRepository: SessionTraceRepositoryInterface
|
||||
let domainEventPublisher: DomainEventPublisherInterface
|
||||
let domainEventFactory: DomainEventFactoryInterface
|
||||
let timer: TimerInterface
|
||||
|
||||
const createUseCase = () =>
|
||||
new PersistStatistics(sessionTracesRepository, domainEventPublisher, domainEventFactory, timer)
|
||||
|
||||
beforeEach(() => {
|
||||
sessionTracesRepository = {} as jest.Mocked<SessionTraceRepositoryInterface>
|
||||
sessionTracesRepository.countByDate = jest.fn().mockReturnValue(1)
|
||||
sessionTracesRepository.countByDateAndSubscriptionPlanName = jest.fn().mockReturnValue(2)
|
||||
|
||||
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
||||
domainEventFactory.createStatisticPersistenceRequestedEvent = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<StatisticPersistenceRequestedEvent>)
|
||||
|
||||
domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
|
||||
domainEventPublisher.publish = jest.fn()
|
||||
|
||||
timer = {} as jest.Mocked<TimerInterface>
|
||||
timer.convertDateToMicroseconds = jest.fn().mockReturnValue(3)
|
||||
})
|
||||
|
||||
it('should request statistic persistence', async () => {
|
||||
await createUseCase().execute({ sessionsInADay: new Date() })
|
||||
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalledTimes(4)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Result, SubscriptionPlanName, UseCaseInterface } from '@standardnotes/domain-core'
|
||||
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
|
||||
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||
import { SessionTraceRepositoryInterface } from '../../Session/SessionTraceRepositoryInterface'
|
||||
import { PersistStatisticsDTO } from './PersistStatisticsDTO'
|
||||
|
||||
export class PersistStatistics implements UseCaseInterface<string> {
|
||||
constructor(
|
||||
private sessionTracesRepository: SessionTraceRepositoryInterface,
|
||||
private domainEventPublisher: DomainEventPublisherInterface,
|
||||
private domainEventFactory: DomainEventFactoryInterface,
|
||||
private timer: TimerInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: PersistStatisticsDTO): Promise<Result<string>> {
|
||||
const countSessionsInADay = await this.sessionTracesRepository.countByDate(dto.sessionsInADay)
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
|
||||
statisticMeasureName: 'active-users',
|
||||
value: countSessionsInADay,
|
||||
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
|
||||
}),
|
||||
)
|
||||
|
||||
const proSubscriptionPlanName = SubscriptionPlanName.create(SubscriptionPlanName.NAMES.ProPlan).getValue()
|
||||
const countProSessionsInADay = await this.sessionTracesRepository.countByDateAndSubscriptionPlanName(
|
||||
dto.sessionsInADay,
|
||||
proSubscriptionPlanName,
|
||||
)
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
|
||||
statisticMeasureName: 'active-pro-users',
|
||||
value: countProSessionsInADay,
|
||||
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
|
||||
}),
|
||||
)
|
||||
|
||||
const plusSubscriptionPlanName = SubscriptionPlanName.create(SubscriptionPlanName.NAMES.PlusPlan).getValue()
|
||||
const countPlusSessionsInADay = await this.sessionTracesRepository.countByDateAndSubscriptionPlanName(
|
||||
dto.sessionsInADay,
|
||||
plusSubscriptionPlanName,
|
||||
)
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
|
||||
statisticMeasureName: 'active-plus-users',
|
||||
value: countPlusSessionsInADay,
|
||||
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
|
||||
}),
|
||||
)
|
||||
|
||||
const countFreeSessionsInADay = countSessionsInADay - countProSessionsInADay - countPlusSessionsInADay
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createStatisticPersistenceRequestedEvent({
|
||||
statisticMeasureName: 'active-free-users',
|
||||
value: countFreeSessionsInADay,
|
||||
date: this.timer.convertDateToMicroseconds(dto.sessionsInADay),
|
||||
}),
|
||||
)
|
||||
|
||||
return Result.ok('Statistics persisted.')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface PersistStatisticsDTO {
|
||||
sessionsInADay: Date
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MapperInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { MapperInterface, SubscriptionPlanName, Uuid } from '@standardnotes/domain-core'
|
||||
import { Repository } from 'typeorm'
|
||||
import { SessionTrace } from '../../Domain/Session/SessionTrace'
|
||||
import { SessionTraceRepositoryInterface } from '../../Domain/Session/SessionTraceRepositoryInterface'
|
||||
@@ -10,6 +10,27 @@ export class MySQLSessionTraceRepository implements SessionTraceRepositoryInterf
|
||||
private mapper: MapperInterface<SessionTrace, TypeORMSessionTrace>,
|
||||
) {}
|
||||
|
||||
async countByDateAndSubscriptionPlanName(date: Date, subscriptionPlanName: SubscriptionPlanName): Promise<number> {
|
||||
return this.ormRepository
|
||||
.createQueryBuilder('trace')
|
||||
.where('trace.creation_date = :creationDate', {
|
||||
creationDate: new Date(date.getFullYear(), date.getMonth(), date.getDate()),
|
||||
})
|
||||
.andWhere('trace.subscription_plan_name = :subscriptionPlanName', {
|
||||
subscriptionPlanName: subscriptionPlanName.value,
|
||||
})
|
||||
.getCount()
|
||||
}
|
||||
|
||||
async countByDate(date: Date): Promise<number> {
|
||||
return this.ormRepository
|
||||
.createQueryBuilder('trace')
|
||||
.where('trace.creation_date = :creationDate', {
|
||||
creationDate: new Date(date.getFullYear(), date.getMonth(), date.getDate()),
|
||||
})
|
||||
.getCount()
|
||||
}
|
||||
|
||||
async removeExpiredBefore(date: Date): Promise<void> {
|
||||
await this.ormRepository
|
||||
.createQueryBuilder()
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.9.59](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.58...@standardnotes/domain-events-infra@1.9.59) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
## [1.9.58](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.9.57...@standardnotes/domain-events-infra@1.9.58) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/domain-events-infra
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events-infra",
|
||||
"version": "1.9.58",
|
||||
"version": "1.9.59",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [2.105.1](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.105.0...@standardnotes/domain-events@2.105.1) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** replace date object with number timestamp ([5b4bb6e](https://github.com/standardnotes/server/commit/5b4bb6e7a78a1b0f4e663bb990619f65f6a5c757))
|
||||
|
||||
# [2.105.0](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.104.2...@standardnotes/domain-events@2.105.0) (2022-12-19)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/domain-events",
|
||||
"version": "2.105.0",
|
||||
"version": "2.105.1",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export interface StatisticPersistenceRequestedEventPayload {
|
||||
statisticMeasureName: string
|
||||
value: number
|
||||
date: Date
|
||||
date: number
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.6.56](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.55...@standardnotes/event-store@1.6.56) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
## [1.6.55](https://github.com/standardnotes/server/compare/@standardnotes/event-store@1.6.54...@standardnotes/event-store@1.6.55) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/event-store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/event-store",
|
||||
"version": "1.6.55",
|
||||
"version": "1.6.56",
|
||||
"description": "Event Store Service",
|
||||
"private": true,
|
||||
"main": "dist/src/index.js",
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.9.2](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.9.1...@standardnotes/files-server@1.9.2) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
## [1.9.1](https://github.com/standardnotes/files/compare/@standardnotes/files-server@1.9.0...@standardnotes/files-server@1.9.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/files-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/files-server",
|
||||
"version": "1.9.1",
|
||||
"version": "1.9.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.10.2](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.10.1...@standardnotes/revisions-server@1.10.2) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||
|
||||
## [1.10.1](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.10.0...@standardnotes/revisions-server@1.10.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/revisions-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/revisions-server",
|
||||
"version": "1.10.1",
|
||||
"version": "1.10.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.16.2](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.16.1...@standardnotes/scheduler-server@1.16.2) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
## [1.16.1](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.16.0...@standardnotes/scheduler-server@1.16.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/scheduler-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/scheduler-server",
|
||||
"version": "1.16.1",
|
||||
"version": "1.16.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.2](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.28.1...@standardnotes/syncing-server@1.28.2) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
## [1.28.1](https://github.com/standardnotes/syncing-server-js/compare/@standardnotes/syncing-server@1.28.0...@standardnotes/syncing-server@1.28.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/syncing-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/syncing-server",
|
||||
"version": "1.28.1",
|
||||
"version": "1.28.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.5.2](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.5.1...@standardnotes/websockets-server@1.5.2) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
## [1.5.1](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.5.0...@standardnotes/websockets-server@1.5.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/websockets-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/websockets-server",
|
||||
"version": "1.5.1",
|
||||
"version": "1.5.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.19.3](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.2...@standardnotes/workspace-server@1.19.3) (2022-12-20)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **workspace:** specs ([c8203cf](https://github.com/standardnotes/server/commit/c8203cf04cb93cc65d30b69f10fb275f5e6be449))
|
||||
|
||||
## [1.19.2](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.1...@standardnotes/workspace-server@1.19.2) (2022-12-20)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/workspace-server
|
||||
|
||||
## [1.19.1](https://github.com/standardnotes/server/compare/@standardnotes/workspace-server@1.19.0...@standardnotes/workspace-server@1.19.1) (2022-12-19)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/workspace-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@standardnotes/workspace-server",
|
||||
"version": "1.19.1",
|
||||
"version": "1.19.3",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0"
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@ import { WorkspaceInviteRepositoryInterface } from '../../Invite/WorkspaceInvite
|
||||
|
||||
import { InviteToWorkspace } from './InviteToWorkspace'
|
||||
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
|
||||
import { DomainEventPublisherInterface, WorkspaceInviteCreatedEvent } from '@standardnotes/domain-events'
|
||||
import { DomainEventPublisherInterface, EmailRequestedEvent } from '@standardnotes/domain-events'
|
||||
import { WorkspaceAccessLevel } from '@standardnotes/common'
|
||||
|
||||
describe('InviteToWorkspace', () => {
|
||||
@@ -33,9 +33,7 @@ describe('InviteToWorkspace', () => {
|
||||
domainEventPublisher.publish = jest.fn()
|
||||
|
||||
domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
|
||||
domainEventFactory.createWorkspaceInviteCreatedEvent = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<WorkspaceInviteCreatedEvent>)
|
||||
domainEventFactory.createEmailRequestedEvent = jest.fn().mockReturnValue({} as jest.Mocked<EmailRequestedEvent>)
|
||||
})
|
||||
|
||||
it('should create an invite', async () => {
|
||||
|
||||
Reference in New Issue
Block a user