-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'
// 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()
activityPubClientRouter.get('/videos/watch/:id',
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
- executeIfActivityPub(videoController)
+ executeIfActivityPub(asyncMiddleware(videoController))
)
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))
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) {
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) {
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())
+}
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'
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'
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()
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'
import * as express from 'express'
-
+import { OAuthClientLocal } from '../../../shared'
+import { logger } from '../../helpers/logger'
import { CONFIG } from '../../initializers'
-import { logger } from '../../helpers'
import { asyncMiddleware } from '../../middlewares'
-import { OAuthClientLocal } from '../../../shared'
import { OAuthClientModel } from '../../models/oauth/oauth-client'
const oauthClientsRouter = express.Router()
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,
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'
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'
import * as express from 'express'
-import { logger, getFormattedObjects } from '../../../helpers'
+import { BlacklistedVideo, UserRight } from '../../../../shared'
+import { logger } from '../../../helpers/logger'
+import { getFormattedObjects } from '../../../helpers/utils'
import {
- authenticate,
- ensureUserHasRight,
- videosBlacklistAddValidator,
- videosBlacklistRemoveValidator,
- paginationValidator,
- blacklistSortValidator,
- setBlacklistSort,
- setPagination,
- asyncMiddleware
+ asyncMiddleware, authenticate, blacklistSortValidator, ensureUserHasRight, paginationValidator, setBlacklistSort, setPagination,
+ videosBlacklistAddValidator, videosBlacklistRemoveValidator
} from '../../../middlewares'
-import { BlacklistedVideo, UserRight } from '../../../../shared'
import { VideoBlacklistModel } from '../../../models/video/video-blacklist'
const blacklistRouter = express.Router()
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'
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'
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'
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'
+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'
}
function isRemoteActorValid (remoteActor: any) {
- return isActivityPubUrlValid(remoteActor.id) &&
+ return exists(remoteActor) &&
+ isActivityPubUrlValid(remoteActor.id) &&
isActorTypeValid(remoteActor.type) &&
isActivityPubUrlValid(remoteActor.following) &&
isActivityPubUrlValid(remoteActor.followers) &&
import { isVideoTorrentCreateActivityValid } from './videos'
function isAnnounceActivityValid (activity: any) {
- console.log(activity)
return isBaseActivityValid(activity, 'Announce') &&
(
isVideoTorrentCreateActivityValid(activity.object) ||
+++ /dev/null
-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'
+++ /dev/null
-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'
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 }))
})
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,
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'
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'
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,
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'
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'
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
async function fetchActorTotalItems (url: string) {
const options = {
uri: url,
- method: 'GET'
+ method: 'GET',
+ json: true,
+ activityPub: true
}
let requestResult
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'
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)
}
}
+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
}
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'
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'
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
// 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
}
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'
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'
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'
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'
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'
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'
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'
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'
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'
}
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) {
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) {
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'
-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) {
-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'
const options = {
method: 'GET',
uri: '',
- json: true
+ json: true,
+ activityPub: true
}
for (const uri of payload.uris) {
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'
-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) {
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'
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'
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'
-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'
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'
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,
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()
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'
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) {
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 = [
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 = [
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 = [
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'
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'
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 = [
-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'
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'
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)
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'
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'
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'
}
]
+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
}
// ---------------------------------------------------------------------------
}
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)
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'
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'
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'
} 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'
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'
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'
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'
} 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'
enum ScopeNames {
WITH_ACCOUNT = 'WITH_ACCOUNT',
WITH_IN_REPLY_TO = 'WITH_IN_REPLY_TO',
+ WITH_VIDEO = 'WITH_VIDEO',
ATTRIBUTES_FOR_API = 'ATTRIBUTES_FOR_API'
}
include: [
{
model: () => VideoCommentModel,
- as: 'InReplyTo'
+ as: 'InReplyToVideoComment'
+ }
+ ]
+ },
+ [ScopeNames.WITH_VIDEO]: {
+ include: [
+ {
+ model: () => VideoModel,
+ required: false
}
]
}
foreignKey: {
allowNull: true
},
- as: 'InReplyTo',
+ as: 'InReplyToVideoComment',
onDelete: 'CASCADE'
})
InReplyToVideoComment: 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: {
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
}
}
}
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'
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'
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({
include: [ () => AccountModel ]
}
]
+ },
+ [ScopeNames.WITH_COMMENTS]: {
+ include: [
+ {
+ model: () => VideoCommentModel
+ }
+ ]
}
})
@Table({
})
AccountVideoRates: AccountVideoRateModel[]
+ @HasMany(() => VideoCommentModel, {
+ foreignKey: {
+ name: 'videoId',
+ allowNull: false
+ },
+ onDelete: 'cascade'
+ })
+ VideoComments: VideoCommentModel[]
+
@AfterDestroy
static removeFilesAndSendDelete (instance: VideoModel) {
const tasks = []
include: [ AccountModel ]
},
VideoFileModel,
- TagModel
+ TagModel,
+ VideoCommentModel
]
}
}
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)
}
}
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)
}
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({
likes: likesObject,
dislikes: dislikesObject,
shares: sharesObject,
+ comments: commentsObject,
attributedTo: [
{
type: 'Group',
content: string
inReplyTo: string
published: string
+ updated: string
url: string
+ attributedTo: string
}
likes?: ActivityPubOrderedCollection<string>
dislikes?: ActivityPubOrderedCollection<string>
shares?: ActivityPubOrderedCollection<string>
+ comments?: ActivityPubOrderedCollection<string>
attributedTo: ActivityPubAttributedTo[]
}