Propagate old comment on new follow
authorChocobozzz <me@florianbigard.com>
Thu, 28 Dec 2017 10:16:08 +0000 (11:16 +0100)
committerChocobozzz <me@florianbigard.com>
Thu, 28 Dec 2017 10:16:08 +0000 (11:16 +0100)
78 files changed:
scripts/update-host.ts
server/controllers/activitypub/client.ts
server/controllers/activitypub/inbox.ts
server/controllers/api/config.ts
server/controllers/api/index.ts
server/controllers/api/jobs.ts
server/controllers/api/oauth-clients.ts
server/controllers/api/server/follows.ts
server/controllers/api/users.ts
server/controllers/api/videos/abuse.ts
server/controllers/api/videos/blacklist.ts
server/controllers/api/videos/channel.ts
server/controllers/api/videos/comment.ts
server/controllers/api/videos/index.ts
server/controllers/api/videos/rate.ts
server/controllers/client.ts
server/helpers/custom-validators/activitypub/actor.ts
server/helpers/custom-validators/activitypub/announce.ts
server/helpers/custom-validators/activitypub/index.ts [deleted file]
server/helpers/index.ts [deleted file]
server/helpers/requests.ts
server/helpers/webfinger.ts
server/initializers/checker.ts
server/initializers/installer.ts
server/initializers/migrations/0135-video-channel-actor.ts
server/initializers/migrator.ts
server/lib/activitypub/actor.ts
server/lib/activitypub/process/misc.ts
server/lib/activitypub/process/process-announce.ts
server/lib/activitypub/process/process-create.ts
server/lib/activitypub/process/process-delete.ts
server/lib/activitypub/process/process-follow.ts
server/lib/activitypub/process/process-like.ts
server/lib/activitypub/process/process-undo.ts
server/lib/activitypub/process/process-update.ts
server/lib/activitypub/process/process.ts
server/lib/activitypub/send/misc.ts
server/lib/activitypub/send/send-create.ts
server/lib/activitypub/share.ts
server/lib/activitypub/url.ts
server/lib/activitypub/videos.ts
server/lib/cache/videos-preview-cache.ts
server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-broadcast-handler.ts
server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-fetcher-handler.ts
server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler.ts
server/lib/jobs/activitypub-http-job-scheduler/activitypub-http-unicast-handler.ts
server/lib/jobs/job-scheduler.ts
server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts
server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts
server/lib/oauth-model.ts
server/middlewares/activitypub.ts
server/middlewares/oauth.ts
server/middlewares/servers.ts
server/middlewares/sort.ts
server/middlewares/user-right.ts
server/middlewares/validators/account.ts
server/middlewares/validators/activitypub/activity.ts
server/middlewares/validators/activitypub/signature.ts
server/middlewares/validators/follows.ts
server/middlewares/validators/oembed.ts
server/middlewares/validators/pagination.ts
server/middlewares/validators/sort.ts
server/middlewares/validators/users.ts
server/middlewares/validators/utils.ts
server/middlewares/validators/video-blacklist.ts
server/middlewares/validators/video-channels.ts
server/middlewares/validators/video-comments.ts
server/middlewares/validators/videos.ts
server/middlewares/validators/webfinger.ts
server/models/account/user.ts
server/models/activitypub/actor.ts
server/models/oauth/oauth-token.ts
server/models/server/server.ts
server/models/video/video-blacklist.ts
server/models/video/video-comment.ts
server/models/video/video.ts
shared/models/activitypub/objects/video-comment-object.ts
shared/models/activitypub/objects/video-torrent-object.ts

index 4551a4702aac0243c1fc1badf9319d1ad5794fd6..3fb5f1972dd85b6491fed4d9979533743dbeefe7 100755 (executable)
@@ -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'
index 8c6294ff7193201e8b0bc810a5c34a83641d7dbe..71e706346ed129e2fe289e7758f26b7d4cbef46a 100644 (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())
+}
index 8332eabb111d74061935248e39a7437a887b4b44..bfcb7b3695200b994b15c354c6a0ab97a1eac4cb 100644 (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'
index 5f704f0eeef38d84645b8d072e8b618eaefe424f..2f1132904fef5846bf54e8a93c75a096d7115513 100644 (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'
index 737ea46027b9257fa7779d103d1d2bf0c7345808..1fd44ac11afd4f496cb1fda24418e213856a98ce 100644 (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()
 
index 4e7cd1ee3edd23525ffda96583f772e7c8c943a3..d9d6030a4851b5872422c9673246f6b700a2b328 100644 (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'
index bc02fce904a20785af626b34194d3e979e9760d2..3dcc023e6e20ba80ffc099e499cca56ac96feb7d 100644 (file)
@@ -1,9 +1,8 @@
 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()
index ae5413b7502459535294e5abbcb8d7d1e7f72499..c87107197e585f9313a3752882a3aac2d7396c3f 100644 (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,
index 3106df9b9279105175eb63785d39757c75c8fd36..75393ad17d9956603bbe80935bcd95c5c45c103e 100644 (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'
index fecdaf5a36ec8a2b3cd2e23a280ef2df496b3067..e78f0f6fce4df412776a84e51cb169aa8e4b8a7f 100644 (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'
index d08c6e13f0e6c4a614e0aae5fa306715f1141f76..c9087fd97ed744caece8c2ae835d9e02ce017eda 100644 (file)
@@ -1,17 +1,11 @@
 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()
index cc00d9f8de5116443d84a236b39a2d438025d637..7c62b54761178e4edbf6cd34a1251bfadee3ba68 100644 (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'
index 276948098ce9775afd4c6521a694f9847a67f2cc..b11da2ef736dabfcf0c7a6030acc2caceb79ceba 100644 (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'
index 8e54d95abd97d6ed4c3b72e0dc7c4fc511c58518..11e3da5cc835a768ef3eaac1d05f63e76161ac47 100644 (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'
index 48b744b0c9dc447d4b8660bd9938934388924a66..b470f27f6e960fca192af0aba50af2dbf9a9d1e2 100644 (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'
index 9a72fe8e085180b0e093ccf5b31f305e7014829f..39e046727291714afa75ded7b1a0945dfd8f859b 100644 (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'
 
index ec8da33509c27a4dbac6d4f247450e626bae21f1..630bace3098c0ffb156a06f0d34dd00477d33926 100644 (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) &&
index 1baea4f6047c697e3eb6684f767baec852b28c74..7dd1d6988a74962388c9ece9ca7408f572b8bf02 100644 (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) ||
diff --git a/server/helpers/custom-validators/activitypub/index.ts b/server/helpers/custom-validators/activitypub/index.ts
deleted file mode 100644 (file)
index ba411f1..0000000
+++ /dev/null
@@ -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'
diff --git a/server/helpers/index.ts b/server/helpers/index.ts
deleted file mode 100644 (file)
index d96bc48..0000000
+++ /dev/null
@@ -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'
index 4b1deeadce1fb0772378ea9690d54bd042668343..ce185a2c0248b3999e0902f2c08cb73abaf3956a 100644 (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 }))
   })
index 76444fbe305e77e2eec5efb1650fdaa9636efd40..de8d52c9ba6b809b5d1f04d86061b464ddd063ef 100644 (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,
index 7e76990b56026eb8dcd6fbe9ac841ad2abc64fe7..45647ab1d5ecc56154e4c26f7820a6a589855412 100644 (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'
index ee3c9dfd9c79a2073ea7136c9d3a2eb45504800e..58713c2c415da6aa81044d1b9a4f474fd5f40950 100644 (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'
index 9b5acb338631493f6f085b0f0e5fa9cfd31c07ec..033f43b681954f8a45da098159d280179d27281f 100644 (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,
index bb2539fc88e3297b8f1af44df4b7acf027b05317..29310b91372a89a4d3b4b8bdbca50b0cb97f17e7 100644 (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'
 
index ff0a291e840bc920ad5e737073781719a733a264..e590dc72d02069107efb1f0b41c4ec13a6c79d05 100644 (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
index a9c6f913c948c6714d7ac25cb42f45c8ecc2eb03..f65395c995f0809dca072731bd12f0d8977f56f9 100644 (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
 }
index 55f8a62d2b028e99fdedc2a05dbe71dec21f5218..9adb40e01c63f6087a15034e21bca920cfdc277e 100644 (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'
index 628942a58add480335b3cda770ddcee1472b0113..ffd20fe7433622aeaacac65381855c364e349f7c 100644 (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
 }
 
index 65a4e5bccd87a0f10c729549583f2d410d3242c5..523a318227407dc3fcef4910442054ab3c249c1e 100644 (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'
index e78005dd06608d81147d19b9f71787edb9e2aa14..5085c5da9af690b7b90adeed282808234be5aa32 100644 (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'
index a7fcec21c37dd924697eae155b23f0ded568bfe5..77fadabe149a7cd2582c48cea0a80b8ce34494c3 100644 (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'
index 4a0181137f465a2a87aa43fced11772ccdbcf3bd..9cad592334b13bf3f9dd830fa0265910eff89b6d 100644 (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'
index 35912ee878cc4b5d6d224abf7f18e427736be04b..a5ad406cba7c8c0cb7a1c85e5cfd40e988b97cfd 100644 (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'
index dfb60c1bfe1904a3ecca0b187d3d253f9afb3bbf..62d310f2101d08c0dc4abb0387161fd44673e8da 100644 (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'
index 2dc8d3d5915a7bfde2dc37fffb71464ebd59fca4..05f327b29714f31d0b456e8ae00c892a8b2d1a5d 100644 (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'
index ca50460be444229ae89703268b334c137309e53a..2f5cdc8c5f46c8924b9d4bbe09c476d6d53d46c7 100644 (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'
index 294a6838d3ec699eb07f68a36b98789146c24009..fd374d03d178a3e1e33c6cc8aaecc6edeac7177f 100644 (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'
index 729bb8dda446a8376a2a2be10e548eebdc83261e..3d5f0523cfd4bb17daeaa15ba6737838c903a74b 100644 (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) {
index 83f3e99331bbd559033a88eca96bec6e90069df1..8bc928b935015cded14667fc998d4ef45e4e2e3d 100644 (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) {
index 930298dbe5fa67d2a066ae20ea7ea23b5d52d7af..d09d55e111704db11c16f490d40ece8819d630f9 100644 (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'
index 3c4d5556fa24426666a7912c3fe35edae4702540..c20a48a4efd55e4037c00da0e4bdfffbc0cba739 100644 (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) {
index 6381502021b415f590e3c8ba956451232e640d15..a7b5aabd059e0e0cd657ad8cdc8bd262219d19f8 100644 (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) {
index 88885cf9723cfa3d196cfb3f5a6a22da4ac02ffa..d576cd42ecaf6471f92d80dd54dae36c9f9ca795 100644 (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'
index 7a5caa679978f18a1141e5e3993e292da8586c76..175ec6642c995db6931375154a4ff6babbd2d82a 100644 (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) {
index 88fe8a4a3a47700af4a45971292092592ec0d22b..9d55880e65b904705fd1ca4418ba73ee7767bfde 100644 (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'
 
index d905882be510721b9a8070a0203a1c66a602ba34..23677e8d54d3fd342f70ac769c267be5c084c9aa 100644 (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'
index 409123bfe47deeaebe64a0cdec0cb53c43d7c69c..883d3eba89bc85b0013bd5962824756407fb1f20 100644 (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'
 
index dce71e83bb4e4677b2ec042b6284911b93f0af72..b3cc75590724775fbb57245f1bb78bf146f61d32 100644 (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'
index c00a6affa07892777ccf4394940f9acf060d0057..1488b42ab1164bd701db841182da7d92c7eb0613 100644 (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'
index 3faecdbcc69fbb818ef28189f22b04ffe32b6a9a..e59168ea81fbec737a7da1ecb0aca601740186ad 100644 (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,
index e16bc4a86206fe20e1b5e3cd91d135b9718dd5e1..a9dcad2d48acebea556ba2155aaedaefff4d6036 100644 (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()
index 0eb50db893655dfd9c946e9ad1fa2699526d1957..fdd6d419fb87f43495bff0e8bebb3da89f0f0915 100644 (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'
index 5d63ebaf4f361dfaf373c2a8db5b5200b877b0ed..5bb5bdfbda5aaee10dcb6902be3bfaf730be9a8c 100644 (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) {
index 6951dfc80d6fbef8c6a9ff7cec0a1d19e70a9285..3573a9a5053a970a9c8abdeb1d75df51e0cd4ee1 100644 (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 = [
index e0225f30cea88a90a5bf9eb804af0b80cc684d87..208e23f8692c1872640b7f9393ef5fba4ba39391 100644 (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 = [
index d41bb6a8d6e387062ef21c0a30607fde98e4577c..4efe9aafa63cacd5a50ceece0e2ebe2927615eae 100644 (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 = [
index 2240d30dba8acfe181f0104043aa1d1040e5e82a..7dadf6a19e49a0c4e716833f55cfcdbb67408ab3 100644 (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'
index fb7b726e5c7913857a6242e2d41d4b52169c70d8..cd9b27b164490e7a5d5e12724e2e4e810c0e4281 100644 (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'
 
index 25debfa6e5c95792d3ef66a19684e76bb2334ee5..e1ed8cd65cb6979c7c85fdb1aee46f1b6cceec01 100644 (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 = [
index 56855bda0e6bf17342df40439a9bb5a5a4ed86f1..e1d8d7d1b681f1ea0a97e31a4c9d2fa5bea5812a 100644 (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'
 
index a6fdbe26805ee1a2777b6c7f872db9204b99dd3b..db40a5c889e09cf40d1b245b7ffd06ef94dfd534 100644 (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'
 
index 61f76b457a4e5df65f67369ddad3329eb4d986af..55b14010387e6406ac5e88aee4b889b73e3bac01 100644 (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)
index 98099fe3f53727d00bb17952c55bc7bb2c9385af..3c1ef1b4ed391ff391ab9321cf6454d3350256b2 100644 (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'
index 0e6eff493d71e7003c7452ae08ed21e8881952c5..86bddde8268dbe4085b919031ac44dff0688662c 100644 (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'
index 1d19fac58fd9c79d5b7c610feba2e512529ccc24..fdd092571bc8897376dd0fc6ff1dcd19acb7f6d4 100644 (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)
index b52d5f28548fb80fd8e1782933c07606655bbb33..bffc5032256273ff55c24c3eaf60ac0314a36341 100644 (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'
index 894c724982004e03b042eec673b61864917bbea6..3dbec6e4481d2af07f0428e1c9120e3913e48fd4 100644 (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'
 
index 1d5759ea3f6c7874f0d1bdabf6c2fc3f781fd360..d7e09e3288d12d597c342fe3884d4ace152dbab5 100644 (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'
index e7eb35e2c000637ceb929a4de0552a764d7b9933..3d96b3706bc4c5690c9be56c90e206125c291b51 100644 (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'
index 995fa33d5926b93e024e287b408b0af6bca569c3..9d1b63813642b3b0792ad0a434accbeae2dd22b7 100644 (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'
index edfd8010b9f5e6b8fd67ae36871c7c6366b569ac..d35aa0ca402222f3ec6a2c54bdf371739867846f 100644 (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'
 
index 6db56271907d9456d9f1239c4c1985158c5d9732..3adcec149f402a1956f952e51b8bdbd3a9e588ca 100644 (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'
 
index 8ceeb563add9748866355f0dfa06779bdc21c7c3..1992c2dd88f1d175d6e88f32f3f0594ad3f86008 100644 (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
     }
   }
 }
index b6a2ce6b5f915a11b06134e841ffbafb7e59da3e..2504ae58a1693d668e677a596a0298e15e593c6a 100644 (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',
index fc2a9e83709cff15e9fbf61a4113bc5b1d3f73c5..785fbbc0df1e9aa90023d071a0ff50cee78e8900 100644 (file)
@@ -4,5 +4,7 @@ export interface VideoCommentObject {
   content: string
   inReplyTo: string
   published: string
+  updated: string
   url: string
+  attributedTo: string
 }
index 1405f7748c414f347aabe9fe1f41a04fbf9a99f4..5ccc80bcbfdbea8c6b732a2558afc51be975503c 100644 (file)
@@ -27,5 +27,6 @@ export interface VideoTorrentObject {
   likes?: ActivityPubOrderedCollection<string>
   dislikes?: ActivityPubOrderedCollection<string>
   shares?: ActivityPubOrderedCollection<string>
+  comments?: ActivityPubOrderedCollection<string>
   attributedTo: ActivityPubAttributedTo[]
 }