aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/api/videos/index.ts3
-rw-r--r--server/helpers/database-utils.ts18
-rw-r--r--server/lib/activitypub/actor.ts2
-rw-r--r--server/lib/activitypub/videos.ts3
-rw-r--r--server/models/account/account.ts1
-rw-r--r--server/models/activitypub/actor.ts3
-rw-r--r--server/models/video/video-channel.ts8
-rw-r--r--server/models/video/video.ts7
-rw-r--r--server/tests/api/videos/video-channels.ts82
-rw-r--r--shared/models/actors/account.model.ts2
-rw-r--r--shared/models/actors/actor.model.ts1
-rw-r--r--shared/models/videos/channel/video-channel.model.ts3
12 files changed, 95 insertions, 38 deletions
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 6ec6478e4..fbdb0f776 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -248,6 +248,9 @@ async function addVideo (req: express.Request, res: express.Response) {
248 }, { transaction: t }) 248 }, { transaction: t })
249 } 249 }
250 250
251 // Channel has a new content, set as updated
252 await videoCreated.VideoChannel.setAsUpdated(t)
253
251 await autoBlacklistVideoIfNeeded({ 254 await autoBlacklistVideoIfNeeded({
252 video, 255 video,
253 user: res.locals.oauth.token.User, 256 user: res.locals.oauth.token.User,
diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts
index 2b916efc2..f9cb33aca 100644
--- a/server/helpers/database-utils.ts
+++ b/server/helpers/database-utils.ts
@@ -1,8 +1,9 @@
1import * as retry from 'async/retry' 1import * as retry from 'async/retry'
2import * as Bluebird from 'bluebird' 2import * as Bluebird from 'bluebird'
3import { QueryTypes, Transaction } from 'sequelize'
3import { Model } from 'sequelize-typescript' 4import { Model } from 'sequelize-typescript'
5import { sequelizeTypescript } from '@server/initializers/database'
4import { logger } from './logger' 6import { logger } from './logger'
5import { Transaction } from 'sequelize'
6 7
7function retryTransactionWrapper <T, A, B, C, D> ( 8function retryTransactionWrapper <T, A, B, C, D> (
8 functionToRetry: (arg1: A, arg2: B, arg3: C, arg4: D) => Promise<T> | Bluebird<T>, 9 functionToRetry: (arg1: A, arg2: B, arg3: C, arg4: D) => Promise<T> | Bluebird<T>,
@@ -96,6 +97,18 @@ function deleteNonExistingModels <T extends { hasSameUniqueKeysThan (other: T):
96 .map(f => f.destroy({ transaction: t })) 97 .map(f => f.destroy({ transaction: t }))
97} 98}
98 99
100// Sequelize always skip the update if we only update updatedAt field
101function setAsUpdated (table: string, id: number, transaction?: Transaction) {
102 return sequelizeTypescript.query(
103 `UPDATE "${table}" SET "updatedAt" = :updatedAt WHERE id = :id`,
104 {
105 replacements: { table, id, updatedAt: new Date() },
106 type: QueryTypes.UPDATE,
107 transaction
108 }
109 )
110}
111
99// --------------------------------------------------------------------------- 112// ---------------------------------------------------------------------------
100 113
101export { 114export {
@@ -104,5 +117,6 @@ export {
104 transactionRetryer, 117 transactionRetryer,
105 updateInstanceWithAnother, 118 updateInstanceWithAnother,
106 afterCommitIfTransaction, 119 afterCommitIfTransaction,
107 deleteNonExistingModels 120 deleteNonExistingModels,
121 setAsUpdated
108} 122}
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index 34d53bd52..5fe7381c9 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -154,8 +154,6 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ
154 const followersCount = await fetchActorTotalItems(attributes.followers) 154 const followersCount = await fetchActorTotalItems(attributes.followers)
155 const followingCount = await fetchActorTotalItems(attributes.following) 155 const followingCount = await fetchActorTotalItems(attributes.following)
156 156
157 logger.info('coucou', { attributes })
158
159 actorInstance.type = attributes.type 157 actorInstance.type = attributes.type
160 actorInstance.preferredUsername = attributes.preferredUsername 158 actorInstance.preferredUsername = attributes.preferredUsername
161 actorInstance.url = attributes.id 159 actorInstance.url = attributes.id
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 506204674..15726f90b 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -697,6 +697,9 @@ async function createVideo (videoObject: VideoObject, channel: MChannelAccountLi
697 videoCreated.VideoLive = await videoLive.save({ transaction: t }) 697 videoCreated.VideoLive = await videoLive.save({ transaction: t })
698 } 698 }
699 699
700 // We added a video in this channel, set it as updated
701 await channel.setAsUpdated(t)
702
700 const autoBlacklisted = await autoBlacklistVideoIfNeeded({ 703 const autoBlacklisted = await autoBlacklistVideoIfNeeded({
701 video: videoCreated, 704 video: videoCreated,
702 user: undefined, 705 user: undefined,
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 44be0fd3c..d33353af7 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -411,6 +411,7 @@ export class AccountModel extends Model {
411 id: this.id, 411 id: this.id,
412 displayName: this.getDisplayName(), 412 displayName: this.getDisplayName(),
413 description: this.description, 413 description: this.description,
414 updatedAt: this.updatedAt,
414 userId: this.userId ? this.userId : undefined 415 userId: this.userId ? this.userId : undefined
415 } 416 }
416 417
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index 396a52337..1af9efac2 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -557,8 +557,7 @@ export class ActorModel extends Model {
557 followingCount: this.followingCount, 557 followingCount: this.followingCount,
558 followersCount: this.followersCount, 558 followersCount: this.followersCount,
559 banner, 559 banner,
560 createdAt: this.getCreatedAt(), 560 createdAt: this.getCreatedAt()
561 updatedAt: this.updatedAt
562 }) 561 })
563 } 562 }
564 563
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index b627595c9..081b21f2d 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -1,4 +1,4 @@
1import { FindOptions, Includeable, literal, Op, QueryTypes, ScopeOptions } from 'sequelize' 1import { FindOptions, Includeable, literal, Op, QueryTypes, ScopeOptions, Transaction } from 'sequelize'
2import { 2import {
3 AllowNull, 3 AllowNull,
4 BeforeDestroy, 4 BeforeDestroy,
@@ -17,6 +17,7 @@ import {
17 Table, 17 Table,
18 UpdatedAt 18 UpdatedAt
19} from 'sequelize-typescript' 19} from 'sequelize-typescript'
20import { setAsUpdated } from '@server/helpers/database-utils'
20import { MAccountActor } from '@server/types/models' 21import { MAccountActor } from '@server/types/models'
21import { ActivityPubActor } from '../../../shared/models/activitypub' 22import { ActivityPubActor } from '../../../shared/models/activitypub'
22import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' 23import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos'
@@ -653,6 +654,7 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
653 description: this.description, 654 description: this.description,
654 support: this.support, 655 support: this.support,
655 isLocal: this.Actor.isOwned(), 656 isLocal: this.Actor.isOwned(),
657 updatedAt: this.updatedAt,
656 ownerAccount: undefined, 658 ownerAccount: undefined,
657 videosCount, 659 videosCount,
658 viewsPerDay 660 viewsPerDay
@@ -689,4 +691,8 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
689 isOutdated () { 691 isOutdated () {
690 return this.Actor.isOutdated() 692 return this.Actor.isOutdated()
691 } 693 }
694
695 setAsUpdated (transaction: Transaction) {
696 return setAsUpdated('videoChannel', this.id, transaction)
697 }
692} 698}
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index e55a21a6b..8c316e00c 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -24,6 +24,7 @@ import {
24 Table, 24 Table,
25 UpdatedAt 25 UpdatedAt
26} from 'sequelize-typescript' 26} from 'sequelize-typescript'
27import { setAsUpdated } from '@server/helpers/database-utils'
27import { buildNSFWFilter } from '@server/helpers/express-utils' 28import { buildNSFWFilter } from '@server/helpers/express-utils'
28import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video' 29import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video'
29import { LiveManager } from '@server/lib/live-manager' 30import { LiveManager } from '@server/lib/live-manager'
@@ -2053,11 +2054,7 @@ export class VideoModel extends Model {
2053 } 2054 }
2054 2055
2055 setAsRefreshed () { 2056 setAsRefreshed () {
2056 const options = { 2057 return setAsUpdated('video', this.id)
2057 where: { id: this.id }
2058 }
2059
2060 return VideoModel.update({ updatedAt: new Date() }, options)
2061 } 2058 }
2062 2059
2063 requiresAuth () { 2060 requiresAuth () {
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts
index d12d58e75..7e7ad028c 100644
--- a/server/tests/api/videos/video-channels.ts
+++ b/server/tests/api/videos/video-channels.ts
@@ -3,6 +3,7 @@
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { basename } from 'path' 5import { basename } from 'path'
6import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
6import { 7import {
7 cleanupTests, 8 cleanupTests,
8 createUser, 9 createUser,
@@ -13,6 +14,7 @@ import {
13 getVideo, 14 getVideo,
14 getVideoChannel, 15 getVideoChannel,
15 getVideoChannelVideos, 16 getVideoChannelVideos,
17 setDefaultVideoChannel,
16 testImage, 18 testImage,
17 updateVideo, 19 updateVideo,
18 updateVideoChannelImage, 20 updateVideoChannelImage,
@@ -33,7 +35,6 @@ import {
33} from '../../../../shared/extra-utils/index' 35} from '../../../../shared/extra-utils/index'
34import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 36import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
35import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index' 37import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index'
36import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
37 38
38const expect = chai.expect 39const expect = chai.expect
39 40
@@ -47,9 +48,10 @@ async function findChannel (server: ServerInfo, channelId: number) {
47describe('Test video channels', function () { 48describe('Test video channels', function () {
48 let servers: ServerInfo[] 49 let servers: ServerInfo[]
49 let userInfo: User 50 let userInfo: User
50 let firstVideoChannelId: number
51 let secondVideoChannelId: number 51 let secondVideoChannelId: number
52 let totoChannel: number
52 let videoUUID: string 53 let videoUUID: string
54 let accountName: string
53 55
54 before(async function () { 56 before(async function () {
55 this.timeout(60000) 57 this.timeout(60000)
@@ -57,16 +59,9 @@ describe('Test video channels', function () {
57 servers = await flushAndRunMultipleServers(2) 59 servers = await flushAndRunMultipleServers(2)
58 60
59 await setAccessTokensToServers(servers) 61 await setAccessTokensToServers(servers)
60 await doubleFollow(servers[0], servers[1]) 62 await setDefaultVideoChannel(servers)
61
62 {
63 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
64 const user: User = res.body
65
66 firstVideoChannelId = user.videoChannels[0].id
67 }
68 63
69 await waitJobs(servers) 64 await doubleFollow(servers[0], servers[1])
70 }) 65 })
71 66
72 it('Should have one video channel (created with root)', async () => { 67 it('Should have one video channel (created with root)', async () => {
@@ -116,12 +111,14 @@ describe('Test video channels', function () {
116 expect(videoChannels[1].displayName).to.equal('second video channel') 111 expect(videoChannels[1].displayName).to.equal('second video channel')
117 expect(videoChannels[1].description).to.equal('super video channel description') 112 expect(videoChannels[1].description).to.equal('super video channel description')
118 expect(videoChannels[1].support).to.equal('super video channel support text') 113 expect(videoChannels[1].support).to.equal('super video channel support text')
114
115 accountName = userInfo.account.name + '@' + userInfo.account.host
119 }) 116 })
120 117
121 it('Should have two video channels when getting account channels on server 1', async function () { 118 it('Should have two video channels when getting account channels on server 1', async function () {
122 const res = await getAccountVideoChannelsList({ 119 const res = await getAccountVideoChannelsList({
123 url: servers[0].url, 120 url: servers[0].url,
124 accountName: userInfo.account.name + '@' + userInfo.account.host 121 accountName
125 }) 122 })
126 123
127 expect(res.body.total).to.equal(2) 124 expect(res.body.total).to.equal(2)
@@ -142,7 +139,7 @@ describe('Test video channels', function () {
142 { 139 {
143 const res = await getAccountVideoChannelsList({ 140 const res = await getAccountVideoChannelsList({
144 url: servers[0].url, 141 url: servers[0].url,
145 accountName: userInfo.account.name + '@' + userInfo.account.host, 142 accountName,
146 start: 0, 143 start: 0,
147 count: 1, 144 count: 1,
148 sort: 'createdAt' 145 sort: 'createdAt'
@@ -158,7 +155,7 @@ describe('Test video channels', function () {
158 { 155 {
159 const res = await getAccountVideoChannelsList({ 156 const res = await getAccountVideoChannelsList({
160 url: servers[0].url, 157 url: servers[0].url,
161 accountName: userInfo.account.name + '@' + userInfo.account.host, 158 accountName,
162 start: 0, 159 start: 0,
163 count: 1, 160 count: 1,
164 sort: '-createdAt' 161 sort: '-createdAt'
@@ -174,7 +171,7 @@ describe('Test video channels', function () {
174 { 171 {
175 const res = await getAccountVideoChannelsList({ 172 const res = await getAccountVideoChannelsList({
176 url: servers[0].url, 173 url: servers[0].url,
177 accountName: userInfo.account.name + '@' + userInfo.account.host, 174 accountName,
178 start: 1, 175 start: 1,
179 count: 1, 176 count: 1,
180 sort: '-createdAt' 177 sort: '-createdAt'
@@ -191,7 +188,7 @@ describe('Test video channels', function () {
191 it('Should have one video channel when getting account channels on server 2', async function () { 188 it('Should have one video channel when getting account channels on server 2', async function () {
192 const res = await getAccountVideoChannelsList({ 189 const res = await getAccountVideoChannelsList({
193 url: servers[1].url, 190 url: servers[1].url,
194 accountName: userInfo.account.name + '@' + userInfo.account.host 191 accountName
195 }) 192 })
196 193
197 expect(res.body.total).to.equal(1) 194 expect(res.body.total).to.equal(1)
@@ -379,7 +376,7 @@ describe('Test video channels', function () {
379 it('Should change the video channel of a video', async function () { 376 it('Should change the video channel of a video', async function () {
380 this.timeout(10000) 377 this.timeout(10000)
381 378
382 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { channelId: firstVideoChannelId }) 379 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { channelId: servers[0].videoChannel.id })
383 380
384 await waitJobs(servers) 381 await waitJobs(servers)
385 }) 382 })
@@ -419,7 +416,8 @@ describe('Test video channels', function () {
419 it('Should create the main channel with an uuid if there is a conflict', async function () { 416 it('Should create the main channel with an uuid if there is a conflict', async function () {
420 { 417 {
421 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } 418 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
422 await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) 419 const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
420 totoChannel = res.body.videoChannel.id
423 } 421 }
424 422
425 { 423 {
@@ -438,7 +436,7 @@ describe('Test video channels', function () {
438 { 436 {
439 const res = await getAccountVideoChannelsList({ 437 const res = await getAccountVideoChannelsList({
440 url: servers[0].url, 438 url: servers[0].url,
441 accountName: userInfo.account.name + '@' + userInfo.account.host, 439 accountName,
442 withStats: true 440 withStats: true
443 }) 441 })
444 442
@@ -456,7 +454,7 @@ describe('Test video channels', function () {
456 } 454 }
457 455
458 { 456 {
459 // video has been posted on channel firstVideoChannelId since last update 457 // video has been posted on channel servers[0].videoChannel.id since last update
460 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.1,127.0.0.1') 458 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.1,127.0.0.1')
461 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.2,127.0.0.1') 459 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.2,127.0.0.1')
462 460
@@ -465,10 +463,10 @@ describe('Test video channels', function () {
465 463
466 const res = await getAccountVideoChannelsList({ 464 const res = await getAccountVideoChannelsList({
467 url: servers[0].url, 465 url: servers[0].url,
468 accountName: userInfo.account.name + '@' + userInfo.account.host, 466 accountName,
469 withStats: true 467 withStats: true
470 }) 468 })
471 const channelWithView = res.body.data.find((channel: VideoChannel) => channel.id === firstVideoChannelId) 469 const channelWithView = res.body.data.find((channel: VideoChannel) => channel.id === servers[0].videoChannel.id)
472 expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2) 470 expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2)
473 } 471 }
474 }) 472 })
@@ -476,7 +474,7 @@ describe('Test video channels', function () {
476 it('Should report correct videos count', async function () { 474 it('Should report correct videos count', async function () {
477 const res = await getAccountVideoChannelsList({ 475 const res = await getAccountVideoChannelsList({
478 url: servers[0].url, 476 url: servers[0].url,
479 accountName: userInfo.account.name + '@' + userInfo.account.host, 477 accountName,
480 withStats: true 478 withStats: true
481 }) 479 })
482 const channels: VideoChannel[] = res.body.data 480 const channels: VideoChannel[] = res.body.data
@@ -492,7 +490,7 @@ describe('Test video channels', function () {
492 { 490 {
493 const res = await getAccountVideoChannelsList({ 491 const res = await getAccountVideoChannelsList({
494 url: servers[0].url, 492 url: servers[0].url,
495 accountName: userInfo.account.name + '@' + userInfo.account.host, 493 accountName,
496 search: 'root' 494 search: 'root'
497 }) 495 })
498 expect(res.body.total).to.equal(1) 496 expect(res.body.total).to.equal(1)
@@ -504,7 +502,7 @@ describe('Test video channels', function () {
504 { 502 {
505 const res = await getAccountVideoChannelsList({ 503 const res = await getAccountVideoChannelsList({
506 url: servers[0].url, 504 url: servers[0].url,
507 accountName: userInfo.account.name + '@' + userInfo.account.host, 505 accountName,
508 search: 'does not exist' 506 search: 'does not exist'
509 }) 507 })
510 expect(res.body.total).to.equal(0) 508 expect(res.body.total).to.equal(0)
@@ -514,6 +512,40 @@ describe('Test video channels', function () {
514 } 512 }
515 }) 513 })
516 514
515 it('Should list channels by updatedAt desc if a video has been uploaded', async function () {
516 this.timeout(30000)
517
518 await uploadVideo(servers[0].url, servers[0].accessToken, { channelId: totoChannel })
519 await waitJobs(servers)
520
521 for (const server of servers) {
522 const res = await getAccountVideoChannelsList({
523 url: server.url,
524 accountName,
525 sort: '-updatedAt'
526 })
527
528 const channels: VideoChannel[] = res.body.data
529 expect(channels[0].name).to.equal('toto_channel')
530 expect(channels[1].name).to.equal('root_channel')
531 }
532
533 await uploadVideo(servers[0].url, servers[0].accessToken, { channelId: servers[0].videoChannel.id })
534 await waitJobs(servers)
535
536 for (const server of servers) {
537 const res = await getAccountVideoChannelsList({
538 url: server.url,
539 accountName,
540 sort: '-updatedAt'
541 })
542
543 const channels: VideoChannel[] = res.body.data
544 expect(channels[0].name).to.equal('root_channel')
545 expect(channels[1].name).to.equal('toto_channel')
546 }
547 })
548
517 after(async function () { 549 after(async function () {
518 await cleanupTests(servers) 550 await cleanupTests(servers)
519 }) 551 })
diff --git a/shared/models/actors/account.model.ts b/shared/models/actors/account.model.ts
index 120dec271..f2138077e 100644
--- a/shared/models/actors/account.model.ts
+++ b/shared/models/actors/account.model.ts
@@ -5,6 +5,8 @@ export interface Account extends Actor {
5 displayName: string 5 displayName: string
6 description: string 6 description: string
7 7
8 updatedAt: Date | string
9
8 userId?: number 10 userId?: number
9} 11}
10 12
diff --git a/shared/models/actors/actor.model.ts b/shared/models/actors/actor.model.ts
index 7d9f35b10..fd0662331 100644
--- a/shared/models/actors/actor.model.ts
+++ b/shared/models/actors/actor.model.ts
@@ -8,6 +8,5 @@ export interface Actor {
8 followingCount: number 8 followingCount: number
9 followersCount: number 9 followersCount: number
10 createdAt: Date | string 10 createdAt: Date | string
11 updatedAt: Date | string
12 avatar?: ActorImage 11 avatar?: ActorImage
13} 12}
diff --git a/shared/models/videos/channel/video-channel.model.ts b/shared/models/videos/channel/video-channel.model.ts
index 56517972d..5393f924d 100644
--- a/shared/models/videos/channel/video-channel.model.ts
+++ b/shared/models/videos/channel/video-channel.model.ts
@@ -11,6 +11,9 @@ export interface VideoChannel extends Actor {
11 description: string 11 description: string
12 support: string 12 support: string
13 isLocal: boolean 13 isLocal: boolean
14
15 updatedAt: Date | string
16
14 ownerAccount?: Account 17 ownerAccount?: Account
15 18
16 videosCount?: number 19 videosCount?: number