Propagate old comment on new follow

This commit is contained in:
Chocobozzz 2017-12-28 11:16:08 +01:00
parent f40bbe3146
commit da854ddd50
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
78 changed files with 386 additions and 307 deletions

View File

@ -1,4 +1,4 @@
import { getServerActor } from '../server/helpers'
import { getServerActor } from '../server/helpers/utils'
import { initDatabaseModels } from '../server/initializers'
import { ActorFollowModel } from '../server/models/activitypub/actor-follow'
import { VideoModel } from '../server/models/video/video'

View File

@ -1,14 +1,17 @@
// Intercept ActivityPub client requests
import * as express from 'express'
import { activityPubCollectionPagination, pageToStartAndCount } from '../../helpers'
import { activityPubCollectionPagination } from '../../helpers/activitypub'
import { pageToStartAndCount } from '../../helpers/core-utils'
import { ACTIVITY_PUB, CONFIG } from '../../initializers'
import { buildVideoAnnounceToFollowers } from '../../lib/activitypub/send'
import { asyncMiddleware, executeIfActivityPub, localAccountValidator } from '../../middlewares'
import { videoChannelsGetValidator, videosGetValidator, videosShareValidator } from '../../middlewares/validators'
import { videoCommentGetValidator } from '../../middlewares/validators/video-comments'
import { AccountModel } from '../../models/account/account'
import { ActorFollowModel } from '../../models/activitypub/actor-follow'
import { VideoModel } from '../../models/video/video'
import { VideoChannelModel } from '../../models/video/video-channel'
import { VideoCommentModel } from '../../models/video/video-comment'
import { VideoShareModel } from '../../models/video/video-share'
const activityPubClientRouter = express.Router()
@ -30,7 +33,7 @@ activityPubClientRouter.get('/account/:name/following',
activityPubClientRouter.get('/videos/watch/:id',
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
executeIfActivityPub(videoController)
executeIfActivityPub(asyncMiddleware(videoController))
)
activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
@ -38,6 +41,11 @@ activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
executeIfActivityPub(asyncMiddleware(videoAnnounceController))
)
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',
executeIfActivityPub(asyncMiddleware(videoCommentGetValidator)),
executeIfActivityPub(asyncMiddleware(videoCommentController))
)
activityPubClientRouter.get('/video-channels/:id',
executeIfActivityPub(asyncMiddleware(videoChannelsGetValidator)),
executeIfActivityPub(asyncMiddleware(videoChannelController))
@ -54,7 +62,8 @@ export {
function accountController (req: express.Request, res: express.Response, next: express.NextFunction) {
const account: AccountModel = res.locals.account
return res.json(account.toActivityPubObject()).end()
return res.json(account.toActivityPubObject())
.end()
}
async function accountFollowersController (req: express.Request, res: express.Response, next: express.NextFunction) {
@ -81,10 +90,12 @@ async function accountFollowingController (req: express.Request, res: express.Re
return res.json(activityPubResult)
}
function videoController (req: express.Request, res: express.Response, next: express.NextFunction) {
async function videoController (req: express.Request, res: express.Response, next: express.NextFunction) {
const video: VideoModel = res.locals.video
return res.json(video.toActivityPubObject())
// We need more attributes
const videoAll = await VideoModel.loadAndPopulateAll(video.id)
return res.json(videoAll.toActivityPubObject())
}
async function videoAnnounceController (req: express.Request, res: express.Response, next: express.NextFunction) {
@ -99,3 +110,9 @@ async function videoChannelController (req: express.Request, res: express.Respon
return res.json(videoChannel.toActivityPubObject())
}
async function videoCommentController (req: express.Request, res: express.Response, next: express.NextFunction) {
const videoComment: VideoCommentModel = res.locals.videoComment
return res.json(videoComment.toActivityPubObject())
}

View File

@ -1,7 +1,7 @@
import * as express from 'express'
import { Activity, ActivityPubCollection, ActivityPubOrderedCollection, RootActivity } from '../../../shared'
import { logger } from '../../helpers'
import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity'
import { logger } from '../../helpers/logger'
import { processActivities } from '../../lib/activitypub/process/process'
import { asyncMiddleware, checkSignature, localAccountValidator, signatureValidator } from '../../middlewares'
import { activityPubValidator } from '../../middlewares/validators/activitypub/activity'

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import { isSignupAllowed } from '../../helpers/utils'
import { isSignupAllowed } from '../../helpers'
import { CONFIG } from '../../initializers'
import { asyncMiddleware } from '../../middlewares'
import { ServerConfig } from '../../../shared'

View File

@ -1,13 +1,11 @@
import * as express from 'express'
import { badRequest } from '../../helpers'
import { oauthClientsRouter } from './oauth-clients'
import { badRequest } from '../../helpers/utils'
import { configRouter } from './config'
import { jobsRouter } from './jobs'
import { oauthClientsRouter } from './oauth-clients'
import { serverRouter } from './server'
import { usersRouter } from './users'
import { videosRouter } from './videos'
import { jobsRouter } from './jobs'
const apiRouter = express.Router()

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import { UserRight } from '../../../shared/models/users'
import { getFormattedObjects } from '../../helpers'
import { getFormattedObjects } from '../../helpers/utils'
import { asyncMiddleware, authenticate, ensureUserHasRight, jobsSortValidator, setJobsSort, setPagination } from '../../middlewares'
import { paginationValidator } from '../../middlewares/validators'
import { JobModel } from '../../models/job/job'

View File

@ -1,9 +1,8 @@
import * as express from 'express'
import { CONFIG } from '../../initializers'
import { logger } from '../../helpers'
import { asyncMiddleware } from '../../middlewares'
import { OAuthClientLocal } from '../../../shared'
import { logger } from '../../helpers/logger'
import { CONFIG } from '../../initializers'
import { asyncMiddleware } from '../../middlewares'
import { OAuthClientModel } from '../../models/oauth/oauth-client'
const oauthClientsRouter = express.Router()

View File

@ -1,11 +1,12 @@
import * as express from 'express'
import { UserRight } from '../../../../shared/models/users'
import {
getFormattedObjects, getServerActor, loadActorUrlOrGetFromWebfinger, logger, retryTransactionWrapper,
sanitizeHost
} from '../../../helpers'
import { sanitizeHost } from '../../../helpers/core-utils'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { getFormattedObjects, getServerActor } from '../../../helpers/utils'
import { loadActorUrlOrGetFromWebfinger } from '../../../helpers/webfinger'
import { REMOTE_SCHEME, sequelizeTypescript, SERVER_ACTOR_NAME } from '../../../initializers'
import { getOrCreateActorAndServerAndModel } from '../../../lib/activitypub'
import { getOrCreateActorAndServerAndModel } from '../../../lib/activitypub/actor'
import { sendFollow, sendUndoFollow } from '../../../lib/activitypub/send'
import {
asyncMiddleware, authenticate, ensureUserHasRight, paginationValidator, removeFollowingValidator, setBodyHostsPort,

View File

@ -1,26 +1,14 @@
import * as express from 'express'
import { UserCreate, UserRight, UserRole, UserUpdate, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../shared'
import { getFormattedObjects, logger, retryTransactionWrapper } from '../../helpers'
import { retryTransactionWrapper } from '../../helpers/database-utils'
import { logger } from '../../helpers/logger'
import { getFormattedObjects } from '../../helpers/utils'
import { CONFIG } from '../../initializers'
import { createUserAccountAndChannel } from '../../lib/user'
import {
asyncMiddleware,
authenticate,
ensureUserHasRight,
ensureUserRegistrationAllowed,
paginationValidator,
setPagination,
setUsersSort,
setVideosSort,
token,
usersAddValidator,
usersGetValidator,
usersRegisterValidator,
usersRemoveValidator,
usersSortValidator,
usersUpdateMeValidator,
usersUpdateValidator,
usersVideoRatingValidator
asyncMiddleware, authenticate, ensureUserHasRight, ensureUserRegistrationAllowed, paginationValidator, setPagination, setUsersSort,
setVideosSort, token, usersAddValidator, usersGetValidator, usersRegisterValidator, usersRemoveValidator, usersSortValidator,
usersUpdateMeValidator, usersUpdateValidator, usersVideoRatingValidator
} from '../../middlewares'
import { videosSortValidator } from '../../middlewares/validators'
import { AccountVideoRateModel } from '../../models/account/account-video-rate'

View File

@ -1,17 +1,13 @@
import * as express from 'express'
import { UserRight, VideoAbuseCreate } from '../../../../shared'
import { getFormattedObjects, logger, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { getFormattedObjects } from '../../../helpers/utils'
import { sequelizeTypescript } from '../../../initializers'
import { sendVideoAbuse } from '../../../lib/activitypub/send'
import {
asyncMiddleware,
authenticate,
ensureUserHasRight,
paginationValidator,
setPagination,
setVideoAbusesSort,
videoAbuseReportValidator,
videoAbusesSortValidator
asyncMiddleware, authenticate, ensureUserHasRight, paginationValidator, setPagination, setVideoAbusesSort,
videoAbuseReportValidator, videoAbusesSortValidator
} from '../../../middlewares'
import { AccountModel } from '../../../models/account/account'
import { VideoModel } from '../../../models/video/video'

View File

@ -1,17 +1,11 @@
import * as express from 'express'
import { logger, getFormattedObjects } from '../../../helpers'
import {
authenticate,
ensureUserHasRight,
videosBlacklistAddValidator,
videosBlacklistRemoveValidator,
paginationValidator,
blacklistSortValidator,
setBlacklistSort,
setPagination,
asyncMiddleware
} from '../../../middlewares'
import { BlacklistedVideo, UserRight } from '../../../../shared'
import { logger } from '../../../helpers/logger'
import { getFormattedObjects } from '../../../helpers/utils'
import {
asyncMiddleware, authenticate, blacklistSortValidator, ensureUserHasRight, paginationValidator, setBlacklistSort, setPagination,
videosBlacklistAddValidator, videosBlacklistRemoveValidator
} from '../../../middlewares'
import { VideoBlacklistModel } from '../../../models/video/video-blacklist'
const blacklistRouter = express.Router()

View File

@ -1,20 +1,14 @@
import * as express from 'express'
import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared'
import { getFormattedObjects, logger, resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { getFormattedObjects, resetSequelizeInstance } from '../../../helpers/utils'
import { sequelizeTypescript } from '../../../initializers'
import { setAsyncActorKeys } from '../../../lib/activitypub'
import { createVideoChannel } from '../../../lib/video-channel'
import {
asyncMiddleware,
authenticate,
listVideoAccountChannelsValidator,
paginationValidator,
setPagination,
setVideoChannelsSort,
videoChannelsAddValidator,
videoChannelsGetValidator,
videoChannelsRemoveValidator,
videoChannelsSortValidator,
asyncMiddleware, authenticate, listVideoAccountChannelsValidator, paginationValidator, setPagination, setVideoChannelsSort,
videoChannelsAddValidator, videoChannelsGetValidator, videoChannelsRemoveValidator, videoChannelsSortValidator,
videoChannelsUpdateValidator
} from '../../../middlewares'
import { AccountModel } from '../../../models/account/account'

View File

@ -1,6 +1,7 @@
import * as express from 'express'
import { VideoCommentCreate } from '../../../../shared/models/videos/video-comment.model'
import { getFormattedObjects, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { getFormattedObjects } from '../../../helpers/utils'
import { sequelizeTypescript } from '../../../initializers'
import { buildFormattedCommentTree, createVideoComment } from '../../../lib/video-comment'
import { asyncMiddleware, authenticate, paginationValidator, setPagination, setVideoCommentThreadsSort } from '../../../middlewares'

View File

@ -2,44 +2,21 @@ import * as express from 'express'
import * as multer from 'multer'
import { extname, join } from 'path'
import { VideoCreate, VideoPrivacy, VideoUpdate } from '../../../../shared'
import { renamePromise } from '../../../helpers/core-utils'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { getVideoFileHeight } from '../../../helpers/ffmpeg-utils'
import { logger } from '../../../helpers/logger'
import { generateRandomString, getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils'
import {
generateRandomString,
getFormattedObjects,
getVideoFileHeight,
logger,
renamePromise,
resetSequelizeInstance,
retryTransactionWrapper
} from '../../../helpers'
import { getServerActor } from '../../../helpers/utils'
import {
CONFIG,
sequelizeTypescript,
VIDEO_CATEGORIES,
VIDEO_LANGUAGES,
VIDEO_LICENCES,
VIDEO_MIMETYPE_EXT,
CONFIG, sequelizeTypescript, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_MIMETYPE_EXT,
VIDEO_PRIVACIES
} from '../../../initializers'
import {
fetchRemoteVideoDescription,
getVideoActivityPubUrl,
shareVideoByServerAndChannel
} from '../../../lib/activitypub'
import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServerAndChannel } from '../../../lib/activitypub'
import { sendCreateVideo, sendCreateViewToOrigin, sendCreateViewToVideoFollowers, sendUpdateVideo } from '../../../lib/activitypub/send'
import { transcodingJobScheduler } from '../../../lib/jobs/transcoding-job-scheduler'
import {
asyncMiddleware,
authenticate,
paginationValidator,
setPagination,
setVideosSort,
videosAddValidator,
videosGetValidator,
videosRemoveValidator,
videosSearchValidator,
videosSortValidator,
videosUpdateValidator
asyncMiddleware, authenticate, paginationValidator, setPagination, setVideosSort, videosAddValidator, videosGetValidator,
videosRemoveValidator, videosSearchValidator, videosSortValidator, videosUpdateValidator
} from '../../../middlewares'
import { TagModel } from '../../../models/video/tag'
import { VideoModel } from '../../../models/video/video'

View File

@ -1,6 +1,7 @@
import * as express from 'express'
import { UserVideoRateUpdate } from '../../../../shared'
import { logger, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript, VIDEO_RATE_TYPES } from '../../../initializers'
import { sendVideoRateChangeToFollowers, sendVideoRateChangeToOrigin } from '../../../lib/activitypub'
import { asyncMiddleware, authenticate, videoRateValidator } from '../../../middlewares'

View File

@ -1,15 +1,9 @@
import * as Bluebird from 'bluebird'
import * as express from 'express'
import { join } from 'path'
import * as validator from 'validator'
import * as Bluebird from 'bluebird'
import {
CONFIG,
STATIC_PATHS,
STATIC_MAX_AGE,
OPENGRAPH_AND_OEMBED_COMMENT,
EMBED_SIZE
} from '../initializers'
import { root, readFileBufferPromise, escapeHTML } from '../helpers'
import { escapeHTML, readFileBufferPromise, root } from '../helpers/core-utils'
import { CONFIG, EMBED_SIZE, OPENGRAPH_AND_OEMBED_COMMENT, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers'
import { asyncMiddleware } from '../middlewares'
import { VideoModel } from '../models/video/video'

View File

@ -46,7 +46,8 @@ function isActorPrivateKeyValid (privateKey: string) {
}
function isRemoteActorValid (remoteActor: any) {
return isActivityPubUrlValid(remoteActor.id) &&
return exists(remoteActor) &&
isActivityPubUrlValid(remoteActor.id) &&
isActorTypeValid(remoteActor.type) &&
isActivityPubUrlValid(remoteActor.following) &&
isActivityPubUrlValid(remoteActor.followers) &&

View File

@ -2,7 +2,6 @@ import { isActivityPubUrlValid, isBaseActivityValid } from './misc'
import { isVideoTorrentCreateActivityValid } from './videos'
function isAnnounceActivityValid (activity: any) {
console.log(activity)
return isBaseActivityValid(activity, 'Announce') &&
(
isVideoTorrentCreateActivityValid(activity.object) ||

View File

@ -1,8 +0,0 @@
export * from './actor'
export * from './activity'
export * from './misc'
export * from './signature'
export * from './undo'
export * from './video-channels'
export * from './videos'
export * from './view'

View File

@ -1,9 +0,0 @@
export * from './activitypub'
export * from './core-utils'
export * from './logger'
export * from './ffmpeg-utils'
export * from './database-utils'
export * from './peertube-crypto'
export * from './requests'
export * from './utils'
export * from './webfinger'

View File

@ -1,8 +1,14 @@
import * as Promise from 'bluebird'
import { createWriteStream } from 'fs'
import * as request from 'request'
import { ACTIVITY_PUB } from '../initializers'
function doRequest (requestOptions: request.CoreOptions & request.UriOptions & { activityPub?: boolean }) {
if (requestOptions.activityPub === true) {
if (!Array.isArray(requestOptions.headers)) requestOptions.headers = {}
requestOptions.headers['accept'] = ACTIVITY_PUB.ACCEPT_HEADER
}
function doRequest (requestOptions: request.CoreOptions & request.UriOptions) {
return new Promise<{ response: request.RequestResponse, body: any }>((res, rej) => {
request(requestOptions, (err, response, body) => err ? rej(err) : res({ response, body }))
})

View File

@ -2,7 +2,7 @@ import * as WebFinger from 'webfinger.js'
import { WebFingerData } from '../../shared'
import { ActorModel } from '../models/activitypub/actor'
import { isTestInstance } from './core-utils'
import { isActivityPubUrlValid } from './custom-validators/activitypub'
import { isActivityPubUrlValid } from './custom-validators/activitypub/misc'
const webfinger = new WebFinger({
webfist_fallback: false,

View File

@ -1,5 +1,5 @@
import * as config from 'config'
import { promisify0 } from '../helpers'
import { promisify0 } from '../helpers/core-utils'
import { UserModel } from '../models/account/user'
import { ApplicationModel } from '../models/application/application'
import { OAuthClientModel } from '../models/oauth/oauth-client'

View File

@ -1,6 +1,7 @@
import * as passwordGenerator from 'password-generator'
import { UserRole } from '../../shared'
import { logger, mkdirpPromise, rimrafPromise } from '../helpers'
import { mkdirpPromise, rimrafPromise } from '../helpers/core-utils'
import { logger } from '../helpers/logger'
import { createApplicationActor, createUserAccountAndChannel } from '../lib/user'
import { UserModel } from '../models/account/user'
import { ApplicationModel } from '../models/application/application'

View File

@ -1,6 +1,6 @@
import * as Sequelize from 'sequelize'
import { DataType } from 'sequelize-typescript'
import { createPrivateAndPublicKeys } from '../../helpers'
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
async function up (utils: {
transaction: Sequelize.Transaction,

View File

@ -1,5 +1,6 @@
import * as path from 'path'
import { logger, readdirPromise } from '../helpers'
import { readdirPromise } from '../helpers/core-utils'
import { logger } from '../helpers/logger'
import { LAST_MIGRATION_VERSION } from './constants'
import { sequelizeTypescript } from './database'

View File

@ -3,9 +3,12 @@ import { Transaction } from 'sequelize'
import * as url from 'url'
import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub'
import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
import { createPrivateAndPublicKeys, doRequest, logger, retryTransactionWrapper } from '../../helpers'
import { isRemoteActorValid } from '../../helpers/custom-validators/activitypub'
import { ACTIVITY_PUB, CONFIG, sequelizeTypescript } from '../../initializers'
import { isRemoteActorValid } from '../../helpers/custom-validators/activitypub/actor'
import { retryTransactionWrapper } from '../../helpers/database-utils'
import { logger } from '../../helpers/logger'
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
import { doRequest } from '../../helpers/requests'
import { CONFIG, sequelizeTypescript } from '../../initializers'
import { AccountModel } from '../../models/account/account'
import { ActorModel } from '../../models/activitypub/actor'
import { ServerModel } from '../../models/server/server'
@ -115,22 +118,15 @@ async function fetchRemoteActor (actorUrl: string): Promise<FetchRemoteActorResu
const options = {
uri: actorUrl,
method: 'GET',
headers: {
'Accept': ACTIVITY_PUB.ACCEPT_HEADER
}
json: true,
activityPub: true
}
logger.info('Fetching remote actor %s.', actorUrl)
let requestResult
try {
requestResult = await doRequest(options)
} catch (err) {
logger.warn('Cannot fetch remote actor %s.', actorUrl, err)
return undefined
}
const requestResult = await doRequest(options)
const actorJSON: ActivityPubActor = requestResult.body
const actorJSON: ActivityPubActor = JSON.parse(requestResult.body)
if (isRemoteActorValid(actorJSON) === false) {
logger.debug('Remote actor JSON is not valid.', { actorJSON: actorJSON })
return undefined
@ -195,7 +191,9 @@ export {
async function fetchActorTotalItems (url: string) {
const options = {
uri: url,
method: 'GET'
method: 'GET',
json: true,
activityPub: true
}
let requestResult

View File

@ -1,11 +1,15 @@
import * as magnetUtil from 'magnet-uri'
import { VideoTorrentObject } from '../../../../shared'
import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object'
import { VideoPrivacy } from '../../../../shared/models/videos'
import { doRequest } from '../../../helpers'
import { isVideoFileInfoHashValid } from '../../../helpers/custom-validators/videos'
import { logger } from '../../../helpers/logger'
import { doRequest } from '../../../helpers/requests'
import { ACTIVITY_PUB, VIDEO_MIMETYPE_EXT } from '../../../initializers'
import { ActorModel } from '../../../models/activitypub/actor'
import { VideoModel } from '../../../models/video/video'
import { VideoChannelModel } from '../../../models/video/video-channel'
import { VideoCommentModel } from '../../../models/video/video-comment'
import { VideoShareModel } from '../../../models/video/video-share'
import { getOrCreateActorAndServerAndModel } from '../actor'
@ -97,14 +101,43 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
return attributes
}
async function addVideoShares (instance: VideoModel, shares: string[]) {
for (const share of shares) {
async function videoCommentActivityObjectToDBAttributes (video: VideoModel, actor: ActorModel, comment: VideoCommentObject) {
let originCommentId: number = null
let inReplyToCommentId: number = null
// If this is not a reply to the video (thread), create or get the parent comment
if (video.url !== comment.inReplyTo) {
const [ parent ] = await addVideoComment(video, comment.inReplyTo)
if (!parent) {
logger.warn('Cannot fetch or get parent comment %s of comment %s.', comment.inReplyTo, comment.id)
return undefined
}
originCommentId = parent.originCommentId || parent.id
inReplyToCommentId = parent.id
}
return {
url: comment.url,
text: comment.content,
videoId: video.id,
accountId: actor.Account.id,
inReplyToCommentId,
originCommentId,
createdAt: new Date(comment.published),
updatedAt: new Date(comment.updated)
}
}
async function addVideoShares (instance: VideoModel, shareUrls: string[]) {
for (const shareUrl of shareUrls) {
// Fetch url
const json = await doRequest({
uri: share,
json: true
const { body } = await doRequest({
uri: shareUrl,
json: true,
activityPub: true
})
const actorUrl = json['actor']
const actorUrl = body.actor
if (!actorUrl) continue
const actor = await getOrCreateActorAndServerAndModel(actorUrl)
@ -121,10 +154,40 @@ async function addVideoShares (instance: VideoModel, shares: string[]) {
}
}
async function addVideoComments (instance: VideoModel, commentUrls: string[]) {
for (const commentUrl of commentUrls) {
await addVideoComment(instance, commentUrl)
}
}
async function addVideoComment (instance: VideoModel, commentUrl: string) {
// Fetch url
const { body } = await doRequest({
uri: commentUrl,
json: true,
activityPub: true
})
const actorUrl = body.attributedTo
if (!actorUrl) return []
const actor = await getOrCreateActorAndServerAndModel(actorUrl)
const entry = await videoCommentActivityObjectToDBAttributes(instance, actor, body)
if (!entry) return []
return VideoCommentModel.findOrCreate({
where: {
url: body.id
},
defaults: entry
})
}
// ---------------------------------------------------------------------------
export {
videoFileActivityUrlToDBAttributes,
videoActivityObjectToDBAttributes,
addVideoShares
addVideoShares,
addVideoComments
}

View File

@ -1,5 +1,6 @@
import { ActivityAnnounce } from '../../../../shared/models/activitypub'
import { logger, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers'
import { ActorModel } from '../../../models/activitypub/actor'
import { VideoModel } from '../../../models/video/video'

View File

@ -3,7 +3,8 @@ import { ActivityCreate, VideoTorrentObject } from '../../../../shared'
import { DislikeObject, VideoAbuseObject, ViewObject } from '../../../../shared/models/activitypub/objects'
import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object'
import { VideoRateType } from '../../../../shared/models/videos'
import { logger, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers'
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
import { ActorModel } from '../../../models/activitypub/actor'
@ -15,7 +16,7 @@ import { VideoFileModel } from '../../../models/video/video-file'
import { getOrCreateActorAndServerAndModel } from '../actor'
import { forwardActivity } from '../send/misc'
import { generateThumbnailFromUrl } from '../videos'
import { addVideoShares, videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc'
import { addVideoComments, addVideoShares, videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc'
async function processCreateActivity (activity: ActivityCreate) {
const activityObject = activity.object
@ -66,17 +67,25 @@ async function processCreateVideo (
// Process outside the transaction because we could fetch remote data
if (videoToCreateData.likes && Array.isArray(videoToCreateData.likes.orderedItems)) {
logger.info('Adding likes of video %s.', video.uuid)
await createRates(videoToCreateData.likes.orderedItems, video, 'like')
}
if (videoToCreateData.dislikes && Array.isArray(videoToCreateData.dislikes.orderedItems)) {
logger.info('Adding dislikes of video %s.', video.uuid)
await createRates(videoToCreateData.dislikes.orderedItems, video, 'dislike')
}
if (videoToCreateData.shares && Array.isArray(videoToCreateData.shares.orderedItems)) {
logger.info('Adding shares of video %s.', video.uuid)
await addVideoShares(video, videoToCreateData.shares.orderedItems)
}
if (videoToCreateData.comments && Array.isArray(videoToCreateData.comments.orderedItems)) {
logger.info('Adding comments of video %s.', video.uuid)
await addVideoComments(video, videoToCreateData.comments.orderedItems)
}
return video
}

View File

@ -1,5 +1,6 @@
import { ActivityDelete } from '../../../../shared/models/activitypub'
import { logger, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers'
import { AccountModel } from '../../../models/account/account'
import { ActorModel } from '../../../models/activitypub/actor'

View File

@ -1,5 +1,6 @@
import { ActivityFollow } from '../../../../shared/models/activitypub'
import { logger, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers'
import { ActorModel } from '../../../models/activitypub/actor'
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'

View File

@ -1,5 +1,5 @@
import { ActivityLike } from '../../../../shared/models/activitypub'
import { retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { sequelizeTypescript } from '../../../initializers'
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
import { ActorModel } from '../../../models/activitypub/actor'

View File

@ -1,6 +1,7 @@
import { ActivityFollow, ActivityLike, ActivityUndo } from '../../../../shared/models/activitypub'
import { DislikeObject } from '../../../../shared/models/activitypub/objects'
import { logger, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers'
import { AccountModel } from '../../../models/account/account'
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'

View File

@ -1,6 +1,8 @@
import * as Bluebird from 'bluebird'
import { ActivityUpdate } from '../../../../shared/models/activitypub'
import { logger, resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { logger } from '../../../helpers/logger'
import { resetSequelizeInstance } from '../../../helpers/utils'
import { sequelizeTypescript } from '../../../initializers'
import { ActorModel } from '../../../models/activitypub/actor'
import { TagModel } from '../../../models/video/tag'

View File

@ -1,5 +1,5 @@
import { Activity, ActivityType } from '../../../../shared/models/activitypub'
import { logger } from '../../../helpers'
import { logger } from '../../../helpers/logger'
import { ActorModel } from '../../../models/activitypub/actor'
import { processAcceptActivity } from './process-accept'
import { processAnnounceActivity } from './process-announce'

View File

@ -1,6 +1,6 @@
import { Transaction } from 'sequelize'
import { Activity, ActivityAudience } from '../../../../shared/models/activitypub'
import { logger } from '../../../helpers'
import { logger } from '../../../helpers/logger'
import { ACTIVITY_PUB } from '../../../initializers'
import { ActorModel } from '../../../models/activitypub/actor'
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'

View File

@ -1,7 +1,7 @@
import { Transaction } from 'sequelize'
import { ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub'
import { VideoPrivacy } from '../../../../shared/models/videos'
import { getServerActor } from '../../../helpers'
import { getServerActor } from '../../../helpers/utils'
import { ActorModel } from '../../../models/activitypub/actor'
import { VideoModel } from '../../../models/video/video'
import { VideoAbuseModel } from '../../../models/video/video-abuse'

View File

@ -1,6 +1,6 @@
import { Transaction } from 'sequelize'
import { VideoPrivacy } from '../../../shared/models/videos'
import { getServerActor } from '../../helpers'
import { getServerActor } from '../../helpers/utils'
import { VideoModel } from '../../models/video/video'
import { VideoShareModel } from '../../models/video/video-share'
import { sendVideoAnnounceToFollowers } from './send'

View File

@ -10,7 +10,7 @@ function getVideoActivityPubUrl (video: VideoModel) {
}
function getVideoCommentActivityPubUrl (video: VideoModel, videoComment: VideoCommentModel) {
return CONFIG.WEBSERVER.URL + '/videos/watch/' + video.uuid + '#comment-' + videoComment.id
return CONFIG.WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id
}
function getVideoChannelActivityPubUrl (videoChannelUUID: string) {

View File

@ -2,19 +2,13 @@ import { join } from 'path'
import * as request from 'request'
import { Transaction } from 'sequelize'
import { ActivityIconObject } from '../../../shared/index'
import { doRequest, doRequestAndSaveToFile } from '../../helpers'
import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
import { CONFIG, REMOTE_SCHEME, STATIC_PATHS } from '../../initializers'
import { AccountModel } from '../../models/account/account'
import { VideoModel } from '../../models/video/video'
import {
sendCreateDislikeToOrigin,
sendCreateDislikeToVideoFollowers,
sendLikeToOrigin,
sendLikeToVideoFollowers,
sendUndoDislikeToOrigin,
sendUndoDislikeToVideoFollowers,
sendUndoLikeToOrigin,
sendUndoLikeToVideoFollowers
sendCreateDislikeToOrigin, sendCreateDislikeToVideoFollowers, sendLikeToOrigin, sendLikeToVideoFollowers, sendUndoDislikeToOrigin,
sendUndoDislikeToVideoFollowers, sendUndoLikeToOrigin, sendUndoLikeToVideoFollowers
} from './send'
function fetchRemoteVideoPreview (video: VideoModel, reject: Function) {

View File

@ -1,7 +1,8 @@
import * as asyncLRU from 'async-lru'
import { createWriteStream } from 'fs'
import { join } from 'path'
import { logger, unlinkPromise } from '../../helpers'
import { unlinkPromise } from '../../helpers/core-utils'
import { logger } from '../../helpers/logger'
import { CACHE, CONFIG } from '../../initializers'
import { VideoModel } from '../../models/video/video'
import { fetchRemoteVideoPreview } from '../activitypub'

View File

@ -1,4 +1,5 @@
import { doRequest, logger } from '../../../helpers'
import { logger } from '../../../helpers/logger'
import { doRequest } from '../../../helpers/requests'
import { ActivityPubHttpPayload, buildSignedRequestOptions, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler'
async function process (payload: ActivityPubHttpPayload, jobId: number) {

View File

@ -1,4 +1,5 @@
import { doRequest, logger } from '../../../helpers'
import { logger } from '../../../helpers/logger'
import { doRequest } from '../../../helpers/requests'
import { ACTIVITY_PUB } from '../../../initializers'
import { processActivities } from '../../activitypub/process'
import { ActivityPubHttpPayload } from './activitypub-http-job-scheduler'
@ -9,7 +10,8 @@ async function process (payload: ActivityPubHttpPayload, jobId: number) {
const options = {
method: 'GET',
uri: '',
json: true
json: true,
activityPub: true
}
for (const uri of payload.uris) {

View File

@ -1,5 +1,7 @@
import { JobCategory } from '../../../../shared'
import { buildSignedActivity, getServerActor, logger } from '../../../helpers'
import { buildSignedActivity } from '../../../helpers/activitypub'
import { logger } from '../../../helpers/logger'
import { getServerActor } from '../../../helpers/utils'
import { ACTIVITY_PUB } from '../../../initializers'
import { ActorModel } from '../../../models/activitypub/actor'
import { JobHandler, JobScheduler } from '../job-scheduler'

View File

@ -1,4 +1,5 @@
import { doRequest, logger } from '../../../helpers'
import { logger } from '../../../helpers/logger'
import { doRequest } from '../../../helpers/requests'
import { ActivityPubHttpPayload, buildSignedRequestOptions, computeBody, maybeRetryRequestLater } from './activitypub-http-job-scheduler'
async function process (payload: ActivityPubHttpPayload, jobId: number) {

View File

@ -1,7 +1,7 @@
import { AsyncQueue, forever, queue } from 'async'
import * as Sequelize from 'sequelize'
import { JobCategory } from '../../../shared'
import { logger } from '../../helpers'
import { logger } from '../../helpers/logger'
import { JOB_STATES, JOBS_FETCH_LIMIT_PER_CYCLE, JOBS_FETCHING_INTERVAL } from '../../initializers'
import { JobModel } from '../../models/job/job'

View File

@ -1,6 +1,7 @@
import * as Bluebird from 'bluebird'
import { VideoPrivacy } from '../../../../shared/models/videos'
import { computeResolutionsToTranscode, logger } from '../../../helpers'
import { logger } from '../../../helpers/logger'
import { computeResolutionsToTranscode } from '../../../helpers/utils'
import { sequelizeTypescript } from '../../../initializers'
import { VideoModel } from '../../../models/video/video'
import { shareVideoByServerAndChannel } from '../../activitypub'

View File

@ -1,6 +1,6 @@
import { VideoResolution } from '../../../../shared'
import { VideoPrivacy } from '../../../../shared/models/videos'
import { logger } from '../../../helpers'
import { logger } from '../../../helpers/logger'
import { VideoModel } from '../../../models/video/video'
import { sendUpdateVideo } from '../../activitypub/send'

View File

@ -1,4 +1,4 @@
import { logger } from '../helpers'
import { logger } from '../helpers/logger'
import { UserModel } from '../models/account/user'
import { OAuthClientModel } from '../models/oauth/oauth-client'
import { OAuthTokenModel } from '../models/oauth/oauth-token'

View File

@ -1,7 +1,8 @@
import { eachSeries } from 'async'
import { NextFunction, Request, RequestHandler, Response } from 'express'
import { ActivityPubSignature } from '../../shared'
import { isSignatureVerified, logger } from '../helpers'
import { logger } from '../helpers/logger'
import { isSignatureVerified } from '../helpers/peertube-crypto'
import { ACCEPT_HEADERS, ACTIVITY_PUB } from '../initializers'
import { getOrCreateActorAndServerAndModel } from '../lib/activitypub'
import { ActorModel } from '../models/activitypub/actor'

View File

@ -1,9 +1,8 @@
import 'express-validator'
import * as express from 'express'
import * as OAuthServer from 'express-oauth-server'
import { logger } from '../helpers/logger'
import { OAUTH_LIFETIME } from '../initializers'
import { logger } from '../helpers'
const oAuthServer = new OAuthServer({
accessTokenLifetime: OAUTH_LIFETIME.ACCESS_TOKEN,

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import 'express-validator'
import { getHostWithPort } from '../helpers'
import { getHostWithPort } from '../helpers/utils'
function setBodyHostsPort (req: express.Request, res: express.Response, next: express.NextFunction) {
if (!req.body.hosts) return next()

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import 'express-validator'
import { SortType } from '../helpers'
import { SortType } from '../helpers/utils'
function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) {
if (!req.query.sort) req.query.sort = '-createdAt'

View File

@ -1,7 +1,7 @@
import * as express from 'express'
import 'express-validator'
import { UserRight } from '../../shared'
import { logger } from '../helpers'
import { logger } from '../helpers/logger'
import { UserModel } from '../models/account/user'
function ensureUserHasRight (userRight: UserRight) {

View File

@ -1,7 +1,7 @@
import * as express from 'express'
import { param } from 'express-validator/check'
import { logger } from '../../helpers'
import { isAccountNameValid, isLocalAccountNameExist } from '../../helpers/custom-validators/accounts'
import { logger } from '../../helpers/logger'
import { areValidationErrors } from './utils'
const localAccountValidator = [

View File

@ -1,7 +1,7 @@
import * as express from 'express'
import { body } from 'express-validator/check'
import { logger } from '../../../helpers'
import { isRootActivityValid } from '../../../helpers/custom-validators/activitypub'
import { isRootActivityValid } from '../../../helpers/custom-validators/activitypub/activity'
import { logger } from '../../../helpers/logger'
import { areValidationErrors } from '../utils'
const activityPubValidator = [

View File

@ -1,8 +1,11 @@
import * as express from 'express'
import { body } from 'express-validator/check'
import { logger } from '../../../helpers'
import { isSignatureCreatorValid, isSignatureTypeValid, isSignatureValueValid } from '../../../helpers/custom-validators/activitypub'
import {
isSignatureCreatorValid, isSignatureTypeValid,
isSignatureValueValid
} from '../../../helpers/custom-validators/activitypub/signature'
import { isDateValid } from '../../../helpers/custom-validators/misc'
import { logger } from '../../../helpers/logger'
import { areValidationErrors } from '../utils'
const signatureValidator = [

View File

@ -1,7 +1,9 @@
import * as express from 'express'
import { body, param } from 'express-validator/check'
import { getServerActor, isTestInstance, logger } from '../../helpers'
import { isTestInstance } from '../../helpers/core-utils'
import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers'
import { logger } from '../../helpers/logger'
import { getServerActor } from '../../helpers/utils'
import { CONFIG } from '../../initializers'
import { ActorFollowModel } from '../../models/activitypub/actor-follow'
import { areValidationErrors } from './utils'

View File

@ -1,9 +1,10 @@
import * as express from 'express'
import { query } from 'express-validator/check'
import { join } from 'path'
import { isTestInstance, logger } from '../../helpers'
import { isTestInstance } from '../../helpers/core-utils'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import { isVideoExist } from '../../helpers/custom-validators/videos'
import { logger } from '../../helpers/logger'
import { CONFIG } from '../../initializers'
import { areValidationErrors } from './utils'

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import { query } from 'express-validator/check'
import { logger } from '../../helpers'
import { logger } from '../../helpers/logger'
import { areValidationErrors } from './utils'
const paginationValidator = [

View File

@ -1,6 +1,6 @@
import { query } from 'express-validator/check'
import * as express from 'express'
import { logger } from '../../helpers'
import { query } from 'express-validator/check'
import { logger } from '../../helpers/logger'
import { SORTABLE_COLUMNS } from '../../initializers'
import { areValidationErrors } from './utils'

View File

@ -1,17 +1,14 @@
import * as express from 'express'
import 'express-validator'
import { body, param } from 'express-validator/check'
import { isSignupAllowed, logger } from '../../helpers'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import {
isUserDisplayNSFWValid,
isUserAutoPlayVideoValid,
isUserPasswordValid,
isUserRoleValid,
isUserUsernameValid,
isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
isUserVideoQuotaValid
} from '../../helpers/custom-validators/users'
import { isVideoExist } from '../../helpers/custom-validators/videos'
import { logger } from '../../helpers/logger'
import { isSignupAllowed } from '../../helpers/utils'
import { UserModel } from '../../models/account/user'
import { areValidationErrors } from './utils'

View File

@ -1,6 +1,6 @@
import * as express from 'express'
import { validationResult } from 'express-validator/check'
import { logger } from '../../helpers'
import { logger } from '../../helpers/logger'
function areValidationErrors (req: express.Request, res: express.Response) {
const errors = validationResult(req)

View File

@ -1,8 +1,8 @@
import * as express from 'express'
import { param } from 'express-validator/check'
import { logger } from '../../helpers'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import { isVideoExist } from '../../helpers/custom-validators/videos'
import { logger } from '../../helpers/logger'
import { VideoModel } from '../../models/video/video'
import { VideoBlacklistModel } from '../../models/video/video-blacklist'
import { areValidationErrors } from './utils'

View File

@ -1,14 +1,13 @@
import * as express from 'express'
import { body, param } from 'express-validator/check'
import { UserRight } from '../../../shared'
import { logger } from '../../helpers'
import { isAccountIdExist } from '../../helpers/custom-validators/accounts'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import {
isVideoChannelDescriptionValid,
isVideoChannelExist,
isVideoChannelDescriptionValid, isVideoChannelExist,
isVideoChannelNameValid
} from '../../helpers/custom-validators/video-channels'
import { logger } from '../../helpers/logger'
import { UserModel } from '../../models/account/user'
import { VideoChannelModel } from '../../models/video/video-channel'
import { areValidationErrors } from './utils'

View File

@ -1,9 +1,9 @@
import * as express from 'express'
import { body, param } from 'express-validator/check'
import { logger } from '../../helpers'
import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc'
import { isValidVideoCommentText } from '../../helpers/custom-validators/video-comments'
import { isVideoExist } from '../../helpers/custom-validators/videos'
import { logger } from '../../helpers/logger'
import { VideoModel } from '../../models/video/video'
import { VideoCommentModel } from '../../models/video/video-comment'
import { areValidationErrors } from './utils'
@ -66,13 +66,29 @@ const addVideoCommentReplyValidator = [
}
]
const videoCommentGetValidator = [
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.videoId, res)) return
if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return
return next()
}
]
// ---------------------------------------------------------------------------
export {
listVideoCommentThreadsValidator,
listVideoThreadCommentsValidator,
addVideoCommentThreadValidator,
addVideoCommentReplyValidator
addVideoCommentReplyValidator,
videoCommentGetValidator
}
// ---------------------------------------------------------------------------
@ -109,7 +125,7 @@ async function isVideoCommentThreadExist (id: number, video: VideoModel, res: ex
}
async function isVideoCommentExist (id: number, video: VideoModel, res: express.Response) {
const videoComment = await VideoCommentModel.loadById(id)
const videoComment = await VideoCommentModel.loadByIdAndPopulateVideoAndAccountAndReply(id)
if (!videoComment) {
res.status(404)

View File

@ -2,22 +2,13 @@ import * as express from 'express'
import 'express-validator'
import { body, param, query } from 'express-validator/check'
import { UserRight, VideoPrivacy } from '../../../shared'
import { getDurationFromVideoFile, logger } from '../../helpers'
import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc'
import {
isVideoAbuseReasonValid,
isVideoCategoryValid,
isVideoDescriptionValid,
isVideoExist,
isVideoFile,
isVideoLanguageValid,
isVideoLicenceValid,
isVideoNameValid,
isVideoNSFWValid,
isVideoPrivacyValid,
isVideoRatingTypeValid,
isVideoTagsValid
isVideoAbuseReasonValid, isVideoCategoryValid, isVideoDescriptionValid, isVideoExist, isVideoFile, isVideoLanguageValid,
isVideoLicenceValid, isVideoNameValid, isVideoNSFWValid, isVideoPrivacyValid, isVideoRatingTypeValid, isVideoTagsValid
} from '../../helpers/custom-validators/videos'
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
import { logger } from '../../helpers/logger'
import { CONSTRAINTS_FIELDS } from '../../initializers'
import { UserModel } from '../../models/account/user'
import { VideoModel } from '../../models/video/video'

View File

@ -1,7 +1,8 @@
import * as express from 'express'
import { query } from 'express-validator/check'
import { getHostWithPort, logger } from '../../helpers'
import { isWebfingerResourceValid } from '../../helpers/custom-validators/webfinger'
import { logger } from '../../helpers/logger'
import { getHostWithPort } from '../../helpers/utils'
import { ActorModel } from '../../models/activitypub/actor'
import { areValidationErrors } from './utils'

View File

@ -4,11 +4,11 @@ import {
Scopes, Table, UpdatedAt
} from 'sequelize-typescript'
import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
import { comparePassword, cryptPassword } from '../../helpers'
import {
isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
isUserVideoQuotaValid
} from '../../helpers/custom-validators/users'
import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
import { OAuthTokenModel } from '../oauth/oauth-token'
import { getSort, throwIfNotValid } from '../utils'
import { VideoChannelModel } from '../video/video-channel'

View File

@ -7,11 +7,12 @@ import {
} from 'sequelize-typescript'
import { ActivityPubActorType } from '../../../shared/models/activitypub'
import { Avatar } from '../../../shared/models/avatars/avatar.model'
import { activityPubContextify } from '../../helpers'
import { activityPubContextify } from '../../helpers/activitypub'
import {
isActivityPubUrlValid, isActorFollowersCountValid, isActorFollowingCountValid, isActorPreferredUsernameValid,
isActorPrivateKeyValid, isActorPublicKeyValid
} from '../../helpers/custom-validators/activitypub'
isActorFollowersCountValid, isActorFollowingCountValid, isActorPreferredUsernameValid, isActorPrivateKeyValid,
isActorPublicKeyValid
} from '../../helpers/custom-validators/activitypub/actor'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { ACTIVITY_PUB_ACTOR_TYPES, AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
import { AccountModel } from '../account/account'
import { AvatarModel } from '../avatar/avatar'

View File

@ -1,5 +1,5 @@
import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
import { logger } from '../../helpers'
import { logger } from '../../helpers/logger'
import { AccountModel } from '../account/account'
import { UserModel } from '../account/user'
import { OAuthClientModel } from './oauth-client'

View File

@ -1,7 +1,7 @@
import * as Sequelize from 'sequelize'
import { AllowNull, Column, CreatedAt, Default, Is, IsInt, Max, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { logger } from '../../helpers'
import { isHostValid } from '../../helpers/custom-validators/servers'
import { logger } from '../../helpers/logger'
import { SERVERS_SCORE } from '../../initializers'
import { throwIfNotValid } from '../utils'

View File

@ -1,5 +1,5 @@
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { SortType } from '../../helpers'
import { SortType } from '../../helpers/utils'
import { getSortOnModel } from '../utils'
import { VideoModel } from './video'

View File

@ -5,7 +5,7 @@ import {
} from 'sequelize-typescript'
import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object'
import { VideoComment } from '../../../shared/models/videos/video-comment.model'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { CONSTRAINTS_FIELDS } from '../../initializers'
import { AccountModel } from '../account/account'
import { ActorModel } from '../activitypub/actor'
@ -16,6 +16,7 @@ import { VideoModel } from './video'
enum ScopeNames {
WITH_ACCOUNT = 'WITH_ACCOUNT',
WITH_IN_REPLY_TO = 'WITH_IN_REPLY_TO',
WITH_VIDEO = 'WITH_VIDEO',
ATTRIBUTES_FOR_API = 'ATTRIBUTES_FOR_API'
}
@ -56,7 +57,15 @@ enum ScopeNames {
include: [
{
model: () => VideoCommentModel,
as: 'InReplyTo'
as: 'InReplyToVideoComment'
}
]
},
[ScopeNames.WITH_VIDEO]: {
include: [
{
model: () => VideoModel,
required: false
}
]
}
@ -108,7 +117,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
foreignKey: {
allowNull: true
},
as: 'InReplyTo',
as: 'InReplyToVideoComment',
onDelete: 'CASCADE'
})
InReplyToVideoComment: VideoCommentModel
@ -155,6 +164,20 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
return VideoCommentModel.findOne(query)
}
static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Sequelize.Transaction) {
const query: IFindOptions<VideoCommentModel> = {
where: {
id
}
}
if (t !== undefined) query.transaction = t
return VideoCommentModel
.scope([ ScopeNames.WITH_VIDEO, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_IN_REPLY_TO ])
.findOne(query)
}
static loadByUrl (url: string, t?: Sequelize.Transaction) {
const query: IFindOptions<VideoCommentModel> = {
where: {
@ -238,8 +261,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
id: this.url,
content: this.text,
inReplyTo,
updated: this.updatedAt.toISOString(),
published: this.createdAt.toISOString(),
url: this.url
url: this.url,
attributedTo: this.Account.Actor.url
}
}
}

View File

@ -5,65 +5,25 @@ import * as parseTorrent from 'parse-torrent'
import { join } from 'path'
import * as Sequelize from 'sequelize'
import {
AfterDestroy,
AllowNull,
BelongsTo,
BelongsToMany,
Column,
CreatedAt,
DataType,
Default,
ForeignKey,
HasMany,
IFindOptions,
Is,
IsInt,
IsUUID,
Min,
Model,
Scopes,
Table,
UpdatedAt
AfterDestroy, AllowNull, BelongsTo, BelongsToMany, Column, CreatedAt, DataType, Default, ForeignKey, HasMany, IFindOptions, Is,
IsInt, IsUUID, Min, Model, Scopes, Table, UpdatedAt
} from 'sequelize-typescript'
import { IIncludeOptions } from 'sequelize-typescript/lib/interfaces/IIncludeOptions'
import { VideoPrivacy, VideoResolution } from '../../../shared'
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
import { Video, VideoDetails } from '../../../shared/models/videos'
import { activityPubCollection } from '../../helpers/activitypub'
import { createTorrentPromise, renamePromise, statPromise, unlinkPromise, writeFilePromise } from '../../helpers/core-utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import {
activityPubCollection,
createTorrentPromise,
generateImageFromVideoFile,
getVideoFileHeight,
logger,
renamePromise,
statPromise,
transcode,
unlinkPromise,
writeFilePromise
} from '../../helpers'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub'
import {
isVideoCategoryValid,
isVideoDescriptionValid,
isVideoDurationValid,
isVideoLanguageValid,
isVideoLicenceValid,
isVideoNameValid,
isVideoNSFWValid,
isVideoPrivacyValid
isVideoCategoryValid, isVideoDescriptionValid, isVideoDurationValid, isVideoLanguageValid, isVideoLicenceValid, isVideoNameValid,
isVideoNSFWValid, isVideoPrivacyValid
} from '../../helpers/custom-validators/videos'
import { generateImageFromVideoFile, getVideoFileHeight, transcode } from '../../helpers/ffmpeg-utils'
import { logger } from '../../helpers/logger'
import {
API_VERSION,
CONFIG,
CONSTRAINTS_FIELDS,
PREVIEWS_SIZE,
REMOTE_SCHEME,
STATIC_PATHS,
THUMBNAILS_SIZE,
VIDEO_CATEGORIES,
VIDEO_LANGUAGES,
VIDEO_LICENCES,
VIDEO_PRIVACIES
API_VERSION, CONFIG, CONSTRAINTS_FIELDS, PREVIEWS_SIZE, REMOTE_SCHEME, STATIC_PATHS, THUMBNAILS_SIZE, VIDEO_CATEGORIES,
VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES
} from '../../initializers'
import { getAnnounceActivityPubUrl } from '../../lib/activitypub'
import { sendDeleteVideo } from '../../lib/activitypub/send'
@ -75,6 +35,7 @@ import { getSort, throwIfNotValid } from '../utils'
import { TagModel } from './tag'
import { VideoAbuseModel } from './video-abuse'
import { VideoChannelModel } from './video-channel'
import { VideoCommentModel } from './video-comment'
import { VideoFileModel } from './video-file'
import { VideoShareModel } from './video-share'
import { VideoTagModel } from './video-tag'
@ -85,7 +46,8 @@ enum ScopeNames {
WITH_TAGS = 'WITH_TAGS',
WITH_FILES = 'WITH_FILES',
WITH_SHARES = 'WITH_SHARES',
WITH_RATES = 'WITH_RATES'
WITH_RATES = 'WITH_RATES',
WITH_COMMENTS = 'WITH_COMMENTS'
}
@Scopes({
@ -151,6 +113,13 @@ enum ScopeNames {
include: [ () => AccountModel ]
}
]
},
[ScopeNames.WITH_COMMENTS]: {
include: [
{
model: () => VideoCommentModel
}
]
}
})
@Table({
@ -322,6 +291,15 @@ export class VideoModel extends Model<VideoModel> {
})
AccountVideoRates: AccountVideoRateModel[]
@HasMany(() => VideoCommentModel, {
foreignKey: {
name: 'videoId',
allowNull: false
},
onDelete: 'cascade'
})
VideoComments: VideoCommentModel[]
@AfterDestroy
static removeFilesAndSendDelete (instance: VideoModel) {
const tasks = []
@ -417,7 +395,8 @@ export class VideoModel extends Model<VideoModel> {
include: [ AccountModel ]
},
VideoFileModel,
TagModel
TagModel,
VideoCommentModel
]
}
@ -536,7 +515,7 @@ export class VideoModel extends Model<VideoModel> {
}
return VideoModel
.scope([ ScopeNames.WITH_RATES, ScopeNames.WITH_SHARES, ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT ])
.scope([ ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT ])
.findById(id, options)
}
@ -561,7 +540,27 @@ export class VideoModel extends Model<VideoModel> {
}
return VideoModel
.scope([ ScopeNames.WITH_RATES, ScopeNames.WITH_SHARES, ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT ])
.scope([ ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT ])
.findOne(options)
}
static loadAndPopulateAll (id: number) {
const options = {
order: [ [ 'Tags', 'name', 'ASC' ] ],
where: {
id
}
}
return VideoModel
.scope([
ScopeNames.WITH_RATES,
ScopeNames.WITH_SHARES,
ScopeNames.WITH_TAGS,
ScopeNames.WITH_FILES,
ScopeNames.WITH_ACCOUNT,
ScopeNames.WITH_COMMENTS
])
.findOne(options)
}
@ -865,6 +864,17 @@ export class VideoModel extends Model<VideoModel> {
sharesObject = activityPubCollection(shares)
}
let commentsObject
if (Array.isArray(this.VideoComments)) {
const comments: string[] = []
for (const videoComment of this.VideoComments) {
comments.push(videoComment.url)
}
commentsObject = activityPubCollection(comments)
}
const url = []
for (const file of this.VideoFiles) {
url.push({
@ -925,6 +935,7 @@ export class VideoModel extends Model<VideoModel> {
likes: likesObject,
dislikes: dislikesObject,
shares: sharesObject,
comments: commentsObject,
attributedTo: [
{
type: 'Group',

View File

@ -4,5 +4,7 @@ export interface VideoCommentObject {
content: string
inReplyTo: string
published: string
updated: string
url: string
attributedTo: string
}

View File

@ -27,5 +27,6 @@ export interface VideoTorrentObject {
likes?: ActivityPubOrderedCollection<string>
dislikes?: ActivityPubOrderedCollection<string>
shares?: ActivityPubOrderedCollection<string>
comments?: ActivityPubOrderedCollection<string>
attributedTo: ActivityPubAttributedTo[]
}