aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-02-28 18:04:46 +0100
committerChocobozzz <me@florianbigard.com>2018-02-28 18:04:55 +0100
commit09cababd79f9d445aa027c93cdfe823745fa041a (patch)
treef781d6ba78b5c4ce7220dea55f13b21230f203d6
parent22b59e8099947605085cf65a440f07f37fce6b65 (diff)
downloadPeerTube-09cababd79f9d445aa027c93cdfe823745fa041a.tar.gz
PeerTube-09cababd79f9d445aa027c93cdfe823745fa041a.tar.zst
PeerTube-09cababd79f9d445aa027c93cdfe823745fa041a.zip
Add stats route
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts2
-rw-r--r--client/src/app/+admin/config/shared/config.service.ts2
-rw-r--r--client/src/app/+admin/jobs/shared/job.service.ts2
-rw-r--r--client/src/app/core/server/server.service.ts2
-rw-r--r--server/controllers/activitypub/inbox.ts2
-rw-r--r--server/controllers/api/config.ts4
-rw-r--r--server/controllers/api/server/index.ts2
-rw-r--r--server/controllers/api/server/stats.ts39
-rw-r--r--server/models/account/user.ts9
-rw-r--r--server/models/activitypub/actor-follow.ts50
-rw-r--r--server/models/video/video-comment.ts26
-rw-r--r--server/models/video/video.ts23
-rw-r--r--server/tests/api/check-params/config.ts2
-rw-r--r--server/tests/api/index-fast.ts3
-rw-r--r--server/tests/api/index-slow.ts1
-rw-r--r--server/tests/api/server/config.ts4
-rw-r--r--server/tests/api/server/stats.ts102
-rw-r--r--server/tests/utils/server/config.ts2
-rw-r--r--server/tests/utils/server/stats.ts17
-rw-r--r--shared/models/index.ts4
-rw-r--r--shared/models/server/about.model.ts (renamed from shared/models/config/about.model.ts)0
-rw-r--r--shared/models/server/custom-config.model.ts (renamed from shared/models/config/custom-config.model.ts)0
-rw-r--r--shared/models/server/customization.model.ts (renamed from shared/models/config/customization.model.ts)0
-rw-r--r--shared/models/server/job.model.ts (renamed from shared/models/job.model.ts)0
-rw-r--r--shared/models/server/server-config.model.ts (renamed from shared/models/config/server-config.model.ts)0
-rw-r--r--shared/models/server/server-stats.model.ts12
26 files changed, 268 insertions, 42 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
index ccec89a8e..cf93b4060 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
@@ -13,7 +13,7 @@ import {
13 TRANSCODING_THREADS 13 TRANSCODING_THREADS
14} from '@app/shared/forms/form-validators/custom-config' 14} from '@app/shared/forms/form-validators/custom-config'
15import { NotificationsService } from 'angular2-notifications' 15import { NotificationsService } from 'angular2-notifications'
16import { CustomConfig } from '../../../../../../shared/models/config/custom-config.model' 16import { CustomConfig } from '../../../../../../shared/models/server/custom-config.model'
17 17
18@Component({ 18@Component({
19 selector: 'my-edit-custom-config', 19 selector: 'my-edit-custom-config',
diff --git a/client/src/app/+admin/config/shared/config.service.ts b/client/src/app/+admin/config/shared/config.service.ts
index 13f1f6cd2..2a39c7155 100644
--- a/client/src/app/+admin/config/shared/config.service.ts
+++ b/client/src/app/+admin/config/shared/config.service.ts
@@ -1,6 +1,6 @@
1import { HttpClient } from '@angular/common/http' 1import { HttpClient } from '@angular/common/http'
2import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
3import { CustomConfig } from '../../../../../../shared/models/config/custom-config.model' 3import { CustomConfig } from '../../../../../../shared/models/server/custom-config.model'
4import { environment } from '../../../../environments/environment' 4import { environment } from '../../../../environments/environment'
5import { RestExtractor, RestService } from '../../../shared' 5import { RestExtractor, RestService } from '../../../shared'
6 6
diff --git a/client/src/app/+admin/jobs/shared/job.service.ts b/client/src/app/+admin/jobs/shared/job.service.ts
index 1c0915b5e..98f29b742 100644
--- a/client/src/app/+admin/jobs/shared/job.service.ts
+++ b/client/src/app/+admin/jobs/shared/job.service.ts
@@ -6,7 +6,7 @@ import 'rxjs/add/operator/map'
6import { Observable } from 'rxjs/Observable' 6import { Observable } from 'rxjs/Observable'
7import { ResultList } from '../../../../../../shared' 7import { ResultList } from '../../../../../../shared'
8import { JobState } from '../../../../../../shared/models' 8import { JobState } from '../../../../../../shared/models'
9import { Job } from '../../../../../../shared/models/job.model' 9import { Job } from '../../../../../../shared/models/server/job.model'
10import { environment } from '../../../../environments/environment' 10import { environment } from '../../../../environments/environment'
11import { RestExtractor, RestPagination, RestService } from '../../../shared' 11import { RestExtractor, RestPagination, RestService } from '../../../shared'
12 12
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index 3c94f09c6..984738948 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core'
3import 'rxjs/add/operator/do' 3import 'rxjs/add/operator/do'
4import { ReplaySubject } from 'rxjs/ReplaySubject' 4import { ReplaySubject } from 'rxjs/ReplaySubject'
5import { ServerConfig } from '../../../../../shared' 5import { ServerConfig } from '../../../../../shared'
6import { About } from '../../../../../shared/models/config/about.model' 6import { About } from '../../../../../shared/models/server/about.model'
7import { environment } from '../../../environments/environment' 7import { environment } from '../../../environments/environment'
8 8
9@Injectable() 9@Injectable()
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts
index bd0d7a9c8..0354d7833 100644
--- a/server/controllers/activitypub/inbox.ts
+++ b/server/controllers/activitypub/inbox.ts
@@ -56,6 +56,8 @@ async function inboxController (req: express.Request, res: express.Response, nex
56 specificActor = res.locals.videoChannel 56 specificActor = res.locals.videoChannel
57 } 57 }
58 58
59 logger.info('Receiving inbox requests for %d activities by %s.', activities.length, res.locals.signature.actor)
60
59 await processActivities(activities, res.locals.signature.actor, specificActor) 61 await processActivities(activities, res.locals.signature.actor, specificActor)
60 62
61 res.status(204).end() 63 res.status(204).end()
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 7ef0c19e3..427125810 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -1,8 +1,8 @@
1import * as express from 'express' 1import * as express from 'express'
2import { omit } from 'lodash' 2import { omit } from 'lodash'
3import { ServerConfig, UserRight } from '../../../shared' 3import { ServerConfig, UserRight } from '../../../shared'
4import { About } from '../../../shared/models/config/about.model' 4import { About } from '../../../shared/models/server/about.model'
5import { CustomConfig } from '../../../shared/models/config/custom-config.model' 5import { CustomConfig } from '../../../shared/models/server/custom-config.model'
6import { unlinkPromise, writeFilePromise } from '../../helpers/core-utils' 6import { unlinkPromise, writeFilePromise } from '../../helpers/core-utils'
7import { isSignupAllowed } from '../../helpers/utils' 7import { isSignupAllowed } from '../../helpers/utils'
8import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers' 8import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers'
diff --git a/server/controllers/api/server/index.ts b/server/controllers/api/server/index.ts
index 8dc1a0031..850a52cdb 100644
--- a/server/controllers/api/server/index.ts
+++ b/server/controllers/api/server/index.ts
@@ -1,9 +1,11 @@
1import * as express from 'express' 1import * as express from 'express'
2import { serverFollowsRouter } from './follows' 2import { serverFollowsRouter } from './follows'
3import { statsRouter } from './stats'
3 4
4const serverRouter = express.Router() 5const serverRouter = express.Router()
5 6
6serverRouter.use('/', serverFollowsRouter) 7serverRouter.use('/', serverFollowsRouter)
8serverRouter.use('/', statsRouter)
7 9
8// --------------------------------------------------------------------------- 10// ---------------------------------------------------------------------------
9 11
diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts
new file mode 100644
index 000000000..6f4fe938c
--- /dev/null
+++ b/server/controllers/api/server/stats.ts
@@ -0,0 +1,39 @@
1import * as express from 'express'
2import { ServerStats } from '../../../../shared/models/server/server-stats.model'
3import { asyncMiddleware } from '../../../middlewares'
4import { UserModel } from '../../../models/account/user'
5import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
6import { VideoModel } from '../../../models/video/video'
7import { VideoCommentModel } from '../../../models/video/video-comment'
8
9const statsRouter = express.Router()
10
11statsRouter.get('/stats',
12 asyncMiddleware(getStats)
13)
14
15async function getStats (req: express.Request, res: express.Response, next: express.NextFunction) {
16 const { totalLocalVideos, totalLocalVideoViews, totalVideos } = await VideoModel.getStats()
17 const { totalLocalVideoComments, totalVideoComments } = await VideoCommentModel.getStats()
18 const { totalUsers } = await UserModel.getStats()
19 const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats()
20
21 const data: ServerStats = {
22 totalLocalVideos,
23 totalLocalVideoViews,
24 totalVideos,
25 totalLocalVideoComments,
26 totalVideoComments,
27 totalUsers,
28 totalInstanceFollowers,
29 totalInstanceFollowing
30 }
31
32 return res.json(data).end()
33}
34
35// ---------------------------------------------------------------------------
36
37export {
38 statsRouter
39}
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 74cf0f4a8..afa9d7be0 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -13,6 +13,7 @@ import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
13import { OAuthTokenModel } from '../oauth/oauth-token' 13import { OAuthTokenModel } from '../oauth/oauth-token'
14import { getSort, throwIfNotValid } from '../utils' 14import { getSort, throwIfNotValid } from '../utils'
15import { VideoChannelModel } from '../video/video-channel' 15import { VideoChannelModel } from '../video/video-channel'
16import { VideoCommentModel } from '../video/video-comment'
16import { AccountModel } from './account' 17import { AccountModel } from './account'
17 18
18@DefaultScope({ 19@DefaultScope({
@@ -226,6 +227,14 @@ export class UserModel extends Model<UserModel> {
226 }) 227 })
227 } 228 }
228 229
230 static async getStats () {
231 const totalUsers = await UserModel.count()
232
233 return {
234 totalUsers
235 }
236 }
237
229 hasRight (right: UserRight) { 238 hasRight (right: UserRight) {
230 return hasUserRight(this.role, right) 239 return hasUserRight(this.role, right)
231 } 240 }
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 8260904a1..3c11d1b67 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -8,6 +8,7 @@ import {
8import { FollowState } from '../../../shared/models/actors' 8import { FollowState } from '../../../shared/models/actors'
9import { AccountFollow } from '../../../shared/models/actors/follow.model' 9import { AccountFollow } from '../../../shared/models/actors/follow.model'
10import { logger } from '../../helpers/logger' 10import { logger } from '../../helpers/logger'
11import { getServerActor } from '../../helpers/utils'
11import { ACTOR_FOLLOW_SCORE } from '../../initializers' 12import { ACTOR_FOLLOW_SCORE } from '../../initializers'
12import { FOLLOW_STATES } from '../../initializers/constants' 13import { FOLLOW_STATES } from '../../initializers/constants'
13import { ServerModel } from '../server/server' 14import { ServerModel } from '../server/server'
@@ -182,34 +183,6 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
182 return ActorFollowModel.findOne(query) 183 return ActorFollowModel.findOne(query)
183 } 184 }
184 185
185 static loadByFollowerInbox (url: string, t?: Sequelize.Transaction) {
186 const query = {
187 where: {
188 state: 'accepted'
189 },
190 include: [
191 {
192 model: ActorModel,
193 required: true,
194 as: 'ActorFollower',
195 where: {
196 [Sequelize.Op.or]: [
197 {
198 inboxUrl: url
199 },
200 {
201 sharedInboxUrl: url
202 }
203 ]
204 }
205 }
206 ],
207 transaction: t
208 } as any // FIXME: typings does not work
209
210 return ActorFollowModel.findOne(query)
211 }
212
213 static listFollowingForApi (id: number, start: number, count: number, sort: string) { 186 static listFollowingForApi (id: number, start: number, count: number, sort: string) {
214 const query = { 187 const query = {
215 distinct: true, 188 distinct: true,
@@ -296,6 +269,27 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
296 return ActorFollowModel.createListAcceptedFollowForApiQuery('following', actorIds, t, start, count) 269 return ActorFollowModel.createListAcceptedFollowForApiQuery('following', actorIds, t, start, count)
297 } 270 }
298 271
272 static async getStats () {
273 const serverActor = await getServerActor()
274
275 const totalInstanceFollowing = await ActorFollowModel.count({
276 where: {
277 actorId: serverActor.id
278 }
279 })
280
281 const totalInstanceFollowers = await ActorFollowModel.count({
282 where: {
283 targetActorId: serverActor.id
284 }
285 })
286
287 return {
288 totalInstanceFollowing,
289 totalInstanceFollowers
290 }
291 }
292
299 private static async createListAcceptedFollowForApiQuery ( 293 private static async createListAcceptedFollowForApiQuery (
300 type: 'followers' | 'following', 294 type: 'followers' | 'following',
301 actorIds: number[], 295 actorIds: number[],
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts
index 47e3211a3..bf8da924d 100644
--- a/server/models/video/video-comment.ts
+++ b/server/models/video/video-comment.ts
@@ -326,6 +326,32 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
326 .findAll(query) 326 .findAll(query)
327 } 327 }
328 328
329 static async getStats () {
330 const totalLocalVideoComments = await VideoCommentModel.count({
331 include: [
332 {
333 model: AccountModel,
334 required: true,
335 include: [
336 {
337 model: ActorModel,
338 required: true,
339 where: {
340 serverId: null
341 }
342 }
343 ]
344 }
345 ]
346 })
347 const totalVideoComments = await VideoCommentModel.count()
348
349 return {
350 totalLocalVideoComments,
351 totalVideoComments
352 }
353 }
354
329 getThreadId (): number { 355 getThreadId (): number {
330 return this.originCommentId || this.id 356 return this.originCommentId || this.id
331 } 357 }
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 80ca513bf..f6a21814c 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -761,6 +761,29 @@ export class VideoModel extends Model<VideoModel> {
761 .findOne(options) 761 .findOne(options)
762 } 762 }
763 763
764 static async getStats () {
765 const totalLocalVideos = await VideoModel.count({
766 where: {
767 remote: false
768 }
769 })
770 const totalVideos = await VideoModel.count()
771
772 let totalLocalVideoViews = await VideoModel.sum('views', {
773 where: {
774 remote: false
775 }
776 })
777 // Sequelize could return null...
778 if (!totalLocalVideoViews) totalLocalVideoViews = 0
779
780 return {
781 totalLocalVideos,
782 totalLocalVideoViews,
783 totalVideos
784 }
785 }
786
764 getOriginalFile () { 787 getOriginalFile () {
765 if (Array.isArray(this.VideoFiles) === false) return undefined 788 if (Array.isArray(this.VideoFiles) === false) return undefined
766 789
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts
index c1c0a3f59..a66e51a6a 100644
--- a/server/tests/api/check-params/config.ts
+++ b/server/tests/api/check-params/config.ts
@@ -2,7 +2,7 @@
2 2
3import { omit } from 'lodash' 3import { omit } from 'lodash'
4import 'mocha' 4import 'mocha'
5import { CustomConfig } from '../../../../shared/models/config/custom-config.model' 5import { CustomConfig } from '../../../../shared/models/server/custom-config.model'
6 6
7import { 7import {
8 createUser, flushTests, killallServers, makeDeleteRequest, makeGetRequest, makePutBodyRequest, runServer, ServerInfo, 8 createUser, flushTests, killallServers, makeDeleteRequest, makeGetRequest, makePutBodyRequest, runServer, ServerInfo,
diff --git a/server/tests/api/index-fast.ts b/server/tests/api/index-fast.ts
index 9f52310dd..464dcb5e0 100644
--- a/server/tests/api/index-fast.ts
+++ b/server/tests/api/index-fast.ts
@@ -1,5 +1,5 @@
1// Order of the tests we want to execute 1// Order of the tests we want to execute
2import './server/config' 2import './server/stats'
3import './check-params' 3import './check-params'
4import './users/users' 4import './users/users'
5import './videos/single-server' 5import './videos/single-server'
@@ -10,3 +10,4 @@ import './videos/video-description'
10import './videos/video-privacy' 10import './videos/video-privacy'
11import './videos/services' 11import './videos/services'
12import './server/email' 12import './server/email'
13import './server/config'
diff --git a/server/tests/api/index-slow.ts b/server/tests/api/index-slow.ts
index 0082bcb56..cde546856 100644
--- a/server/tests/api/index-slow.ts
+++ b/server/tests/api/index-slow.ts
@@ -1,5 +1,4 @@
1// Order of the tests we want to execute 1// Order of the tests we want to execute
2// import './multiple-servers'
3import './videos/video-transcoder' 2import './videos/video-transcoder'
4import './videos/multiple-servers' 3import './videos/multiple-servers'
5import './server/follows' 4import './server/follows'
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts
index 048135a34..3d90580d8 100644
--- a/server/tests/api/server/config.ts
+++ b/server/tests/api/server/config.ts
@@ -2,8 +2,8 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { About } from '../../../../shared/models/config/about.model' 5import { About } from '../../../../shared/models/server/about.model'
6import { CustomConfig } from '../../../../shared/models/config/custom-config.model' 6import { CustomConfig } from '../../../../shared/models/server/custom-config.model'
7import { deleteCustomConfig, getAbout, killallServers, reRunServer } from '../../utils' 7import { deleteCustomConfig, getAbout, killallServers, reRunServer } from '../../utils'
8const expect = chai.expect 8const expect = chai.expect
9 9
diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts
new file mode 100644
index 000000000..71d54c0ab
--- /dev/null
+++ b/server/tests/api/server/stats.ts
@@ -0,0 +1,102 @@
1/* tslint:disable:no-unused-expression */
2
3import * as chai from 'chai'
4import 'mocha'
5import { ServerStats } from '../../../../shared/models/server/server-stats.model'
6import {
7 createUser,
8 doubleFollow,
9 flushAndRunMultipleServers,
10 follow,
11 killallServers,
12 ServerInfo,
13 uploadVideo,
14 viewVideo,
15 wait
16} from '../../utils'
17import { flushTests, setAccessTokensToServers } from '../../utils/index'
18import { getStats } from '../../utils/server/stats'
19import { addVideoCommentThread } from '../../utils/videos/video-comments'
20
21const expect = chai.expect
22
23describe('Test stats', function () {
24 let servers: ServerInfo[] = []
25
26 before(async function () {
27 this.timeout(60000)
28
29 await flushTests()
30 servers = await flushAndRunMultipleServers(3)
31 await setAccessTokensToServers(servers)
32
33 await doubleFollow(servers[0], servers[1])
34
35 const user = {
36 username: 'user1',
37 password: 'super_password'
38 }
39 await createUser(servers[0].url, servers[0].accessToken, user.username, user.password)
40
41 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, {})
42 const videoUUID = resVideo.body.video.uuid
43
44 await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'comment')
45
46 await viewVideo(servers[0].url, videoUUID)
47
48 await follow(servers[2].url, [ servers[0].url ], servers[2].accessToken)
49 await wait(5000)
50 })
51
52 it('Should have the correct stats on instance 1', async function () {
53 const res = await getStats(servers[0].url)
54 const data: ServerStats = res.body
55
56 expect(data.totalLocalVideoComments).to.equal(1)
57 expect(data.totalLocalVideos).to.equal(1)
58 expect(data.totalLocalVideoViews).to.equal(1)
59 expect(data.totalUsers).to.equal(2)
60 expect(data.totalVideoComments).to.equal(1)
61 expect(data.totalVideos).to.equal(1)
62 expect(data.totalInstanceFollowers).to.equal(2)
63 expect(data.totalInstanceFollowing).to.equal(1)
64 })
65
66 it('Should have the correct stats on instance 2', async function () {
67 const res = await getStats(servers[1].url)
68 const data: ServerStats = res.body
69
70 expect(data.totalLocalVideoComments).to.equal(0)
71 expect(data.totalLocalVideos).to.equal(0)
72 expect(data.totalLocalVideoViews).to.equal(0)
73 expect(data.totalUsers).to.equal(1)
74 expect(data.totalVideoComments).to.equal(1)
75 expect(data.totalVideos).to.equal(1)
76 expect(data.totalInstanceFollowers).to.equal(1)
77 expect(data.totalInstanceFollowing).to.equal(1)
78 })
79
80 it('Should have the correct stats on instance 3', async function () {
81 const res = await getStats(servers[2].url)
82 const data: ServerStats = res.body
83
84 expect(data.totalLocalVideoComments).to.equal(0)
85 expect(data.totalLocalVideos).to.equal(0)
86 expect(data.totalLocalVideoViews).to.equal(0)
87 expect(data.totalUsers).to.equal(1)
88 expect(data.totalVideoComments).to.equal(1)
89 expect(data.totalVideos).to.equal(1)
90 expect(data.totalInstanceFollowing).to.equal(1)
91 expect(data.totalInstanceFollowers).to.equal(0)
92 })
93
94 after(async function () {
95 killallServers(servers)
96
97 // Keep the logs if the test failed
98 if (this['ok']) {
99 await flushTests()
100 }
101 })
102})
diff --git a/server/tests/utils/server/config.ts b/server/tests/utils/server/config.ts
index e5411117a..57f95a603 100644
--- a/server/tests/utils/server/config.ts
+++ b/server/tests/utils/server/config.ts
@@ -1,5 +1,5 @@
1import { makeDeleteRequest, makeGetRequest, makePutBodyRequest } from '../' 1import { makeDeleteRequest, makeGetRequest, makePutBodyRequest } from '../'
2import { CustomConfig } from '../../../../shared/models/config/custom-config.model' 2import { CustomConfig } from '../../../../shared/models/server/custom-config.model'
3 3
4function getConfig (url: string) { 4function getConfig (url: string) {
5 const path = '/api/v1/config' 5 const path = '/api/v1/config'
diff --git a/server/tests/utils/server/stats.ts b/server/tests/utils/server/stats.ts
new file mode 100644
index 000000000..9cdec6cff
--- /dev/null
+++ b/server/tests/utils/server/stats.ts
@@ -0,0 +1,17 @@
1import { makeGetRequest } from '../'
2
3function getStats (url: string) {
4 const path = '/api/v1/server/stats'
5
6 return makeGetRequest({
7 url,
8 path,
9 statusCodeExpected: 200
10 })
11}
12
13// ---------------------------------------------------------------------------
14
15export {
16 getStats
17}
diff --git a/shared/models/index.ts b/shared/models/index.ts
index 1b877774c..ae3a44777 100644
--- a/shared/models/index.ts
+++ b/shared/models/index.ts
@@ -2,7 +2,7 @@ export * from './actors'
2export * from './activitypub' 2export * from './activitypub'
3export * from './users' 3export * from './users'
4export * from './videos' 4export * from './videos'
5export * from './job.model' 5export * from './server/job.model'
6export * from './oauth-client-local.model' 6export * from './oauth-client-local.model'
7export * from './result-list.model' 7export * from './result-list.model'
8export * from './config/server-config.model' 8export * from './server/server-config.model'
diff --git a/shared/models/config/about.model.ts b/shared/models/server/about.model.ts
index 7d11da850..7d11da850 100644
--- a/shared/models/config/about.model.ts
+++ b/shared/models/server/about.model.ts
diff --git a/shared/models/config/custom-config.model.ts b/shared/models/server/custom-config.model.ts
index 46d0a86ef..46d0a86ef 100644
--- a/shared/models/config/custom-config.model.ts
+++ b/shared/models/server/custom-config.model.ts
diff --git a/shared/models/config/customization.model.ts b/shared/models/server/customization.model.ts
index 4e4d0d193..4e4d0d193 100644
--- a/shared/models/config/customization.model.ts
+++ b/shared/models/server/customization.model.ts
diff --git a/shared/models/job.model.ts b/shared/models/server/job.model.ts
index 5ebb75a5c..5ebb75a5c 100644
--- a/shared/models/job.model.ts
+++ b/shared/models/server/job.model.ts
diff --git a/shared/models/config/server-config.model.ts b/shared/models/server/server-config.model.ts
index 004cf6ddb..004cf6ddb 100644
--- a/shared/models/config/server-config.model.ts
+++ b/shared/models/server/server-config.model.ts
diff --git a/shared/models/server/server-stats.model.ts b/shared/models/server/server-stats.model.ts
new file mode 100644
index 000000000..5c1bf3468
--- /dev/null
+++ b/shared/models/server/server-stats.model.ts
@@ -0,0 +1,12 @@
1export interface ServerStats {
2 totalUsers: number
3 totalLocalVideos: number
4 totalLocalVideoViews: number
5 totalLocalVideoComments: number
6
7 totalVideos: number
8 totalVideoComments: number
9
10 totalInstanceFollowers: number
11 totalInstanceFollowing: number
12}