InviteUserToSharedVault.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { Result, SharedVaultUserPermission, Timestamps, UseCaseInterface, Uuid } from '@standardnotes/domain-core'
  2. import { TimerInterface } from '@standardnotes/time'
  3. import { SharedVaultInvite } from '../../../SharedVault/User/Invite/SharedVaultInvite'
  4. import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
  5. import { InviteUserToSharedVaultDTO } from './InviteUserToSharedVaultDTO'
  6. import { SharedVaultInviteRepositoryInterface } from '../../../SharedVault/User/Invite/SharedVaultInviteRepositoryInterface'
  7. import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
  8. import { Logger } from 'winston'
  9. import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
  10. import { SendEventToClient } from '../../Syncing/SendEventToClient/SendEventToClient'
  11. import { DomainEventPublisherInterface } from '@standardnotes/domain-events'
  12. export class InviteUserToSharedVault implements UseCaseInterface<SharedVaultInvite> {
  13. constructor(
  14. private sharedVaultRepository: SharedVaultRepositoryInterface,
  15. private sharedVaultInviteRepository: SharedVaultInviteRepositoryInterface,
  16. private sharedVaultUserRepository: SharedVaultUserRepositoryInterface,
  17. private timer: TimerInterface,
  18. private domainEventFactory: DomainEventFactoryInterface,
  19. private domainEventPublisher: DomainEventPublisherInterface,
  20. private sendEventToClientUseCase: SendEventToClient,
  21. private logger: Logger,
  22. ) {}
  23. async execute(dto: InviteUserToSharedVaultDTO): Promise<Result<SharedVaultInvite>> {
  24. const sharedVaultUuidOrError = Uuid.create(dto.sharedVaultUuid)
  25. if (sharedVaultUuidOrError.isFailed()) {
  26. return Result.fail(sharedVaultUuidOrError.getError())
  27. }
  28. const sharedVaultUuid = sharedVaultUuidOrError.getValue()
  29. const senderUuidOrError = Uuid.create(dto.senderUuid)
  30. if (senderUuidOrError.isFailed()) {
  31. return Result.fail(senderUuidOrError.getError())
  32. }
  33. const senderUuid = senderUuidOrError.getValue()
  34. const recipientUuidOrError = Uuid.create(dto.recipientUuid)
  35. if (recipientUuidOrError.isFailed()) {
  36. return Result.fail(recipientUuidOrError.getError())
  37. }
  38. const recipientUuid = recipientUuidOrError.getValue()
  39. const permissionOrError = SharedVaultUserPermission.create(dto.permission)
  40. if (permissionOrError.isFailed()) {
  41. return Result.fail(permissionOrError.getError())
  42. }
  43. const permission = permissionOrError.getValue()
  44. const sharedVault = await this.sharedVaultRepository.findByUuid(sharedVaultUuid)
  45. if (!sharedVault) {
  46. return Result.fail('Attempting to invite a user to a non-existent shared vault')
  47. }
  48. if (sharedVault.props.userUuid.value !== senderUuid.value) {
  49. return Result.fail('Only the owner of a shared vault can invite users to it')
  50. }
  51. const alreadyExistingMember = await this.sharedVaultUserRepository.findByUserUuidAndSharedVaultUuid({
  52. userUuid: recipientUuid,
  53. sharedVaultUuid,
  54. })
  55. if (alreadyExistingMember) {
  56. return Result.fail('User is already a member of this shared vault')
  57. }
  58. const existingInvite = await this.sharedVaultInviteRepository.findByUserUuidAndSharedVaultUuid({
  59. userUuid: recipientUuid,
  60. sharedVaultUuid,
  61. })
  62. if (existingInvite) {
  63. await this.sharedVaultInviteRepository.remove(existingInvite)
  64. }
  65. const sharedVaultInviteOrError = SharedVaultInvite.create({
  66. encryptedMessage: dto.encryptedMessage,
  67. userUuid: recipientUuid,
  68. sharedVaultUuid,
  69. senderUuid,
  70. permission,
  71. timestamps: Timestamps.create(
  72. this.timer.getTimestampInMicroseconds(),
  73. this.timer.getTimestampInMicroseconds(),
  74. ).getValue(),
  75. })
  76. if (sharedVaultInviteOrError.isFailed()) {
  77. return Result.fail(sharedVaultInviteOrError.getError())
  78. }
  79. const sharedVaultInvite = sharedVaultInviteOrError.getValue()
  80. await this.sharedVaultInviteRepository.save(sharedVaultInvite)
  81. const event = this.domainEventFactory.createUserInvitedToSharedVaultEvent({
  82. invite: {
  83. uuid: sharedVaultInvite.id.toString(),
  84. shared_vault_uuid: sharedVaultInvite.props.sharedVaultUuid.value,
  85. user_uuid: sharedVaultInvite.props.userUuid.value,
  86. sender_uuid: sharedVaultInvite.props.senderUuid.value,
  87. encrypted_message: sharedVaultInvite.props.encryptedMessage,
  88. permission: sharedVaultInvite.props.permission.value,
  89. created_at_timestamp: sharedVaultInvite.props.timestamps.createdAt,
  90. updated_at_timestamp: sharedVaultInvite.props.timestamps.updatedAt,
  91. },
  92. })
  93. await this.domainEventPublisher.publish(event)
  94. const result = await this.sendEventToClientUseCase.execute({
  95. userUuid: sharedVaultInvite.props.userUuid.value,
  96. event,
  97. })
  98. if (result.isFailed()) {
  99. this.logger.error(
  100. `Failed to send user invited to shared vault event to client for user ${
  101. sharedVaultInvite.props.userUuid.value
  102. }: ${result.getError()}`,
  103. )
  104. }
  105. return Result.ok(sharedVaultInvite)
  106. }
  107. }