Add ability to skip count query
authorChocobozzz <me@florianbigard.com>
Wed, 8 Jan 2020 13:15:16 +0000 (14:15 +0100)
committerChocobozzz <me@florianbigard.com>
Wed, 8 Jan 2020 13:15:16 +0000 (14:15 +0100)
13 files changed:
server/controllers/api/accounts.ts
server/controllers/api/overviews.ts
server/controllers/api/users/my-subscriptions.ts
server/controllers/api/video-channel.ts
server/controllers/api/videos/index.ts
server/controllers/bots.ts
server/helpers/express-utils.ts
server/middlewares/validators/videos/videos.ts
server/models/video/video.ts
server/tests/api/check-params/videos-filter.ts
server/tests/api/check-params/videos.ts
server/tests/api/videos/single-server.ts
shared/extra-utils/videos/videos.ts

index c49da3c0ac79b145a57fa5228967805d2978b713..00148ff555a7dd0282ff30fb7fcbf14c77edc8ef 100644 (file)
@@ -22,7 +22,7 @@ import {
 import { AccountModel } from '../../models/account/account'
 import { AccountVideoRateModel } from '../../models/account/account-video-rate'
 import { VideoModel } from '../../models/video/video'
-import { buildNSFWFilter, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
+import { buildNSFWFilter, isUserAbleToSearchRemoteURI, getCountVideos } from '../../helpers/express-utils'
 import { VideoChannelModel } from '../../models/video/video-channel'
 import { JobQueue } from '../../lib/job-queue'
 import { logger } from '../../helpers/logger'
@@ -155,6 +155,7 @@ async function listAccountPlaylists (req: express.Request, res: express.Response
 async function listAccountVideos (req: express.Request, res: express.Response) {
   const account = res.locals.account
   const followerActorId = isUserAbleToSearchRemoteURI(res) ? null : undefined
+  const countVideos = getCountVideos(req)
 
   const resultList = await VideoModel.listForApi({
     followerActorId,
@@ -171,7 +172,8 @@ async function listAccountVideos (req: express.Request, res: express.Response) {
     nsfw: buildNSFWFilter(res, req.query.nsfw),
     withFiles: false,
     accountId: account.id,
-    user: res.locals.oauth ? res.locals.oauth.token.User : undefined
+    user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
+    countVideos
   })
 
   return res.json(getFormattedObjects(resultList.data, resultList.total))
index 37ac152dbe5ee2f47f28da27fc2fa86df3e07ce3..23706767a66069f02810646f775eacf00377fb30 100644 (file)
@@ -98,10 +98,11 @@ async function getVideos (
     sort: '-createdAt',
     includeLocalVideos: true,
     nsfw: buildNSFWFilter(res),
-    withFiles: false
+    withFiles: false,
+    countVideos: false
   }, where)
 
-  const { data } = await VideoModel.listForApi(query, false)
+  const { data } = await VideoModel.listForApi(query)
 
   return data.map(d => d.toFormattedJSON())
 }
index c52df31544fbe546998cf142a205fdba3f8200e9..43c4c37d84b1ae08f8bdc6da21928268dd6809e2 100644 (file)
@@ -15,7 +15,7 @@ import {
 } from '../../../middlewares'
 import { areSubscriptionsExistValidator, userSubscriptionsSortValidator, videosSortValidator } from '../../../middlewares/validators'
 import { VideoModel } from '../../../models/video/video'
-import { buildNSFWFilter } from '../../../helpers/express-utils'
+import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils'
 import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
 import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 import { JobQueue } from '../../../lib/job-queue'
@@ -149,6 +149,8 @@ async function getUserSubscriptions (req: express.Request, res: express.Response
 
 async function getUserSubscriptionVideos (req: express.Request, res: express.Response) {
   const user = res.locals.oauth.token.User
+  const countVideos = getCountVideos(req)
+
   const resultList = await VideoModel.listForApi({
     start: req.query.start,
     count: req.query.count,
@@ -163,7 +165,8 @@ async function getUserSubscriptionVideos (req: express.Request, res: express.Res
     filter: req.query.filter as VideoFilter,
     withFiles: false,
     followerActorId: user.Account.Actor.id,
-    user
+    user,
+    countVideos
   })
 
   return res.json(getFormattedObjects(resultList.data, resultList.total))
index acc5b2987c652e6f10f69951bab16a45983b41c8..e1f37a8fb7a3213290e6a5c72b210c9a407d7c33 100644 (file)
@@ -20,7 +20,7 @@ import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../m
 import { sendUpdateActor } from '../../lib/activitypub/send'
 import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
 import { createLocalVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel'
-import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
+import { buildNSFWFilter, createReqFiles, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
 import { setAsyncActorKeys } from '../../lib/activitypub'
 import { AccountModel } from '../../models/account/account'
 import { MIMETYPES } from '../../initializers/constants'
@@ -256,6 +256,7 @@ async function listVideoChannelPlaylists (req: express.Request, res: express.Res
 async function listVideoChannelVideos (req: express.Request, res: express.Response) {
   const videoChannelInstance = res.locals.videoChannel
   const followerActorId = isUserAbleToSearchRemoteURI(res) ? null : undefined
+  const countVideos = getCountVideos(req)
 
   const resultList = await VideoModel.listForApi({
     followerActorId,
@@ -272,7 +273,8 @@ async function listVideoChannelVideos (req: express.Request, res: express.Respon
     nsfw: buildNSFWFilter(res, req.query.nsfw),
     withFiles: false,
     videoChannelId: videoChannelInstance.id,
-    user: res.locals.oauth ? res.locals.oauth.token.User : undefined
+    user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
+    countVideos
   })
 
   return res.json(getFormattedObjects(resultList.data, resultList.total))
index 35f0b3152934e97cdbda3e4c2fba5220e9ea3fab..8d4ff07eb8b35daaeab6c672f6078e24e2dfccf9 100644 (file)
@@ -48,7 +48,7 @@ import { videoCommentRouter } from './comment'
 import { rateVideoRouter } from './rate'
 import { ownershipVideoRouter } from './ownership'
 import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
-import { buildNSFWFilter, createReqFiles } from '../../../helpers/express-utils'
+import { buildNSFWFilter, createReqFiles, getCountVideos } from '../../../helpers/express-utils'
 import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
 import { videoCaptionsRouter } from './captions'
 import { videoImportsRouter } from './import'
@@ -495,6 +495,8 @@ async function getVideoDescription (req: express.Request, res: express.Response)
 }
 
 async function listVideos (req: express.Request, res: express.Response) {
+  const countVideos = getCountVideos(req)
+
   const apiOptions = await Hooks.wrapObject({
     start: req.query.start,
     count: req.query.count,
@@ -508,7 +510,8 @@ async function listVideos (req: express.Request, res: express.Response) {
     nsfw: buildNSFWFilter(res, req.query.nsfw),
     filter: req.query.filter as VideoFilter,
     withFiles: false,
-    user: res.locals.oauth ? res.locals.oauth.token.User : undefined
+    user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
+    countVideos
   }, 'filter:api.videos.list.params')
 
   const resultList = await Hooks.wrapPromiseFun(
index ed10401768560c3cb56117006edd03c64d5a36c8..f3e778b04b11ce3cf475305a87f39af8ac34fcdb 100644 (file)
@@ -61,17 +61,18 @@ async function getSitemapAccountUrls () {
 }
 
 async function getSitemapLocalVideoUrls () {
-  const resultList = await VideoModel.listForApi({
+  const { data } = await VideoModel.listForApi({
     start: 0,
     count: undefined,
     sort: 'createdAt',
     includeLocalVideos: true,
     nsfw: buildNSFWFilter(),
     filter: 'local',
-    withFiles: false
+    withFiles: false,
+    countVideos: false
   })
 
-  return resultList.data.map(v => ({
+  return data.map(v => ({
     url: WEBSERVER.URL + '/videos/watch/' + v.uuid,
     video: [
       {
index 00f3f198bc2195087a69333cf4c46ab37f2d204d..9bf6d85a87a21f76338090a551cabb425e4dd463 100644 (file)
@@ -117,6 +117,10 @@ function isUserAbleToSearchRemoteURI (res: express.Response) {
     (CONFIG.SEARCH.REMOTE_URI.USERS === true && user !== undefined)
 }
 
+function getCountVideos (req: express.Request) {
+  return req.query.skipCount !== true
+}
+
 // ---------------------------------------------------------------------------
 
 export {
@@ -125,5 +129,6 @@ export {
   isUserAbleToSearchRemoteURI,
   badRequest,
   createReqFiles,
-  cleanUpReqFiles
+  cleanUpReqFiles,
+  getCountVideos
 }
index 5e0182cc341389244e37dfb8e852d75ea43ef6c5..6733d9dec4366cf32b821a7b3a03d715ca0e00d6 100644 (file)
@@ -381,6 +381,10 @@ const commonVideosFiltersValidator = [
   query('filter')
     .optional()
     .custom(isVideoFilterValid).withMessage('Should have a valid filter attribute'),
+  query('skipCount')
+    .optional()
+    .customSanitizer(toBooleanOrNull)
+    .custom(isBooleanValid).withMessage('Should have a valid skip count boolean'),
 
   (req: express.Request, res: express.Response, next: express.NextFunction) => {
     logger.debug('Checking commons video filters query', { parameters: req.query })
index e85c5e38eee6a1a87f0dc20308c9cb51ecbbf073..cd3245ee400c45d8805c8dcdea1c13bdae017437 100644 (file)
@@ -1284,8 +1284,9 @@ export class VideoModel extends Model<VideoModel> {
     videoPlaylistId?: number,
     trendingDays?: number,
     user?: MUserAccountId,
-    historyOfUser?: MUserId
-  }, countVideos = true) {
+    historyOfUser?: MUserId,
+    countVideos?: boolean
+  }) {
     if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
       throw new Error('Try to filter all-local but no user has not the see all videos right')
     }
@@ -1328,7 +1329,7 @@ export class VideoModel extends Model<VideoModel> {
       trendingDays
     }
 
-    return VideoModel.getAvailableForApi(query, queryOptions, countVideos)
+    return VideoModel.getAvailableForApi(query, queryOptions, options.countVideos)
   }
 
   static async searchAndPopulateAccountAndServer (options: {
index 5a5668665f6553a39df2078c6cbcbb385889e60a..811756745c299387ad5981ee0a0c01082eecd256 100644 (file)
@@ -40,7 +40,6 @@ describe('Test videos filters', function () {
   let server: ServerInfo
   let userAccessToken: string
   let moderatorAccessToken: string
-  let playlistUUID: string
 
   // ---------------------------------------------------------------
 
index fa6d6f6226d9a773a10d7df761024a975b00f2c7..16ef1c50521761dc71fca2d86a4c73dc087201a1 100644 (file)
@@ -75,8 +75,12 @@ describe('Test videos API validator', function () {
       await checkBadSortPagination(server.url, path)
     })
 
+    it('Should fail with a bad skipVideos query', async function () {
+      await makeGetRequest({ url: server.url, path, statusCodeExpected: 200, query: { skipCount: 'toto' } })
+    })
+
     it('Should success with the correct parameters', async function () {
-      await makeGetRequest({ url: server.url, path, statusCodeExpected: 200 })
+      await makeGetRequest({ url: server.url, path, statusCodeExpected: 200, query: { skipCount: false } })
     })
   })
 
index d8f394ac749b6cc5c2ca646b74fcf6ddd750ecbe..362d6b78fb0068e70f6410c15d31acb8737f585b 100644 (file)
@@ -322,6 +322,15 @@ describe('Test a single server', function () {
     expect(videos[0].name).to.equal(videosListBase[5].name)
   })
 
+  it('Should not have the total field', async function () {
+    const res = await getVideosListPagination(server.url, 5, 6, 'name', true)
+
+    const videos = res.body.data
+    expect(res.body.total).to.not.exist
+    expect(videos.length).to.equal(1)
+    expect(videos[0].name).to.equal(videosListBase[5].name)
+  })
+
   it('Should list and sort by name in descending order', async function () {
     const res = await getVideosListSort(server.url, '-name')
 
index c5de15552117d3895bcae1523bb32d5c1259367f..9dec12703d0080720850288424e0788b01c19462 100644 (file)
@@ -248,7 +248,7 @@ function getPlaylistVideos (
   })
 }
 
-function getVideosListPagination (url: string, start: number, count: number, sort?: string) {
+function getVideosListPagination (url: string, start: number, count: number, sort?: string, skipCount?: boolean) {
   const path = '/api/v1/videos'
 
   const req = request(url)
@@ -257,6 +257,7 @@ function getVideosListPagination (url: string, start: number, count: number, sor
               .query({ count: count })
 
   if (sort) req.query({ sort })
+  if (skipCount) req.query({ skipCount })
 
   return req.set('Accept', 'application/json')
            .expect(200)