1 import { values } from 'lodash'
2 import * as Sequelize from 'sequelize'
3 import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
4 import { shareVideoByServerAndChannel } from '../../lib/activitypub/share'
5 import { getVideoActivityPubUrl, getVideoChannelActivityPubUrl } from '../../lib/activitypub/url'
6 import { createLocalAccountWithoutKeys } from '../../lib/user'
7 import { ApplicationModel } from '../../models/application/application'
8 import { JOB_CATEGORIES, SERVER_ACTOR_NAME } from '../constants'
10 async function up (utils: {
11 transaction: Sequelize.Transaction,
12 queryInterface: Sequelize.QueryInterface,
13 sequelize: Sequelize.Sequelize,
16 const q = utils.queryInterface
19 // Assert there are no friends
21 const query = 'SELECT COUNT(*) as total FROM "Pods"'
23 type: Sequelize.QueryTypes.SELECT
25 const res = await utils.sequelize.query(query, options)
27 if (!res[0] || res[0].total !== 0) {
28 throw new Error('You need to quit friends.')
33 await utils.queryInterface.renameTable('Pods', 'Servers')
35 // Create Account table
36 await db.Account.sync()
38 // Create AccountFollows table
39 await db.AccountFollow.sync()
41 // Modify video abuse table
42 await db.VideoAbuse.destroy({ truncate: true })
43 await utils.queryInterface.removeColumn('VideoAbuses', 'reporterPodId')
44 await utils.queryInterface.removeColumn('VideoAbuses', 'reporterUsername')
46 // Create column link with Account table
49 type: Sequelize.INTEGER,
57 await q.addColumn('VideoAbuses', 'reporterAccountId', data)
60 // Drop request tables
61 await utils.queryInterface.dropTable('RequestToPods')
62 await utils.queryInterface.dropTable('RequestVideoEvents')
63 await utils.queryInterface.dropTable('RequestVideoQadus')
64 await utils.queryInterface.dropTable('Requests')
66 // Create application account
68 const applicationInstance = await ApplicationModel.findOne()
69 const accountCreated = await createLocalAccountWithoutKeys(SERVER_ACTOR_NAME, null, applicationInstance.id, undefined)
71 const { publicKey, privateKey } = await createPrivateAndPublicKeys()
72 accountCreated.set('publicKey', publicKey)
73 accountCreated.set('privateKey', privateKey)
75 await accountCreated.save()
78 // Drop old video channel foreign key (referencing Authors)
80 const query = 'ALTER TABLE "VideoChannels" DROP CONSTRAINT "VideoChannels_authorId_fkey"'
81 await utils.sequelize.query(query)
84 // Recreate accounts for each user
85 const users = await db.User.findAll()
86 for (const user of users) {
87 const account = await createLocalAccountWithoutKeys(user.username, user.id, null, undefined)
89 const { publicKey, privateKey } = await createPrivateAndPublicKeys()
90 account.set('publicKey', publicKey)
91 account.set('privateKey', privateKey)
97 type: Sequelize.INTEGER,
105 await q.addColumn('VideoChannels', 'accountId', data)
108 const query = 'UPDATE "VideoChannels" SET "accountId" = ' +
109 '(SELECT "Accounts"."id" FROM "Accounts" INNER JOIN "Authors" ON "Authors"."userId" = "Accounts"."userId" ' +
110 'WHERE "VideoChannels"."authorId" = "Authors"."id")'
111 await utils.sequelize.query(query)
114 data.allowNull = false
115 await q.changeColumn('VideoChannels', 'accountId', data)
117 await q.removeColumn('VideoChannels', 'authorId')
120 // Add url column to "Videos"
123 type: Sequelize.STRING,
127 await q.addColumn('Videos', 'url', data)
129 const videos = await db.Video.findAll()
130 for (const video of videos) {
131 video.url = getVideoActivityPubUrl(video)
135 data.allowNull = false
136 await q.changeColumn('Videos', 'url', data)
139 // Add url column to "VideoChannels"
142 type: Sequelize.STRING,
146 await q.addColumn('VideoChannels', 'url', data)
148 const videoChannels = await db.VideoChannel.findAll()
149 for (const videoChannel of videoChannels) {
150 videoChannel.url = getVideoChannelActivityPubUrl(videoChannel)
151 await videoChannel.save()
154 data.allowNull = false
155 await q.changeColumn('VideoChannels', 'url', data)
158 // Loss old video rates, whatever
159 await utils.queryInterface.dropTable('UserVideoRates')
160 await db.AccountVideoRate.sync()
164 type: Sequelize.ENUM(values(JOB_CATEGORIES)),
165 defaultValue: 'transcoding',
168 await q.addColumn('Jobs', 'category', data)
171 await db.VideoShare.sync()
172 await db.VideoChannelShare.sync()
175 const videos = await db.Video.findAll({
178 model: db.Video['sequelize'].models.VideoChannel,
181 model: db.Video['sequelize'].models.Account,
182 include: [ { model: db.Video['sequelize'].models.Server, required: false } ]
187 model: db.Video['sequelize'].models.AccountVideoRate,
188 include: [ db.Video['sequelize'].models.Account ]
191 model: db.Video['sequelize'].models.VideoShare,
192 include: [ db.Video['sequelize'].models.Account ]
194 db.Video['sequelize'].models.Tag,
195 db.Video['sequelize'].models.VideoFile
199 for (const video of videos) {
200 await shareVideoByServerAndChannel(video, undefined)
205 function down (options) {
206 throw new Error('Not implemented.')