Add videos count in channels list

pull/2879/head
Chocobozzz 2020-06-16 14:13:01 +02:00
parent af75e2d8df
commit 1ba471c55f
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
8 changed files with 63 additions and 18 deletions

View 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-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"> <div class="video-channel-buttons">
<my-edit-button [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button> <my-edit-button [routerLink]="[ 'update', videoChannel.nameWithHost ]"></my-edit-button>
<my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button> <my-delete-button (click)="deleteVideoChannel(videoChannel)"></my-delete-button>

View File

@ -96,8 +96,8 @@ export class MyAccountVideoChannelsComponent implements OnInit {
const res = await this.confirmService.confirmWithInput( const res = await this.confirmService.confirmWithInput(
this.i18n( this.i18n(
// tslint:disable // 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}})!', '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, channelName: videoChannel.name } { channelDisplayName: videoChannel.displayName, videosCount: videoChannel.videosCount, channelName: videoChannel.name }
), ),
this.i18n( this.i18n(
'Please type the display name of the video channel ({{displayName}}) to confirm', 'Please type the display name of the video channel ({{displayName}}) to confirm',

View File

@ -1,6 +1,10 @@
@import '_variables'; @import '_variables';
@import '_mixins'; @import '_mixins';
.modal-body {
font-size: 15px;
}
.button { .button {
padding: 0 13px; padding: 0 13px;
} }

View File

@ -9,9 +9,13 @@ export class VideoChannel extends Actor implements ServerVideoChannel {
isLocal: boolean isLocal: boolean
nameWithHost: string nameWithHost: string
nameWithHostForced: string nameWithHostForced: string
ownerAccount?: Account ownerAccount?: Account
ownerBy?: string ownerBy?: string
ownerAvatarUrl?: string ownerAvatarUrl?: string
videosCount?: number
viewsPerDay?: ViewsPerDate[] viewsPerDay?: ViewsPerDate[]
constructor (hash: ServerVideoChannel) { 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.nameWithHost = Actor.CREATE_BY_STRING(this.name, this.host)
this.nameWithHostForced = Actor.CREATE_BY_STRING(this.name, this.host, true) this.nameWithHostForced = Actor.CREATE_BY_STRING(this.name, this.host, true)
this.videosCount = hash.videosCount
if (hash.viewsPerDay) { if (hash.viewsPerDay) {
this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) })) this.viewsPerDay = hash.viewsPerDay.map(v => ({ ...v, date: new Date(v.date) }))
} }

View File

@ -172,6 +172,10 @@ export type SummaryOptions = {
return { return {
attributes: { attributes: {
include: [ include: [
[
literal('(SELECT COUNT(*) FROM "video" WHERE "channelId" = "VideoChannelModel"."id")'),
'videosCount'
],
[ [
literal( literal(
'(' + '(' +
@ -544,7 +548,22 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
} }
toFormattedJSON (this: MChannelFormattable): VideoChannel { 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 actor = this.Actor.toFormattedJSON()
const videoChannel = { const videoChannel = {
@ -556,15 +575,8 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
createdAt: this.createdAt, createdAt: this.createdAt,
updatedAt: this.updatedAt, updatedAt: this.updatedAt,
ownerAccount: undefined, ownerAccount: undefined,
viewsPerDay: viewsPerDay videosCount,
? viewsPerDay.split(',').map(v => { viewsPerDay
const o = v.split('|')
return {
date: new Date(o[0]),
views: +o[1]
}
})
: undefined
} }
if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON() if (this.Account) videoChannel.ownerAccount = this.Account.toFormattedJSON()

View File

@ -500,7 +500,7 @@ export class VideoModel extends Model<VideoModel> {
@AllowNull(false) @AllowNull(false)
@Is('VideoPrivacy', value => throwIfNotValid(value, isVideoPrivacyValid, 'privacy')) @Is('VideoPrivacy', value => throwIfNotValid(value, isVideoPrivacyValid, 'privacy'))
@Column @Column
privacy: number privacy: VideoPrivacy
@AllowNull(false) @AllowNull(false)
@Is('VideoNSFW', value => throwIfNotValid(value, isBooleanValid, 'NSFW boolean')) @Is('VideoNSFW', value => throwIfNotValid(value, isBooleanValid, 'NSFW boolean'))

View 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) this.timeout(10000)
{ {
@ -374,14 +374,18 @@ describe('Test video channels', function () {
accountName: userInfo.account.name + '@' + userInfo.account.host, accountName: userInfo.account.name + '@' + userInfo.account.host,
withStats: true 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).to.haveOwnProperty('viewsPerDay')
expect(channel.viewsPerDay).to.have.length(30 + 1) // daysPrior + today 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.date).to.be.an('string')
expect(v.views).to.equal(0) 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 () { after(async function () {
await cleanupTests(servers) await cleanupTests(servers)
}) })

View File

@ -13,6 +13,8 @@ export interface VideoChannel extends Actor {
support: string support: string
isLocal: boolean isLocal: boolean
ownerAccount?: Account ownerAccount?: Account
videosCount?: number
viewsPerDay?: ViewsPerDate[] // chronologically ordered viewsPerDay?: ViewsPerDate[] // chronologically ordered
} }