]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Update channel updatedAt when uploading a video
authorChocobozzz <me@florianbigard.com>
Fri, 7 May 2021 15:14:39 +0000 (17:14 +0200)
committerChocobozzz <me@florianbigard.com>
Mon, 10 May 2021 07:38:11 +0000 (09:38 +0200)
12 files changed:
server/controllers/api/videos/index.ts
server/helpers/database-utils.ts
server/lib/activitypub/actor.ts
server/lib/activitypub/videos.ts
server/models/account/account.ts
server/models/activitypub/actor.ts
server/models/video/video-channel.ts
server/models/video/video.ts
server/tests/api/videos/video-channels.ts
shared/models/actors/account.model.ts
shared/models/actors/actor.model.ts
shared/models/videos/channel/video-channel.model.ts

index 6ec6478e4666f1e10210f83eb0d684fb8ccc10f4..fbdb0f77687cdcf19b43cf6d577279ce2cb072a1 100644 (file)
@@ -248,6 +248,9 @@ async function addVideo (req: express.Request, res: express.Response) {
       }, { transaction: t })
     }
 
+    // Channel has a new content, set as updated
+    await videoCreated.VideoChannel.setAsUpdated(t)
+
     await autoBlacklistVideoIfNeeded({
       video,
       user: res.locals.oauth.token.User,
index 2b916efc2d948663e504be0c719cc6c7b1e47b0c..f9cb33acafbb4729b4b997e603e9e5805ad4c9a4 100644 (file)
@@ -1,8 +1,9 @@
 import * as retry from 'async/retry'
 import * as Bluebird from 'bluebird'
+import { QueryTypes, Transaction } from 'sequelize'
 import { Model } from 'sequelize-typescript'
+import { sequelizeTypescript } from '@server/initializers/database'
 import { logger } from './logger'
-import { Transaction } from 'sequelize'
 
 function retryTransactionWrapper <T, A, B, C, D> (
   functionToRetry: (arg1: A, arg2: B, arg3: C, arg4: D) => Promise<T> | Bluebird<T>,
@@ -96,6 +97,18 @@ function deleteNonExistingModels <T extends { hasSameUniqueKeysThan (other: T):
               .map(f => f.destroy({ transaction: t }))
 }
 
+// Sequelize always skip the update if we only update updatedAt field
+function setAsUpdated (table: string, id: number, transaction?: Transaction) {
+  return sequelizeTypescript.query(
+    `UPDATE "${table}" SET "updatedAt" = :updatedAt WHERE id = :id`,
+    {
+      replacements: { table, id, updatedAt: new Date() },
+      type: QueryTypes.UPDATE,
+      transaction
+    }
+  )
+}
+
 // ---------------------------------------------------------------------------
 
 export {
@@ -104,5 +117,6 @@ export {
   transactionRetryer,
   updateInstanceWithAnother,
   afterCommitIfTransaction,
-  deleteNonExistingModels
+  deleteNonExistingModels,
+  setAsUpdated
 }
index 34d53bd52e4055aaf6064a9a18a1ca6eb88eb7be..5fe7381c9753784aa507c000549cfd701aea61e7 100644 (file)
@@ -154,8 +154,6 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ
   const followersCount = await fetchActorTotalItems(attributes.followers)
   const followingCount = await fetchActorTotalItems(attributes.following)
 
-  logger.info('coucou', { attributes })
-
   actorInstance.type = attributes.type
   actorInstance.preferredUsername = attributes.preferredUsername
   actorInstance.url = attributes.id
index 506204674dbafad0f6bced6113d74b83a2e4ec85..15726f90be25cb0b2d19cebba31eae1638d305bb 100644 (file)
@@ -697,6 +697,9 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi
         videoCreated.VideoLive = await videoLive.save({ transaction: t })
       }
 
+      // We added a video in this channel, set it as updated
+      await channel.setAsUpdated(t)
+
       const autoBlacklisted = await autoBlacklistVideoIfNeeded({
         video: videoCreated,
         user: undefined,
index 44be0fd3ca1930cffb9390b5b79967afc87b136c..d33353af71d7bef35eac78f9a3e97b2c1d032bcf 100644 (file)
@@ -411,6 +411,7 @@ export class AccountModel extends Model {
       id: this.id,
       displayName: this.getDisplayName(),
       description: this.description,
+      updatedAt: this.updatedAt,
       userId: this.userId ? this.userId : undefined
     }
 
index 396a52337e5f27b5fbfdca8ada076dfc2138110c..1af9efac2b740cedf7bf0435c477b190bcff27a9 100644 (file)
@@ -557,8 +557,7 @@ export class ActorModel extends Model {
       followingCount: this.followingCount,
       followersCount: this.followersCount,
       banner,
-      createdAt: this.getCreatedAt(),
-      updatedAt: this.updatedAt
+      createdAt: this.getCreatedAt()
     })
   }
 
index b627595c9347628bd1e6893d1fd042a97fe128df..081b21f2d7d0a6c437c8e4f589ac49ad62f1799c 100644 (file)
@@ -1,4 +1,4 @@
-import { FindOptions, Includeable, literal, Op, QueryTypes, ScopeOptions } from 'sequelize'
+import { FindOptions, Includeable, literal, Op, QueryTypes, ScopeOptions, Transaction } from 'sequelize'
 import {
   AllowNull,
   BeforeDestroy,
@@ -17,6 +17,7 @@ import {
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
+import { setAsUpdated } from '@server/helpers/database-utils'
 import { MAccountActor } from '@server/types/models'
 import { ActivityPubActor } from '../../../shared/models/activitypub'
 import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos'
@@ -653,6 +654,7 @@ ON              "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
       description: this.description,
       support: this.support,
       isLocal: this.Actor.isOwned(),
+      updatedAt: this.updatedAt,
       ownerAccount: undefined,
       videosCount,
       viewsPerDay
@@ -689,4 +691,8 @@ ON              "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
   isOutdated () {
     return this.Actor.isOutdated()
   }
+
+  setAsUpdated (transaction: Transaction) {
+    return setAsUpdated('videoChannel', this.id, transaction)
+  }
 }
index e55a21a6b69c0c031ebc195423adf42e03975862..8c316e00c78a283f6e312b4c6d7450269b65292f 100644 (file)
@@ -24,6 +24,7 @@ import {
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
+import { setAsUpdated } from '@server/helpers/database-utils'
 import { buildNSFWFilter } from '@server/helpers/express-utils'
 import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video'
 import { LiveManager } from '@server/lib/live-manager'
@@ -2053,11 +2054,7 @@ export class VideoModel extends Model {
   }
 
   setAsRefreshed () {
-    const options = {
-      where: { id: this.id }
-    }
-
-    return VideoModel.update({ updatedAt: new Date() }, options)
+    return setAsUpdated('video', this.id)
   }
 
   requiresAuth () {
index d12d58e75e771d76afb3493125dc045895076da8..7e7ad028cc72c5ba53a0a47badff07e049f90b8d 100644 (file)
@@ -3,6 +3,7 @@
 import 'mocha'
 import * as chai from 'chai'
 import { basename } from 'path'
+import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
 import {
   cleanupTests,
   createUser,
@@ -13,6 +14,7 @@ import {
   getVideo,
   getVideoChannel,
   getVideoChannelVideos,
+  setDefaultVideoChannel,
   testImage,
   updateVideo,
   updateVideoChannelImage,
@@ -33,7 +35,6 @@ import {
 } from '../../../../shared/extra-utils/index'
 import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index'
-import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
 
 const expect = chai.expect
 
@@ -47,9 +48,10 @@ async function findChannel (server: ServerInfo, channelId: number) {
 describe('Test video channels', function () {
   let servers: ServerInfo[]
   let userInfo: User
-  let firstVideoChannelId: number
   let secondVideoChannelId: number
+  let totoChannel: number
   let videoUUID: string
+  let accountName: string
 
   before(async function () {
     this.timeout(60000)
@@ -57,16 +59,9 @@ describe('Test video channels', function () {
     servers = await flushAndRunMultipleServers(2)
 
     await setAccessTokensToServers(servers)
-    await doubleFollow(servers[0], servers[1])
-
-    {
-      const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
-      const user: User = res.body
-
-      firstVideoChannelId = user.videoChannels[0].id
-    }
+    await setDefaultVideoChannel(servers)
 
-    await waitJobs(servers)
+    await doubleFollow(servers[0], servers[1])
   })
 
   it('Should have one video channel (created with root)', async () => {
@@ -116,12 +111,14 @@ describe('Test video channels', function () {
     expect(videoChannels[1].displayName).to.equal('second video channel')
     expect(videoChannels[1].description).to.equal('super video channel description')
     expect(videoChannels[1].support).to.equal('super video channel support text')
+
+    accountName = userInfo.account.name + '@' + userInfo.account.host
   })
 
   it('Should have two video channels when getting account channels on server 1', async function () {
     const res = await getAccountVideoChannelsList({
       url: servers[0].url,
-      accountName: userInfo.account.name + '@' + userInfo.account.host
+      accountName
     })
 
     expect(res.body.total).to.equal(2)
@@ -142,7 +139,7 @@ describe('Test video channels', function () {
     {
       const res = await getAccountVideoChannelsList({
         url: servers[0].url,
-        accountName: userInfo.account.name + '@' + userInfo.account.host,
+        accountName,
         start: 0,
         count: 1,
         sort: 'createdAt'
@@ -158,7 +155,7 @@ describe('Test video channels', function () {
     {
       const res = await getAccountVideoChannelsList({
         url: servers[0].url,
-        accountName: userInfo.account.name + '@' + userInfo.account.host,
+        accountName,
         start: 0,
         count: 1,
         sort: '-createdAt'
@@ -174,7 +171,7 @@ describe('Test video channels', function () {
     {
       const res = await getAccountVideoChannelsList({
         url: servers[0].url,
-        accountName: userInfo.account.name + '@' + userInfo.account.host,
+        accountName,
         start: 1,
         count: 1,
         sort: '-createdAt'
@@ -191,7 +188,7 @@ describe('Test video channels', function () {
   it('Should have one video channel when getting account channels on server 2', async function () {
     const res = await getAccountVideoChannelsList({
       url: servers[1].url,
-      accountName: userInfo.account.name + '@' + userInfo.account.host
+      accountName
     })
 
     expect(res.body.total).to.equal(1)
@@ -379,7 +376,7 @@ describe('Test video channels', function () {
   it('Should change the video channel of a video', async function () {
     this.timeout(10000)
 
-    await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { channelId: firstVideoChannelId })
+    await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { channelId: servers[0].videoChannel.id })
 
     await waitJobs(servers)
   })
@@ -419,7 +416,8 @@ describe('Test video channels', function () {
   it('Should create the main channel with an uuid if there is a conflict', async function () {
     {
       const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
-      await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
+      const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
+      totoChannel = res.body.videoChannel.id
     }
 
     {
@@ -438,7 +436,7 @@ describe('Test video channels', function () {
     {
       const res = await getAccountVideoChannelsList({
         url: servers[0].url,
-        accountName: userInfo.account.name + '@' + userInfo.account.host,
+        accountName,
         withStats: true
       })
 
@@ -456,7 +454,7 @@ describe('Test video channels', function () {
     }
 
     {
-      // video has been posted on channel firstVideoChannelId since last update
+      // video has been posted on channel servers[0].videoChannel.id since last update
       await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.1,127.0.0.1')
       await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.2,127.0.0.1')
 
@@ -465,10 +463,10 @@ describe('Test video channels', function () {
 
       const res = await getAccountVideoChannelsList({
         url: servers[0].url,
-        accountName: userInfo.account.name + '@' + userInfo.account.host,
+        accountName,
         withStats: true
       })
-      const channelWithView = res.body.data.find((channel: VideoChannel) => channel.id === firstVideoChannelId)
+      const channelWithView = res.body.data.find((channel: VideoChannel) => channel.id === servers[0].videoChannel.id)
       expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2)
     }
   })
@@ -476,7 +474,7 @@ describe('Test video channels', function () {
   it('Should report correct videos count', async function () {
     const res = await getAccountVideoChannelsList({
       url: servers[0].url,
-      accountName: userInfo.account.name + '@' + userInfo.account.host,
+      accountName,
       withStats: true
     })
     const channels: VideoChannel[] = res.body.data
@@ -492,7 +490,7 @@ describe('Test video channels', function () {
     {
       const res = await getAccountVideoChannelsList({
         url: servers[0].url,
-        accountName: userInfo.account.name + '@' + userInfo.account.host,
+        accountName,
         search: 'root'
       })
       expect(res.body.total).to.equal(1)
@@ -504,7 +502,7 @@ describe('Test video channels', function () {
     {
       const res = await getAccountVideoChannelsList({
         url: servers[0].url,
-        accountName: userInfo.account.name + '@' + userInfo.account.host,
+        accountName,
         search: 'does not exist'
       })
       expect(res.body.total).to.equal(0)
@@ -514,6 +512,40 @@ describe('Test video channels', function () {
     }
   })
 
+  it('Should list channels by updatedAt desc if a video has been uploaded', async function () {
+    this.timeout(30000)
+
+    await uploadVideo(servers[0].url, servers[0].accessToken, { channelId: totoChannel })
+    await waitJobs(servers)
+
+    for (const server of servers) {
+      const res = await getAccountVideoChannelsList({
+        url: server.url,
+        accountName,
+        sort: '-updatedAt'
+      })
+
+      const channels: VideoChannel[] = res.body.data
+      expect(channels[0].name).to.equal('toto_channel')
+      expect(channels[1].name).to.equal('root_channel')
+    }
+
+    await uploadVideo(servers[0].url, servers[0].accessToken, { channelId: servers[0].videoChannel.id })
+    await waitJobs(servers)
+
+    for (const server of servers) {
+      const res = await getAccountVideoChannelsList({
+        url: server.url,
+        accountName,
+        sort: '-updatedAt'
+      })
+
+      const channels: VideoChannel[] = res.body.data
+      expect(channels[0].name).to.equal('root_channel')
+      expect(channels[1].name).to.equal('toto_channel')
+    }
+  })
+
   after(async function () {
     await cleanupTests(servers)
   })
index 120dec271db48a40a912bf7bb002b1ecd54f546c..f2138077e682b44bd82d6dcf50909d70473c24c4 100644 (file)
@@ -5,6 +5,8 @@ export interface Account extends Actor {
   displayName: string
   description: string
 
+  updatedAt: Date | string
+
   userId?: number
 }
 
index 7d9f35b1052bea31a9f0c263cf7d643bbc5ab7dd..fd066233138576717a1170a3cb20e0434c98c811 100644 (file)
@@ -8,6 +8,5 @@ export interface Actor {
   followingCount: number
   followersCount: number
   createdAt: Date | string
-  updatedAt: Date | string
   avatar?: ActorImage
 }
index 56517972d8aa23fd008be925dcbc0b0119689d7c..5393f924da89b60748d3a482eddbf610bf74ebbb 100644 (file)
@@ -11,6 +11,9 @@ export interface VideoChannel extends Actor {
   description: string
   support: string
   isLocal: boolean
+
+  updatedAt: Date | string
+
   ownerAccount?: Account
 
   videosCount?: number