aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-06-16 14:13:01 +0200
committerChocobozzz <me@florianbigard.com>2020-06-16 14:13:01 +0200
commit1ba471c55fdbf05ef2c10152b3e4b0c5d8da3213 (patch)
tree0f231073a848f3089752fda5fe378ff5b64c229b
parentaf75e2d8df92d5d602e11353536ec6804a25f16f (diff)
downloadPeerTube-1ba471c55fdbf05ef2c10152b3e4b0c5d8da3213.tar.gz
PeerTube-1ba471c55fdbf05ef2c10152b3e4b0c5d8da3213.tar.zst
PeerTube-1ba471c55fdbf05ef2c10152b3e4b0c5d8da3213.zip
Add videos count in channels list
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html2
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts4
-rw-r--r--client/src/app/shared/confirm/confirm.component.scss4
-rw-r--r--client/src/app/shared/video-channel/video-channel.model.ts6
-rw-r--r--server/models/video/video-channel.ts32
-rw-r--r--server/models/video/video.ts2
-rw-r--r--server/tests/api/videos/video-channels.ts29
-rw-r--r--shared/models/videos/channel/video-channel.model.ts2
8 files changed, 63 insertions, 18 deletions
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html
index 2499b6ed5..bf4fa9396 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html
@@ -20,6 +20,8 @@
20 20
21 <div i18n class="video-channel-followers">{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div> 21 <div i18n class="video-channel-followers">{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div>
22 22
23 <div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div>
24
23 <div class="video-channel-buttons"> 25 <div class="video-channel-buttons">
24 <my-edit-button [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button> 26 <my-edit-button [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button>
25 <my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button> 27 <my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button>
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
index 75d6d8acd..9caefe5b1 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
@@ -96,8 +96,8 @@ export class MyAccountVideoChannelsComponent implements OnInit {
96 const res = await this.confirmService.confirmWithInput( 96 const res = await this.confirmService.confirmWithInput(
97 this.i18n( 97 this.i18n(
98 // tslint:disable 98 // tslint:disable
99 'Do you really want to delete {{channelDisplayName}}? It will delete all videos uploaded in this channel, and you will not be able to create another channel with the same name ({{channelName}})!', 99 'Do you really want to delete {{channelDisplayName}}? It will delete {{videosCount}} videos uploaded in this channel, and you will not be able to create another channel with the same name ({{channelName}})!',
100 { channelDisplayName: videoChannel.displayName, channelName: videoChannel.name } 100 { channelDisplayName: videoChannel.displayName, videosCount: videoChannel.videosCount, channelName: videoChannel.name }
101 ), 101 ),
102 this.i18n( 102 this.i18n(
103 'Please type the display name of the video channel ({{displayName}}) to confirm', 103 'Please type the display name of the video channel ({{displayName}}) to confirm',
diff --git a/client/src/app/shared/confirm/confirm.component.scss b/client/src/app/shared/confirm/confirm.component.scss
index 93dd7926b..ed226bc09 100644
--- a/client/src/app/shared/confirm/confirm.component.scss
+++ b/client/src/app/shared/confirm/confirm.component.scss
@@ -1,6 +1,10 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4.modal-body {
5 font-size: 15px;
6}
7
4.button { 8.button {
5 padding: 0 13px; 9 padding: 0 13px;
6} 10}
diff --git a/client/src/app/shared/video-channel/video-channel.model.ts b/client/src/app/shared/video-channel/video-channel.model.ts
index 617d6d44d..2f4597343 100644
--- a/client/src/app/shared/video-channel/video-channel.model.ts
+++ b/client/src/app/shared/video-channel/video-channel.model.ts
@@ -9,9 +9,13 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
9 isLocal: boolean 9 isLocal: boolean
10 nameWithHost: string 10 nameWithHost: string
11 nameWithHostForced: string 11 nameWithHostForced: string
12
12 ownerAccount?: Account 13 ownerAccount?: Account
13 ownerBy?: string 14 ownerBy?: string
14 ownerAvatarUrl?: string 15 ownerAvatarUrl?: string
16
17 videosCount?: number
18
15 viewsPerDay?: ViewsPerDate[] 19 viewsPerDay?: ViewsPerDate[]
16 20
17 constructor (hash: ServerVideoChannel) { 21 constructor (hash: ServerVideoChannel) {
@@ -24,6 +28,8 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
24 this.nameWithHost = Actor.CREATE_BY_STRING(this.name, this.host) 28 this.nameWithHost = Actor.CREATE_BY_STRING(this.name, this.host)
25 this.nameWithHostForced = Actor.CREATE_BY_STRING(this.name, this.host, true) 29 this.nameWithHostForced = Actor.CREATE_BY_STRING(this.name, this.host, true)
26 30
31 this.videosCount = hash.videosCount
32
27 if (hash.viewsPerDay) { 33 if (hash.viewsPerDay) {
28 this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) })) 34 this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) }))
29 } 35 }
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index b5bcbdc65..a4231b6b3 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -173,6 +173,10 @@ export type SummaryOptions = {
173 attributes: { 173 attributes: {
174 include: [ 174 include: [
175 [ 175 [
176 literal('(SELECT COUNT(*) FROM "video" WHERE "channelId" = "VideoChannelModel"."id")'),
177 'videosCount'
178 ],
179 [
176 literal( 180 literal(
177 '(' + 181 '(' +
178 `SELECT string_agg(concat_ws('|', t.day, t.views), ',') ` + 182 `SELECT string_agg(concat_ws('|', t.day, t.views), ',') ` +
@@ -544,7 +548,22 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
544 } 548 }
545 549
546 toFormattedJSON (this: MChannelFormattable): VideoChannel { 550 toFormattedJSON (this: MChannelFormattable): VideoChannel {
547 const viewsPerDay = this.get('viewsPerDay') as string 551 const viewsPerDayString = this.get('viewsPerDay') as string
552 const videosCount = this.get('videosCount') as number
553
554 let viewsPerDay: { date: Date, views: number }[]
555
556 if (viewsPerDayString) {
557 viewsPerDay = viewsPerDayString.split(',')
558 .map(v => {
559 const [ dateString, amount ] = v.split('|')
560
561 return {
562 date: new Date(dateString),
563 views: +amount
564 }
565 })
566 }
548 567
549 const actor = this.Actor.toFormattedJSON() 568 const actor = this.Actor.toFormattedJSON()
550 const videoChannel = { 569 const videoChannel = {
@@ -556,15 +575,8 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
556 createdAt: this.createdAt, 575 createdAt: this.createdAt,
557 updatedAt: this.updatedAt, 576 updatedAt: this.updatedAt,
558 ownerAccount: undefined, 577 ownerAccount: undefined,
559 viewsPerDay: viewsPerDay 578 videosCount,
560 ? viewsPerDay.split(',').map(v => { 579 viewsPerDay
561 const o = v.split('|')
562 return {
563 date: new Date(o[0]),
564 views: +o[1]
565 }
566 })
567 : undefined
568 } 580 }
569 581
570 if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON() 582 if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON()
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index ae2483b2f..1f590c02d 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -500,7 +500,7 @@ export class VideoModel extends Model<VideoModel> {
500 @AllowNull(false) 500 @AllowNull(false)
501 @Is('VideoPrivacy', value => throwIfNotValid(value, isVideoPrivacyValid, 'privacy')) 501 @Is('VideoPrivacy', value => throwIfNotValid(value, isVideoPrivacyValid, 'privacy'))
502 @Column 502 @Column
503 privacy: number 503 privacy: VideoPrivacy
504 504
505 @AllowNull(false) 505 @AllowNull(false)
506 @Is('VideoNSFW', value => throwIfNotValid(value, isBooleanValid, 'NSFW boolean')) 506 @Is('VideoNSFW', value => throwIfNotValid(value, isBooleanValid, 'NSFW boolean'))
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts
index 89026aba7..e7d9238dd 100644
--- a/server/tests/api/videos/video-channels.ts
+++ b/server/tests/api/videos/video-channels.ts
@@ -365,7 +365,7 @@ describe('Test video channels', function () {
365 } 365 }
366 }) 366 })
367 367
368 it('Should report correct channel statistics', async function () { 368 it('Should report correct channel views per days', async function () {
369 this.timeout(10000) 369 this.timeout(10000)
370 370
371 { 371 {
@@ -374,14 +374,18 @@ describe('Test video channels', function () {
374 accountName: userInfo.account.name + '@' + userInfo.account.host, 374 accountName: userInfo.account.name + '@' + userInfo.account.host,
375 withStats: true 375 withStats: true
376 }) 376 })
377 res.body.data.forEach((channel: VideoChannel) => { 377
378 const channels: VideoChannel[] = res.body.data
379
380 for (const channel of channels) {
378 expect(channel).to.haveOwnProperty('viewsPerDay') 381 expect(channel).to.haveOwnProperty('viewsPerDay')
379 expect(channel.viewsPerDay).to.have.length(30 + 1) // daysPrior + today 382 expect(channel.viewsPerDay).to.have.length(30 + 1) // daysPrior + today
380 channel.viewsPerDay.forEach((v: ViewsPerDate) => { 383
384 for (const v of channel.viewsPerDay) {
381 expect(v.date).to.be.an('string') 385 expect(v.date).to.be.an('string')
382 expect(v.views).to.equal(0) 386 expect(v.views).to.equal(0)
383 }) 387 }
384 }) 388 }
385 } 389 }
386 390
387 { 391 {
@@ -402,6 +406,21 @@ describe('Test video channels', function () {
402 } 406 }
403 }) 407 })
404 408
409 it('Should report correct videos count', async function () {
410 const res = await getAccountVideoChannelsList({
411 url: servers[0].url,
412 accountName: userInfo.account.name + '@' + userInfo.account.host,
413 withStats: true
414 })
415 const channels: VideoChannel[] = res.body.data
416
417 const totoChannel = channels.find(c => c.name === 'toto_channel')
418 const rootChannel = channels.find(c => c.name === 'root_channel')
419
420 expect(rootChannel.videosCount).to.equal(1)
421 expect(totoChannel.videosCount).to.equal(0)
422 })
423
405 after(async function () { 424 after(async function () {
406 await cleanupTests(servers) 425 await cleanupTests(servers)
407 }) 426 })
diff --git a/shared/models/videos/channel/video-channel.model.ts b/shared/models/videos/channel/video-channel.model.ts
index 421004e68..32829e92a 100644
--- a/shared/models/videos/channel/video-channel.model.ts
+++ b/shared/models/videos/channel/video-channel.model.ts
@@ -13,6 +13,8 @@ export interface VideoChannel extends Actor {
13 support: string 13 support: string
14 isLocal: boolean 14 isLocal: boolean
15 ownerAccount?: Account 15 ownerAccount?: Account
16
17 videosCount?: number
16 viewsPerDay?: ViewsPerDate[] // chronologically ordered 18 viewsPerDay?: ViewsPerDate[] // chronologically ordered
17} 19}
18 20