import { values } from 'lodash'
import * as Sequelize from 'sequelize'
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
import { shareVideoByServer } from '../../lib/activitypub/share'
import { getVideoActivityPubUrl, getVideoChannelActivityPubUrl } from '../../lib/activitypub/url'
import { createLocalAccountWithoutKeys } from '../../lib/user'
import { JOB_CATEGORIES, SERVER_ACCOUNT_NAME } from '../constants'
import { PeerTubeDatabase } from '../database'
async function up (utils: {
transaction: Sequelize.Transaction,
queryInterface: Sequelize.QueryInterface,
sequelize: Sequelize.Sequelize,
db: PeerTubeDatabase
}): Promise<void> {
const q = utils.queryInterface
const db = utils.db
// Assert there are no friends
{
const query = 'SELECT COUNT(*) as total FROM "Pods"'
const options = {
type: Sequelize.QueryTypes.SELECT
}
const res = await utils.sequelize.query(query, options)
if (!res[0] || res[0].total !== 0) {
throw new Error('You need to quit friends.')
}
}
// Pods -> Servers
await utils.queryInterface.renameTable('Pods', 'Servers')
// Create Account table
await db.Account.sync()
// Create AccountFollows table
await db.AccountFollow.sync()
// Modify video abuse table
await db.VideoAbuse.destroy({ truncate: true })
await utils.queryInterface.removeColumn('VideoAbuses', 'reporterPodId')
await utils.queryInterface.removeColumn('VideoAbuses', 'reporterUsername')
// Create column link with Account table
{
const data = {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Accounts',
key: 'id'
},
onDelete: 'CASCADE'
}
await q.addColumn('VideoAbuses', 'reporterAccountId', data)
}
// Drop request tables
await utils.queryInterface.dropTable('RequestToPods')
await utils.queryInterface.dropTable('RequestVideoEvents')
await utils.queryInterface.dropTable('RequestVideoQadus')
await utils.queryInterface.dropTable('Requests')
// Create application account
{
const applicationInstance = await db.Application.findOne()
const accountCreated = await createLocalAccountWithoutKeys(SERVER_ACCOUNT_NAME, null, applicationInstance.id, undefined)
const { publicKey, privateKey } = await createPrivateAndPublicKeys()
accountCreated.set('publicKey', publicKey)
accountCreated.set('privateKey', privateKey)
await accountCreated.save()
}
// Drop old video channel foreign key (referencing Authors)
{
const query = 'ALTER TABLE "VideoChannels" DROP CONSTRAINT "VideoChannels_authorId_fkey"'
await utils.sequelize.query(query)
}
// Recreate accounts for each user
const users = await db.User.findAll()
for (const user of users) {
const account = await createLocalAccountWithoutKeys(user.username, user.id, null, undefined)
const { publicKey, privateKey } = await createPrivateAndPublicKeys()
account.set('publicKey', publicKey)
account.set('privateKey', privateKey)
await account.save()
}
{
const data = {
type: Sequelize.INTEGER,
allowNull: true,
onDelete: 'CASCADE',
reference: {
model: 'Account',
key: 'id'
}
}
await q.addColumn('VideoChannels', 'accountId', data)
{
const query = 'UPDATE "VideoChannels" SET "accountId" = ' +
'(SELECT "Accounts"."id" FROM "Accounts" INNER JOIN "Authors" ON "Authors"."userId" = "Accounts"."userId" ' +
'WHERE "VideoChannels"."authorId" = "Authors"."id")'
await utils.sequelize.query(query)
}
data.allowNull = false
await q.changeColumn('VideoChannels', 'accountId', data)
await q.removeColumn('VideoChannels', 'authorId')
}
// Add url column to "Videos"
{
const data = {
type: Sequelize.STRING,
defaultValue: null,
allowNull: true
}
await q.addColumn('Videos', 'url', data)
const videos = await db.Video.findAll()
for (const video of videos) {
video.url = getVideoActivityPubUrl(video)
await video.save()
}
data.allowNull = false
await q.changeColumn('Videos', 'url', data)
}
// Add url column to "VideoChannels"
{
const data = {
type: Sequelize.STRING,
defaultValue: null,
allowNull: true
}
await q.addColumn('VideoChannels', 'url', data)
const videoChannels = await db.VideoChannel.findAll()
for (const videoChannel of videoChannels) {
videoChannel.url = getVideoChannelActivityPubUrl(videoChannel)
await videoChannel.save()
}
data.allowNull = false
await q.changeColumn('VideoChannels', 'url', data)
}
// Loss old video rates, whatever
await utils.queryInterface.dropTable('UserVideoRates')
await db.AccountVideoRate.sync()
{
const data = {
type: Sequelize.ENUM(values(JOB_CATEGORIES)),
defaultValue: 'transcoding',
allowNull: false
}
await q.addColumn('Jobs', 'category', data)
}
await db.VideoShare.sync()
await db.VideoChannelShare.sync()
{
const videos = await db.Video.findAll({
include: [
{
model: db.Video['sequelize'].models.VideoChannel,
include: [
{
model: db.Video['sequelize'].models.Account,
include: [ { model: db.Video['sequelize'].models.Server, required: false } ]
}
]
},
{
model: db.Video['sequelize'].models.AccountVideoRate,
include: [ db.Video['sequelize'].models.Account ]
},
{
model: db.Video['sequelize'].models.VideoShare,
include: [ db.Video['sequelize'].models.Account ]
},
db.Video['sequelize'].models.Tag,
db.Video['sequelize'].models.VideoFile
]
})
for (const video of videos) {
await shareVideoByServer(video, undefined)
}
}
}
function down (options) {
throw new Error('Not implemented.')
}
export {
up,
down
}