Add total moderators/admins in stats

This commit is contained in:
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: abuses:
enabled: true enabled: true
total_moderators:
enabled: true
total_admins:
enabled: true
cache: cache:
previews: previews:
size: 500 # Max number of previews you want to cache size: 500 # Max number of previews you want to cache

View File

@ -454,6 +454,12 @@ stats:
abuses: abuses:
enabled: true enabled: true
total_moderators:
enabled: true
total_admins:
enabled: true
############################################################################### ###############################################################################
# #
# From this point, almost all following keys can be overridden by the web interface # 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 totalWeeklyActiveUsers: number
totalMonthlyActiveUsers: number totalMonthlyActiveUsers: number
totalModerators: number
totalAdmins: number
totalLocalVideos: number totalLocalVideos: number
totalLocalVideoViews: number totalLocalVideoViews: number
totalLocalVideoComments: number totalLocalVideoComments: number

View File

@ -56,7 +56,11 @@ describe('Test stats (excluding redundancy)', function () {
expect(data.totalLocalVideos).to.equal(1) expect(data.totalLocalVideos).to.equal(1)
expect(data.totalLocalVideoViews).to.equal(1) expect(data.totalLocalVideoViews).to.equal(1)
expect(data.totalLocalVideoFilesSize).to.equal(218910) expect(data.totalLocalVideoFilesSize).to.equal(218910)
expect(data.totalUsers).to.equal(2) 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.totalVideoComments).to.equal(1)
expect(data.totalVideos).to.equal(1) expect(data.totalVideos).to.equal(1)
expect(data.totalInstanceFollowers).to.equal(2) expect(data.totalInstanceFollowers).to.equal(2)
@ -71,7 +75,11 @@ describe('Test stats (excluding redundancy)', function () {
expect(data.totalLocalVideos).to.equal(0) expect(data.totalLocalVideos).to.equal(0)
expect(data.totalLocalVideoViews).to.equal(0) expect(data.totalLocalVideoViews).to.equal(0)
expect(data.totalLocalVideoFilesSize).to.equal(0) expect(data.totalLocalVideoFilesSize).to.equal(0)
expect(data.totalUsers).to.equal(1) 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.totalVideoComments).to.equal(1)
expect(data.totalVideos).to.equal(1) expect(data.totalVideos).to.equal(1)
expect(data.totalInstanceFollowers).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.totalLocalVideoComments).to.equal(0)
expect(data.totalLocalVideos).to.equal(0) expect(data.totalLocalVideos).to.equal(0)
expect(data.totalLocalVideoViews).to.equal(0) expect(data.totalLocalVideoViews).to.equal(0)
expect(data.totalUsers).to.equal(1) 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.totalVideoComments).to.equal(1)
expect(data.totalVideos).to.equal(1) expect(data.totalVideos).to.equal(1)
expect(data.totalInstanceFollowing).to.equal(1) expect(data.totalInstanceFollowing).to.equal(1)
@ -420,7 +432,9 @@ describe('Test stats (excluding redundancy)', function () {
await servers[0].run({ await servers[0].run({
stats: { stats: {
registration_requests: { enabled: false }, 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.totalAbuses).to.be.null
expect(data.totalAbusesProcessed).to.be.null expect(data.totalAbusesProcessed).to.be.null
expect(data.averageAbuseResponseTimeMs).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: { ABUSES: {
ENABLED: config.get<boolean>('stats.abuses.enabled') 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: { ADMIN: {

View File

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

View File

@ -8,7 +8,8 @@ import {
VideoPlaylistType, VideoPlaylistType,
type NSFWPolicyType, type NSFWPolicyType,
type UserAdminFlagType, type UserAdminFlagType,
type UserRoleType type UserRoleType,
UserRole
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { TokensCache } from '@server/lib/auth/tokens-cache.js' import { TokensCache } from '@server/lib/auth/tokens-cache.js'
import { LiveQuotaStore } from '@server/lib/live/index.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 { ActorImageModel } from '../actor/actor-image.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { OAuthTokenModel } from '../oauth/oauth-token.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 { VideoChannelModel } from '../video/video-channel.js'
import { VideoImportModel } from '../video/video-import.js' import { VideoImportModel } from '../video/video-import.js'
import { VideoLiveModel } from '../video/video-live.js' import { VideoLiveModel } from '../video/video-live.js'
@ -875,32 +876,31 @@ export class UserModel extends SequelizeModel<UserModel> {
return parseInt(total, 10) return parseInt(total, 10)
} }
static async getStats () { static getStats () {
function getActiveUsers (days: number) { const query = `SELECT ` +
const query = { `COUNT(*) AS "totalUsers", ` +
where: { `COUNT(*) FILTER (WHERE "lastLoginDate" > NOW() - INTERVAL '1d') AS "totalDailyActiveUsers", ` +
[Op.and]: [ `COUNT(*) FILTER (WHERE "lastLoginDate" > NOW() - INTERVAL '7d') AS "totalWeeklyActiveUsers", ` +
literal(`"lastLoginDate" > NOW() - INTERVAL '${days}d'`) `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) { static autoComplete (search: string) {

View File

@ -8569,6 +8569,12 @@ components:
type: number type: number
totalMonthlyActiveUsers: totalMonthlyActiveUsers:
type: number 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: totalLocalVideos:
type: number type: number
totalLocalVideoViews: totalLocalVideoViews: