Fix video upload and videos list
authorChocobozzz <florian.bigard@gmail.com>
Wed, 15 Nov 2017 15:28:35 +0000 (16:28 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Mon, 27 Nov 2017 18:40:52 +0000 (19:40 +0100)
12 files changed:
server/controllers/api/server/follows.ts
server/helpers/custom-validators/activitypub/videos.ts
server/helpers/custom-validators/videos.ts
server/lib/activitypub/send-request.ts
server/lib/jobs/http-request-job-scheduler/http-request-broadcast-handler.ts
server/lib/jobs/http-request-job-scheduler/http-request-unicast-handler.ts
server/lib/jobs/job-scheduler.ts
server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts
server/models/account/account-follow-interface.ts
server/models/account/account-follow.ts
server/models/account/account.ts
server/models/video/video.ts

index c9775ad21f7cb9b2ddcdc9df8eb215ba356d41e3..ac8ea87f93cbf1947bf287171eb9eccf218b11b9 100644 (file)
@@ -108,7 +108,11 @@ async function follow (req: express.Request, res: express.Response, next: expres
     tasks.push(p)
   }
 
-  await Promise.all(tasks)
+  // Don't make the client wait the tasks
+  Promise.all(tasks)
+    .catch(err => {
+      logger.error('Error in follow.', err)
+    })
 
   return res.status(204).end()
 }
index c9ecf1f3de0b75fd0e86b3e68c831b290c26d738..a46757397e74e7bf80c6bab35a43a2c883b85386 100644 (file)
@@ -1,20 +1,17 @@
 import * as validator from 'validator'
-
-import {
-  ACTIVITY_PUB
-} from '../../../initializers'
-import { isDateValid, isUUIDValid } from '../misc'
+import { ACTIVITY_PUB } from '../../../initializers'
+import { exists, isDateValid, isUUIDValid } from '../misc'
+import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
 import {
-  isVideoViewsValid,
-  isVideoNSFWValid,
-  isVideoTruncatedDescriptionValid,
   isVideoDurationValid,
   isVideoNameValid,
+  isVideoNSFWValid,
   isVideoTagValid,
-  isVideoUrlValid
+  isVideoTruncatedDescriptionValid,
+  isVideoUrlValid,
+  isVideoViewsValid
 } from '../videos'
-import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
-import { isActivityPubUrlValid, isBaseActivityValid } from './misc'
+import { isBaseActivityValid } from './misc'
 
 function isVideoTorrentAddActivityValid (activity: any) {
   return isBaseActivityValid(activity, 'Add') &&
@@ -30,10 +27,19 @@ function isVideoTorrentDeleteActivityValid (activity: any) {
   return isBaseActivityValid(activity, 'Delete')
 }
 
+function isActivityPubVideoDurationValid (value: string) {
+  // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
+  return exists(value) &&
+    typeof value === 'string' &&
+    value.startsWith('PT') &&
+    value.endsWith('S') &&
+    isVideoDurationValid(value.replace(/[^0-9]+/, ''))
+}
+
 function isVideoTorrentObjectValid (video: any) {
   return video.type === 'Video' &&
     isVideoNameValid(video.name) &&
-    isVideoDurationValid(video.duration) &&
+    isActivityPubVideoDurationValid(video.duration) &&
     isUUIDValid(video.uuid) &&
     setValidRemoteTags(video) &&
     isRemoteIdentifierValid(video.category) &&
index 1505632da8720a6baee20ff2077d17b0e4f1a8ed..c97c9a2add26ee2d8704c009a10eeebb21ba7ab8 100644 (file)
@@ -69,6 +69,10 @@ function isVideoNSFWValid (value: any) {
   return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
 }
 
+function isVideoDurationValid (value: string) {
+  return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
+}
+
 function isVideoTruncatedDescriptionValid (value: string) {
   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
 }
@@ -77,15 +81,6 @@ function isVideoDescriptionValid (value: string) {
   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
 }
 
-function isVideoDurationValid (value: string) {
-  // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
-  return exists(value) &&
-    typeof value === 'string' &&
-    value.startsWith('PT') &&
-    value.endsWith('S') &&
-    validator.isInt(value.replace(/[^0-9]+/, ''), VIDEOS_CONSTRAINTS_FIELDS.DURATION)
-}
-
 function isVideoNameValid (value: string) {
   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
 }
@@ -197,7 +192,6 @@ export {
   isVideoNSFWValid,
   isVideoTruncatedDescriptionValid,
   isVideoDescriptionValid,
-  isVideoDurationValid,
   isVideoFileInfoHashValid,
   isVideoNameValid,
   isVideoTagsValid,
@@ -214,6 +208,7 @@ export {
   isVideoFileSizeValid,
   isVideoPrivacyValid,
   isRemoteVideoPrivacyValid,
+  isVideoDurationValid,
   isVideoFileResolutionValid,
   checkVideoExists,
   isVideoTagValid,
index 1a6cebc0391a931e9d0c2d1cc993cf2842770c02..1dad51828b15085f76dc8f91d767a3d0b221af96 100644 (file)
@@ -11,6 +11,7 @@ import { signObject, activityPubContextify } from '../../helpers'
 import { Activity } from '../../../shared'
 import { VideoAbuseInstance } from '../../models/video/video-abuse-interface'
 import { getActivityPubUrl } from '../../helpers/activitypub'
+import { logger } from '../../helpers/logger'
 
 async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
   const videoChannelObject = videoChannel.toActivityPubObject()
@@ -100,7 +101,11 @@ export {
 // ---------------------------------------------------------------------------
 
 async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
-  const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id, 0)
+  const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id)
+  if (result.data.length === 0) {
+    logger.info('Not broadcast because of 0 followers.')
+    return
+  }
 
   const jobPayload = {
     uris: result.data,
index 2f1d9ee9284737488627569d4dc9454377162a5b..ccb008e4d0222ce2c28b066202f88b4990143e4f 100644 (file)
@@ -22,8 +22,9 @@ function onError (err: Error, jobId: number) {
   return Promise.resolve()
 }
 
-async function onSuccess (jobId: number) {
+function onSuccess (jobId: number) {
   logger.info('Job %d is a success.', jobId)
+  return Promise.resolve()
 }
 
 // ---------------------------------------------------------------------------
index 3a1a7fabf681b010bc541c211aa6ecda32762360..9e4e73891854b97eadbc214028dd4dc0883fbd2c 100644 (file)
@@ -20,8 +20,9 @@ function onError (err: Error, jobId: number) {
   return Promise.resolve()
 }
 
-async function onSuccess (jobId: number) {
+function onSuccess (jobId: number) {
   logger.info('Job %d is a success.', jobId)
+  return Promise.resolve()
 }
 
 // ---------------------------------------------------------------------------
index b25bb7ab399dbae6f055a64d894bd3384c852ca1..73c44027907fefae700148fc574475966ab44804 100644 (file)
@@ -9,7 +9,7 @@ import { error } from 'util'
 export interface JobHandler<P, T> {
   process (data: object, jobId: number): Promise<T>
   onError (err: Error, jobId: number)
-  onSuccess (jobId: number, jobResult: T, jobScheduler: JobScheduler<P, T>)
+  onSuccess (jobId: number, jobResult: T, jobScheduler: JobScheduler<P, T>): Promise<any>
 }
 type JobQueueCallback = (err: Error) => void
 
@@ -127,7 +127,7 @@ class JobScheduler<P, T> {
 
     try {
       await job.save()
-      jobHandler.onSuccess(job.id, jobResult, this)
+      await jobHandler.onSuccess(job.id, jobResult, this)
     } catch (err) {
       this.cannotSaveJobError(err)
     }
index d3ee886e7f535e7d394aa1088fad0b6e9739675b..f6d9627a5322fbf29d77351d0647b6d5fa1a98f6 100644 (file)
@@ -39,8 +39,8 @@ async function onSuccess (jobId: number, video: VideoInstance, jobScheduler: Job
   await sendAddVideo(video, undefined)
 
   const originalFileHeight = await videoDatabase.getOriginalFileHeight()
-  // Create transcoding jobs if there are enabled resolutions
 
+  // Create transcoding jobs if there are enabled resolutions
   const resolutionsEnabled = computeResolutionsToTranscode(originalFileHeight)
   logger.info(
     'Resolutions computed for video %s and origin file height of %d.', videoDatabase.uuid, originalFileHeight,
index 413dad190f0afa9042fcc696f6c6c40484e5fffc..54baf45ed4b857b76bafd6345fdb74461f87b3a7 100644 (file)
@@ -10,8 +10,8 @@ export namespace AccountFollowMethods {
   export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
   export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
 
-  export type ListAcceptedFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
-  export type ListAcceptedFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
+  export type ListAcceptedFollowerUrlsForApi = (id: number, start?: number, count?: number) => Promise< ResultList<string> >
+  export type ListAcceptedFollowingUrlsForApi = (id: number, start?: number, count?: number) => Promise< ResultList<string> >
 }
 
 export interface AccountFollowClass {
index c940d7cd4d3987aa8ae3be54bc8be03999aee85c..f457e43e9d28e6b8be764b0fad7f9a1eb9299c86 100644 (file)
@@ -146,17 +146,17 @@ listFollowersForApi = function (id: number, start: number, count: number, sort:
   })
 }
 
-listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) {
-  return createListAcceptedFollowForApiQuery('followers', id, start, count)
+listAcceptedFollowerUrlsForApi = function (accountId: number, start?: number, count?: number) {
+  return createListAcceptedFollowForApiQuery('followers', accountId, start, count)
 }
 
-listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) {
-  return createListAcceptedFollowForApiQuery('following', id, start, count)
+listAcceptedFollowingUrlsForApi = function (accountId: number, start?: number, count?: number) {
+  return createListAcceptedFollowForApiQuery('following', accountId, start, count)
 }
 
 // ------------------------------ UTILS ------------------------------
 
-async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
+async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', accountId: number, start?: number, count?: number) {
   let firstJoin: string
   let secondJoin: string
 
@@ -168,20 +168,20 @@ async function createListAcceptedFollowForApiQuery (type: 'followers' | 'followi
     secondJoin = 'targetAccountId'
   }
 
-  const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ]
+  const selections = [ '"Follows"."url" AS "url"', 'COUNT(*) AS "total"' ]
   const tasks: Promise<any>[] = []
 
   for (const selection of selections) {
-    let query = 'SELECT ' + selection + ' FROM "Account" ' +
-      'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' +
-      'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
-      'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' +
-      'LIMIT ' + start
+    let query = 'SELECT ' + selection + ' FROM "Accounts" ' +
+      'INNER JOIN "AccountFollows" ON "AccountFollows"."' + firstJoin + '" = "Accounts"."id" ' +
+      'INNER JOIN "Accounts" AS "Follows" ON "AccountFollows"."' + secondJoin + '" = "Follows"."id" ' +
+      'WHERE "Accounts"."id" = $accountId AND "AccountFollows"."state" = \'accepted\' '
 
+    if (start !== undefined) query += 'LIMIT ' + start
     if (count !== undefined) query += ', ' + count
 
     const options = {
-      bind: { id },
+      bind: { accountId },
       type: Sequelize.QueryTypes.SELECT
     }
     tasks.push(AccountFollow['sequelize'].query(query, options))
index 464105261a463bba2e58b03dae10cce89fc5ab29..84461a2eb481be098591d5569a1a77ece95a2de0 100644 (file)
@@ -263,6 +263,7 @@ function associate (models) {
       name: 'targetAccountId',
       allowNull: false
     },
+    as: 'followers',
     onDelete: 'cascade'
   })
 }
index 86800fb8897248a1411ff5e80e283db94d1be32b..b00081f25ef54966f49a588be353de849d24aafe 100644 (file)
@@ -329,7 +329,7 @@ function associate (models) {
     onDelete: 'cascade'
   })
 
-  Video.belongsTo(models.VideoChannel, {
+  Video.belongsTo(models.Video, {
     foreignKey: {
       name: 'parentId',
       allowNull: true
@@ -825,9 +825,11 @@ listForApi = function (start: number, count: number, sort: string) {
     include: [
       {
         model: Video['sequelize'].models.VideoChannel,
+        required: true,
         include: [
           {
             model: Video['sequelize'].models.Account,
+            required: true,
             include: [
               {
                 model: Video['sequelize'].models.Server,