Add videos count in channels list
authorChocobozzz <me@florianbigard.com>
Tue, 16 Jun 2020 12:13:01 +0000 (14:13 +0200)
committerChocobozzz <me@florianbigard.com>
Tue, 16 Jun 2020 12:13:01 +0000 (14:13 +0200)
client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.html
client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts
client/src/app/shared/confirm/confirm.component.scss
client/src/app/shared/video-channel/video-channel.model.ts
server/models/video/video-channel.ts
server/models/video/video.ts
server/tests/api/videos/video-channels.ts
shared/models/videos/channel/video-channel.model.ts

index 2499b6ed5708fcfb1e188d588376ecd903ff2633..bf4fa9396d98421795997e0c4b2b0fa4e3c7bdb8 100644 (file)
@@ -20,6 +20,8 @@
 
       <div i18n class="video-channel-followers">{videoChannel.followersCount, plural, =1 {1 subscriber} other {{{ videoChannel.followersCount }} subscribers}}</div>
 
+      <div i18n class="video-channel-videos">{videoChannel.videosCount, plural, =0 {No videos} =1 {1 video} other {{{ videoChannel.videosCount }} videos}}</div>
+
       <div class="video-channel-buttons">
         <my-edit-button [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button>
         <my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button>
index 75d6d8acd0c4f21868e45fd0100d92b3171d6035..9caefe5b15073e88a6ff0f526e14087b91041d9e 100644 (file)
@@ -96,8 +96,8 @@ export class MyAccountVideoChannelsComponent implements OnInit {
     const res = await this.confirmService.confirmWithInput(
       this.i18n(
         // tslint:disable
-        '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}})!',
-        { channelDisplayName: videoChannel.displayName, channelName: videoChannel.name }
+        '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}})!',
+        { channelDisplayName: videoChannel.displayName, videosCount: videoChannel.videosCount, channelName: videoChannel.name }
       ),
       this.i18n(
         'Please type the display name of the video channel ({{displayName}}) to confirm',
index 93dd7926b0415ed58a62915726f64f1c0bcafc5a..ed226bc091cf88d0d2b2d45e60ec24e4fcb2e802 100644 (file)
@@ -1,6 +1,10 @@
 @import '_variables';
 @import '_mixins';
 
+.modal-body {
+  font-size: 15px;
+}
+
 .button {
   padding: 0 13px;
 }
index 617d6d44d93b88b7427e6fa8a041f4e6dd059415..2f4597343bb291a1c61d6b2740e64371c2038e51 100644 (file)
@@ -9,9 +9,13 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
   isLocal: boolean
   nameWithHost: string
   nameWithHostForced: string
+
   ownerAccount?: Account
   ownerBy?: string
   ownerAvatarUrl?: string
+
+  videosCount?: number
+
   viewsPerDay?: ViewsPerDate[]
 
   constructor (hash: ServerVideoChannel) {
@@ -24,6 +28,8 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
     this.nameWithHost = Actor.CREATE_BY_STRING(this.name, this.host)
     this.nameWithHostForced = Actor.CREATE_BY_STRING(this.name, this.host, true)
 
+    this.videosCount = hash.videosCount
+
     if (hash.viewsPerDay) {
       this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) }))
     }
index b5bcbdc655b16f3487b263b5a4bb5dc8481d7fb1..a4231b6b3756322bcc68f21aee5c409af4383a01 100644 (file)
@@ -172,6 +172,10 @@ export type SummaryOptions = {
     return {
       attributes: {
         include: [
+          [
+            literal('(SELECT COUNT(*) FROM "video" WHERE "channelId" = "VideoChannelModel"."id")'),
+            'videosCount'
+          ],
           [
             literal(
               '(' +
@@ -544,7 +548,22 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
   }
 
   toFormattedJSON (this: MChannelFormattable): VideoChannel {
-    const viewsPerDay = this.get('viewsPerDay') as string
+    const viewsPerDayString = this.get('viewsPerDay') as string
+    const videosCount = this.get('videosCount') as number
+
+    let viewsPerDay: { date: Date, views: number }[]
+
+    if (viewsPerDayString) {
+      viewsPerDay = viewsPerDayString.split(',')
+        .map(v => {
+          const [ dateString, amount ] = v.split('|')
+
+          return {
+            date: new Date(dateString),
+            views: +amount
+          }
+        })
+    }
 
     const actor = this.Actor.toFormattedJSON()
     const videoChannel = {
@@ -556,15 +575,8 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
       createdAt: this.createdAt,
       updatedAt: this.updatedAt,
       ownerAccount: undefined,
-      viewsPerDay: viewsPerDay
-        ? viewsPerDay.split(',').map(v => {
-          const o = v.split('|')
-          return {
-            date: new Date(o[0]),
-            views: +o[1]
-          }
-        })
-        : undefined
+      videosCount,
+      viewsPerDay
     }
 
     if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON()
index ae2483b2f920ee2439161f0b2fa3616941b83050..1f590c02dcc5b15442c70afb0fce31899435d77a 100644 (file)
@@ -500,7 +500,7 @@ export class VideoModel extends Model<VideoModel> {
   @AllowNull(false)
   @Is('VideoPrivacy', value => throwIfNotValid(value, isVideoPrivacyValid, 'privacy'))
   @Column
-  privacy: number
+  privacy: VideoPrivacy
 
   @AllowNull(false)
   @Is('VideoNSFW', value => throwIfNotValid(value, isBooleanValid, 'NSFW boolean'))
index 89026aba79feb62b6f49d15b1ec23b4854dd043a..e7d9238dd4f8d3af1ca4b29f3add959c94f79dd1 100644 (file)
@@ -365,7 +365,7 @@ describe('Test video channels', function () {
     }
   })
 
-  it('Should report correct channel statistics', async function () {
+  it('Should report correct channel views per days', async function () {
     this.timeout(10000)
 
     {
@@ -374,14 +374,18 @@ describe('Test video channels', function () {
         accountName: userInfo.account.name + '@' + userInfo.account.host,
         withStats: true
       })
-      res.body.data.forEach((channel: VideoChannel) => {
+
+      const channels: VideoChannel[] = res.body.data
+
+      for (const channel of channels) {
         expect(channel).to.haveOwnProperty('viewsPerDay')
         expect(channel.viewsPerDay).to.have.length(30 + 1) // daysPrior + today
-        channel.viewsPerDay.forEach((v: ViewsPerDate) => {
+
+        for (const v of channel.viewsPerDay) {
           expect(v.date).to.be.an('string')
           expect(v.views).to.equal(0)
-        })
-      })
+        }
+      }
     }
 
     {
@@ -402,6 +406,21 @@ 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,
+      withStats: true
+    })
+    const channels: VideoChannel[] = res.body.data
+
+    const totoChannel = channels.find(c => c.name === 'toto_channel')
+    const rootChannel = channels.find(c => c.name === 'root_channel')
+
+    expect(rootChannel.videosCount).to.equal(1)
+    expect(totoChannel.videosCount).to.equal(0)
+  })
+
   after(async function () {
     await cleanupTests(servers)
   })
index 421004e68957881628d47853a5183c6184b00147..32829e92a053194467b5a47462dc6573ab1603a2 100644 (file)
@@ -13,6 +13,8 @@ export interface VideoChannel extends Actor {
   support: string
   isLocal: boolean
   ownerAccount?: Account
+
+  videosCount?: number
   viewsPerDay?: ViewsPerDate[] // chronologically ordered
 }