BaseItemsController.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { ControllerContainerInterface, MapperInterface, Validator } from '@standardnotes/domain-core'
  2. import { BaseHttpController, results } from 'inversify-express-utils'
  3. import { Request, Response } from 'express'
  4. import { HttpStatusCode } from '@standardnotes/responses'
  5. import { Role } from '@standardnotes/security'
  6. import { Item } from '../../../Domain/Item/Item'
  7. import { SyncResponseFactoryResolverInterface } from '../../../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface'
  8. import { CheckIntegrity } from '../../../Domain/UseCase/Syncing/CheckIntegrity/CheckIntegrity'
  9. import { GetItem } from '../../../Domain/UseCase/Syncing/GetItem/GetItem'
  10. import { ApiVersion } from '../../../Domain/Api/ApiVersion'
  11. import { SyncItems } from '../../../Domain/UseCase/Syncing/SyncItems/SyncItems'
  12. import { ItemHttpRepresentation } from '../../../Mapping/Http/ItemHttpRepresentation'
  13. import { ItemHash } from '../../../Domain/Item/ItemHash'
  14. export class BaseItemsController extends BaseHttpController {
  15. constructor(
  16. protected syncItems: SyncItems,
  17. protected checkIntegrity: CheckIntegrity,
  18. protected getItem: GetItem,
  19. protected itemHttpMapper: MapperInterface<Item, ItemHttpRepresentation>,
  20. protected syncResponseFactoryResolver: SyncResponseFactoryResolverInterface,
  21. private controllerContainer?: ControllerContainerInterface,
  22. ) {
  23. super()
  24. if (this.controllerContainer !== undefined) {
  25. this.controllerContainer.register('sync.items.sync', this.sync.bind(this))
  26. this.controllerContainer.register('sync.items.check_integrity', this.checkItemsIntegrity.bind(this))
  27. this.controllerContainer.register('sync.items.get_item', this.getSingleItem.bind(this))
  28. }
  29. }
  30. async sync(request: Request, response: Response): Promise<results.JsonResult> {
  31. const itemHashes: ItemHash[] = []
  32. if ('items' in request.body) {
  33. for (const itemHashInput of request.body.items) {
  34. const itemHashOrError = ItemHash.create({
  35. ...itemHashInput,
  36. user_uuid: response.locals.user.uuid,
  37. key_system_identifier: itemHashInput.key_system_identifier ?? null,
  38. shared_vault_uuid: itemHashInput.shared_vault_uuid ?? null,
  39. })
  40. if (itemHashOrError.isFailed()) {
  41. return this.json({ error: { message: itemHashOrError.getError() } }, HttpStatusCode.BadRequest)
  42. }
  43. itemHashes.push(itemHashOrError.getValue())
  44. }
  45. }
  46. let sharedVaultUuids: string[] | undefined = undefined
  47. if ('shared_vault_uuids' in request.body) {
  48. const sharedVaultUuidsValidation = Validator.isNotEmpty(request.body.shared_vault_uuids)
  49. if (!sharedVaultUuidsValidation.isFailed()) {
  50. sharedVaultUuids = request.body.shared_vault_uuids
  51. }
  52. }
  53. const syncResult = await this.syncItems.execute({
  54. userUuid: response.locals.user.uuid,
  55. roleNames: response.locals.roles.map((role: Role) => role.name),
  56. itemHashes,
  57. computeIntegrityHash: request.body.compute_integrity === true,
  58. syncToken: request.body.sync_token,
  59. cursorToken: request.body.cursor_token,
  60. limit: request.body.limit,
  61. contentType: request.body.content_type,
  62. apiVersion: request.body.api ?? ApiVersion.v20161215,
  63. snjsVersion: <string>request.headers['x-snjs-version'],
  64. readOnlyAccess: response.locals.readOnlyAccess,
  65. sessionUuid: response.locals.session ? response.locals.session.uuid : null,
  66. sharedVaultUuids,
  67. })
  68. if (syncResult.isFailed()) {
  69. return this.json({ error: { message: syncResult.getError() } }, HttpStatusCode.BadRequest)
  70. }
  71. const syncResponse = await this.syncResponseFactoryResolver
  72. .resolveSyncResponseFactoryVersion(request.body.api)
  73. .createResponse(syncResult.getValue())
  74. return this.json(syncResponse)
  75. }
  76. async checkItemsIntegrity(request: Request, response: Response): Promise<results.JsonResult> {
  77. let integrityPayloads = []
  78. if ('integrityPayloads' in request.body) {
  79. integrityPayloads = request.body.integrityPayloads
  80. }
  81. const result = await this.checkIntegrity.execute({
  82. userUuid: response.locals.user.uuid,
  83. integrityPayloads,
  84. roleNames: response.locals.roles.map((role: Role) => role.name),
  85. })
  86. if (result.isFailed()) {
  87. return this.json({ error: { message: result.getError() } }, HttpStatusCode.BadRequest)
  88. }
  89. return this.json({
  90. mismatches: result.getValue(),
  91. })
  92. }
  93. async getSingleItem(request: Request, response: Response): Promise<results.JsonResult> {
  94. const result = await this.getItem.execute({
  95. userUuid: response.locals.user.uuid,
  96. itemUuid: request.params.uuid,
  97. roleNames: response.locals.roles.map((role: Role) => role.name),
  98. })
  99. if (result.isFailed()) {
  100. return this.json(
  101. {
  102. error: { message: 'Item not found' },
  103. },
  104. 404,
  105. )
  106. }
  107. return this.json({ item: this.itemHttpMapper.toProjection(result.getValue()) })
  108. }
  109. }