Add total moderators/admins in stats

pull/6266/head
Chocobozzz 2024-02-23 14:52:35 +01:00
parent bb7cb0d2fd
commit 0165786f65
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
8 changed files with 88 additions and 29 deletions

View File

@ -456,6 +456,12 @@ stats:
abuses:
enabled: true
total_moderators:
enabled: true
total_admins:
enabled: true
cache:
previews:
size: 500 # Max number of previews you want to cache

View File

@ -454,6 +454,12 @@ stats:
abuses:
enabled: true
total_moderators:
enabled: true
total_admins:
enabled: true
###############################################################################
#
# From this point, almost all following keys can be overridden by the web interface

View File

@ -10,6 +10,9 @@ export interface ServerStats extends ActivityPubMessagesSuccess, ActivityPubMess
totalWeeklyActiveUsers: number
totalMonthlyActiveUsers: number
totalModerators: number
totalAdmins: number
totalLocalVideos: number
totalLocalVideoViews: number
totalLocalVideoComments: number

View File

@ -56,7 +56,11 @@ describe('Test stats (excluding redundancy)', function () {
expect(data.totalLocalVideos).to.equal(1)
expect(data.totalLocalVideoViews).to.equal(1)
expect(data.totalLocalVideoFilesSize).to.equal(218910)
expect(data.totalUsers).to.equal(2)
expect(data.totalModerators).to.equal(0)
expect(data.totalAdmins).to.equal(1)
expect(data.totalVideoComments).to.equal(1)
expect(data.totalVideos).to.equal(1)
expect(data.totalInstanceFollowers).to.equal(2)
@ -71,7 +75,11 @@ describe('Test stats (excluding redundancy)', function () {
expect(data.totalLocalVideos).to.equal(0)
expect(data.totalLocalVideoViews).to.equal(0)
expect(data.totalLocalVideoFilesSize).to.equal(0)
expect(data.totalUsers).to.equal(1)
expect(data.totalModerators).to.equal(0)
expect(data.totalAdmins).to.equal(1)
expect(data.totalVideoComments).to.equal(1)
expect(data.totalVideos).to.equal(1)
expect(data.totalInstanceFollowers).to.equal(1)
@ -85,7 +93,11 @@ describe('Test stats (excluding redundancy)', function () {
expect(data.totalLocalVideoComments).to.equal(0)
expect(data.totalLocalVideos).to.equal(0)
expect(data.totalLocalVideoViews).to.equal(0)
expect(data.totalUsers).to.equal(1)
expect(data.totalModerators).to.equal(0)
expect(data.totalAdmins).to.equal(1)
expect(data.totalVideoComments).to.equal(1)
expect(data.totalVideos).to.equal(1)
expect(data.totalInstanceFollowing).to.equal(1)
@ -420,7 +432,9 @@ describe('Test stats (excluding redundancy)', function () {
await servers[0].run({
stats: {
registration_requests: { enabled: false },
abuses: { enabled: false }
abuses: { enabled: false },
total_admins: { enabled: false },
total_moderators: { enabled: false }
}
})
@ -433,6 +447,9 @@ describe('Test stats (excluding redundancy)', function () {
expect(data.totalAbuses).to.be.null
expect(data.totalAbusesProcessed).to.be.null
expect(data.averageAbuseResponseTimeMs).to.be.null
expect(data.totalAdmins).to.be.null
expect(data.totalModerators).to.be.null
})
})

View File

@ -369,6 +369,12 @@ const CONFIG = {
},
ABUSES: {
ENABLED: config.get<boolean>('stats.abuses.enabled')
},
TOTAL_MODERATORS: {
ENABLED: config.get<boolean>('stats.total_moderators.enabled')
},
TOTAL_ADMINS: {
ENABLED: config.get<boolean>('stats.total_admins.enabled')
}
},
ADMIN: {

View File

@ -49,7 +49,14 @@ class StatsManager {
async getStats () {
const { totalLocalVideos, totalLocalVideoViews, totalVideos } = await VideoModel.getStats()
const { totalLocalVideoComments, totalVideoComments } = await VideoCommentModel.getStats()
const { totalUsers, totalDailyActiveUsers, totalWeeklyActiveUsers, totalMonthlyActiveUsers } = await UserModel.getStats()
const {
totalUsers,
totalDailyActiveUsers,
totalWeeklyActiveUsers,
totalMonthlyActiveUsers,
totalAdmins,
totalModerators
} = await UserModel.getStats()
const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats()
const { totalLocalVideoFilesSize } = await VideoFileModel.getStats()
const {
@ -68,6 +75,14 @@ class StatsManager {
totalWeeklyActiveUsers,
totalMonthlyActiveUsers,
totalModerators: CONFIG.STATS.TOTAL_MODERATORS.ENABLED
? totalModerators
: null,
totalAdmins: CONFIG.STATS.TOTAL_ADMINS.ENABLED
? totalAdmins
: null,
totalLocalVideos,
totalLocalVideoViews,
totalLocalVideoComments,

View File

@ -8,7 +8,8 @@ import {
VideoPlaylistType,
type NSFWPolicyType,
type UserAdminFlagType,
type UserRoleType
type UserRoleType,
UserRole
} from '@peertube/peertube-models'
import { TokensCache } from '@server/lib/auth/tokens-cache.js'
import { LiveQuotaStore } from '@server/lib/live/index.js'
@ -67,7 +68,7 @@ import { ActorFollowModel } from '../actor/actor-follow.js'
import { ActorImageModel } from '../actor/actor-image.js'
import { ActorModel } from '../actor/actor.js'
import { OAuthTokenModel } from '../oauth/oauth-token.js'
import { getAdminUsersSort, SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { getAdminUsersSort, parseAggregateResult, SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { VideoChannelModel } from '../video/video-channel.js'
import { VideoImportModel } from '../video/video-import.js'
import { VideoLiveModel } from '../video/video-live.js'
@ -875,32 +876,31 @@ export class UserModel extends SequelizeModel<UserModel> {
return parseInt(total, 10)
}
static async getStats () {
function getActiveUsers (days: number) {
const query = {
where: {
[Op.and]: [
literal(`"lastLoginDate" > NOW() - INTERVAL '${days}d'`)
]
}
static getStats () {
const query = `SELECT ` +
`COUNT(*) AS "totalUsers", ` +
`COUNT(*) FILTER (WHERE "lastLoginDate" > NOW() - INTERVAL '1d') AS "totalDailyActiveUsers", ` +
`COUNT(*) FILTER (WHERE "lastLoginDate" > NOW() - INTERVAL '7d') AS "totalWeeklyActiveUsers", ` +
`COUNT(*) FILTER (WHERE "lastLoginDate" > NOW() - INTERVAL '30d') AS "totalMonthlyActiveUsers", ` +
`COUNT(*) FILTER (WHERE "lastLoginDate" > NOW() - INTERVAL '180d') AS "totalHalfYearActiveUsers", ` +
`COUNT(*) FILTER (WHERE "role" = ${UserRole.MODERATOR}) AS "totalModerators", ` +
`COUNT(*) FILTER (WHERE "role" = ${UserRole.ADMINISTRATOR}) AS "totalAdmins" ` +
`FROM "user"`
return UserModel.sequelize.query<any>(query, {
type: QueryTypes.SELECT,
raw: true
}).then(([ row ]) => {
return {
totalUsers: parseAggregateResult(row.totalUsers),
totalDailyActiveUsers: parseAggregateResult(row.totalDailyActiveUsers),
totalWeeklyActiveUsers: parseAggregateResult(row.totalWeeklyActiveUsers),
totalMonthlyActiveUsers: parseAggregateResult(row.totalMonthlyActiveUsers),
totalHalfYearActiveUsers: parseAggregateResult(row.totalHalfYearActiveUsers),
totalModerators: parseAggregateResult(row.totalModerators),
totalAdmins: parseAggregateResult(row.totalAdmins)
}
return UserModel.unscoped().count(query)
}
const totalUsers = await UserModel.unscoped().count()
const totalDailyActiveUsers = await getActiveUsers(1)
const totalWeeklyActiveUsers = await getActiveUsers(7)
const totalMonthlyActiveUsers = await getActiveUsers(30)
const totalHalfYearActiveUsers = await getActiveUsers(180)
return {
totalUsers,
totalDailyActiveUsers,
totalWeeklyActiveUsers,
totalMonthlyActiveUsers,
totalHalfYearActiveUsers
}
})
}
static autoComplete (search: string) {

View File

@ -8569,6 +8569,12 @@ components:
type: number
totalMonthlyActiveUsers:
type: number
totalModerators:
type: number
description: "**PeerTube >= 6.1** Value is null if the admin disabled total moderators stats"
totalAdmins:
type: number
description: "**PeerTube >= 6.1** Value is null if the admin disabled total admins stats"
totalLocalVideos:
type: number
totalLocalVideoViews: