import * as express from 'express'
import { body, param, query } from 'express-validator'
+import { VIDEO_CHANNELS } from '@server/initializers/constants'
+import { MChannelAccountDefault, MUser } from '@server/typings/models'
import { UserRight } from '../../../../shared'
+import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor'
+import { isBooleanValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc'
import {
isVideoChannelDescriptionValid,
isVideoChannelNameValid,
isVideoChannelSupportValid
} from '../../../helpers/custom-validators/video-channels'
import { logger } from '../../../helpers/logger'
+import { doesLocalVideoChannelNameExist, doesVideoChannelNameWithHostExist } from '../../../helpers/middlewares'
+import { ActorModel } from '../../../models/activitypub/actor'
import { VideoChannelModel } from '../../../models/video/video-channel'
import { areValidationErrors } from '../utils'
-import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor'
-import { ActorModel } from '../../../models/activitypub/actor'
-import { isBooleanValid } from '../../../helpers/custom-validators/misc'
-import { doesLocalVideoChannelNameExist, doesVideoChannelNameWithHostExist } from '../../../helpers/middlewares'
-import { MChannelAccountDefault, MUser } from '@server/typings/models'
-import { VIDEO_CHANNELS } from '@server/initializers/constants'
const videoChannelsAddValidator = [
body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'),
]
const videoChannelStatsValidator = [
- query('withStats').optional().isBoolean().withMessage('Should have a valid stats flag'),
+ query('withStats')
+ .optional()
+ .customSanitizer(toBooleanOrNull)
+ .custom(isBooleanValid).withMessage('Should have a valid stats flag'),
(req: express.Request, res: express.Response, next: express.NextFunction) => {
if (areValidationErrors(req, res)) return
'days AS ( ' +
`SELECT generate_series(date_trunc('day', now()) - '${daysPrior} day'::interval, ` +
`date_trunc('day', now()), '1 day'::interval) AS day ` +
- '), ' +
- 'views AS ( ' +
- 'SELECT v.* ' +
- 'FROM "videoView" AS v ' +
- 'INNER JOIN "video" ON "video"."id" = v."videoId" ' +
- 'WHERE "video"."channelId" = "VideoChannelModel"."id" ' +
') ' +
- 'SELECT days.day AS day, ' +
- 'COALESCE(SUM(views.views), 0) AS views ' +
- 'FROM days ' +
- `LEFT JOIN views ON date_trunc('day', "views"."startDate") = date_trunc('day', days.day) ` +
- 'GROUP BY day ' +
- 'ORDER BY day ' +
- ') t' +
+ 'SELECT days.day AS day, COALESCE(SUM("videoView".views), 0) AS views ' +
+ 'FROM days ' +
+ 'LEFT JOIN (' +
+ '"videoView" INNER JOIN "video" ON "videoView"."videoId" = "video"."id" ' +
+ 'AND "video"."channelId" = "VideoChannelModel"."id"' +
+ `) ON date_trunc('day', "videoView"."startDate") = date_trunc('day', days.day) ` +
+ 'GROUP BY day ' +
+ 'ORDER BY day ' +
+ ') t' +
')'
),
'viewsPerDay'
const scopes: string | ScopeOptions | (string | ScopeOptions)[] = [ ScopeNames.WITH_ACTOR ]
- if (options.withStats) {
+ if (options.withStats === true) {
scopes.push({
method: [ ScopeNames.WITH_STATS, { daysPrior: 30 } as AvailableWithStatsOptions ]
})
createdAt: this.createdAt,
updatedAt: this.updatedAt,
ownerAccount: undefined,
- viewsPerDay: viewsPerDay !== undefined
+ viewsPerDay: viewsPerDay
? viewsPerDay.split(',').map(v => {
const o = v.split('|')
return {