mirror of
https://github.com/standardnotes/server
synced 2026-01-16 20:04:32 -05:00
feat: add removing revisions from shared vaults (#811)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import { DomainEventInterface } from './DomainEventInterface'
|
||||
import { ItemRemovedFromSharedVaultEventPayload } from './ItemRemovedFromSharedVaultEventPayload'
|
||||
|
||||
export interface ItemRemovedFromSharedVaultEvent extends DomainEventInterface {
|
||||
type: 'ITEM_REMOVED_FROM_SHARED_VAULT'
|
||||
payload: ItemRemovedFromSharedVaultEventPayload
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface ItemRemovedFromSharedVaultEventPayload {
|
||||
userUuid: string
|
||||
itemUuid: string
|
||||
sharedVaultUuid: string
|
||||
roleNames: string[]
|
||||
}
|
||||
@@ -32,6 +32,8 @@ export * from './Event/FileUploadedEvent'
|
||||
export * from './Event/FileUploadedEventPayload'
|
||||
export * from './Event/ItemDumpedEvent'
|
||||
export * from './Event/ItemDumpedEventPayload'
|
||||
export * from './Event/ItemRemovedFromSharedVaultEvent'
|
||||
export * from './Event/ItemRemovedFromSharedVaultEventPayload'
|
||||
export * from './Event/ItemRevisionCreationRequestedEvent'
|
||||
export * from './Event/ItemRevisionCreationRequestedEventPayload'
|
||||
export * from './Event/ListedAccountCreatedEvent'
|
||||
|
||||
@@ -66,6 +66,8 @@ import { SQLRevision } from '../Infra/TypeORM/SQL/SQLRevision'
|
||||
import { SQLRevisionRepository } from '../Infra/TypeORM/SQL/SQLRevisionRepository'
|
||||
import { SQLRevisionMetadataPersistenceMapper } from '../Mapping/Persistence/SQL/SQLRevisionMetadataPersistenceMapper'
|
||||
import { SQLRevisionPersistenceMapper } from '../Mapping/Persistence/SQL/SQLRevisionPersistenceMapper'
|
||||
import { RemoveRevisionsFromSharedVault } from '../Domain/UseCase/RemoveRevisionsFromSharedVault/RemoveRevisionsFromSharedVault'
|
||||
import { ItemRemovedFromSharedVaultEventHandler } from '../Domain/Handler/ItemRemovedFromSharedVaultEventHandler'
|
||||
|
||||
export class ContainerConfigLoader {
|
||||
async load(configuration?: {
|
||||
@@ -358,6 +360,13 @@ export class ContainerConfigLoader {
|
||||
container.get<DomainEventFactoryInterface>(TYPES.Revisions_DomainEventFactory),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<RemoveRevisionsFromSharedVault>(TYPES.Revisions_RemoveRevisionsFromSharedVault)
|
||||
.toConstantValue(
|
||||
new RemoveRevisionsFromSharedVault(
|
||||
container.get<RevisionRepositoryResolverInterface>(TYPES.Revisions_RevisionRepositoryResolver),
|
||||
),
|
||||
)
|
||||
|
||||
// env vars
|
||||
container.bind(TYPES.Revisions_AUTH_JWT_SECRET).toConstantValue(env.get('AUTH_JWT_SECRET'))
|
||||
@@ -437,12 +446,21 @@ export class ContainerConfigLoader {
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
container
|
||||
.bind<ItemRemovedFromSharedVaultEventHandler>(TYPES.Revisions_ItemRemovedFromSharedVaultEventHandler)
|
||||
.toConstantValue(
|
||||
new ItemRemovedFromSharedVaultEventHandler(
|
||||
container.get<RemoveRevisionsFromSharedVault>(TYPES.Revisions_RemoveRevisionsFromSharedVault),
|
||||
container.get<winston.Logger>(TYPES.Revisions_Logger),
|
||||
),
|
||||
)
|
||||
|
||||
const eventHandlers: Map<string, DomainEventHandlerInterface> = new Map([
|
||||
['ITEM_DUMPED', container.get(TYPES.Revisions_ItemDumpedEventHandler)],
|
||||
['ACCOUNT_DELETION_REQUESTED', container.get(TYPES.Revisions_AccountDeletionRequestedEventHandler)],
|
||||
['REVISIONS_COPY_REQUESTED', container.get(TYPES.Revisions_RevisionsCopyRequestedEventHandler)],
|
||||
['TRANSITION_STATUS_UPDATED', container.get(TYPES.Revisions_TransitionStatusUpdatedEventHandler)],
|
||||
['ITEM_REMOVED_FROM_SHARED_VAULT', container.get(TYPES.Revisions_ItemRemovedFromSharedVaultEventHandler)],
|
||||
])
|
||||
|
||||
if (isConfiguredForHomeServer) {
|
||||
|
||||
@@ -49,6 +49,7 @@ const TYPES = {
|
||||
Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser: Symbol.for(
|
||||
'Revisions_TriggerTransitionFromPrimaryToSecondaryDatabaseForUser',
|
||||
),
|
||||
Revisions_RemoveRevisionsFromSharedVault: Symbol.for('Revisions_RemoveRevisionsFromSharedVault'),
|
||||
// Controller
|
||||
Revisions_ControllerContainer: Symbol.for('Revisions_ControllerContainer'),
|
||||
Revisions_RevisionsController: Symbol.for('Revisions_RevisionsController'),
|
||||
@@ -58,6 +59,7 @@ const TYPES = {
|
||||
Revisions_AccountDeletionRequestedEventHandler: Symbol.for('Revisions_AccountDeletionRequestedEventHandler'),
|
||||
Revisions_RevisionsCopyRequestedEventHandler: Symbol.for('Revisions_RevisionsCopyRequestedEventHandler'),
|
||||
Revisions_TransitionStatusUpdatedEventHandler: Symbol.for('Revisions_TransitionStatusUpdatedEventHandler'),
|
||||
Revisions_ItemRemovedFromSharedVaultEventHandler: Symbol.for('Revisions_ItemRemovedFromSharedVaultEventHandler'),
|
||||
// Services
|
||||
Revisions_CrossServiceTokenDecoder: Symbol.for('Revisions_CrossServiceTokenDecoder'),
|
||||
Revisions_DomainEventSubscriberFactory: Symbol.for('Revisions_DomainEventSubscriberFactory'),
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { DomainEventHandlerInterface, ItemRemovedFromSharedVaultEvent } from '@standardnotes/domain-events'
|
||||
import { RemoveRevisionsFromSharedVault } from '../UseCase/RemoveRevisionsFromSharedVault/RemoveRevisionsFromSharedVault'
|
||||
import { Logger } from 'winston'
|
||||
|
||||
export class ItemRemovedFromSharedVaultEventHandler implements DomainEventHandlerInterface {
|
||||
constructor(
|
||||
private removeRevisionsFromSharedVault: RemoveRevisionsFromSharedVault,
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async handle(event: ItemRemovedFromSharedVaultEvent): Promise<void> {
|
||||
const result = await this.removeRevisionsFromSharedVault.execute({
|
||||
sharedVaultUuid: event.payload.sharedVaultUuid,
|
||||
itemUuid: event.payload.itemUuid,
|
||||
roleNames: event.payload.roleNames,
|
||||
})
|
||||
|
||||
if (result.isFailed()) {
|
||||
this.logger.error(`Failed to remove revisions from shared vault: ${result.getError()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,5 @@ export interface RevisionRepositoryInterface {
|
||||
updateUserUuid(itemUuid: Uuid, userUuid: Uuid): Promise<void>
|
||||
findByUserUuid(dto: { userUuid: Uuid; offset?: number; limit?: number }): Promise<Array<Revision>>
|
||||
insert(revision: Revision): Promise<boolean>
|
||||
clearSharedVaultAndKeySystemAssociations(itemUuid: Uuid, sharedVaultUuid: Uuid): Promise<void>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { RevisionRepositoryInterface } from '../../Revision/RevisionRepositoryInterface'
|
||||
import { RevisionRepositoryResolverInterface } from '../../Revision/RevisionRepositoryResolverInterface'
|
||||
import { RemoveRevisionsFromSharedVault } from './RemoveRevisionsFromSharedVault'
|
||||
|
||||
describe('RemoveRevisionsFromSharedVault', () => {
|
||||
let revisionRepositoryResolver: RevisionRepositoryResolverInterface
|
||||
let revisionRepository: RevisionRepositoryInterface
|
||||
|
||||
const createUseCase = () => new RemoveRevisionsFromSharedVault(revisionRepositoryResolver)
|
||||
|
||||
beforeEach(() => {
|
||||
revisionRepository = {} as jest.Mocked<RevisionRepositoryInterface>
|
||||
revisionRepository.clearSharedVaultAndKeySystemAssociations = jest.fn()
|
||||
|
||||
revisionRepositoryResolver = {} as jest.Mocked<RevisionRepositoryResolverInterface>
|
||||
revisionRepositoryResolver.resolve = jest.fn().mockReturnValue(revisionRepository)
|
||||
})
|
||||
|
||||
it('should clear shared vault and key system associations', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
await useCase.execute({
|
||||
itemUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000001',
|
||||
roleNames: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(revisionRepository.clearSharedVaultAndKeySystemAssociations).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return error when shared vault uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
itemUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: 'invalid',
|
||||
roleNames: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
|
||||
it('should return error when item uuid is invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
itemUuid: 'invalid',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000001',
|
||||
roleNames: ['CORE_USER'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
|
||||
it('should return error when role names are invalid', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
const result = await useCase.execute({
|
||||
itemUuid: '00000000-0000-0000-0000-000000000000',
|
||||
sharedVaultUuid: '00000000-0000-0000-0000-000000000001',
|
||||
roleNames: ['invalid'],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Result, RoleNameCollection, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
|
||||
import { RevisionRepositoryResolverInterface } from '../../Revision/RevisionRepositoryResolverInterface'
|
||||
import { RemoveRevisionsFromSharedVaultDTO } from './RemoveRevisionsFromSharedVaultDTO'
|
||||
|
||||
export class RemoveRevisionsFromSharedVault implements UseCaseInterface<void> {
|
||||
constructor(private revisionRepositoryResolver: RevisionRepositoryResolverInterface) {}
|
||||
|
||||
async execute(dto: RemoveRevisionsFromSharedVaultDTO): Promise<Result<void>> {
|
||||
const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
|
||||
if (sharedVaultUuidOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultUuidOrError.getError())
|
||||
}
|
||||
const sharedVaultUuid = sharedVaultUuidOrError.getValue()
|
||||
|
||||
const itemUuidOrError = Uuid.create(dto.itemUuid)
|
||||
if (itemUuidOrError.isFailed()) {
|
||||
return Result.fail(itemUuidOrError.getError())
|
||||
}
|
||||
const itemUuid = itemUuidOrError.getValue()
|
||||
|
||||
const roleNamesOrError = RoleNameCollection.create(dto.roleNames)
|
||||
if (roleNamesOrError.isFailed()) {
|
||||
return Result.fail(roleNamesOrError.getError())
|
||||
}
|
||||
const roleNames = roleNamesOrError.getValue()
|
||||
|
||||
const revisionRepository = this.revisionRepositoryResolver.resolve(roleNames)
|
||||
|
||||
await revisionRepository.clearSharedVaultAndKeySystemAssociations(itemUuid, sharedVaultUuid)
|
||||
|
||||
return Result.ok()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface RemoveRevisionsFromSharedVaultDTO {
|
||||
itemUuid: string
|
||||
sharedVaultUuid: string
|
||||
roleNames: string[]
|
||||
}
|
||||
@@ -16,6 +16,21 @@ export class MongoDBRevisionRepository implements RevisionRepositoryInterface {
|
||||
private logger: Logger,
|
||||
) {}
|
||||
|
||||
async clearSharedVaultAndKeySystemAssociations(itemUuid: Uuid, sharedVaultUuid: Uuid): Promise<void> {
|
||||
await this.mongoRepository.updateMany(
|
||||
{
|
||||
itemUuid: { $eq: itemUuid.value },
|
||||
sharedVaultUuid: { $eq: sharedVaultUuid.value },
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
sharedVaultUuid: null,
|
||||
keySystemIdentifier: null,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
async countByUserUuid(userUuid: Uuid): Promise<number> {
|
||||
return this.mongoRepository.count({ userUuid: { $eq: userUuid.value } })
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ export class SQLLegacyRevisionRepository implements RevisionRepositoryInterface
|
||||
protected logger: Logger,
|
||||
) {}
|
||||
|
||||
async clearSharedVaultAndKeySystemAssociations(_itemUuid: Uuid, _sharedVaultUuid: Uuid): Promise<void> {
|
||||
this.logger.error('Method clearSharedVaultAndKeySystemAssociations not implemented.')
|
||||
}
|
||||
|
||||
async countByUserUuid(userUuid: Uuid): Promise<number> {
|
||||
return this.ormRepository
|
||||
.createQueryBuilder()
|
||||
|
||||
@@ -45,6 +45,21 @@ export class SQLRevisionRepository extends SQLLegacyRevisionRepository {
|
||||
return this.revisionMapper.toDomain(sqlRevision)
|
||||
}
|
||||
|
||||
override async clearSharedVaultAndKeySystemAssociations(itemUuid: Uuid, sharedVaultUuid: Uuid): Promise<void> {
|
||||
await this.ormRepository
|
||||
.createQueryBuilder()
|
||||
.update()
|
||||
.set({
|
||||
sharedVaultUuid: null,
|
||||
keySystemIdentifier: null,
|
||||
})
|
||||
.where('item_uuid = :itemUuid AND shared_vault_uuid = :sharedVaultUuid', {
|
||||
itemUuid: itemUuid.value,
|
||||
sharedVaultUuid: sharedVaultUuid.value,
|
||||
})
|
||||
.execute()
|
||||
}
|
||||
|
||||
override async findMetadataByItemId(
|
||||
itemUuid: Uuid,
|
||||
userUuid: Uuid,
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
DuplicateItemSyncedEvent,
|
||||
EmailRequestedEvent,
|
||||
ItemDumpedEvent,
|
||||
ItemRemovedFromSharedVaultEvent,
|
||||
ItemRevisionCreationRequestedEvent,
|
||||
MessageSentToUserEvent,
|
||||
NotificationAddedForUserEvent,
|
||||
@@ -20,6 +21,26 @@ import { DomainEventFactoryInterface } from './DomainEventFactoryInterface'
|
||||
export class DomainEventFactory implements DomainEventFactoryInterface {
|
||||
constructor(private timer: TimerInterface) {}
|
||||
|
||||
createItemRemovedFromSharedVaultEvent(dto: {
|
||||
sharedVaultUuid: string
|
||||
itemUuid: string
|
||||
userUuid: string
|
||||
roleNames: string[]
|
||||
}): ItemRemovedFromSharedVaultEvent {
|
||||
return {
|
||||
type: 'ITEM_REMOVED_FROM_SHARED_VAULT',
|
||||
createdAt: this.timer.getUTCDate(),
|
||||
meta: {
|
||||
correlation: {
|
||||
userIdentifier: dto.userUuid,
|
||||
userIdentifierType: 'uuid',
|
||||
},
|
||||
origin: DomainEventService.SyncingServer,
|
||||
},
|
||||
payload: dto,
|
||||
}
|
||||
}
|
||||
|
||||
createUserRemovedFromSharedVaultEvent(dto: {
|
||||
sharedVaultUuid: string
|
||||
userUuid: string
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
DuplicateItemSyncedEvent,
|
||||
EmailRequestedEvent,
|
||||
ItemDumpedEvent,
|
||||
ItemRemovedFromSharedVaultEvent,
|
||||
ItemRevisionCreationRequestedEvent,
|
||||
MessageSentToUserEvent,
|
||||
NotificationAddedForUserEvent,
|
||||
@@ -93,4 +94,10 @@ export interface DomainEventFactoryInterface {
|
||||
sharedVaultUuid: string
|
||||
userUuid: string
|
||||
}): UserRemovedFromSharedVaultEvent
|
||||
createItemRemovedFromSharedVaultEvent(dto: {
|
||||
sharedVaultUuid: string
|
||||
itemUuid: string
|
||||
userUuid: string
|
||||
roleNames: string[]
|
||||
}): ItemRemovedFromSharedVaultEvent
|
||||
}
|
||||
|
||||
@@ -111,6 +111,9 @@ describe('UpdateExistingItem', () => {
|
||||
domainEventFactory.createItemRevisionCreationRequested = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<DomainEventInterface>)
|
||||
domainEventFactory.createItemRemovedFromSharedVaultEvent = jest
|
||||
.fn()
|
||||
.mockReturnValue({} as jest.Mocked<DomainEventInterface>)
|
||||
|
||||
determineSharedVaultOperationOnItem = {} as jest.Mocked<DetermineSharedVaultOperationOnItem>
|
||||
determineSharedVaultOperationOnItem.execute = jest.fn().mockResolvedValue(
|
||||
@@ -400,6 +403,47 @@ describe('UpdateExistingItem', () => {
|
||||
expect(item1.props.sharedVaultAssociation).not.toBeUndefined()
|
||||
})
|
||||
|
||||
it('should remove a shared vault association and publish an event that item has been removed from shared vault', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
item1.props.sharedVaultAssociation = SharedVaultAssociation.create({
|
||||
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
lastEditedBy: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
}).getValue()
|
||||
|
||||
const itemHash = ItemHash.create({
|
||||
...itemHash1.props,
|
||||
shared_vault_uuid: null,
|
||||
}).getValue()
|
||||
|
||||
determineSharedVaultOperationOnItem.execute = jest.fn().mockReturnValue(
|
||||
Result.ok(
|
||||
SharedVaultOperationOnItem.create({
|
||||
existingItem: item1,
|
||||
incomingItemHash: itemHash1,
|
||||
sharedVaultUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
type: SharedVaultOperationOnItem.TYPES.RemoveFromSharedVault,
|
||||
userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
|
||||
}).getValue(),
|
||||
),
|
||||
)
|
||||
|
||||
const result = await useCase.execute({
|
||||
existingItem: item1,
|
||||
itemHash,
|
||||
sessionUuid: '00000000-0000-0000-0000-000000000000',
|
||||
performingUserUuid: '00000000-0000-0000-0000-000000000000',
|
||||
roleNames: [RoleName.NAMES.CoreUser],
|
||||
})
|
||||
|
||||
expect(result.isFailed()).toBeFalsy()
|
||||
|
||||
expect(item1.props.sharedVaultAssociation).toBeUndefined()
|
||||
|
||||
expect(domainEventFactory.createItemRemovedFromSharedVaultEvent).toHaveBeenCalled()
|
||||
expect(domainEventPublisher.publish).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should return error if shared vault association could not be created', async () => {
|
||||
const useCase = createUseCase()
|
||||
|
||||
|
||||
@@ -37,16 +37,6 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
) {}
|
||||
|
||||
async execute(dto: UpdateExistingItemDTO): Promise<Result<Item>> {
|
||||
let sessionUuid = null
|
||||
if (dto.sessionUuid) {
|
||||
const sessionUuidOrError = Uuid.create(dto.sessionUuid)
|
||||
if (sessionUuidOrError.isFailed()) {
|
||||
return Result.fail(sessionUuidOrError.getError())
|
||||
}
|
||||
sessionUuid = sessionUuidOrError.getValue()
|
||||
}
|
||||
dto.existingItem.props.updatedWithSession = sessionUuid
|
||||
|
||||
const userUuidOrError = Uuid.create(dto.performingUserUuid)
|
||||
if (userUuidOrError.isFailed()) {
|
||||
return Result.fail(userUuidOrError.getError())
|
||||
@@ -59,6 +49,29 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
}
|
||||
const roleNames = roleNamesOrError.getValue()
|
||||
|
||||
let sharedVaultOperation: SharedVaultOperationOnItem | null = null
|
||||
if (dto.itemHash.representsASharedVaultItem() || dto.existingItem.isAssociatedWithASharedVault()) {
|
||||
const sharedVaultOperationOrError = await this.determineSharedVaultOperationOnItem.execute({
|
||||
existingItem: dto.existingItem,
|
||||
itemHash: dto.itemHash,
|
||||
userUuid: userUuid.value,
|
||||
})
|
||||
if (sharedVaultOperationOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultOperationOrError.getError())
|
||||
}
|
||||
sharedVaultOperation = sharedVaultOperationOrError.getValue()
|
||||
}
|
||||
|
||||
let sessionUuid = null
|
||||
if (dto.sessionUuid) {
|
||||
const sessionUuidOrError = Uuid.create(dto.sessionUuid)
|
||||
if (sessionUuidOrError.isFailed()) {
|
||||
return Result.fail(sessionUuidOrError.getError())
|
||||
}
|
||||
sessionUuid = sessionUuidOrError.getValue()
|
||||
}
|
||||
dto.existingItem.props.updatedWithSession = sessionUuid
|
||||
|
||||
if (dto.itemHash.props.content) {
|
||||
dto.existingItem.props.content = dto.itemHash.props.content
|
||||
}
|
||||
@@ -128,7 +141,6 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
|
||||
dto.existingItem.props.contentSize = Buffer.byteLength(JSON.stringify(dto.existingItem))
|
||||
|
||||
let sharedVaultOperation: SharedVaultOperationOnItem | null = null
|
||||
if (dto.itemHash.representsASharedVaultItem()) {
|
||||
const sharedVaultAssociationOrError = SharedVaultAssociation.create({
|
||||
lastEditedBy: userUuid,
|
||||
@@ -140,16 +152,6 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
}
|
||||
|
||||
dto.existingItem.props.sharedVaultAssociation = sharedVaultAssociationOrError.getValue()
|
||||
|
||||
const sharedVaultOperationOrError = await this.determineSharedVaultOperationOnItem.execute({
|
||||
existingItem: dto.existingItem,
|
||||
itemHash: dto.itemHash,
|
||||
userUuid: userUuid.value,
|
||||
})
|
||||
if (sharedVaultOperationOrError.isFailed()) {
|
||||
return Result.fail(sharedVaultOperationOrError.getError())
|
||||
}
|
||||
sharedVaultOperation = sharedVaultOperationOrError.getValue()
|
||||
} else {
|
||||
dto.existingItem.props.sharedVaultAssociation = undefined
|
||||
}
|
||||
@@ -209,7 +211,7 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
)
|
||||
}
|
||||
|
||||
const notificationsResult = await this.addNotifications(dto.existingItem.uuid, userUuid, sharedVaultOperation)
|
||||
const notificationsResult = await this.addNotificationsAndPublishEvents(userUuid, sharedVaultOperation, dto)
|
||||
if (notificationsResult.isFailed()) {
|
||||
return Result.fail(notificationsResult.getError())
|
||||
}
|
||||
@@ -217,10 +219,10 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
return Result.ok(dto.existingItem)
|
||||
}
|
||||
|
||||
private async addNotifications(
|
||||
itemUuid: Uuid,
|
||||
private async addNotificationsAndPublishEvents(
|
||||
userUuid: Uuid,
|
||||
sharedVaultOperation: SharedVaultOperationOnItem | null,
|
||||
dto: UpdateExistingItemDTO,
|
||||
): Promise<Result<void>> {
|
||||
if (
|
||||
sharedVaultOperation &&
|
||||
@@ -229,7 +231,7 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
const notificationPayloadOrError = NotificationPayload.create({
|
||||
sharedVaultUuid: sharedVaultOperation.props.sharedVaultUuid,
|
||||
type: NotificationType.create(NotificationType.TYPES.SharedVaultItemRemoved).getValue(),
|
||||
itemUuid: itemUuid,
|
||||
itemUuid: dto.existingItem.uuid,
|
||||
version: '1.0',
|
||||
})
|
||||
if (notificationPayloadOrError.isFailed()) {
|
||||
@@ -246,6 +248,15 @@ export class UpdateExistingItem implements UseCaseInterface<Item> {
|
||||
if (result.isFailed()) {
|
||||
return Result.fail(result.getError())
|
||||
}
|
||||
|
||||
await this.domainEventPublisher.publish(
|
||||
this.domainEventFactory.createItemRemovedFromSharedVaultEvent({
|
||||
sharedVaultUuid: sharedVaultOperation.props.sharedVaultUuid.value,
|
||||
itemUuid: dto.existingItem.uuid.value,
|
||||
userUuid: userUuid.value,
|
||||
roleNames: dto.roleNames,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (sharedVaultOperation && sharedVaultOperation.props.type === SharedVaultOperationOnItem.TYPES.AddToSharedVault) {
|
||||
|
||||
@@ -155,15 +155,23 @@ export class MongoDBItemRepository implements ItemRepositoryInterface {
|
||||
|
||||
async markItemsAsDeleted(itemUuids: string[], updatedAtTimestamp: number): Promise<void> {
|
||||
await this.mongoRepository.updateMany(
|
||||
{ where: { _id: { $in: itemUuids.map((uuid) => BSON.UUID.createFromHexString(uuid)) } } },
|
||||
{ deleted: true, content: null, encItemKey: null, authHash: null, updatedAtTimestamp },
|
||||
{ _id: { $in: itemUuids.map((uuid) => BSON.UUID.createFromHexString(uuid)) } },
|
||||
{
|
||||
$set: {
|
||||
deleted: true,
|
||||
content: null,
|
||||
encItemKey: null,
|
||||
authHash: null,
|
||||
updatedAtTimestamp,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
async updateContentSize(itemUuid: string, contentSize: number): Promise<void> {
|
||||
await this.mongoRepository.updateOne(
|
||||
{ where: { _id: { $eq: BSON.UUID.createFromHexString(itemUuid) } } },
|
||||
{ contentSize },
|
||||
{ _id: { $eq: BSON.UUID.createFromHexString(itemUuid) } },
|
||||
{ $set: { contentSize } },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user