Compare commits

...

8 Commits

Author SHA1 Message Date
standardci 664a92132b chore(release): publish new version
- @standardnotes/auth-server@1.177.9
 - @standardnotes/home-server@1.22.34
2023-12-29 10:29:32 +00:00
Karol Sójko 26b13ed6d4 fix(auth): adding user roles upon renewal of shared subscription (#1012)
* fix(auth): adding user roles upon renewal of shared subscription

* feat(auth): add procedure to fix roles on shared subscriptions
2023-12-29 11:07:51 +01:00
standardci be7c66b145 chore(release): publish new version
- @standardnotes/analytics@2.34.11
 - @standardnotes/api-gateway@1.89.11
 - @standardnotes/auth-server@1.177.8
 - @standardnotes/domain-events-infra@1.22.10
 - @standardnotes/domain-events@2.139.3
 - @standardnotes/files-server@1.37.5
 - @standardnotes/home-server@1.22.33
 - @standardnotes/revisions-server@1.51.11
 - @standardnotes/scheduler-server@1.27.16
 - @standardnotes/syncing-server@1.129.8
 - @standardnotes/websockets-server@1.22.7
2023-12-29 07:16:40 +00:00
Karol Sójko 7e8d7f6874 fix: cleanup revision requests 2023-12-29 07:55:16 +01:00
standardci c1805ee2ac chore(release): publish new version
- @standardnotes/auth-server@1.177.7
 - @standardnotes/home-server@1.22.32
2023-12-28 15:59:49 +00:00
Karol Sójko eff1d642cf fix(auth): missing return statement in lock middleware 2023-12-28 16:39:38 +01:00
standardci a05d7afe00 chore(release): publish new version
- @standardnotes/api-gateway@1.89.10
 - @standardnotes/home-server@1.22.31
2023-12-28 15:13:45 +00:00
Karol Sójko c2650646d1 fix(api-gateway): log severity 2023-12-28 15:53:26 +01:00
42 changed files with 268 additions and 205 deletions
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.34.11](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.10...@standardnotes/analytics@2.34.11) (2023-12-29)
**Note:** Version bump only for package @standardnotes/analytics
## [2.34.10](https://github.com/standardnotes/server/compare/@standardnotes/analytics@2.34.9...@standardnotes/analytics@2.34.10) (2023-12-28)
**Note:** Version bump only for package @standardnotes/analytics
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/analytics",
"version": "2.34.10",
"version": "2.34.11",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+10
View File
@@ -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.89.11](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.10...@standardnotes/api-gateway@1.89.11) (2023-12-29)
**Note:** Version bump only for package @standardnotes/api-gateway
## [1.89.10](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.9...@standardnotes/api-gateway@1.89.10) (2023-12-28)
### Bug Fixes
* **api-gateway:** log severity ([c265064](https://github.com/standardnotes/server/commit/c2650646d1f89ca509b4d256e4305a592d12f850))
## [1.89.9](https://github.com/standardnotes/server/compare/@standardnotes/api-gateway@1.89.8...@standardnotes/api-gateway@1.89.9) (2023-12-28)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api-gateway",
"version": "1.89.9",
"version": "1.89.11",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -89,7 +89,7 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
const result = await promise
if (retryAttempt) {
this.logger.info(`Request to Auth Server succeeded after ${retryAttempt} retries`)
this.logger.debug(`Request to Auth Server succeeded after ${retryAttempt} retries`)
}
return result as { status: number; data: unknown; headers: { contentType: string } }
@@ -103,7 +103,7 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
this.logger.info(`Retrying request to Auth Server for the ${nextRetryAttempt} time`)
this.logger.debug(`Retrying request to Auth Server for the ${nextRetryAttempt} time`)
return this.validateSession(headers, nextRetryAttempt)
}
@@ -153,7 +153,7 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
})
if (retryAttempt) {
this.logger.info(`Request to Syncing Server succeeded after ${retryAttempt} retries`, {
this.logger.debug(`Request to Syncing Server succeeded after ${retryAttempt} retries`, {
userId: response.locals.user ? response.locals.user.uuid : undefined,
})
}
@@ -167,7 +167,7 @@ export class GRPCServiceProxy implements ServiceProxyInterface {
const nextRetryAttempt = retryAttempt ? retryAttempt + 1 : 1
this.logger.info(`Retrying request to Syncing Server for the ${nextRetryAttempt} time`, {
this.logger.debug(`Retrying request to Syncing Server for the ${nextRetryAttempt} time`, {
userId: response.locals.user ? response.locals.user.uuid : undefined,
})
+18
View File
@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.177.9](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.8...@standardnotes/auth-server@1.177.9) (2023-12-29)
### Bug Fixes
* **auth:** adding user roles upon renewal of shared subscription ([#1012](https://github.com/standardnotes/server/issues/1012)) ([26b13ed](https://github.com/standardnotes/server/commit/26b13ed6d488fb5038a3928482b3079ab2b5f8d8))
## [1.177.8](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.7...@standardnotes/auth-server@1.177.8) (2023-12-29)
### Bug Fixes
* cleanup revision requests ([7e8d7f6](https://github.com/standardnotes/server/commit/7e8d7f6874bb1db55ee6feb9e128c684a6900189))
## [1.177.7](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.6...@standardnotes/auth-server@1.177.7) (2023-12-28)
### Bug Fixes
* **auth:** missing return statement in lock middleware ([eff1d64](https://github.com/standardnotes/server/commit/eff1d642cfd3502f479761a3bb76a543ae0166af))
## [1.177.6](https://github.com/standardnotes/server/compare/@standardnotes/auth-server@1.177.5...@standardnotes/auth-server@1.177.6) (2023-12-28)
### Bug Fixes
+67
View File
@@ -0,0 +1,67 @@
import 'reflect-metadata'
import { Logger } from 'winston'
import * as dayjs from 'dayjs'
import * as utc from 'dayjs/plugin/utc'
import { Uuid } from '@standardnotes/domain-core'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { UserSubscriptionRepositoryInterface } from '../src/Domain/Subscription/UserSubscriptionRepositoryInterface'
import { RoleServiceInterface } from '../src/Domain/Role/RoleServiceInterface'
import { UserSubscriptionType } from '../src/Domain/Subscription/UserSubscriptionType'
import { UserRepositoryInterface } from '../src/Domain/User/UserRepositoryInterface'
const fixRoles = async (
userRepository: UserRepositoryInterface,
userSubscriptionRepository: UserSubscriptionRepositoryInterface,
roleService: RoleServiceInterface,
): Promise<void> => {
const subscriptions = await userSubscriptionRepository.findActiveByType(UserSubscriptionType.Shared)
for (const subscription of subscriptions) {
const userUuidOrError = Uuid.create(subscription.userUuid)
if (userUuidOrError.isFailed()) {
continue
}
const userUuid = userUuidOrError.getValue()
const user = await userRepository.findOneByUuid(userUuid)
if (!user) {
continue
}
await roleService.addUserRoleBasedOnSubscription(user, subscription.planName)
}
}
const container = new ContainerConfigLoader('worker')
void container.load().then((container) => {
dayjs.extend(utc)
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Auth_Logger)
logger.info('Starting roles fix for shared subscriptions...')
const userRepository = container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository)
const userSubscriptionRepository = container.get<UserSubscriptionRepositoryInterface>(
TYPES.Auth_UserSubscriptionRepository,
)
const roleService = container.get<RoleServiceInterface>(TYPES.Auth_RoleService)
Promise.resolve(fixRoles(userRepository, userSubscriptionRepository, roleService))
.then(() => {
logger.info('Finished fixing roles for shared subscriptions')
process.exit(0)
})
.catch((error) => {
logger.error(`Error while fixing roles for shared subscriptions: ${(error as Error).message}`)
process.exit(1)
})
})
-71
View File
@@ -1,71 +0,0 @@
import 'reflect-metadata'
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
import { DomainEventFactoryInterface } from '../src/Domain/Event/DomainEventFactoryInterface'
import { UserSubscriptionRepositoryInterface } from '../src/Domain/Subscription/UserSubscriptionRepositoryInterface'
import { SubscriptionPlanName } from '@standardnotes/domain-core'
const requestCleanup = async (
userSubscriptionRepository: UserSubscriptionRepositoryInterface,
domainEventFactory: DomainEventFactoryInterface,
domainEventPublisher: DomainEventPublisherInterface,
): Promise<void> => {
const proSubscriptionPlan = SubscriptionPlanName.create(SubscriptionPlanName.NAMES.ProPlan).getValue()
const plusSubscriptionPlan = SubscriptionPlanName.create(SubscriptionPlanName.NAMES.PlusPlan).getValue()
const totalSubscriptions = await userSubscriptionRepository.countByPlanName([
proSubscriptionPlan,
plusSubscriptionPlan,
])
const limitPerPage = 100
const numberOfPages = Math.ceil(totalSubscriptions / limitPerPage)
for (let i = 0; i < numberOfPages; i++) {
const subscriptions = await userSubscriptionRepository.findByPlanName(
[proSubscriptionPlan, plusSubscriptionPlan],
i * limitPerPage,
limitPerPage,
)
for (const subscription of subscriptions) {
await domainEventPublisher.publish(
domainEventFactory.createRevisionsCleanupRequestedEvent({
userUuid: subscription.userUuid,
}),
)
}
}
}
const container = new ContainerConfigLoader('worker')
void container.load().then((container) => {
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Auth_Logger)
logger.info('Starting revisions cleanup triggering...')
const domainEventFactory = container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory)
const domainEventPublisher = container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher)
const userSubscriptionRepository = container.get<UserSubscriptionRepositoryInterface>(
TYPES.Auth_UserSubscriptionRepository,
)
Promise.resolve(requestCleanup(userSubscriptionRepository, domainEventFactory, domainEventPublisher))
.then(() => {
logger.info('Finished revisions cleanup triggering')
process.exit(0)
})
.catch((error) => {
logger.error(`Failed to trigger revisions cleanup: ${(error as Error).message}`)
process.exit(1)
})
})
+8 -2
View File
@@ -58,8 +58,14 @@ void container.load().then((container) => {
const logger: winston.Logger = container.get(TYPES.Auth_Logger)
server.setErrorConfig((app) => {
app.use((error: Record<string, unknown>, _request: Request, response: Response, _next: NextFunction) => {
logger.error(error.stack)
app.use((error: Record<string, unknown>, request: Request, response: Response, _next: NextFunction) => {
logger.error(`${error.stack}`, {
method: request.method,
url: request.url,
snjs: request.headers['x-snjs-version'],
application: request.headers['x-application-version'],
userId: response.locals.user ? response.locals.user.uuid : undefined,
})
response.status(500).send({
error: {
@@ -4,7 +4,7 @@ const path = require('path')
const pnp = require(path.normalize(path.resolve(__dirname, '../../..', '.pnp.cjs'))).setup()
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/revisions_cleanup.js')))
const index = require(path.normalize(path.resolve(__dirname, '../dist/bin/fix_roles.js')))
Object.defineProperty(exports, '__esModule', { value: true })
+4 -4
View File
@@ -38,16 +38,16 @@ case "$COMMAND" in
exec node docker/entrypoint-fix-quota.js $EMAIL
;;
'fix-roles' )
exec node docker/entrypoint-fix-roles.js
;;
'delete-accounts' )
FILE_NAME=$1 && shift 1
MODE=$1 && shift 1
exec node docker/entrypoint-delete-accounts.js $FILE_NAME $MODE
;;
'revisions-cleanup' )
exec node docker/entrypoint-revisions-cleanup.js
;;
* )
echo "[Docker] Unknown command"
;;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/auth-server",
"version": "1.177.6",
"version": "1.177.9",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+1
View File
@@ -1284,6 +1284,7 @@ export class ContainerConfigLoader {
),
container.get<UserSubscriptionRepositoryInterface>(TYPES.Auth_UserSubscriptionRepository),
container.get<UserRepositoryInterface>(TYPES.Auth_UserRepository),
container.get<RoleServiceInterface>(TYPES.Auth_RoleService),
container.get<winston.Logger>(TYPES.Auth_Logger),
),
)
@@ -22,7 +22,6 @@ import {
SessionRefreshedEvent,
AccountDeletionVerificationRequestedEvent,
FileQuotaRecalculationRequestedEvent,
RevisionsCleanupRequestedEvent,
} from '@standardnotes/domain-events'
import { Predicate, PredicateVerificationResult } from '@standardnotes/predicates'
import { TimerInterface } from '@standardnotes/time'
@@ -35,22 +34,6 @@ import { KeyParamsData } from '@standardnotes/responses'
@injectable()
export class DomainEventFactory implements DomainEventFactoryInterface {
constructor(@inject(TYPES.Auth_Timer) private timer: TimerInterface) {}
createRevisionsCleanupRequestedEvent(dto: { userUuid: string }): RevisionsCleanupRequestedEvent {
return {
type: 'REVISIONS_CLEANUP_REQUESTED',
createdAt: this.timer.getUTCDate(),
meta: {
correlation: {
userIdentifier: dto.userUuid,
userIdentifierType: 'uuid',
},
origin: DomainEventService.Auth,
},
payload: dto,
}
}
createFileQuotaRecalculationRequestedEvent(dto: { userUuid: string }): FileQuotaRecalculationRequestedEvent {
return {
type: 'FILE_QUOTA_RECALCULATION_REQUESTED',
@@ -20,13 +20,11 @@ import {
SessionRefreshedEvent,
AccountDeletionVerificationRequestedEvent,
FileQuotaRecalculationRequestedEvent,
RevisionsCleanupRequestedEvent,
} from '@standardnotes/domain-events'
import { InviteeIdentifierType } from '../SharedSubscription/InviteeIdentifierType'
import { KeyParamsData } from '@standardnotes/responses'
export interface DomainEventFactoryInterface {
createRevisionsCleanupRequestedEvent(dto: { userUuid: string }): RevisionsCleanupRequestedEvent
createFileQuotaRecalculationRequestedEvent(dto: { userUuid: string }): FileQuotaRecalculationRequestedEvent
createWebSocketMessageRequestedEvent(dto: { userUuid: string; message: JSONString }): WebSocketMessageRequestedEvent
createEmailRequestedEvent(dto: {
@@ -10,6 +10,7 @@ export interface UserSubscriptionRepositoryInterface {
findByUserUuid(userUuid: string): Promise<UserSubscription[]>
countByPlanName(planNames: SubscriptionPlanName[]): Promise<number>
findByPlanName(planNames: SubscriptionPlanName[], offset: number, limit: number): Promise<UserSubscription[]>
findActiveByType(type: UserSubscriptionType): Promise<UserSubscription[]>
findOneByUserUuidAndSubscriptionId(userUuid: string, subscriptionId: number): Promise<UserSubscription | null>
findBySubscriptionIdAndType(subscriptionId: number, type: UserSubscriptionType): Promise<UserSubscription[]>
findBySubscriptionId(subscriptionId: number): Promise<UserSubscription[]>
@@ -8,6 +8,7 @@ import { SharedSubscriptionInvitation } from '../../SharedSubscription/SharedSub
import { InviteeIdentifierType } from '../../SharedSubscription/InviteeIdentifierType'
import { User } from '../../User/User'
import { InvitationStatus } from '../../SharedSubscription/InvitationStatus'
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
describe('RenewSharedSubscriptions', () => {
let listSharedSubscriptionInvitations: ListSharedSubscriptionInvitations
@@ -17,6 +18,7 @@ describe('RenewSharedSubscriptions', () => {
let logger: Logger
let sharedSubscriptionInvitation: SharedSubscriptionInvitation
let user: User
let roleService: RoleServiceInterface
const createUseCase = () =>
new RenewSharedSubscriptions(
@@ -24,6 +26,7 @@ describe('RenewSharedSubscriptions', () => {
sharedSubscriptionInvitationRepository,
userSubscriptionRepository,
userRepository,
roleService,
logger,
)
@@ -48,8 +51,12 @@ describe('RenewSharedSubscriptions', () => {
userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
userSubscriptionRepository.save = jest.fn()
roleService = {} as jest.Mocked<RoleServiceInterface>
roleService.addUserRoleBasedOnSubscription = jest.fn()
userRepository = {} as jest.Mocked<UserRepositoryInterface>
userRepository.findOneByUsernameOrEmail = jest.fn().mockReturnValue(user)
userRepository.findOneByUuid = jest.fn().mockReturnValue(user)
logger = {} as jest.Mocked<Logger>
logger.error = jest.fn()
@@ -71,7 +78,7 @@ describe('RenewSharedSubscriptions', () => {
expect(userSubscriptionRepository.save).toBeCalledTimes(1)
})
it('should log error if user not found', async () => {
it('should log error if user not found by email', async () => {
userRepository.findOneByUsernameOrEmail = jest.fn().mockReturnValue(null)
const useCase = createUseCase()
@@ -88,6 +95,42 @@ describe('RenewSharedSubscriptions', () => {
expect(logger.error).toBeCalledTimes(1)
})
it('should log error if user not found by uuid', async () => {
sharedSubscriptionInvitation.inviteeIdentifierType = InviteeIdentifierType.Uuid
sharedSubscriptionInvitation.inviteeIdentifier = '00000000-0000-0000-0000-000000000000'
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
const useCase = createUseCase()
const result = await useCase.execute({
inviterEmail: 'inviter@test.te',
newSubscriptionId: 123,
newSubscriptionName: 'test',
newSubscriptionExpiresAt: 123,
timestamp: 123,
})
expect(result.isFailed()).toBeFalsy()
expect(logger.error).toBeCalledTimes(1)
})
it('should log error if user not found by unknown identifier type', async () => {
sharedSubscriptionInvitation.inviteeIdentifierType = 'unknown' as InviteeIdentifierType
const useCase = createUseCase()
const result = await useCase.execute({
inviterEmail: 'inviter@test.te',
newSubscriptionId: 123,
newSubscriptionName: 'test',
newSubscriptionExpiresAt: 123,
timestamp: 123,
})
expect(result.isFailed()).toBeFalsy()
expect(logger.error).toBeCalledTimes(1)
})
it('should log error if error occurs', async () => {
userRepository.findOneByUsernameOrEmail = jest.fn().mockImplementation(() => {
throw new Error('test')
@@ -125,6 +168,24 @@ describe('RenewSharedSubscriptions', () => {
expect(logger.error).toBeCalledTimes(1)
})
it('should log error if uuid is invalid', async () => {
sharedSubscriptionInvitation.inviteeIdentifierType = InviteeIdentifierType.Uuid
sharedSubscriptionInvitation.inviteeIdentifier = 'invalid'
const useCase = createUseCase()
const result = await useCase.execute({
inviterEmail: 'inviter@test.te',
newSubscriptionId: 123,
newSubscriptionName: 'test',
newSubscriptionExpiresAt: 123,
timestamp: 123,
})
expect(result.isFailed()).toBeFalsy()
expect(logger.error).toBeCalledTimes(1)
})
it('should renew shared subscription for invitations by user uuid', async () => {
sharedSubscriptionInvitation.inviteeIdentifierType = InviteeIdentifierType.Uuid
sharedSubscriptionInvitation.inviteeIdentifier = '00000000-0000-0000-0000-000000000000'
@@ -1,4 +1,4 @@
import { Result, UseCaseInterface, Username } from '@standardnotes/domain-core'
import { Result, UseCaseInterface, Username, Uuid } from '@standardnotes/domain-core'
import { Logger } from 'winston'
import { RenewSharedSubscriptionsDTO } from './RenewSharedSubscriptionsDTO'
@@ -10,6 +10,8 @@ import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType'
import { UserSubscriptionRepositoryInterface } from '../../Subscription/UserSubscriptionRepositoryInterface'
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
import { InviteeIdentifierType } from '../../SharedSubscription/InviteeIdentifierType'
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
import { User } from '../../User/User'
export class RenewSharedSubscriptions implements UseCaseInterface<void> {
constructor(
@@ -17,6 +19,7 @@ export class RenewSharedSubscriptions implements UseCaseInterface<void> {
private sharedSubscriptionInvitationRepository: SharedSubscriptionInvitationRepositoryInterface,
private userSubscriptionRepository: UserSubscriptionRepositoryInterface,
private userRepository: UserRepositoryInterface,
private roleService: RoleServiceInterface,
private logger: Logger,
) {}
@@ -31,8 +34,8 @@ export class RenewSharedSubscriptions implements UseCaseInterface<void> {
for (const invitation of acceptedInvitations) {
try {
const userUuid = await this.getInviteeUserUuid(invitation.inviteeIdentifier, invitation.inviteeIdentifierType)
if (userUuid === null) {
const user = await this.getInviteeUserUuid(invitation.inviteeIdentifier, invitation.inviteeIdentifierType)
if (user === null) {
this.logger.error(
`[SUBSCRIPTION: ${dto.newSubscriptionId}] Could not renew shared subscription for invitation: ${invitation.uuid}: Could not find user with identifier: ${invitation.inviteeIdentifier}`,
)
@@ -42,11 +45,13 @@ export class RenewSharedSubscriptions implements UseCaseInterface<void> {
await this.createSharedSubscription({
subscriptionId: dto.newSubscriptionId,
subscriptionName: dto.newSubscriptionName,
userUuid,
userUuid: user.uuid,
timestamp: dto.timestamp,
subscriptionExpiresAt: dto.newSubscriptionExpiresAt,
})
await this.roleService.addUserRoleBasedOnSubscription(user, dto.newSubscriptionName)
invitation.subscriptionId = dto.newSubscriptionId
invitation.updatedAt = dto.timestamp
@@ -83,7 +88,7 @@ export class RenewSharedSubscriptions implements UseCaseInterface<void> {
return this.userSubscriptionRepository.save(subscription)
}
private async getInviteeUserUuid(inviteeIdentifier: string, inviteeIdentifierType: string): Promise<string | null> {
private async getInviteeUserUuid(inviteeIdentifier: string, inviteeIdentifierType: string): Promise<User | null> {
if (inviteeIdentifierType === InviteeIdentifierType.Email) {
const usernameOrError = Username.create(inviteeIdentifier)
if (usernameOrError.isFailed()) {
@@ -91,14 +96,16 @@ export class RenewSharedSubscriptions implements UseCaseInterface<void> {
}
const username = usernameOrError.getValue()
const user = await this.userRepository.findOneByUsernameOrEmail(username)
if (user === null) {
return this.userRepository.findOneByUsernameOrEmail(username)
} else if (inviteeIdentifierType === InviteeIdentifierType.Uuid) {
const uuidOrError = Uuid.create(inviteeIdentifier)
if (uuidOrError.isFailed()) {
return null
}
return user.uuid
const uuid = uuidOrError.getValue()
return this.userRepository.findOneByUuid(uuid)
}
return inviteeIdentifier
return null
}
}
@@ -26,6 +26,8 @@ export class LockMiddleware extends BaseMiddleware {
message: usernameOrError.getError(),
},
})
return
}
const username = usernameOrError.getValue()
@@ -1,3 +1,4 @@
import { SubscriptionPlanName } from '@standardnotes/domain-core'
import { TimerInterface } from '@standardnotes/time'
import { inject, injectable } from 'inversify'
import { Repository } from 'typeorm'
@@ -6,7 +7,6 @@ import TYPES from '../../Bootstrap/Types'
import { UserSubscription } from '../../Domain/Subscription/UserSubscription'
import { UserSubscriptionRepositoryInterface } from '../../Domain/Subscription/UserSubscriptionRepositoryInterface'
import { UserSubscriptionType } from '../../Domain/Subscription/UserSubscriptionType'
import { SubscriptionPlanName } from '@standardnotes/domain-core'
@injectable()
export class TypeORMUserSubscriptionRepository implements UserSubscriptionRepositoryInterface {
@@ -16,6 +16,15 @@ export class TypeORMUserSubscriptionRepository implements UserSubscriptionReposi
@inject(TYPES.Auth_Timer) private timer: TimerInterface,
) {}
async findActiveByType(type: UserSubscriptionType): Promise<UserSubscription[]> {
return await this.ormRepository
.createQueryBuilder()
.where('ends_at > :timestamp', { timestamp: this.timer.getTimestampInMicroseconds() })
.andWhere('subscription_type = :type', { type })
.orderBy('created_at', 'ASC')
.getMany()
}
async countByPlanName(planNames: SubscriptionPlanName[]): Promise<number> {
return 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.22.10](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.22.9...@standardnotes/domain-events-infra@1.22.10) (2023-12-29)
**Note:** Version bump only for package @standardnotes/domain-events-infra
## [1.22.9](https://github.com/standardnotes/server/compare/@standardnotes/domain-events-infra@1.22.8...@standardnotes/domain-events-infra@1.22.9) (2023-12-28)
**Note:** Version bump only for package @standardnotes/domain-events-infra
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events-infra",
"version": "1.22.9",
"version": "1.22.10",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+6
View File
@@ -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.139.3](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.139.2...@standardnotes/domain-events@2.139.3) (2023-12-29)
### Bug Fixes
* cleanup revision requests ([7e8d7f6](https://github.com/standardnotes/server/commit/7e8d7f6874bb1db55ee6feb9e128c684a6900189))
## [2.139.2](https://github.com/standardnotes/server/compare/@standardnotes/domain-events@2.139.1...@standardnotes/domain-events@2.139.2) (2023-12-28)
**Note:** Version bump only for package @standardnotes/domain-events
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/domain-events",
"version": "2.139.2",
"version": "2.139.3",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -1,7 +0,0 @@
import { DomainEventInterface } from './DomainEventInterface'
import { RevisionsCleanupRequestedEventPayload } from './RevisionsCleanupRequestedEventPayload'
export interface RevisionsCleanupRequestedEvent extends DomainEventInterface {
type: 'REVISIONS_CLEANUP_REQUESTED'
payload: RevisionsCleanupRequestedEventPayload
}
@@ -1,3 +0,0 @@
export interface RevisionsCleanupRequestedEventPayload {
userUuid: string
}
@@ -72,8 +72,6 @@ export * from './Event/PredicateVerifiedEvent'
export * from './Event/PredicateVerifiedEventPayload'
export * from './Event/RefundProcessedEvent'
export * from './Event/RefundProcessedEventPayload'
export * from './Event/RevisionsCleanupRequestedEvent'
export * from './Event/RevisionsCleanupRequestedEventPayload'
export * from './Event/RevisionsCopyRequestedEvent'
export * from './Event/RevisionsCopyRequestedEventPayload'
export * from './Event/SessionCreatedEvent'
+4
View File
@@ -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.37.5](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.4...@standardnotes/files-server@1.37.5) (2023-12-29)
**Note:** Version bump only for package @standardnotes/files-server
## [1.37.4](https://github.com/standardnotes/server/compare/@standardnotes/files-server@1.37.3...@standardnotes/files-server@1.37.4) (2023-12-28)
**Note:** Version bump only for package @standardnotes/files-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/files-server",
"version": "1.37.4",
"version": "1.37.5",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+16
View File
@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.34](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.33...@standardnotes/home-server@1.22.34) (2023-12-29)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.33](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.32...@standardnotes/home-server@1.22.33) (2023-12-29)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.32](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.31...@standardnotes/home-server@1.22.32) (2023-12-28)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.31](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.30...@standardnotes/home-server@1.22.31) (2023-12-28)
**Note:** Version bump only for package @standardnotes/home-server
## [1.22.30](https://github.com/standardnotes/server/compare/@standardnotes/home-server@1.22.29...@standardnotes/home-server@1.22.30) (2023-12-28)
**Note:** Version bump only for package @standardnotes/home-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/home-server",
"version": "1.22.30",
"version": "1.22.34",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+4
View File
@@ -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.51.11](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.10...@standardnotes/revisions-server@1.51.11) (2023-12-29)
**Note:** Version bump only for package @standardnotes/revisions-server
## [1.51.10](https://github.com/standardnotes/server/compare/@standardnotes/revisions-server@1.51.9...@standardnotes/revisions-server@1.51.10) (2023-12-28)
**Note:** Version bump only for package @standardnotes/revisions-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/revisions-server",
"version": "1.51.10",
"version": "1.51.11",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+4
View File
@@ -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.27.16](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.15...@standardnotes/scheduler-server@1.27.16) (2023-12-29)
**Note:** Version bump only for package @standardnotes/scheduler-server
## [1.27.15](https://github.com/standardnotes/server/compare/@standardnotes/scheduler-server@1.27.14...@standardnotes/scheduler-server@1.27.15) (2023-12-28)
**Note:** Version bump only for package @standardnotes/scheduler-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/scheduler-server",
"version": "1.27.15",
"version": "1.27.16",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
+6
View File
@@ -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.129.8](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.129.7...@standardnotes/syncing-server@1.129.8) (2023-12-29)
### Bug Fixes
* cleanup revision requests ([7e8d7f6](https://github.com/standardnotes/server/commit/7e8d7f6874bb1db55ee6feb9e128c684a6900189))
## [1.129.7](https://github.com/standardnotes/server/compare/@standardnotes/syncing-server@1.129.6...@standardnotes/syncing-server@1.129.7) (2023-12-28)
### Bug Fixes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/syncing-server",
"version": "1.129.7",
"version": "1.129.8",
"engines": {
"node": ">=18.0.0 <21.0.0"
},
@@ -162,7 +162,6 @@ import { SyncResponse } from '@standardnotes/grpc'
import { SyncResponseGRPCMapper } from '../Mapping/gRPC/SyncResponseGRPCMapper'
import { AccountDeletionVerificationRequestedEventHandler } from '../Domain/Handler/AccountDeletionVerificationRequestedEventHandler'
import { SendEventToClients } from '../Domain/UseCase/Syncing/SendEventToClients/SendEventToClients'
import { RevisionsCleanupRequestedEventHandler } from '../Domain/Handler/RevisionsCleanupRequestedEventHandler'
export class ContainerConfigLoader {
private readonly DEFAULT_CONTENT_SIZE_TRANSFER_LIMIT = 10_000_000
@@ -981,16 +980,6 @@ export class ContainerConfigLoader {
container.get<Logger>(TYPES.Sync_Logger),
),
)
container
.bind<RevisionsCleanupRequestedEventHandler>(TYPES.Sync_RevisionsCleanupRequestedEventHandler)
.toConstantValue(
new RevisionsCleanupRequestedEventHandler(
container.get<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository),
container.get<DomainEventFactoryInterface>(TYPES.Sync_DomainEventFactory),
container.get<DomainEventPublisherInterface>(TYPES.Sync_DomainEventPublisher),
container.get<Logger>(TYPES.Sync_Logger),
),
)
// Services
container.bind<ContentDecoderInterface>(TYPES.Sync_ContentDecoder).toDynamicValue(() => new ContentDecoder())
@@ -1019,7 +1008,6 @@ export class ContainerConfigLoader {
'SHARED_VAULT_REMOVED',
container.get<SharedVaultRemovedEventHandler>(TYPES.Sync_SharedVaultRemovedEventHandler),
],
['REVISIONS_CLEANUP_REQUESTED', container.get(TYPES.Sync_RevisionsCleanupRequestedEventHandler)],
])
if (!isConfiguredForHomeServer) {
container
@@ -97,7 +97,6 @@ const TYPES = {
Sync_SharedVaultFileUploadedEventHandler: Symbol.for('Sync_SharedVaultFileUploadedEventHandler'),
Sync_SharedVaultFileMovedEventHandler: Symbol.for('Sync_SharedVaultFileMovedEventHandler'),
Sync_SharedVaultRemovedEventHandler: Symbol.for('Sync_SharedVaultRemovedEventHandler'),
Sync_RevisionsCleanupRequestedEventHandler: Symbol.for('Sync_RevisionsCleanupRequestedEventHandler'),
// Services
Sync_ContentDecoder: Symbol.for('Sync_ContentDecoder'),
Sync_DomainEventPublisher: Symbol.for('Sync_DomainEventPublisher'),
@@ -1,56 +0,0 @@
import {
RevisionsCleanupRequestedEvent,
DomainEventHandlerInterface,
DomainEventPublisherInterface,
} from '@standardnotes/domain-events'
import { Logger } from 'winston'
import { ItemRepositoryInterface } from '../Item/ItemRepositoryInterface'
import { DomainEventFactoryInterface } from '../Event/DomainEventFactoryInterface'
export class RevisionsCleanupRequestedEventHandler implements DomainEventHandlerInterface {
constructor(
private itemRepository: ItemRepositoryInterface,
private domainEventFactory: DomainEventFactoryInterface,
private domainEventPublisher: DomainEventPublisherInterface,
private logger: Logger,
) {}
async handle(event: RevisionsCleanupRequestedEvent): Promise<void> {
const totalDeletedItems = await this.itemRepository.countAll({
userUuid: event.payload.userUuid,
deleted: true,
})
this.logger.info(`Found ${totalDeletedItems} deleted items`, {
userId: event.payload.userUuid,
})
const limitPerPage = 100
const numberOfPages = Math.ceil(totalDeletedItems / limitPerPage)
for (let i = 0; i < numberOfPages; i++) {
const items = await this.itemRepository.findAll({
userUuid: event.payload.userUuid,
deleted: true,
offset: i * limitPerPage,
limit: limitPerPage,
sortOrder: 'ASC',
sortBy: 'created_at_timestamp',
})
for (const item of items) {
await this.domainEventPublisher.publish(
this.domainEventFactory.createItemDeletedEvent({
itemUuid: item.id.toString(),
userUuid: item.props.userUuid.value,
}),
)
}
}
this.logger.info(`Finished processing ${totalDeletedItems} deleted items`, {
userId: event.payload.userUuid,
})
}
}
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.7](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.22.6...@standardnotes/websockets-server@1.22.7) (2023-12-29)
**Note:** Version bump only for package @standardnotes/websockets-server
## [1.22.6](https://github.com/standardnotes/server/compare/@standardnotes/websockets-server@1.22.5...@standardnotes/websockets-server@1.22.6) (2023-12-28)
**Note:** Version bump only for package @standardnotes/websockets-server
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/websockets-server",
"version": "1.22.6",
"version": "1.22.7",
"engines": {
"node": ">=18.0.0 <21.0.0"
},