0100-activitypub.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import * as Sequelize from 'sequelize'
  2. import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
  3. import { shareVideoByServerAndChannel } from '../../lib/activitypub/share'
  4. import { getVideoActivityPubUrl, getVideoChannelActivityPubUrl } from '../../lib/activitypub/url'
  5. import { createLocalAccountWithoutKeys } from '../../lib/user'
  6. import { ApplicationModel } from '../../models/application/application'
  7. import { SERVER_ACTOR_NAME } from '../constants'
  8. async function up (utils: {
  9. transaction: Sequelize.Transaction
  10. queryInterface: Sequelize.QueryInterface
  11. sequelize: Sequelize.Sequelize
  12. db: any
  13. }): Promise<void> {
  14. const q = utils.queryInterface
  15. const db = utils.db
  16. // Assert there are no friends
  17. {
  18. const query = 'SELECT COUNT(*) as total FROM "Pods"'
  19. const options = {
  20. type: Sequelize.QueryTypes.SELECT
  21. }
  22. const res = await utils.sequelize.query(query, options) as any
  23. if (!res[0] || res[0].total !== 0) {
  24. throw new Error('You need to quit friends.')
  25. }
  26. }
  27. // Pods -> Servers
  28. await utils.queryInterface.renameTable('Pods', 'Servers')
  29. // Create Account table
  30. await db.Account.sync()
  31. // Create AccountFollows table
  32. await db.AccountFollow.sync()
  33. // Modify video abuse table
  34. await db.VideoAbuse.destroy({ truncate: true })
  35. await utils.queryInterface.removeColumn('VideoAbuses', 'reporterPodId')
  36. await utils.queryInterface.removeColumn('VideoAbuses', 'reporterUsername')
  37. // Create column link with Account table
  38. {
  39. const data = {
  40. type: Sequelize.INTEGER,
  41. allowNull: false,
  42. references: {
  43. model: 'Accounts',
  44. key: 'id'
  45. },
  46. onDelete: 'CASCADE'
  47. }
  48. await q.addColumn('VideoAbuses', 'reporterAccountId', data)
  49. }
  50. // Drop request tables
  51. await utils.queryInterface.dropTable('RequestToPods')
  52. await utils.queryInterface.dropTable('RequestVideoEvents')
  53. await utils.queryInterface.dropTable('RequestVideoQadus')
  54. await utils.queryInterface.dropTable('Requests')
  55. // Create application account
  56. {
  57. const applicationInstance = await ApplicationModel.findOne()
  58. const accountCreated = await createLocalAccountWithoutKeys({
  59. name: SERVER_ACTOR_NAME,
  60. userId: null,
  61. applicationId: applicationInstance.id,
  62. t: undefined
  63. })
  64. const { publicKey, privateKey } = await createPrivateAndPublicKeys()
  65. accountCreated.Actor.publicKey = publicKey
  66. accountCreated.Actor.privateKey = privateKey
  67. await accountCreated.save()
  68. }
  69. // Drop old video channel foreign key (referencing Authors)
  70. {
  71. const query = 'ALTER TABLE "VideoChannels" DROP CONSTRAINT "VideoChannels_authorId_fkey"'
  72. await utils.sequelize.query(query)
  73. }
  74. // Recreate accounts for each user
  75. const users = await db.User.findAll()
  76. for (const user of users) {
  77. const account = await createLocalAccountWithoutKeys({ name: user.username, userId: user.id, applicationId: null, t: undefined })
  78. const { publicKey, privateKey } = await createPrivateAndPublicKeys()
  79. account.Actor.publicKey = publicKey
  80. account.Actor.privateKey = privateKey
  81. await account.save()
  82. }
  83. {
  84. const data = {
  85. type: Sequelize.INTEGER,
  86. allowNull: true,
  87. onDelete: 'CASCADE',
  88. reference: {
  89. model: 'Account',
  90. key: 'id'
  91. }
  92. }
  93. await q.addColumn('VideoChannels', 'accountId', data)
  94. {
  95. const query = 'UPDATE "VideoChannels" SET "accountId" = ' +
  96. '(SELECT "Accounts"."id" FROM "Accounts" INNER JOIN "Authors" ON "Authors"."userId" = "Accounts"."userId" ' +
  97. 'WHERE "VideoChannels"."authorId" = "Authors"."id")'
  98. await utils.sequelize.query(query)
  99. }
  100. data.allowNull = false
  101. await q.changeColumn('VideoChannels', 'accountId', data)
  102. await q.removeColumn('VideoChannels', 'authorId')
  103. }
  104. // Add url column to "Videos"
  105. {
  106. const data = {
  107. type: Sequelize.STRING,
  108. defaultValue: null,
  109. allowNull: true
  110. }
  111. await q.addColumn('Videos', 'url', data)
  112. const videos = await db.Video.findAll()
  113. for (const video of videos) {
  114. video.url = getVideoActivityPubUrl(video)
  115. await video.save()
  116. }
  117. data.allowNull = false
  118. await q.changeColumn('Videos', 'url', data)
  119. }
  120. // Add url column to "VideoChannels"
  121. {
  122. const data = {
  123. type: Sequelize.STRING,
  124. defaultValue: null,
  125. allowNull: true
  126. }
  127. await q.addColumn('VideoChannels', 'url', data)
  128. const videoChannels = await db.VideoChannel.findAll()
  129. for (const videoChannel of videoChannels) {
  130. videoChannel.url = getVideoChannelActivityPubUrl(videoChannel)
  131. await videoChannel.save()
  132. }
  133. data.allowNull = false
  134. await q.changeColumn('VideoChannels', 'url', data)
  135. }
  136. // Loss old video rates, whatever
  137. await utils.queryInterface.dropTable('UserVideoRates')
  138. await db.AccountVideoRate.sync()
  139. {
  140. const data = {
  141. type: Sequelize.ENUM('transcoding', 'activitypub-http'),
  142. defaultValue: 'transcoding',
  143. allowNull: false
  144. }
  145. await q.addColumn('Jobs', 'category', data)
  146. }
  147. await db.VideoShare.sync()
  148. await db.VideoChannelShare.sync()
  149. {
  150. const videos = await db.Video.findAll({
  151. include: [
  152. {
  153. model: db.Video['sequelize'].models.VideoChannel,
  154. include: [
  155. {
  156. model: db.Video['sequelize'].models.Account,
  157. include: [ { model: db.Video['sequelize'].models.Server, required: false } ]
  158. }
  159. ]
  160. },
  161. {
  162. model: db.Video['sequelize'].models.AccountVideoRate,
  163. include: [ db.Video['sequelize'].models.Account ]
  164. },
  165. {
  166. model: db.Video['sequelize'].models.VideoShare,
  167. include: [ db.Video['sequelize'].models.Account ]
  168. },
  169. db.Video['sequelize'].models.Tag,
  170. db.Video['sequelize'].models.VideoFile
  171. ]
  172. })
  173. for (const video of videos) {
  174. await shareVideoByServerAndChannel(video, undefined)
  175. }
  176. }
  177. }
  178. function down (options) {
  179. throw new Error('Not implemented.')
  180. }
  181. export {
  182. up,
  183. down
  184. }