ownership.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import express from 'express'
  2. import { HttpStatusCode, VideoChangeOwnershipStatus, VideoState } from '@peertube/peertube-models'
  3. import { MVideoFullLight } from '@server/types/models/index.js'
  4. import { logger } from '../../../helpers/logger.js'
  5. import { getFormattedObjects } from '../../../helpers/utils.js'
  6. import { sequelizeTypescript } from '../../../initializers/database.js'
  7. import { sendUpdateVideo } from '../../../lib/activitypub/send/index.js'
  8. import { changeVideoChannelShare } from '../../../lib/activitypub/share.js'
  9. import {
  10. asyncMiddleware,
  11. asyncRetryTransactionMiddleware,
  12. authenticate,
  13. paginationValidator,
  14. setDefaultPagination,
  15. videosAcceptChangeOwnershipValidator,
  16. videosChangeOwnershipValidator,
  17. videosTerminateChangeOwnershipValidator
  18. } from '../../../middlewares/index.js'
  19. import { VideoChangeOwnershipModel } from '../../../models/video/video-change-ownership.js'
  20. import { VideoChannelModel } from '../../../models/video/video-channel.js'
  21. import { VideoModel } from '../../../models/video/video.js'
  22. const ownershipVideoRouter = express.Router()
  23. ownershipVideoRouter.post('/:videoId/give-ownership',
  24. authenticate,
  25. asyncMiddleware(videosChangeOwnershipValidator),
  26. asyncRetryTransactionMiddleware(giveVideoOwnership)
  27. )
  28. ownershipVideoRouter.get('/ownership',
  29. authenticate,
  30. paginationValidator,
  31. setDefaultPagination,
  32. asyncRetryTransactionMiddleware(listVideoOwnership)
  33. )
  34. ownershipVideoRouter.post('/ownership/:id/accept',
  35. authenticate,
  36. asyncMiddleware(videosTerminateChangeOwnershipValidator),
  37. asyncMiddleware(videosAcceptChangeOwnershipValidator),
  38. asyncRetryTransactionMiddleware(acceptOwnership)
  39. )
  40. ownershipVideoRouter.post('/ownership/:id/refuse',
  41. authenticate,
  42. asyncMiddleware(videosTerminateChangeOwnershipValidator),
  43. asyncRetryTransactionMiddleware(refuseOwnership)
  44. )
  45. // ---------------------------------------------------------------------------
  46. export {
  47. ownershipVideoRouter
  48. }
  49. // ---------------------------------------------------------------------------
  50. async function giveVideoOwnership (req: express.Request, res: express.Response) {
  51. const videoInstance = res.locals.videoAll
  52. const initiatorAccountId = res.locals.oauth.token.User.Account.id
  53. const nextOwner = res.locals.nextOwner
  54. await sequelizeTypescript.transaction(t => {
  55. return VideoChangeOwnershipModel.findOrCreate({
  56. where: {
  57. initiatorAccountId,
  58. nextOwnerAccountId: nextOwner.id,
  59. videoId: videoInstance.id,
  60. status: VideoChangeOwnershipStatus.WAITING
  61. },
  62. defaults: {
  63. initiatorAccountId,
  64. nextOwnerAccountId: nextOwner.id,
  65. videoId: videoInstance.id,
  66. status: VideoChangeOwnershipStatus.WAITING
  67. },
  68. transaction: t
  69. })
  70. })
  71. logger.info('Ownership change for video %s created.', videoInstance.name)
  72. return res.type('json')
  73. .status(HttpStatusCode.NO_CONTENT_204)
  74. .end()
  75. }
  76. async function listVideoOwnership (req: express.Request, res: express.Response) {
  77. const currentAccountId = res.locals.oauth.token.User.Account.id
  78. const resultList = await VideoChangeOwnershipModel.listForApi(
  79. currentAccountId,
  80. req.query.start || 0,
  81. req.query.count || 10,
  82. req.query.sort || 'createdAt'
  83. )
  84. return res.json(getFormattedObjects(resultList.data, resultList.total))
  85. }
  86. function acceptOwnership (req: express.Request, res: express.Response) {
  87. return sequelizeTypescript.transaction(async t => {
  88. const videoChangeOwnership = res.locals.videoChangeOwnership
  89. const channel = res.locals.videoChannel
  90. // We need more attributes for federation
  91. const targetVideo = await VideoModel.loadFull(videoChangeOwnership.Video.id, t)
  92. const oldVideoChannel = await VideoChannelModel.loadAndPopulateAccount(targetVideo.channelId, t)
  93. targetVideo.channelId = channel.id
  94. const targetVideoUpdated = await targetVideo.save({ transaction: t }) as MVideoFullLight
  95. targetVideoUpdated.VideoChannel = channel
  96. if (targetVideoUpdated.hasPrivacyForFederation() && targetVideoUpdated.state === VideoState.PUBLISHED) {
  97. await changeVideoChannelShare(targetVideoUpdated, oldVideoChannel, t)
  98. await sendUpdateVideo(targetVideoUpdated, t, oldVideoChannel.Account.Actor)
  99. }
  100. videoChangeOwnership.status = VideoChangeOwnershipStatus.ACCEPTED
  101. await videoChangeOwnership.save({ transaction: t })
  102. return res.status(HttpStatusCode.NO_CONTENT_204).end()
  103. })
  104. }
  105. function refuseOwnership (req: express.Request, res: express.Response) {
  106. return sequelizeTypescript.transaction(async t => {
  107. const videoChangeOwnership = res.locals.videoChangeOwnership
  108. videoChangeOwnership.status = VideoChangeOwnershipStatus.REFUSED
  109. await videoChangeOwnership.save({ transaction: t })
  110. return res.status(HttpStatusCode.NO_CONTENT_204).end()
  111. })
  112. }