Implement support field in video and video channel
This commit is contained in:
parent
34cbef8c6c
commit
2422c46b27
|
@ -8,6 +8,7 @@ export class Account implements ServerAccount {
|
||||||
url: string
|
url: string
|
||||||
name: string
|
name: string
|
||||||
displayName: string
|
displayName: string
|
||||||
|
description: string
|
||||||
host: string
|
host: string
|
||||||
followingCount: number
|
followingCount: number
|
||||||
followersCount: number
|
followersCount: number
|
||||||
|
|
|
@ -18,6 +18,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
|
||||||
languageLabel: string
|
languageLabel: string
|
||||||
language: number
|
language: number
|
||||||
description: string
|
description: string
|
||||||
|
support: string
|
||||||
duration: number
|
duration: number
|
||||||
durationLabel: string
|
durationLabel: string
|
||||||
id: number
|
id: number
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { logger } from '../../helpers/logger'
|
||||||
import { createReqFiles, getFormattedObjects } from '../../helpers/utils'
|
import { createReqFiles, getFormattedObjects } from '../../helpers/utils'
|
||||||
import { AVATARS_SIZE, CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers'
|
import { AVATARS_SIZE, CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers'
|
||||||
import { updateActorAvatarInstance } from '../../lib/activitypub'
|
import { updateActorAvatarInstance } from '../../lib/activitypub'
|
||||||
import { sendUpdateUser } from '../../lib/activitypub/send'
|
import { sendUpdateActor } from '../../lib/activitypub/send'
|
||||||
import { Emailer } from '../../lib/emailer'
|
import { Emailer } from '../../lib/emailer'
|
||||||
import { Redis } from '../../lib/redis'
|
import { Redis } from '../../lib/redis'
|
||||||
import { createUserAccountAndChannel } from '../../lib/user'
|
import { createUserAccountAndChannel } from '../../lib/user'
|
||||||
|
@ -270,15 +270,21 @@ async function removeUser (req: express.Request, res: express.Response, next: ex
|
||||||
async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
const body: UserUpdateMe = req.body
|
const body: UserUpdateMe = req.body
|
||||||
|
|
||||||
const user = res.locals.oauth.token.user
|
const user: UserModel = res.locals.oauth.token.user
|
||||||
|
|
||||||
if (body.password !== undefined) user.password = body.password
|
if (body.password !== undefined) user.password = body.password
|
||||||
if (body.email !== undefined) user.email = body.email
|
if (body.email !== undefined) user.email = body.email
|
||||||
if (body.displayNSFW !== undefined) user.displayNSFW = body.displayNSFW
|
if (body.displayNSFW !== undefined) user.displayNSFW = body.displayNSFW
|
||||||
if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
|
if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
|
||||||
|
|
||||||
await user.save()
|
await sequelizeTypescript.transaction(async t => {
|
||||||
await sendUpdateUser(user, undefined)
|
await user.save({ transaction: t })
|
||||||
|
|
||||||
|
if (body.description !== undefined) user.Account.description = body.description
|
||||||
|
await user.Account.save({ transaction: t })
|
||||||
|
|
||||||
|
await sendUpdateActor(user.Account, t)
|
||||||
|
})
|
||||||
|
|
||||||
return res.sendStatus(204)
|
return res.sendStatus(204)
|
||||||
}
|
}
|
||||||
|
@ -297,7 +303,7 @@ async function updateMyAvatar (req: express.Request, res: express.Response, next
|
||||||
const updatedActor = await updateActorAvatarInstance(actor, avatarName, t)
|
const updatedActor = await updateActorAvatarInstance(actor, avatarName, t)
|
||||||
await updatedActor.save({ transaction: t })
|
await updatedActor.save({ transaction: t })
|
||||||
|
|
||||||
await sendUpdateUser(user, t)
|
await sendUpdateActor(user.Account, t)
|
||||||
|
|
||||||
return updatedActor.Avatar
|
return updatedActor.Avatar
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { logger } from '../../../helpers/logger'
|
||||||
import { getFormattedObjects, resetSequelizeInstance } from '../../../helpers/utils'
|
import { getFormattedObjects, resetSequelizeInstance } from '../../../helpers/utils'
|
||||||
import { sequelizeTypescript } from '../../../initializers'
|
import { sequelizeTypescript } from '../../../initializers'
|
||||||
import { setAsyncActorKeys } from '../../../lib/activitypub'
|
import { setAsyncActorKeys } from '../../../lib/activitypub'
|
||||||
|
import { sendUpdateActor } from '../../../lib/activitypub/send'
|
||||||
import { createVideoChannel } from '../../../lib/video-channel'
|
import { createVideoChannel } from '../../../lib/video-channel'
|
||||||
import {
|
import {
|
||||||
asyncMiddleware, authenticate, listVideoAccountChannelsValidator, paginationValidator, setDefaultSort, setDefaultPagination,
|
asyncMiddleware, authenticate, listVideoAccountChannelsValidator, paginationValidator, setDefaultSort, setDefaultPagination,
|
||||||
|
@ -80,23 +81,28 @@ async function addVideoChannelRetryWrapper (req: express.Request, res: express.R
|
||||||
errorMessage: 'Cannot insert the video video channel with many retries.'
|
errorMessage: 'Cannot insert the video video channel with many retries.'
|
||||||
}
|
}
|
||||||
|
|
||||||
await retryTransactionWrapper(addVideoChannel, options)
|
const videoChannel = await retryTransactionWrapper(addVideoChannel, options)
|
||||||
|
return res.json({
|
||||||
// TODO : include Location of the new video channel -> 201
|
videoChannel: {
|
||||||
return res.type('json').status(204).end()
|
id: videoChannel.id
|
||||||
|
}
|
||||||
|
}).end()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addVideoChannel (req: express.Request, res: express.Response) {
|
async function addVideoChannel (req: express.Request, res: express.Response) {
|
||||||
const videoChannelInfo: VideoChannelCreate = req.body
|
const videoChannelInfo: VideoChannelCreate = req.body
|
||||||
const account: AccountModel = res.locals.oauth.token.User.Account
|
const account: AccountModel = res.locals.oauth.token.User.Account
|
||||||
|
|
||||||
const videoChannelCreated = await sequelizeTypescript.transaction(async t => {
|
const videoChannelCreated: VideoChannelModel = await sequelizeTypescript.transaction(async t => {
|
||||||
return createVideoChannel(videoChannelInfo, account, t)
|
return createVideoChannel(videoChannelInfo, account, t)
|
||||||
})
|
})
|
||||||
|
|
||||||
setAsyncActorKeys(videoChannelCreated.Actor)
|
setAsyncActorKeys(videoChannelCreated.Actor)
|
||||||
|
.catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, err))
|
||||||
|
|
||||||
logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
|
logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
|
||||||
|
|
||||||
|
return videoChannelCreated
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
|
@ -123,11 +129,10 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
|
||||||
|
|
||||||
if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
|
if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
|
||||||
if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
|
if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
|
||||||
|
if (videoChannelInfoToUpdate.support !== undefined) videoChannelInstance.set('support', videoChannelInfoToUpdate.support)
|
||||||
|
|
||||||
await videoChannelInstance.save(sequelizeOptions)
|
const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions)
|
||||||
|
await sendUpdateActor(videoChannelInstanceUpdated, t)
|
||||||
// TODO
|
|
||||||
// await sendUpdateVideoChannel(videoChannelInstanceUpdated, t)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
|
logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
|
||||||
|
|
|
@ -178,6 +178,7 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi
|
||||||
commentsEnabled: videoInfo.commentsEnabled,
|
commentsEnabled: videoInfo.commentsEnabled,
|
||||||
nsfw: videoInfo.nsfw,
|
nsfw: videoInfo.nsfw,
|
||||||
description: videoInfo.description,
|
description: videoInfo.description,
|
||||||
|
support: videoInfo.support,
|
||||||
privacy: videoInfo.privacy,
|
privacy: videoInfo.privacy,
|
||||||
duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
|
duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
|
||||||
channelId: res.locals.videoChannel.id
|
channelId: res.locals.videoChannel.id
|
||||||
|
@ -306,6 +307,7 @@ async function updateVideo (req: express.Request, res: express.Response) {
|
||||||
if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
|
if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
|
||||||
if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
|
if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
|
||||||
if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', parseInt(videoInfoToUpdate.privacy.toString(), 10))
|
if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', parseInt(videoInfoToUpdate.privacy.toString(), 10))
|
||||||
|
if (videoInfoToUpdate.support !== undefined) videoInstance.set('support', videoInfoToUpdate.support)
|
||||||
if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
|
if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
|
||||||
if (videoInfoToUpdate.commentsEnabled !== undefined) videoInstance.set('commentsEnabled', videoInfoToUpdate.commentsEnabled)
|
if (videoInfoToUpdate.commentsEnabled !== undefined) videoInstance.set('commentsEnabled', videoInfoToUpdate.commentsEnabled)
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ function activityPubContextify <T> (data: T) {
|
||||||
'language': 'http://schema.org/inLanguage',
|
'language': 'http://schema.org/inLanguage',
|
||||||
'views': 'http://schema.org/Number',
|
'views': 'http://schema.org/Number',
|
||||||
'size': 'http://schema.org/Number',
|
'size': 'http://schema.org/Number',
|
||||||
'commentsEnabled': 'http://schema.org/Boolean'
|
'commentsEnabled': 'http://schema.org/Boolean',
|
||||||
|
'support': 'http://schema.org/Text'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
likes: {
|
likes: {
|
||||||
|
|
|
@ -3,12 +3,16 @@ import { Response } from 'express'
|
||||||
import 'express-validator'
|
import 'express-validator'
|
||||||
import * as validator from 'validator'
|
import * as validator from 'validator'
|
||||||
import { AccountModel } from '../../models/account/account'
|
import { AccountModel } from '../../models/account/account'
|
||||||
import { isUserUsernameValid } from './users'
|
import { isUserDescriptionValid, isUserUsernameValid } from './users'
|
||||||
|
|
||||||
function isAccountNameValid (value: string) {
|
function isAccountNameValid (value: string) {
|
||||||
return isUserUsernameValid(value)
|
return isUserUsernameValid(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAccountDescriptionValid (value: string) {
|
||||||
|
return isUserDescriptionValid(value)
|
||||||
|
}
|
||||||
|
|
||||||
function isAccountIdExist (id: number | string, res: Response) {
|
function isAccountIdExist (id: number | string, res: Response) {
|
||||||
let promise: Bluebird<AccountModel>
|
let promise: Bluebird<AccountModel>
|
||||||
|
|
||||||
|
@ -48,5 +52,6 @@ async function isAccountExist (p: Bluebird<AccountModel>, res: Response) {
|
||||||
export {
|
export {
|
||||||
isAccountIdExist,
|
isAccountIdExist,
|
||||||
isLocalAccountNameExist,
|
isLocalAccountNameExist,
|
||||||
|
isAccountDescriptionValid,
|
||||||
isAccountNameValid
|
isAccountNameValid
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@ function isUserUsernameValid (value: string) {
|
||||||
return exists(value) && validator.matches(value, new RegExp(`^[a-z0-9._]{${min},${max}}$`))
|
return exists(value) && validator.matches(value, new RegExp(`^[a-z0-9._]{${min},${max}}$`))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isUserDescriptionValid (value: string) {
|
||||||
|
return value === null || (exists(value) && validator.isLength(value, CONSTRAINTS_FIELDS.USERS.DESCRIPTION))
|
||||||
|
}
|
||||||
|
|
||||||
function isBoolean (value: any) {
|
function isBoolean (value: any) {
|
||||||
return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
|
return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
|
||||||
}
|
}
|
||||||
|
@ -54,5 +58,6 @@ export {
|
||||||
isUserUsernameValid,
|
isUserUsernameValid,
|
||||||
isUserDisplayNSFWValid,
|
isUserDisplayNSFWValid,
|
||||||
isUserAutoPlayVideoValid,
|
isUserAutoPlayVideoValid,
|
||||||
|
isUserDescriptionValid,
|
||||||
isAvatarFile
|
isAvatarFile
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@ function isVideoChannelNameValid (value: string) {
|
||||||
return exists(value) && validator.isLength(value, VIDEO_CHANNELS_CONSTRAINTS_FIELDS.NAME)
|
return exists(value) && validator.isLength(value, VIDEO_CHANNELS_CONSTRAINTS_FIELDS.NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isVideoChannelSupportValid (value: string) {
|
||||||
|
return value === null || (exists(value) && validator.isLength(value, VIDEO_CHANNELS_CONSTRAINTS_FIELDS.SUPPORT))
|
||||||
|
}
|
||||||
|
|
||||||
async function isVideoChannelExist (id: string, res: express.Response) {
|
async function isVideoChannelExist (id: string, res: express.Response) {
|
||||||
let videoChannel: VideoChannelModel
|
let videoChannel: VideoChannelModel
|
||||||
if (validator.isInt(id)) {
|
if (validator.isInt(id)) {
|
||||||
|
@ -41,5 +45,6 @@ async function isVideoChannelExist (id: string, res: express.Response) {
|
||||||
export {
|
export {
|
||||||
isVideoChannelDescriptionValid,
|
isVideoChannelDescriptionValid,
|
||||||
isVideoChannelNameValid,
|
isVideoChannelNameValid,
|
||||||
|
isVideoChannelSupportValid,
|
||||||
isVideoChannelExist
|
isVideoChannelExist
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,10 @@ function isVideoDescriptionValid (value: string) {
|
||||||
return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
|
return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isVideoSupportValid (value: string) {
|
||||||
|
return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
|
||||||
|
}
|
||||||
|
|
||||||
function isVideoNameValid (value: string) {
|
function isVideoNameValid (value: string) {
|
||||||
return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
|
return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
|
||||||
}
|
}
|
||||||
|
@ -140,5 +144,6 @@ export {
|
||||||
isVideoFileResolutionValid,
|
isVideoFileResolutionValid,
|
||||||
isVideoFileSizeValid,
|
isVideoFileSizeValid,
|
||||||
isVideoExist,
|
isVideoExist,
|
||||||
isVideoImage
|
isVideoImage,
|
||||||
|
isVideoSupportValid
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ let config: IConfig = require('config')
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const LAST_MIGRATION_VERSION = 190
|
const LAST_MIGRATION_VERSION = 195
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -168,6 +168,7 @@ const CONSTRAINTS_FIELDS = {
|
||||||
USERS: {
|
USERS: {
|
||||||
USERNAME: { min: 3, max: 20 }, // Length
|
USERNAME: { min: 3, max: 20 }, // Length
|
||||||
PASSWORD: { min: 6, max: 255 }, // Length
|
PASSWORD: { min: 6, max: 255 }, // Length
|
||||||
|
DESCRIPTION: { min: 3, max: 250 }, // Length
|
||||||
VIDEO_QUOTA: { min: -1 }
|
VIDEO_QUOTA: { min: -1 }
|
||||||
},
|
},
|
||||||
VIDEO_ABUSES: {
|
VIDEO_ABUSES: {
|
||||||
|
@ -176,12 +177,14 @@ const CONSTRAINTS_FIELDS = {
|
||||||
VIDEO_CHANNELS: {
|
VIDEO_CHANNELS: {
|
||||||
NAME: { min: 3, max: 120 }, // Length
|
NAME: { min: 3, max: 120 }, // Length
|
||||||
DESCRIPTION: { min: 3, max: 250 }, // Length
|
DESCRIPTION: { min: 3, max: 250 }, // Length
|
||||||
|
SUPPORT: { min: 3, max: 300 }, // Length
|
||||||
URL: { min: 3, max: 2000 } // Length
|
URL: { min: 3, max: 2000 } // Length
|
||||||
},
|
},
|
||||||
VIDEOS: {
|
VIDEOS: {
|
||||||
NAME: { min: 3, max: 120 }, // Length
|
NAME: { min: 3, max: 120 }, // Length
|
||||||
TRUNCATED_DESCRIPTION: { min: 3, max: 250 }, // Length
|
TRUNCATED_DESCRIPTION: { min: 3, max: 250 }, // Length
|
||||||
DESCRIPTION: { min: 3, max: 3000 }, // Length
|
DESCRIPTION: { min: 3, max: 10000 }, // Length
|
||||||
|
SUPPORT: { min: 3, max: 300 }, // Length
|
||||||
IMAGE: {
|
IMAGE: {
|
||||||
EXTNAME: [ '.jpg', '.jpeg' ],
|
EXTNAME: [ '.jpg', '.jpeg' ],
|
||||||
FILE_SIZE: {
|
FILE_SIZE: {
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import * as Sequelize from 'sequelize'
|
||||||
|
import { CONSTRAINTS_FIELDS } from '../index'
|
||||||
|
|
||||||
|
async function up (utils: {
|
||||||
|
transaction: Sequelize.Transaction,
|
||||||
|
queryInterface: Sequelize.QueryInterface,
|
||||||
|
sequelize: Sequelize.Sequelize
|
||||||
|
}): Promise<void> {
|
||||||
|
{
|
||||||
|
const data = {
|
||||||
|
type: Sequelize.STRING(CONSTRAINTS_FIELDS.VIDEOS.SUPPORT.max),
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null
|
||||||
|
}
|
||||||
|
await utils.queryInterface.addColumn('video', 'support', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const data = {
|
||||||
|
type: Sequelize.STRING(CONSTRAINTS_FIELDS.VIDEO_CHANNELS.SUPPORT.max),
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null
|
||||||
|
}
|
||||||
|
await utils.queryInterface.addColumn('videoChannel', 'support', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const data = {
|
||||||
|
type: Sequelize.STRING(CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max),
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null
|
||||||
|
}
|
||||||
|
await utils.queryInterface.addColumn('account', 'description', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const data = {
|
||||||
|
type: Sequelize.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max),
|
||||||
|
allowNull: true,
|
||||||
|
defaultValue: null
|
||||||
|
}
|
||||||
|
await utils.queryInterface.changeColumn('video', 'description', data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function down (options) {
|
||||||
|
throw new Error('Not implemented.')
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
up,
|
||||||
|
down
|
||||||
|
}
|
|
@ -225,12 +225,10 @@ function saveActorAndServerAndModelIfNotExist (
|
||||||
})
|
})
|
||||||
|
|
||||||
if (actorCreated.type === 'Person' || actorCreated.type === 'Application') {
|
if (actorCreated.type === 'Person' || actorCreated.type === 'Application') {
|
||||||
const account = await saveAccount(actorCreated, result, t)
|
actorCreated.Account = await saveAccount(actorCreated, result, t)
|
||||||
actorCreated.Account = account
|
|
||||||
actorCreated.Account.Actor = actorCreated
|
actorCreated.Account.Actor = actorCreated
|
||||||
} else if (actorCreated.type === 'Group') { // Video channel
|
} else if (actorCreated.type === 'Group') { // Video channel
|
||||||
const videoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t)
|
actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t)
|
||||||
actorCreated.VideoChannel = videoChannel
|
|
||||||
actorCreated.VideoChannel.Actor = actorCreated
|
actorCreated.VideoChannel.Actor = actorCreated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +240,7 @@ type FetchRemoteActorResult = {
|
||||||
actor: ActorModel
|
actor: ActorModel
|
||||||
name: string
|
name: string
|
||||||
summary: string
|
summary: string
|
||||||
|
support?: string
|
||||||
avatarName?: string
|
avatarName?: string
|
||||||
attributedTo: ActivityPubAttributedTo[]
|
attributedTo: ActivityPubAttributedTo[]
|
||||||
}
|
}
|
||||||
|
@ -290,6 +289,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu
|
||||||
name,
|
name,
|
||||||
avatarName,
|
avatarName,
|
||||||
summary: actorJSON.summary,
|
summary: actorJSON.summary,
|
||||||
|
support: actorJSON.support,
|
||||||
attributedTo: actorJSON.attributedTo
|
attributedTo: actorJSON.attributedTo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,6 +298,7 @@ async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t
|
||||||
const [ accountCreated ] = await AccountModel.findOrCreate({
|
const [ accountCreated ] = await AccountModel.findOrCreate({
|
||||||
defaults: {
|
defaults: {
|
||||||
name: result.name,
|
name: result.name,
|
||||||
|
description: result.summary,
|
||||||
actorId: actor.id
|
actorId: actor.id
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
|
@ -314,6 +315,7 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu
|
||||||
defaults: {
|
defaults: {
|
||||||
name: result.name,
|
name: result.name,
|
||||||
description: result.summary,
|
description: result.summary,
|
||||||
|
support: result.support,
|
||||||
actorId: actor.id,
|
actorId: actor.id,
|
||||||
accountId: ownerActor.Account.id
|
accountId: ownerActor.Account.id
|
||||||
},
|
},
|
||||||
|
@ -352,11 +354,14 @@ async function refreshActorIfNeeded (actor: ActorModel) {
|
||||||
await actor.save({ transaction: t })
|
await actor.save({ transaction: t })
|
||||||
|
|
||||||
actor.Account.set('name', result.name)
|
actor.Account.set('name', result.name)
|
||||||
|
actor.Account.set('description', result.summary)
|
||||||
await actor.Account.save({ transaction: t })
|
await actor.Account.save({ transaction: t })
|
||||||
} else if (actor.VideoChannel) {
|
} else if (actor.VideoChannel) {
|
||||||
await actor.save({ transaction: t })
|
await actor.save({ transaction: t })
|
||||||
|
|
||||||
actor.VideoChannel.set('name', result.name)
|
actor.VideoChannel.set('name', result.name)
|
||||||
|
actor.VideoChannel.set('description', result.summary)
|
||||||
|
actor.VideoChannel.set('support', result.support)
|
||||||
await actor.VideoChannel.save({ transaction: t })
|
await actor.VideoChannel.save({ transaction: t })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,20 +9,24 @@ import { sequelizeTypescript } from '../../../initializers'
|
||||||
import { AccountModel } from '../../../models/account/account'
|
import { AccountModel } from '../../../models/account/account'
|
||||||
import { ActorModel } from '../../../models/activitypub/actor'
|
import { ActorModel } from '../../../models/activitypub/actor'
|
||||||
import { TagModel } from '../../../models/video/tag'
|
import { TagModel } from '../../../models/video/tag'
|
||||||
|
import { VideoChannelModel } from '../../../models/video/video-channel'
|
||||||
import { VideoFileModel } from '../../../models/video/video-file'
|
import { VideoFileModel } from '../../../models/video/video-file'
|
||||||
import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor'
|
import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor'
|
||||||
import {
|
import {
|
||||||
generateThumbnailFromUrl, getOrCreateAccountAndVideoAndChannel, videoActivityObjectToDBAttributes,
|
generateThumbnailFromUrl,
|
||||||
|
getOrCreateAccountAndVideoAndChannel,
|
||||||
|
videoActivityObjectToDBAttributes,
|
||||||
videoFileActivityUrlToDBAttributes
|
videoFileActivityUrlToDBAttributes
|
||||||
} from '../videos'
|
} from '../videos'
|
||||||
|
|
||||||
async function processUpdateActivity (activity: ActivityUpdate) {
|
async function processUpdateActivity (activity: ActivityUpdate) {
|
||||||
const actor = await getOrCreateActorAndServerAndModel(activity.actor)
|
const actor = await getOrCreateActorAndServerAndModel(activity.actor)
|
||||||
|
const objectType = activity.object.type
|
||||||
|
|
||||||
if (activity.object.type === 'Video') {
|
if (objectType === 'Video') {
|
||||||
return processUpdateVideo(actor, activity)
|
return processUpdateVideo(actor, activity)
|
||||||
} else if (activity.object.type === 'Person') {
|
} else if (objectType === 'Person' || objectType === 'Application' || objectType === 'Group') {
|
||||||
return processUpdateAccount(actor, activity)
|
return processUpdateActor(actor, activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -75,6 +79,7 @@ async function updateRemoteVideo (actor: ActorModel, activity: ActivityUpdate) {
|
||||||
videoInstance.set('licence', videoData.licence)
|
videoInstance.set('licence', videoData.licence)
|
||||||
videoInstance.set('language', videoData.language)
|
videoInstance.set('language', videoData.language)
|
||||||
videoInstance.set('description', videoData.description)
|
videoInstance.set('description', videoData.description)
|
||||||
|
videoInstance.set('support', videoData.support)
|
||||||
videoInstance.set('nsfw', videoData.nsfw)
|
videoInstance.set('nsfw', videoData.nsfw)
|
||||||
videoInstance.set('commentsEnabled', videoData.commentsEnabled)
|
videoInstance.set('commentsEnabled', videoData.commentsEnabled)
|
||||||
videoInstance.set('duration', videoData.duration)
|
videoInstance.set('duration', videoData.duration)
|
||||||
|
@ -117,33 +122,36 @@ async function updateRemoteVideo (actor: ActorModel, activity: ActivityUpdate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processUpdateAccount (actor: ActorModel, activity: ActivityUpdate) {
|
function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) {
|
||||||
const options = {
|
const options = {
|
||||||
arguments: [ actor, activity ],
|
arguments: [ actor, activity ],
|
||||||
errorMessage: 'Cannot update the remote account with many retries'
|
errorMessage: 'Cannot update the remote actor with many retries'
|
||||||
}
|
}
|
||||||
|
|
||||||
return retryTransactionWrapper(updateRemoteAccount, options)
|
return retryTransactionWrapper(updateRemoteActor, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate) {
|
async function updateRemoteActor (actor: ActorModel, activity: ActivityUpdate) {
|
||||||
const accountAttributesToUpdate = activity.object as ActivityPubActor
|
const actorAttributesToUpdate = activity.object as ActivityPubActor
|
||||||
|
|
||||||
logger.debug('Updating remote account "%s".', accountAttributesToUpdate.uuid)
|
logger.debug('Updating remote account "%s".', actorAttributesToUpdate.uuid)
|
||||||
let accountInstance: AccountModel
|
let accountOrChannelInstance: AccountModel | VideoChannelModel
|
||||||
let actorFieldsSave: object
|
let actorFieldsSave: object
|
||||||
let accountFieldsSave: object
|
let accountOrChannelFieldsSave: object
|
||||||
|
|
||||||
// Fetch icon?
|
// Fetch icon?
|
||||||
const avatarName = await fetchAvatarIfExists(accountAttributesToUpdate)
|
const avatarName = await fetchAvatarIfExists(actorAttributesToUpdate)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await sequelizeTypescript.transaction(async t => {
|
await sequelizeTypescript.transaction(async t => {
|
||||||
actorFieldsSave = actor.toJSON()
|
actorFieldsSave = actor.toJSON()
|
||||||
accountInstance = actor.Account
|
|
||||||
accountFieldsSave = actor.Account.toJSON()
|
|
||||||
|
|
||||||
await updateActorInstance(actor, accountAttributesToUpdate)
|
if (actorAttributesToUpdate.type === 'Group') accountOrChannelInstance = actor.VideoChannel
|
||||||
|
else accountOrChannelInstance = actor.Account
|
||||||
|
|
||||||
|
accountOrChannelFieldsSave = accountOrChannelInstance.toJSON()
|
||||||
|
|
||||||
|
await updateActorInstance(actor, actorAttributesToUpdate)
|
||||||
|
|
||||||
if (avatarName !== undefined) {
|
if (avatarName !== undefined) {
|
||||||
await updateActorAvatarInstance(actor, avatarName, t)
|
await updateActorAvatarInstance(actor, avatarName, t)
|
||||||
|
@ -151,18 +159,20 @@ async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate)
|
||||||
|
|
||||||
await actor.save({ transaction: t })
|
await actor.save({ transaction: t })
|
||||||
|
|
||||||
actor.Account.set('name', accountAttributesToUpdate.name || accountAttributesToUpdate.preferredUsername)
|
accountOrChannelInstance.set('name', actorAttributesToUpdate.name || actorAttributesToUpdate.preferredUsername)
|
||||||
await actor.Account.save({ transaction: t })
|
accountOrChannelInstance.set('description', actorAttributesToUpdate.summary)
|
||||||
|
accountOrChannelInstance.set('support', actorAttributesToUpdate.support)
|
||||||
|
await accountOrChannelInstance.save({ transaction: t })
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info('Remote account with uuid %s updated', accountAttributesToUpdate.uuid)
|
logger.info('Remote account with uuid %s updated', actorAttributesToUpdate.uuid)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (actor !== undefined && actorFieldsSave !== undefined) {
|
if (actor !== undefined && actorFieldsSave !== undefined) {
|
||||||
resetSequelizeInstance(actor, actorFieldsSave)
|
resetSequelizeInstance(actor, actorFieldsSave)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accountInstance !== undefined && accountFieldsSave !== undefined) {
|
if (accountOrChannelInstance !== undefined && accountOrChannelFieldsSave !== undefined) {
|
||||||
resetSequelizeInstance(accountInstance, accountFieldsSave)
|
resetSequelizeInstance(accountOrChannelInstance, accountOrChannelFieldsSave)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is just a debug because we will retry the insert
|
// This is just a debug because we will retry the insert
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { Transaction } from 'sequelize'
|
import { Transaction } from 'sequelize'
|
||||||
import { ActivityAudience, ActivityUpdate } from '../../../../shared/models/activitypub'
|
import { ActivityAudience, ActivityUpdate } from '../../../../shared/models/activitypub'
|
||||||
import { VideoPrivacy } from '../../../../shared/models/videos'
|
import { VideoPrivacy } from '../../../../shared/models/videos'
|
||||||
import { UserModel } from '../../../models/account/user'
|
import { AccountModel } from '../../../models/account/account'
|
||||||
import { ActorModel } from '../../../models/activitypub/actor'
|
import { ActorModel } from '../../../models/activitypub/actor'
|
||||||
import { VideoModel } from '../../../models/video/video'
|
import { VideoModel } from '../../../models/video/video'
|
||||||
|
import { VideoChannelModel } from '../../../models/video/video-channel'
|
||||||
import { VideoShareModel } from '../../../models/video/video-share'
|
import { VideoShareModel } from '../../../models/video/video-share'
|
||||||
import { getUpdateActivityPubUrl } from '../url'
|
import { getUpdateActivityPubUrl } from '../url'
|
||||||
import { audiencify, broadcastToFollowers, getAudience } from './misc'
|
import { audiencify, broadcastToFollowers, getAudience } from './misc'
|
||||||
|
@ -23,15 +24,23 @@ async function sendUpdateVideo (video: VideoModel, t: Transaction) {
|
||||||
return broadcastToFollowers(data, byActor, actorsInvolved, t)
|
return broadcastToFollowers(data, byActor, actorsInvolved, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendUpdateUser (user: UserModel, t: Transaction) {
|
async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelModel, t: Transaction) {
|
||||||
const byActor = user.Account.Actor
|
const byActor = accountOrChannel.Actor
|
||||||
|
|
||||||
const url = getUpdateActivityPubUrl(byActor.url, byActor.updatedAt.toISOString())
|
const url = getUpdateActivityPubUrl(byActor.url, byActor.updatedAt.toISOString())
|
||||||
const accountObject = user.Account.toActivityPubObject()
|
const accountOrChannelObject = accountOrChannel.toActivityPubObject()
|
||||||
const audience = await getAudience(byActor, t)
|
const audience = await getAudience(byActor, t)
|
||||||
const data = await updateActivityData(url, byActor, accountObject, t, audience)
|
const data = await updateActivityData(url, byActor, accountOrChannelObject, t, audience)
|
||||||
|
|
||||||
|
let actorsInvolved: ActorModel[]
|
||||||
|
if (accountOrChannel instanceof AccountModel) {
|
||||||
|
// Actors that shared my videos are involved too
|
||||||
|
actorsInvolved = await VideoShareModel.loadActorsByVideoOwner(byActor.id, t)
|
||||||
|
} else {
|
||||||
|
// Actors that shared videos of my channel are involved too
|
||||||
|
actorsInvolved = await VideoShareModel.loadActorsByVideoChannel(accountOrChannel.id, t)
|
||||||
|
}
|
||||||
|
|
||||||
const actorsInvolved = await VideoShareModel.loadActorsByVideoOwner(byActor.id, t)
|
|
||||||
actorsInvolved.push(byActor)
|
actorsInvolved.push(byActor)
|
||||||
|
|
||||||
return broadcastToFollowers(data, byActor, actorsInvolved, t)
|
return broadcastToFollowers(data, byActor, actorsInvolved, t)
|
||||||
|
@ -40,7 +49,7 @@ async function sendUpdateUser (user: UserModel, t: Transaction) {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
sendUpdateUser,
|
sendUpdateActor,
|
||||||
sendUpdateVideo
|
sendUpdateVideo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,11 @@ async function videoActivityObjectToDBAttributes (videoChannel: VideoChannelMode
|
||||||
description = videoObject.content
|
description = videoObject.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let support = null
|
||||||
|
if (videoObject.support) {
|
||||||
|
support = videoObject.support
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: videoObject.name,
|
name: videoObject.name,
|
||||||
uuid: videoObject.uuid,
|
uuid: videoObject.uuid,
|
||||||
|
@ -91,6 +96,7 @@ async function videoActivityObjectToDBAttributes (videoChannel: VideoChannelMode
|
||||||
licence,
|
licence,
|
||||||
language,
|
language,
|
||||||
description,
|
description,
|
||||||
|
support,
|
||||||
nsfw: videoObject.sensitive,
|
nsfw: videoObject.sensitive,
|
||||||
commentsEnabled: videoObject.commentsEnabled,
|
commentsEnabled: videoObject.commentsEnabled,
|
||||||
channelId: videoChannel.id,
|
channelId: videoChannel.id,
|
||||||
|
|
|
@ -16,6 +16,7 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account
|
||||||
const videoChannelData = {
|
const videoChannelData = {
|
||||||
name: videoChannelInfo.name,
|
name: videoChannelInfo.name,
|
||||||
description: videoChannelInfo.description,
|
description: videoChannelInfo.description,
|
||||||
|
support: videoChannelInfo.support,
|
||||||
accountId: account.id,
|
accountId: account.id,
|
||||||
actorId: actorInstanceCreated.id
|
actorId: actorInstanceCreated.id
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
|
||||||
import {
|
import {
|
||||||
isAvatarFile,
|
isAvatarFile,
|
||||||
isUserAutoPlayVideoValid,
|
isUserAutoPlayVideoValid,
|
||||||
|
isUserDescriptionValid,
|
||||||
isUserDisplayNSFWValid,
|
isUserDisplayNSFWValid,
|
||||||
isUserPasswordValid,
|
isUserPasswordValid,
|
||||||
isUserRoleValid,
|
isUserRoleValid,
|
||||||
|
@ -97,6 +98,7 @@ const usersUpdateValidator = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersUpdateMeValidator = [
|
const usersUpdateMeValidator = [
|
||||||
|
body('description').optional().custom(isUserDescriptionValid).withMessage('Should have a valid description'),
|
||||||
body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'),
|
body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'),
|
||||||
body('email').optional().isEmail().withMessage('Should have a valid email attribute'),
|
body('email').optional().isEmail().withMessage('Should have a valid email attribute'),
|
||||||
body('displayNSFW').optional().custom(isUserDisplayNSFWValid).withMessage('Should have a valid display Not Safe For Work attribute'),
|
body('displayNSFW').optional().custom(isUserDisplayNSFWValid).withMessage('Should have a valid display Not Safe For Work attribute'),
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { isAccountIdExist } from '../../helpers/custom-validators/accounts'
|
||||||
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
|
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
|
||||||
import {
|
import {
|
||||||
isVideoChannelDescriptionValid, isVideoChannelExist,
|
isVideoChannelDescriptionValid, isVideoChannelExist,
|
||||||
isVideoChannelNameValid
|
isVideoChannelNameValid, isVideoChannelSupportValid
|
||||||
} from '../../helpers/custom-validators/video-channels'
|
} from '../../helpers/custom-validators/video-channels'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { UserModel } from '../../models/account/user'
|
import { UserModel } from '../../models/account/user'
|
||||||
|
@ -27,7 +27,8 @@ const listVideoAccountChannelsValidator = [
|
||||||
|
|
||||||
const videoChannelsAddValidator = [
|
const videoChannelsAddValidator = [
|
||||||
body('name').custom(isVideoChannelNameValid).withMessage('Should have a valid name'),
|
body('name').custom(isVideoChannelNameValid).withMessage('Should have a valid name'),
|
||||||
body('description').custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
|
body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
|
||||||
|
body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug('Checking videoChannelsAdd parameters', { parameters: req.body })
|
logger.debug('Checking videoChannelsAdd parameters', { parameters: req.body })
|
||||||
|
@ -42,6 +43,7 @@ const videoChannelsUpdateValidator = [
|
||||||
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
||||||
body('name').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid name'),
|
body('name').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid name'),
|
||||||
body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
|
body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
|
||||||
|
body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'),
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body })
|
logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body })
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
isVideoLicenceValid,
|
isVideoLicenceValid,
|
||||||
isVideoNameValid,
|
isVideoNameValid,
|
||||||
isVideoPrivacyValid,
|
isVideoPrivacyValid,
|
||||||
isVideoRatingTypeValid,
|
isVideoRatingTypeValid, isVideoSupportValid,
|
||||||
isVideoTagsValid
|
isVideoTagsValid
|
||||||
} from '../../helpers/custom-validators/videos'
|
} from '../../helpers/custom-validators/videos'
|
||||||
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
|
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
|
||||||
|
@ -46,6 +46,7 @@ const videosAddValidator = [
|
||||||
body('language').optional().custom(isVideoLanguageValid).withMessage('Should have a valid language'),
|
body('language').optional().custom(isVideoLanguageValid).withMessage('Should have a valid language'),
|
||||||
body('nsfw').custom(isBooleanValid).withMessage('Should have a valid NSFW attribute'),
|
body('nsfw').custom(isBooleanValid).withMessage('Should have a valid NSFW attribute'),
|
||||||
body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
|
body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
|
||||||
|
body('support').optional().custom(isVideoSupportValid).withMessage('Should have a valid support text'),
|
||||||
body('channelId').custom(isIdValid).withMessage('Should have correct video channel id'),
|
body('channelId').custom(isIdValid).withMessage('Should have correct video channel id'),
|
||||||
body('privacy').custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
|
body('privacy').custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
|
||||||
body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'),
|
body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'),
|
||||||
|
@ -116,6 +117,7 @@ const videosUpdateValidator = [
|
||||||
body('nsfw').optional().custom(isBooleanValid).withMessage('Should have a valid NSFW attribute'),
|
body('nsfw').optional().custom(isBooleanValid).withMessage('Should have a valid NSFW attribute'),
|
||||||
body('privacy').optional().custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
|
body('privacy').optional().custom(isVideoPrivacyValid).withMessage('Should have correct video privacy'),
|
||||||
body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
|
body('description').optional().custom(isVideoDescriptionValid).withMessage('Should have a valid description'),
|
||||||
|
body('support').optional().custom(isVideoSupportValid).withMessage('Should have a valid support text'),
|
||||||
body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'),
|
body('tags').optional().custom(isVideoTagsValid).withMessage('Should have correct tags'),
|
||||||
body('commentsEnabled').optional().custom(isBooleanValid).withMessage('Should have comments enabled boolean'),
|
body('commentsEnabled').optional().custom(isBooleanValid).withMessage('Should have comments enabled boolean'),
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import {
|
import {
|
||||||
AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, HasMany, Model, Table,
|
AllowNull,
|
||||||
|
BeforeDestroy,
|
||||||
|
BelongsTo,
|
||||||
|
Column,
|
||||||
|
CreatedAt,
|
||||||
|
Default,
|
||||||
|
DefaultScope,
|
||||||
|
ForeignKey,
|
||||||
|
HasMany,
|
||||||
|
Is,
|
||||||
|
Model,
|
||||||
|
Table,
|
||||||
UpdatedAt
|
UpdatedAt
|
||||||
} from 'sequelize-typescript'
|
} from 'sequelize-typescript'
|
||||||
import { Account } from '../../../shared/models/actors'
|
import { Account } from '../../../shared/models/actors'
|
||||||
|
import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { sendDeleteActor } from '../../lib/activitypub/send'
|
import { sendDeleteActor } from '../../lib/activitypub/send'
|
||||||
import { ActorModel } from '../activitypub/actor'
|
import { ActorModel } from '../activitypub/actor'
|
||||||
import { ApplicationModel } from '../application/application'
|
import { ApplicationModel } from '../application/application'
|
||||||
import { AvatarModel } from '../avatar/avatar'
|
import { AvatarModel } from '../avatar/avatar'
|
||||||
import { ServerModel } from '../server/server'
|
import { ServerModel } from '../server/server'
|
||||||
import { getSort } from '../utils'
|
import { getSort, throwIfNotValid } from '../utils'
|
||||||
import { VideoChannelModel } from '../video/video-channel'
|
import { VideoChannelModel } from '../video/video-channel'
|
||||||
import { VideoCommentModel } from '../video/video-comment'
|
import { VideoCommentModel } from '../video/video-comment'
|
||||||
import { UserModel } from './user'
|
import { UserModel } from './user'
|
||||||
|
@ -42,6 +54,12 @@ export class AccountModel extends Model<AccountModel> {
|
||||||
@Column
|
@Column
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
|
@AllowNull(true)
|
||||||
|
@Default(null)
|
||||||
|
@Is('AccountDescription', value => throwIfNotValid(value, isAccountDescriptionValid, 'description'))
|
||||||
|
@Column
|
||||||
|
description: string
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
|
||||||
|
@ -196,6 +214,7 @@ export class AccountModel extends Model<AccountModel> {
|
||||||
const account = {
|
const account = {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
displayName: this.name,
|
displayName: this.name,
|
||||||
|
description: this.description,
|
||||||
createdAt: this.createdAt,
|
createdAt: this.createdAt,
|
||||||
updatedAt: this.updatedAt
|
updatedAt: this.updatedAt
|
||||||
}
|
}
|
||||||
|
@ -204,7 +223,11 @@ export class AccountModel extends Model<AccountModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
toActivityPubObject () {
|
toActivityPubObject () {
|
||||||
return this.Actor.toActivityPubObject(this.name, 'Account')
|
const obj = this.Actor.toActivityPubObject(this.name, 'Account')
|
||||||
|
|
||||||
|
return Object.assign(obj, {
|
||||||
|
summary: this.description
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwned () {
|
isOwned () {
|
||||||
|
|
|
@ -2,14 +2,31 @@ import { values } from 'lodash'
|
||||||
import { extname } from 'path'
|
import { extname } from 'path'
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import {
|
import {
|
||||||
AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, DefaultScope, ForeignKey, HasMany, HasOne, Is, IsUUID, Model, Scopes,
|
AllowNull,
|
||||||
Table, UpdatedAt
|
BelongsTo,
|
||||||
|
Column,
|
||||||
|
CreatedAt,
|
||||||
|
DataType,
|
||||||
|
Default,
|
||||||
|
DefaultScope,
|
||||||
|
ForeignKey,
|
||||||
|
HasMany,
|
||||||
|
HasOne,
|
||||||
|
Is,
|
||||||
|
IsUUID,
|
||||||
|
Model,
|
||||||
|
Scopes,
|
||||||
|
Table,
|
||||||
|
UpdatedAt
|
||||||
} from 'sequelize-typescript'
|
} from 'sequelize-typescript'
|
||||||
import { ActivityPubActorType } from '../../../shared/models/activitypub'
|
import { ActivityPubActorType } from '../../../shared/models/activitypub'
|
||||||
import { Avatar } from '../../../shared/models/avatars/avatar.model'
|
import { Avatar } from '../../../shared/models/avatars/avatar.model'
|
||||||
import { activityPubContextify } from '../../helpers/activitypub'
|
import { activityPubContextify } from '../../helpers/activitypub'
|
||||||
import {
|
import {
|
||||||
isActorFollowersCountValid, isActorFollowingCountValid, isActorPreferredUsernameValid, isActorPrivateKeyValid,
|
isActorFollowersCountValid,
|
||||||
|
isActorFollowingCountValid,
|
||||||
|
isActorPreferredUsernameValid,
|
||||||
|
isActorPrivateKeyValid,
|
||||||
isActorPublicKeyValid
|
isActorPublicKeyValid
|
||||||
} from '../../helpers/custom-validators/activitypub/actor'
|
} from '../../helpers/custom-validators/activitypub/actor'
|
||||||
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
|
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
import {
|
import {
|
||||||
AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, HasMany, Is, Model, Scopes, Table,
|
AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, HasMany, Is, Model, Scopes, Table,
|
||||||
UpdatedAt
|
UpdatedAt, Default
|
||||||
} from 'sequelize-typescript'
|
} from 'sequelize-typescript'
|
||||||
import { ActivityPubActor } from '../../../shared/models/activitypub'
|
import { ActivityPubActor } from '../../../shared/models/activitypub'
|
||||||
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels'
|
import { VideoChannel } from '../../../shared/models/videos'
|
||||||
|
import {
|
||||||
|
isVideoChannelDescriptionValid, isVideoChannelNameValid,
|
||||||
|
isVideoChannelSupportValid
|
||||||
|
} from '../../helpers/custom-validators/video-channels'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { sendDeleteActor } from '../../lib/activitypub/send'
|
import { sendDeleteActor } from '../../lib/activitypub/send'
|
||||||
import { AccountModel } from '../account/account'
|
import { AccountModel } from '../account/account'
|
||||||
|
@ -67,10 +71,17 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
@AllowNull(true)
|
@AllowNull(true)
|
||||||
|
@Default(null)
|
||||||
@Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description'))
|
@Is('VideoChannelDescription', value => throwIfNotValid(value, isVideoChannelDescriptionValid, 'description'))
|
||||||
@Column
|
@Column
|
||||||
description: string
|
description: string
|
||||||
|
|
||||||
|
@AllowNull(true)
|
||||||
|
@Default(null)
|
||||||
|
@Is('VideoChannelSupport', value => throwIfNotValid(value, isVideoChannelSupportValid, 'support'))
|
||||||
|
@Column
|
||||||
|
support: string
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
|
||||||
|
@ -221,12 +232,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
|
||||||
.findById(id, options)
|
.findById(id, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
toFormattedJSON () {
|
toFormattedJSON (): VideoChannel {
|
||||||
const actor = this.Actor.toFormattedJSON()
|
const actor = this.Actor.toFormattedJSON()
|
||||||
const account = {
|
const account = {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
displayName: this.name,
|
displayName: this.name,
|
||||||
description: this.description,
|
description: this.description,
|
||||||
|
support: this.support,
|
||||||
isLocal: this.Actor.isOwned(),
|
isLocal: this.Actor.isOwned(),
|
||||||
createdAt: this.createdAt,
|
createdAt: this.createdAt,
|
||||||
updatedAt: this.updatedAt
|
updatedAt: this.updatedAt
|
||||||
|
@ -240,6 +252,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
|
||||||
|
|
||||||
return Object.assign(obj, {
|
return Object.assign(obj, {
|
||||||
summary: this.description,
|
summary: this.description,
|
||||||
|
support: this.support,
|
||||||
attributedTo: [
|
attributedTo: [
|
||||||
{
|
{
|
||||||
type: 'Person' as 'Person',
|
type: 'Person' as 'Person',
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
|
import * as Bluebird from 'bluebird'
|
||||||
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
|
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
|
||||||
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
|
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
|
||||||
import { CONSTRAINTS_FIELDS } from '../../initializers'
|
import { CONSTRAINTS_FIELDS } from '../../initializers'
|
||||||
|
@ -115,7 +116,7 @@ export class VideoShareModel extends Model<VideoShareModel> {
|
||||||
.then(res => res.map(r => r.Actor))
|
.then(res => res.map(r => r.Actor))
|
||||||
}
|
}
|
||||||
|
|
||||||
static loadActorsByVideoOwner (actorOwnerId: number, t: Sequelize.Transaction) {
|
static loadActorsByVideoOwner (actorOwnerId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> {
|
||||||
const query = {
|
const query = {
|
||||||
attributes: [],
|
attributes: [],
|
||||||
include: [
|
include: [
|
||||||
|
@ -152,4 +153,29 @@ export class VideoShareModel extends Model<VideoShareModel> {
|
||||||
return VideoShareModel.scope(ScopeNames.FULL).findAll(query)
|
return VideoShareModel.scope(ScopeNames.FULL).findAll(query)
|
||||||
.then(res => res.map(r => r.Actor))
|
.then(res => res.map(r => r.Actor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static loadActorsByVideoChannel (videoChannelId: number, t: Sequelize.Transaction): Bluebird<ActorModel[]> {
|
||||||
|
const query = {
|
||||||
|
attributes: [],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: ActorModel,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: [],
|
||||||
|
model: VideoModel,
|
||||||
|
required: true,
|
||||||
|
where: {
|
||||||
|
channelId: videoChannelId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
transaction: t
|
||||||
|
}
|
||||||
|
|
||||||
|
return VideoShareModel.scope(ScopeNames.FULL)
|
||||||
|
.findAll(query)
|
||||||
|
.then(res => res.map(r => r.Actor))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import {
|
||||||
isVideoLanguageValid,
|
isVideoLanguageValid,
|
||||||
isVideoLicenceValid,
|
isVideoLicenceValid,
|
||||||
isVideoNameValid,
|
isVideoNameValid,
|
||||||
isVideoPrivacyValid
|
isVideoPrivacyValid, isVideoSupportValid
|
||||||
} from '../../helpers/custom-validators/videos'
|
} from '../../helpers/custom-validators/videos'
|
||||||
import { generateImageFromVideoFile, getVideoFileHeight, transcode } from '../../helpers/ffmpeg-utils'
|
import { generateImageFromVideoFile, getVideoFileHeight, transcode } from '../../helpers/ffmpeg-utils'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
|
@ -299,6 +299,12 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max))
|
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max))
|
||||||
description: string
|
description: string
|
||||||
|
|
||||||
|
@AllowNull(true)
|
||||||
|
@Default(null)
|
||||||
|
@Is('VideoSupport', value => throwIfNotValid(value, isVideoSupportValid, 'support'))
|
||||||
|
@Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.SUPPORT.max))
|
||||||
|
support: string
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Is('VideoDuration', value => throwIfNotValid(value, isVideoDurationValid, 'duration'))
|
@Is('VideoDuration', value => throwIfNotValid(value, isVideoDurationValid, 'duration'))
|
||||||
@Column
|
@Column
|
||||||
|
@ -841,7 +847,7 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
return join(STATIC_PATHS.PREVIEWS, this.getPreviewName())
|
return join(STATIC_PATHS.PREVIEWS, this.getPreviewName())
|
||||||
}
|
}
|
||||||
|
|
||||||
toFormattedJSON () {
|
toFormattedJSON (): Video {
|
||||||
let serverHost
|
let serverHost
|
||||||
|
|
||||||
if (this.VideoChannel.Account.Actor.Server) {
|
if (this.VideoChannel.Account.Actor.Server) {
|
||||||
|
@ -875,10 +881,10 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
embedPath: this.getEmbedPath(),
|
embedPath: this.getEmbedPath(),
|
||||||
createdAt: this.createdAt,
|
createdAt: this.createdAt,
|
||||||
updatedAt: this.updatedAt
|
updatedAt: this.updatedAt
|
||||||
} as Video
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toFormattedDetailsJSON () {
|
toFormattedDetailsJSON (): VideoDetails {
|
||||||
const formattedJson = this.toFormattedJSON()
|
const formattedJson = this.toFormattedJSON()
|
||||||
|
|
||||||
// Maybe our server is not up to date and there are new privacy settings since our version
|
// Maybe our server is not up to date and there are new privacy settings since our version
|
||||||
|
@ -888,6 +894,7 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
const detailsJson = {
|
const detailsJson = {
|
||||||
privacyLabel,
|
privacyLabel,
|
||||||
privacy: this.privacy,
|
privacy: this.privacy,
|
||||||
|
support: this.support,
|
||||||
descriptionPath: this.getDescriptionPath(),
|
descriptionPath: this.getDescriptionPath(),
|
||||||
channel: this.VideoChannel.toFormattedJSON(),
|
channel: this.VideoChannel.toFormattedJSON(),
|
||||||
account: this.VideoChannel.Account.toFormattedJSON(),
|
account: this.VideoChannel.Account.toFormattedJSON(),
|
||||||
|
@ -917,7 +924,7 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
return -1
|
return -1
|
||||||
})
|
})
|
||||||
|
|
||||||
return Object.assign(formattedJson, detailsJson) as VideoDetails
|
return Object.assign(formattedJson, detailsJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
toActivityPubObject (): VideoTorrentObject {
|
toActivityPubObject (): VideoTorrentObject {
|
||||||
|
@ -957,17 +964,6 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
let dislikesObject
|
let dislikesObject
|
||||||
|
|
||||||
if (Array.isArray(this.AccountVideoRates)) {
|
if (Array.isArray(this.AccountVideoRates)) {
|
||||||
const likes: string[] = []
|
|
||||||
const dislikes: string[] = []
|
|
||||||
|
|
||||||
for (const rate of this.AccountVideoRates) {
|
|
||||||
if (rate.type === 'like') {
|
|
||||||
likes.push(rate.Account.Actor.url)
|
|
||||||
} else if (rate.type === 'dislike') {
|
|
||||||
dislikes.push(rate.Account.Actor.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = this.toRatesActivityPubObjects()
|
const res = this.toRatesActivityPubObjects()
|
||||||
likesObject = res.likesObject
|
likesObject = res.likesObject
|
||||||
dislikesObject = res.dislikesObject
|
dislikesObject = res.dislikesObject
|
||||||
|
@ -1032,6 +1028,7 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
updated: this.updatedAt.toISOString(),
|
updated: this.updatedAt.toISOString(),
|
||||||
mediaType: 'text/markdown',
|
mediaType: 'text/markdown',
|
||||||
content: this.getTruncatedDescription(),
|
content: this.getTruncatedDescription(),
|
||||||
|
support: this.support,
|
||||||
icon: {
|
icon: {
|
||||||
type: 'Image',
|
type: 'Image',
|
||||||
url: this.getThumbnailUrl(baseUrlHttp),
|
url: this.getThumbnailUrl(baseUrlHttp),
|
||||||
|
|
|
@ -255,6 +255,14 @@ describe('Test users API validators', function () {
|
||||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: 'super token', fields, statusCodeExpected: 401 })
|
await makePutBodyRequest({ url: server.url, path: path + 'me', token: 'super token', fields, statusCodeExpected: 401 })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should fail with a too long description', async function () {
|
||||||
|
const fields = {
|
||||||
|
description: 'super'.repeat(60)
|
||||||
|
}
|
||||||
|
|
||||||
|
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
|
||||||
|
})
|
||||||
|
|
||||||
it('Should succeed with the correct params', async function () {
|
it('Should succeed with the correct params', async function () {
|
||||||
const fields = {
|
const fields = {
|
||||||
password: 'my super password',
|
password: 'my super password',
|
||||||
|
|
|
@ -62,7 +62,8 @@ describe('Test videos API validator', function () {
|
||||||
describe('When adding a video channel', function () {
|
describe('When adding a video channel', function () {
|
||||||
const baseCorrectParams = {
|
const baseCorrectParams = {
|
||||||
name: 'hello',
|
name: 'hello',
|
||||||
description: 'super description'
|
description: 'super description',
|
||||||
|
support: 'super support text'
|
||||||
}
|
}
|
||||||
|
|
||||||
it('Should fail with a non authenticated user', async function () {
|
it('Should fail with a non authenticated user', async function () {
|
||||||
|
@ -89,13 +90,18 @@ describe('Test videos API validator', function () {
|
||||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should fail with a long support text', async function () {
|
||||||
|
const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(70) })
|
||||||
|
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||||
|
})
|
||||||
|
|
||||||
it('Should succeed with the correct parameters', async function () {
|
it('Should succeed with the correct parameters', async function () {
|
||||||
await makePostBodyRequest({
|
await makePostBodyRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
path,
|
path,
|
||||||
token: server.accessToken,
|
token: server.accessToken,
|
||||||
fields: baseCorrectParams,
|
fields: baseCorrectParams,
|
||||||
statusCodeExpected: 204
|
statusCodeExpected: 200
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -143,6 +149,11 @@ describe('Test videos API validator', function () {
|
||||||
await makePutBodyRequest({ url: server.url, path: path + '/' + videoChannelId, token: server.accessToken, fields })
|
await makePutBodyRequest({ url: server.url, path: path + '/' + videoChannelId, token: server.accessToken, fields })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should fail with a long support text', async function () {
|
||||||
|
const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(70) })
|
||||||
|
await makePutBodyRequest({ url: server.url, path: path + '/' + videoChannelId, token: server.accessToken, fields })
|
||||||
|
})
|
||||||
|
|
||||||
it('Should succeed with the correct parameters', async function () {
|
it('Should succeed with the correct parameters', async function () {
|
||||||
await makePutBodyRequest({
|
await makePutBodyRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
|
|
|
@ -102,6 +102,7 @@ describe('Test videos API validator', function () {
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
commentsEnabled: true,
|
commentsEnabled: true,
|
||||||
description: 'my super description',
|
description: 'my super description',
|
||||||
|
support: 'my super support text',
|
||||||
tags: [ 'tag1', 'tag2' ],
|
tags: [ 'tag1', 'tag2' ],
|
||||||
privacy: VideoPrivacy.PUBLIC,
|
privacy: VideoPrivacy.PUBLIC,
|
||||||
channelId
|
channelId
|
||||||
|
@ -178,7 +179,14 @@ describe('Test videos API validator', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a long description', async function () {
|
it('Should fail with a long description', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(1500) })
|
const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) })
|
||||||
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a long support text', async function () {
|
||||||
|
const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(70) })
|
||||||
const attaches = baseCorrectAttaches
|
const attaches = baseCorrectAttaches
|
||||||
|
|
||||||
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
|
||||||
|
@ -417,7 +425,13 @@ describe('Test videos API validator', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a long description', async function () {
|
it('Should fail with a long description', async function () {
|
||||||
const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(1500) })
|
const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) })
|
||||||
|
|
||||||
|
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a long support text', async function () {
|
||||||
|
const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(70) })
|
||||||
|
|
||||||
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
|
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
|
||||||
})
|
})
|
||||||
|
|
|
@ -280,6 +280,7 @@ describe('Test follows', function () {
|
||||||
language: 3,
|
language: 3,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description',
|
description: 'my super description',
|
||||||
|
support: 'my super support text',
|
||||||
host: 'localhost:9003',
|
host: 'localhost:9003',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal,
|
isLocal,
|
||||||
|
|
|
@ -36,6 +36,7 @@ describe('Test handle downs', function () {
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
privacy: VideoPrivacy.PUBLIC,
|
privacy: VideoPrivacy.PUBLIC,
|
||||||
description: 'my super description for server 1',
|
description: 'my super description for server 1',
|
||||||
|
support: 'my super support text for server 1',
|
||||||
tags: [ 'tag1p1', 'tag2p1' ],
|
tags: [ 'tag1p1', 'tag2p1' ],
|
||||||
fixture: 'video_short1.webm'
|
fixture: 'video_short1.webm'
|
||||||
}
|
}
|
||||||
|
@ -51,6 +52,7 @@ describe('Test handle downs', function () {
|
||||||
language: 9,
|
language: 9,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 1',
|
description: 'my super description for server 1',
|
||||||
|
support: 'my super support text for server 1',
|
||||||
host: 'localhost:9001',
|
host: 'localhost:9001',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal: false,
|
isLocal: false,
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import 'mocha'
|
import 'mocha'
|
||||||
import { Account } from '../../../../shared/models/actors'
|
import { Account } from '../../../../shared/models/actors'
|
||||||
import { checkVideoFilesWereRemoved, createUser, doubleFollow, flushAndRunMultipleServers, removeUser, userLogin, wait } from '../../utils'
|
import {
|
||||||
|
checkVideoFilesWereRemoved, createUser, doubleFollow, flushAndRunMultipleServers, removeUser, updateMyUser, userLogin,
|
||||||
|
wait
|
||||||
|
} from '../../utils'
|
||||||
import { flushTests, getMyUserInformation, killallServers, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../utils/index'
|
import { flushTests, getMyUserInformation, killallServers, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../utils/index'
|
||||||
import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../utils/users/accounts'
|
import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../utils/users/accounts'
|
||||||
import { setAccessTokensToServers } from '../../utils/users/login'
|
import { setAccessTokensToServers } from '../../utils/users/login'
|
||||||
|
@ -51,6 +54,22 @@ describe('Test users with multiple servers', function () {
|
||||||
await wait(5000)
|
await wait(5000)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should be able to update my description', async function () {
|
||||||
|
this.timeout(10000)
|
||||||
|
|
||||||
|
await updateMyUser({
|
||||||
|
url: servers[0].url,
|
||||||
|
accessToken: servers[0].accessToken,
|
||||||
|
description: 'my super description updated'
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
|
||||||
|
user = res.body
|
||||||
|
expect(user.account.description).to.equal('my super description updated')
|
||||||
|
|
||||||
|
await wait(5000)
|
||||||
|
})
|
||||||
|
|
||||||
it('Should be able to update my avatar', async function () {
|
it('Should be able to update my avatar', async function () {
|
||||||
this.timeout(10000)
|
this.timeout(10000)
|
||||||
|
|
||||||
|
@ -70,7 +89,7 @@ describe('Test users with multiple servers', function () {
|
||||||
await wait(5000)
|
await wait(5000)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have updated my avatar on other servers too', async function () {
|
it('Should have updated my avatar and my description on other servers too', async function () {
|
||||||
for (const server of servers) {
|
for (const server of servers) {
|
||||||
const resAccounts = await getAccountsList(server.url, '-createdAt')
|
const resAccounts = await getAccountsList(server.url, '-createdAt')
|
||||||
|
|
||||||
|
@ -81,6 +100,7 @@ describe('Test users with multiple servers', function () {
|
||||||
const rootServer1Get = resAccount.body as Account
|
const rootServer1Get = resAccount.body as Account
|
||||||
expect(rootServer1Get.name).to.equal('root')
|
expect(rootServer1Get.name).to.equal('root')
|
||||||
expect(rootServer1Get.host).to.equal('localhost:9001')
|
expect(rootServer1Get.host).to.equal('localhost:9001')
|
||||||
|
expect(rootServer1Get.description).to.equal('my super description updated')
|
||||||
|
|
||||||
await testImage(server.url, 'avatar2-resized', rootServer1Get.avatar.path, '.png')
|
await testImage(server.url, 'avatar2-resized', rootServer1Get.avatar.path, '.png')
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,7 @@ describe('Test users', function () {
|
||||||
expect(user.videoQuota).to.equal(2 * 1024 * 1024)
|
expect(user.videoQuota).to.equal(2 * 1024 * 1024)
|
||||||
expect(user.roleLabel).to.equal('User')
|
expect(user.roleLabel).to.equal('User')
|
||||||
expect(user.id).to.be.a('number')
|
expect(user.id).to.be.a('number')
|
||||||
|
expect(user.account.description).to.be.null
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should be able to upload a video with this user', async function () {
|
it('Should be able to upload a video with this user', async function () {
|
||||||
|
@ -315,6 +316,7 @@ describe('Test users', function () {
|
||||||
expect(user.displayNSFW).to.be.ok
|
expect(user.displayNSFW).to.be.ok
|
||||||
expect(user.videoQuota).to.equal(2 * 1024 * 1024)
|
expect(user.videoQuota).to.equal(2 * 1024 * 1024)
|
||||||
expect(user.id).to.be.a('number')
|
expect(user.id).to.be.a('number')
|
||||||
|
expect(user.account.description).to.be.null
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should be able to change the autoPlayVideo attribute', async function () {
|
it('Should be able to change the autoPlayVideo attribute', async function () {
|
||||||
|
@ -345,6 +347,7 @@ describe('Test users', function () {
|
||||||
expect(user.displayNSFW).to.be.ok
|
expect(user.displayNSFW).to.be.ok
|
||||||
expect(user.videoQuota).to.equal(2 * 1024 * 1024)
|
expect(user.videoQuota).to.equal(2 * 1024 * 1024)
|
||||||
expect(user.id).to.be.a('number')
|
expect(user.id).to.be.a('number')
|
||||||
|
expect(user.account.description).to.be.null
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should be able to update my avatar', async function () {
|
it('Should be able to update my avatar', async function () {
|
||||||
|
@ -362,6 +365,24 @@ describe('Test users', function () {
|
||||||
await testImage(server.url, 'avatar-resized', user.account.avatar.path, '.png')
|
await testImage(server.url, 'avatar-resized', user.account.avatar.path, '.png')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should be able to update my description', async function () {
|
||||||
|
await updateMyUser({
|
||||||
|
url: server.url,
|
||||||
|
accessToken: accessTokenUser,
|
||||||
|
description: 'my super description updated'
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await getMyUserInformation(server.url, accessTokenUser)
|
||||||
|
const user = res.body
|
||||||
|
|
||||||
|
expect(user.username).to.equal('user_1')
|
||||||
|
expect(user.email).to.equal('updated@example.com')
|
||||||
|
expect(user.displayNSFW).to.be.ok
|
||||||
|
expect(user.videoQuota).to.equal(2 * 1024 * 1024)
|
||||||
|
expect(user.id).to.be.a('number')
|
||||||
|
expect(user.account.description).to.equal('my super description updated')
|
||||||
|
})
|
||||||
|
|
||||||
it('Should be able to update another user', async function () {
|
it('Should be able to update another user', async function () {
|
||||||
await updateUser({
|
await updateUser({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
|
|
|
@ -70,6 +70,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 9,
|
language: 9,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 1',
|
description: 'my super description for server 1',
|
||||||
|
support: 'my super support text for server 1',
|
||||||
tags: [ 'tag1p1', 'tag2p1' ],
|
tags: [ 'tag1p1', 'tag2p1' ],
|
||||||
channelId: videoChannelId,
|
channelId: videoChannelId,
|
||||||
fixture: 'video_short1.webm'
|
fixture: 'video_short1.webm'
|
||||||
|
@ -88,6 +89,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 9,
|
language: 9,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 1',
|
description: 'my super description for server 1',
|
||||||
|
support: 'my super support text for server 1',
|
||||||
host: 'localhost:9001',
|
host: 'localhost:9001',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal,
|
isLocal,
|
||||||
|
@ -136,6 +138,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 11,
|
language: 11,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 2',
|
description: 'my super description for server 2',
|
||||||
|
support: 'my super support text for server 2',
|
||||||
tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
|
tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
|
||||||
fixture: 'video_short2.webm',
|
fixture: 'video_short2.webm',
|
||||||
thumbnailfile: 'thumbnail.jpg',
|
thumbnailfile: 'thumbnail.jpg',
|
||||||
|
@ -156,6 +159,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 11,
|
language: 11,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 2',
|
description: 'my super description for server 2',
|
||||||
|
support: 'my super support text for server 2',
|
||||||
host: 'localhost:9002',
|
host: 'localhost:9002',
|
||||||
account: 'user1',
|
account: 'user1',
|
||||||
isLocal,
|
isLocal,
|
||||||
|
@ -211,6 +215,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 11,
|
language: 11,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 3',
|
description: 'my super description for server 3',
|
||||||
|
support: 'my super support text for server 3',
|
||||||
tags: [ 'tag1p3' ],
|
tags: [ 'tag1p3' ],
|
||||||
fixture: 'video_short3.webm'
|
fixture: 'video_short3.webm'
|
||||||
}
|
}
|
||||||
|
@ -223,6 +228,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 12,
|
language: 12,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
description: 'my super description for server 3-2',
|
description: 'my super description for server 3-2',
|
||||||
|
support: 'my super support text for server 3-2',
|
||||||
tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
|
tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
|
||||||
fixture: 'video_short.webm'
|
fixture: 'video_short.webm'
|
||||||
}
|
}
|
||||||
|
@ -257,6 +263,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 11,
|
language: 11,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description for server 3',
|
description: 'my super description for server 3',
|
||||||
|
support: 'my super support text for server 3',
|
||||||
host: 'localhost:9003',
|
host: 'localhost:9003',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal,
|
isLocal,
|
||||||
|
@ -286,6 +293,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 12,
|
language: 12,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
description: 'my super description for server 3-2',
|
description: 'my super description for server 3-2',
|
||||||
|
support: 'my super support text for server 3-2',
|
||||||
host: 'localhost:9003',
|
host: 'localhost:9003',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
commentsEnabled: true,
|
commentsEnabled: true,
|
||||||
|
@ -525,6 +533,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 13,
|
language: 13,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description updated',
|
description: 'my super description updated',
|
||||||
|
support: 'my super support text updated',
|
||||||
tags: [ 'tag_up_1', 'tag_up_2' ],
|
tags: [ 'tag_up_1', 'tag_up_2' ],
|
||||||
thumbnailfile: 'thumbnail.jpg',
|
thumbnailfile: 'thumbnail.jpg',
|
||||||
previewfile: 'preview.jpg'
|
previewfile: 'preview.jpg'
|
||||||
|
@ -553,6 +562,7 @@ describe('Test multiple servers', function () {
|
||||||
language: 13,
|
language: 13,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description updated',
|
description: 'my super description updated',
|
||||||
|
support: 'my super support text updated',
|
||||||
host: 'localhost:9003',
|
host: 'localhost:9003',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal,
|
isLocal,
|
||||||
|
@ -841,6 +851,7 @@ describe('Test multiple servers', function () {
|
||||||
language: null,
|
language: null,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
description: null,
|
description: null,
|
||||||
|
support: null,
|
||||||
host: 'localhost:9002',
|
host: 'localhost:9002',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal,
|
isLocal,
|
||||||
|
|
|
@ -26,6 +26,7 @@ describe('Test a single server', function () {
|
||||||
language: 3,
|
language: 3,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description',
|
description: 'my super description',
|
||||||
|
support: 'my super support text',
|
||||||
host: 'localhost:9001',
|
host: 'localhost:9001',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
|
@ -54,6 +55,7 @@ describe('Test a single server', function () {
|
||||||
language: 5,
|
language: 5,
|
||||||
nsfw: false,
|
nsfw: false,
|
||||||
description: 'my super description updated',
|
description: 'my super description updated',
|
||||||
|
support: 'my super support text updated',
|
||||||
host: 'localhost:9001',
|
host: 'localhost:9001',
|
||||||
account: 'root',
|
account: 'root',
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
/* tslint:disable:no-unused-expression */
|
/* tslint:disable:no-unused-expression */
|
||||||
|
|
||||||
import 'mocha'
|
|
||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
|
import 'mocha'
|
||||||
|
import { User } from '../../../../shared/index'
|
||||||
|
import { doubleFollow, flushAndRunMultipleServers, uploadVideo, wait } from '../../utils'
|
||||||
|
import {
|
||||||
|
addVideoChannel,
|
||||||
|
deleteVideoChannel,
|
||||||
|
flushTests,
|
||||||
|
getAccountVideoChannelsList,
|
||||||
|
getMyUserInformation,
|
||||||
|
getVideoChannel,
|
||||||
|
getVideoChannelsList,
|
||||||
|
killallServers,
|
||||||
|
ServerInfo,
|
||||||
|
setAccessTokensToServers,
|
||||||
|
updateVideoChannel
|
||||||
|
} from '../../utils/index'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
import {
|
describe('Test video channels', function () {
|
||||||
ServerInfo,
|
let servers: ServerInfo[]
|
||||||
flushTests,
|
|
||||||
runServer,
|
|
||||||
setAccessTokensToServers,
|
|
||||||
killallServers,
|
|
||||||
getMyUserInformation,
|
|
||||||
getVideoChannelsList,
|
|
||||||
addVideoChannel,
|
|
||||||
getAccountVideoChannelsList,
|
|
||||||
updateVideoChannel,
|
|
||||||
deleteVideoChannel,
|
|
||||||
getVideoChannel
|
|
||||||
} from '../../utils/index'
|
|
||||||
import { User } from '../../../../shared/index'
|
|
||||||
|
|
||||||
describe('Test a video channels', function () {
|
|
||||||
let server: ServerInfo
|
|
||||||
let userInfo: User
|
let userInfo: User
|
||||||
let videoChannelId: number
|
let videoChannelId: number
|
||||||
|
|
||||||
|
@ -30,29 +30,41 @@ describe('Test a video channels', function () {
|
||||||
|
|
||||||
await flushTests()
|
await flushTests()
|
||||||
|
|
||||||
server = await runServer(1)
|
servers = await flushAndRunMultipleServers(2)
|
||||||
|
|
||||||
await setAccessTokensToServers([ server ])
|
await setAccessTokensToServers(servers)
|
||||||
|
await doubleFollow(servers[0], servers[1])
|
||||||
|
|
||||||
|
await wait(5000)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have one video channel (created with root)', async () => {
|
it('Should have one video channel (created with root)', async () => {
|
||||||
const res = await getVideoChannelsList(server.url, 0, 2)
|
const res = await getVideoChannelsList(servers[0].url, 0, 2)
|
||||||
|
|
||||||
expect(res.body.total).to.equal(1)
|
expect(res.body.total).to.equal(1)
|
||||||
expect(res.body.data).to.be.an('array')
|
expect(res.body.data).to.be.an('array')
|
||||||
expect(res.body.data).to.have.lengthOf(1)
|
expect(res.body.data).to.have.lengthOf(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should create another video channel', async () => {
|
it('Should create another video channel', async function () {
|
||||||
|
this.timeout(10000)
|
||||||
|
|
||||||
const videoChannel = {
|
const videoChannel = {
|
||||||
name: 'second video channel',
|
name: 'second video channel',
|
||||||
description: 'super video channel description'
|
description: 'super video channel description',
|
||||||
|
support: 'super video channel support text'
|
||||||
}
|
}
|
||||||
await addVideoChannel(server.url, server.accessToken, videoChannel)
|
const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
|
||||||
|
videoChannelId = res.body.videoChannel.id
|
||||||
|
|
||||||
|
// The channel is 1 is propagated to servers 2
|
||||||
|
await uploadVideo(servers[0].url, servers[0].accessToken, { channelId: videoChannelId })
|
||||||
|
|
||||||
|
await wait(3000)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have two video channels when getting my information', async () => {
|
it('Should have two video channels when getting my information', async () => {
|
||||||
const res = await getMyUserInformation(server.url, server.accessToken)
|
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
|
||||||
userInfo = res.body
|
userInfo = res.body
|
||||||
|
|
||||||
expect(userInfo.videoChannels).to.be.an('array')
|
expect(userInfo.videoChannels).to.be.an('array')
|
||||||
|
@ -62,11 +74,11 @@ describe('Test a video channels', function () {
|
||||||
expect(videoChannels[0].displayName).to.equal('Default root channel')
|
expect(videoChannels[0].displayName).to.equal('Default root channel')
|
||||||
expect(videoChannels[1].displayName).to.equal('second video channel')
|
expect(videoChannels[1].displayName).to.equal('second video channel')
|
||||||
expect(videoChannels[1].description).to.equal('super video channel description')
|
expect(videoChannels[1].description).to.equal('super video channel description')
|
||||||
|
expect(videoChannels[1].support).to.equal('super video channel support text')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have two video channels when getting account channels', async () => {
|
it('Should have two video channels when getting account channels on server 1', async function () {
|
||||||
const res = await getAccountVideoChannelsList(server.url, userInfo.account.uuid)
|
const res = await getAccountVideoChannelsList(servers[0].url, userInfo.account.uuid)
|
||||||
|
|
||||||
expect(res.body.total).to.equal(2)
|
expect(res.body.total).to.equal(2)
|
||||||
expect(res.body.data).to.be.an('array')
|
expect(res.body.data).to.be.an('array')
|
||||||
expect(res.body.data).to.have.lengthOf(2)
|
expect(res.body.data).to.have.lengthOf(2)
|
||||||
|
@ -75,12 +87,23 @@ describe('Test a video channels', function () {
|
||||||
expect(videoChannels[0].displayName).to.equal('Default root channel')
|
expect(videoChannels[0].displayName).to.equal('Default root channel')
|
||||||
expect(videoChannels[1].displayName).to.equal('second video channel')
|
expect(videoChannels[1].displayName).to.equal('second video channel')
|
||||||
expect(videoChannels[1].description).to.equal('super video channel description')
|
expect(videoChannels[1].description).to.equal('super video channel description')
|
||||||
|
expect(videoChannels[1].support).to.equal('super video channel support text')
|
||||||
videoChannelId = videoChannels[1].id
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should list video channels', async () => {
|
it('Should have one video channel when getting account channels on server 2', async function () {
|
||||||
const res = await getVideoChannelsList(server.url, 1, 1, '-name')
|
const res = await getAccountVideoChannelsList(servers[1].url, userInfo.account.uuid)
|
||||||
|
expect(res.body.total).to.equal(1)
|
||||||
|
expect(res.body.data).to.be.an('array')
|
||||||
|
expect(res.body.data).to.have.lengthOf(1)
|
||||||
|
|
||||||
|
const videoChannels = res.body.data
|
||||||
|
expect(videoChannels[0].displayName).to.equal('second video channel')
|
||||||
|
expect(videoChannels[0].description).to.equal('super video channel description')
|
||||||
|
expect(videoChannels[0].support).to.equal('super video channel support text')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should list video channels', async function () {
|
||||||
|
const res = await getVideoChannelsList(servers[0].url, 1, 1, '-name')
|
||||||
|
|
||||||
expect(res.body.total).to.equal(2)
|
expect(res.body.total).to.equal(2)
|
||||||
expect(res.body.data).to.be.an('array')
|
expect(res.body.data).to.be.an('array')
|
||||||
|
@ -88,39 +111,48 @@ describe('Test a video channels', function () {
|
||||||
expect(res.body.data[0].displayName).to.equal('Default root channel')
|
expect(res.body.data[0].displayName).to.equal('Default root channel')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should update video channel', async () => {
|
it('Should update video channel', async function () {
|
||||||
|
this.timeout(5000)
|
||||||
|
|
||||||
const videoChannelAttributes = {
|
const videoChannelAttributes = {
|
||||||
name: 'video channel updated',
|
name: 'video channel updated',
|
||||||
description: 'video channel description updated'
|
description: 'video channel description updated',
|
||||||
|
support: 'video channel support text updated'
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateVideoChannel(server.url, server.accessToken, videoChannelId, videoChannelAttributes)
|
await updateVideoChannel(servers[0].url, servers[0].accessToken, videoChannelId, videoChannelAttributes)
|
||||||
|
|
||||||
|
await wait(3000)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have video channel updated', async () => {
|
it('Should have video channel updated', async function () {
|
||||||
const res = await getVideoChannelsList(server.url, 0, 1, '-name')
|
for (const server of servers) {
|
||||||
|
const res = await getVideoChannelsList(server.url, 0, 1, '-name')
|
||||||
|
|
||||||
expect(res.body.total).to.equal(2)
|
expect(res.body.total).to.equal(2)
|
||||||
expect(res.body.data).to.be.an('array')
|
expect(res.body.data).to.be.an('array')
|
||||||
expect(res.body.data).to.have.lengthOf(1)
|
expect(res.body.data).to.have.lengthOf(1)
|
||||||
expect(res.body.data[0].displayName).to.equal('video channel updated')
|
expect(res.body.data[0].displayName).to.equal('video channel updated')
|
||||||
expect(res.body.data[0].description).to.equal('video channel description updated')
|
expect(res.body.data[0].description).to.equal('video channel description updated')
|
||||||
|
expect(res.body.data[0].support).to.equal('video channel support text updated')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should get video channel', async () => {
|
it('Should get video channel', async function () {
|
||||||
const res = await getVideoChannel(server.url, videoChannelId)
|
const res = await getVideoChannel(servers[0].url, videoChannelId)
|
||||||
|
|
||||||
const videoChannel = res.body
|
const videoChannel = res.body
|
||||||
expect(videoChannel.displayName).to.equal('video channel updated')
|
expect(videoChannel.displayName).to.equal('video channel updated')
|
||||||
expect(videoChannel.description).to.equal('video channel description updated')
|
expect(videoChannel.description).to.equal('video channel description updated')
|
||||||
|
expect(videoChannel.support).to.equal('video channel support text updated')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should delete video channel', async () => {
|
it('Should delete video channel', async function () {
|
||||||
await deleteVideoChannel(server.url, server.accessToken, videoChannelId)
|
await deleteVideoChannel(servers[0].url, servers[0].accessToken, videoChannelId)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have video channel deleted', async () => {
|
it('Should have video channel deleted', async function () {
|
||||||
const res = await getVideoChannelsList(server.url, 0, 10)
|
const res = await getVideoChannelsList(servers[0].url, 0, 10)
|
||||||
|
|
||||||
expect(res.body.total).to.equal(1)
|
expect(res.body.total).to.equal(1)
|
||||||
expect(res.body.data).to.be.an('array')
|
expect(res.body.data).to.be.an('array')
|
||||||
|
@ -129,7 +161,7 @@ describe('Test a video channels', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
after(async function () {
|
after(async function () {
|
||||||
killallServers([ server ])
|
killallServers(servers)
|
||||||
|
|
||||||
// Keep the logs if the test failed
|
// Keep the logs if the test failed
|
||||||
if (this['ok']) {
|
if (this['ok']) {
|
||||||
|
|
|
@ -131,6 +131,7 @@ function updateMyUser (options: {
|
||||||
displayNSFW?: boolean,
|
displayNSFW?: boolean,
|
||||||
email?: string,
|
email?: string,
|
||||||
autoPlayVideo?: boolean
|
autoPlayVideo?: boolean
|
||||||
|
description?: string
|
||||||
}) {
|
}) {
|
||||||
const path = '/api/v1/users/me'
|
const path = '/api/v1/users/me'
|
||||||
|
|
||||||
|
@ -139,6 +140,7 @@ function updateMyUser (options: {
|
||||||
if (options.displayNSFW !== undefined && options.displayNSFW !== null) toSend['displayNSFW'] = options.displayNSFW
|
if (options.displayNSFW !== undefined && options.displayNSFW !== null) toSend['displayNSFW'] = options.displayNSFW
|
||||||
if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo
|
if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo
|
||||||
if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
|
if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
|
||||||
|
if (options.description !== undefined && options.description !== null) toSend['description'] = options.description
|
||||||
|
|
||||||
return makePutBodyRequest({
|
return makePutBodyRequest({
|
||||||
url: options.url,
|
url: options.url,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as request from 'supertest'
|
||||||
type VideoChannelAttributes = {
|
type VideoChannelAttributes = {
|
||||||
name?: string
|
name?: string
|
||||||
description?: string
|
description?: string
|
||||||
|
support?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVideoChannelsList (url: string, start: number, count: number, sort?: string) {
|
function getVideoChannelsList (url: string, start: number, count: number, sort?: string) {
|
||||||
|
@ -30,13 +31,14 @@ function getAccountVideoChannelsList (url: string, accountId: number | string, s
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addVideoChannel (url: string, token: string, videoChannelAttributesArg: VideoChannelAttributes, expectedStatus = 204) {
|
function addVideoChannel (url: string, token: string, videoChannelAttributesArg: VideoChannelAttributes, expectedStatus = 200) {
|
||||||
const path = '/api/v1/videos/channels'
|
const path = '/api/v1/videos/channels'
|
||||||
|
|
||||||
// Default attributes
|
// Default attributes
|
||||||
let attributes = {
|
let attributes = {
|
||||||
name: 'my super video channel',
|
name: 'my super video channel',
|
||||||
description: 'my super channel description'
|
description: 'my super channel description',
|
||||||
|
support: 'my super channel support'
|
||||||
}
|
}
|
||||||
attributes = Object.assign(attributes, videoChannelAttributesArg)
|
attributes = Object.assign(attributes, videoChannelAttributesArg)
|
||||||
|
|
||||||
|
@ -54,6 +56,7 @@ function updateVideoChannel (url: string, token: string, channelId: number, attr
|
||||||
|
|
||||||
if (attributes.name) body['name'] = attributes.name
|
if (attributes.name) body['name'] = attributes.name
|
||||||
if (attributes.description) body['description'] = attributes.description
|
if (attributes.description) body['description'] = attributes.description
|
||||||
|
if (attributes.support) body['support'] = attributes.support
|
||||||
|
|
||||||
return request(url)
|
return request(url)
|
||||||
.put(path)
|
.put(path)
|
||||||
|
|
|
@ -248,6 +248,7 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
|
||||||
channelId: defaultChannelId,
|
channelId: defaultChannelId,
|
||||||
nsfw: true,
|
nsfw: true,
|
||||||
description: 'my super description',
|
description: 'my super description',
|
||||||
|
support: 'my super support text',
|
||||||
tags: [ 'tag' ],
|
tags: [ 'tag' ],
|
||||||
privacy: VideoPrivacy.PUBLIC,
|
privacy: VideoPrivacy.PUBLIC,
|
||||||
commentsEnabled: true,
|
commentsEnabled: true,
|
||||||
|
@ -277,6 +278,10 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
|
||||||
req.field('licence', attributes.licence.toString())
|
req.field('licence', attributes.licence.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < attributes.tags.length; i++) {
|
||||||
|
req.field('tags[' + i + ']', attributes.tags[i])
|
||||||
|
}
|
||||||
|
|
||||||
if (attributes.thumbnailfile !== undefined) {
|
if (attributes.thumbnailfile !== undefined) {
|
||||||
req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
|
req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
|
||||||
}
|
}
|
||||||
|
@ -284,10 +289,6 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
|
||||||
req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
|
req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < attributes.tags.length; i++) {
|
|
||||||
req.field('tags[' + i + ']', attributes.tags[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
|
return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
|
||||||
.expect(specialStatus)
|
.expect(specialStatus)
|
||||||
}
|
}
|
||||||
|
@ -366,6 +367,7 @@ async function completeVideoCheck (
|
||||||
nsfw: boolean
|
nsfw: boolean
|
||||||
commentsEnabled: boolean
|
commentsEnabled: boolean
|
||||||
description: string
|
description: string
|
||||||
|
support: string
|
||||||
host: string
|
host: string
|
||||||
account: string
|
account: string
|
||||||
isLocal: boolean,
|
isLocal: boolean,
|
||||||
|
|
|
@ -19,6 +19,7 @@ program
|
||||||
.option('-L, --language <language number>', 'Language number')
|
.option('-L, --language <language number>', 'Language number')
|
||||||
.option('-d, --video-description <description>', 'Video description')
|
.option('-d, --video-description <description>', 'Video description')
|
||||||
.option('-t, --tags <tags>', 'Video tags', list)
|
.option('-t, --tags <tags>', 'Video tags', list)
|
||||||
|
.option('-b, --thumbnail <thumbnailPath>', 'Thumbnail path')
|
||||||
.option('-f, --file <file>', 'Video absolute file path')
|
.option('-f, --file <file>', 'Video absolute file path')
|
||||||
.parse(process.argv)
|
.parse(process.argv)
|
||||||
|
|
||||||
|
@ -72,7 +73,8 @@ async function run () {
|
||||||
description: program['videoDescription'],
|
description: program['videoDescription'],
|
||||||
tags: program['tags'],
|
tags: program['tags'],
|
||||||
commentsEnabled: program['commentsEnabled'],
|
commentsEnabled: program['commentsEnabled'],
|
||||||
fixture: program['file']
|
fixture: program['file'],
|
||||||
|
thumbnailfile: program['thumbnailPath']
|
||||||
}
|
}
|
||||||
|
|
||||||
await uploadVideo(program['url'], accessToken, videoAttributes)
|
await uploadVideo(program['url'], accessToken, videoAttributes)
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface ActivityPubActor {
|
||||||
summary: string
|
summary: string
|
||||||
attributedTo: ActivityPubAttributedTo[]
|
attributedTo: ActivityPubAttributedTo[]
|
||||||
|
|
||||||
|
support?: string
|
||||||
uuid: string
|
uuid: string
|
||||||
publicKey: {
|
publicKey: {
|
||||||
id: string
|
id: string
|
||||||
|
@ -26,11 +27,9 @@ export interface ActivityPubActor {
|
||||||
publicKeyPem: string
|
publicKeyPem: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not used
|
|
||||||
icon: {
|
icon: {
|
||||||
type: 'Image'
|
type: 'Image'
|
||||||
mediaType: 'image/png'
|
mediaType: 'image/png'
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
// liked: string
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ export interface VideoTorrentObject {
|
||||||
updated: string
|
updated: string
|
||||||
mediaType: 'text/markdown'
|
mediaType: 'text/markdown'
|
||||||
content: string
|
content: string
|
||||||
|
support: string
|
||||||
icon: ActivityIconObject
|
icon: ActivityIconObject
|
||||||
url: ActivityUrlObject[]
|
url: ActivityUrlObject[]
|
||||||
likes?: ActivityPubOrderedCollection<string>
|
likes?: ActivityPubOrderedCollection<string>
|
||||||
|
|
|
@ -2,4 +2,5 @@ import { Actor } from './actor.model'
|
||||||
|
|
||||||
export interface Account extends Actor {
|
export interface Account extends Actor {
|
||||||
displayName: string
|
displayName: string
|
||||||
|
description: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export interface UserUpdateMe {
|
export interface UserUpdateMe {
|
||||||
|
description?: string
|
||||||
displayNSFW?: boolean
|
displayNSFW?: boolean
|
||||||
autoPlayVideo?: boolean
|
autoPlayVideo?: boolean
|
||||||
email?: string
|
email?: string
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export interface VideoChannelCreate {
|
export interface VideoChannelCreate {
|
||||||
name: string
|
name: string
|
||||||
description?: string
|
description?: string
|
||||||
|
support?: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export interface VideoChannelUpdate {
|
export interface VideoChannelUpdate {
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description?: string
|
||||||
|
support?: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { Video } from './video.model'
|
||||||
export interface VideoChannel extends Actor {
|
export interface VideoChannel extends Actor {
|
||||||
displayName: string
|
displayName: string
|
||||||
description: string
|
description: string
|
||||||
|
support: string
|
||||||
isLocal: boolean
|
isLocal: boolean
|
||||||
owner?: {
|
owner?: {
|
||||||
name: string
|
name: string
|
||||||
|
|
|
@ -5,6 +5,7 @@ export interface VideoCreate {
|
||||||
licence?: number
|
licence?: number
|
||||||
language?: number
|
language?: number
|
||||||
description?: string
|
description?: string
|
||||||
|
support?: string
|
||||||
channelId: number
|
channelId: number
|
||||||
nsfw: boolean
|
nsfw: boolean
|
||||||
name: string
|
name: string
|
||||||
|
|
|
@ -6,6 +6,7 @@ export interface VideoUpdate {
|
||||||
licence?: number
|
licence?: number
|
||||||
language?: number
|
language?: number
|
||||||
description?: string
|
description?: string
|
||||||
|
support?: string
|
||||||
privacy?: VideoPrivacy
|
privacy?: VideoPrivacy
|
||||||
tags?: string[]
|
tags?: string[]
|
||||||
commentsEnabled?: boolean
|
commentsEnabled?: boolean
|
||||||
|
|
|
@ -41,6 +41,7 @@ export interface VideoDetails extends Video {
|
||||||
privacy: VideoPrivacy
|
privacy: VideoPrivacy
|
||||||
privacyLabel: string
|
privacyLabel: string
|
||||||
descriptionPath: string
|
descriptionPath: string
|
||||||
|
support: string
|
||||||
channel: VideoChannel
|
channel: VideoChannel
|
||||||
tags: string[]
|
tags: string[]
|
||||||
files: VideoFile[]
|
files: VideoFile[]
|
||||||
|
|
Loading…
Reference in New Issue