From 7c9f917114603068e1de36106565bc088c86c793 Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Sun, 23 Nov 2025 16:55:06 +0000 Subject: [PATCH] swag: add new statistics tag, add filtered user count route --- api-activities.go | 6 +++--- api-invites.go | 6 +++--- api-users.go | 36 ++++++++++++++++++++++++++++++++++-- main.go | 3 +++ router.go | 1 + 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/api-activities.go b/api-activities.go index 5ceba8b..df797ab 100644 --- a/api-activities.go +++ b/api-activities.go @@ -116,7 +116,7 @@ func (app *appContext) generateActivitiesQuery(req ServerFilterReqDTO) *badgerho // @Success 200 {object} GetActivitiesRespDTO // @Router /activity [post] // @Security Bearer -// @tags Activity +// @tags Activity,Statistics func (app *appContext) GetActivities(gc *gin.Context) { req := ServerSearchReqDTO{} gc.BindJSON(&req) @@ -185,7 +185,7 @@ func (app *appContext) DeleteActivity(gc *gin.Context) { // @Success 200 {object} PageCountDTO // @Router /activity/count [get] // @Security Bearer -// @tags Activity +// @tags Activity,Statistics func (app *appContext) GetActivityCount(gc *gin.Context) { resp := PageCountDTO{} var err error @@ -202,7 +202,7 @@ func (app *appContext) GetActivityCount(gc *gin.Context) { // @Success 200 {object} PageCountDTO // @Router /activity/count [post] // @Security Bearer -// @tags Activity +// @tags Activity,Statistics func (app *appContext) GetFilteredActivityCount(gc *gin.Context) { resp := PageCountDTO{} req := ServerFilterReqDTO{} diff --git a/api-invites.go b/api-invites.go index feb54cb..e8535b6 100644 --- a/api-invites.go +++ b/api-invites.go @@ -270,7 +270,7 @@ func (app *appContext) GenerateInvite(gc *gin.Context) { // @Success 200 {object} PageCountDTO // @Router /invites/count [get] // @Security Bearer -// @tags Invites +// @tags Invites,Statistics func (app *appContext) GetInviteCount(gc *gin.Context) { resp := PageCountDTO{} var err error @@ -286,7 +286,7 @@ func (app *appContext) GetInviteCount(gc *gin.Context) { // @Success 200 {object} PageCountDTO // @Router /invites/count/used [get] // @Security Bearer -// @tags Invites +// @tags Invites,Statistics func (app *appContext) GetInviteUsedCount(gc *gin.Context) { resp := PageCountDTO{} var err error @@ -310,7 +310,7 @@ func (app *appContext) GetInviteUsedCount(gc *gin.Context) { // @Success 200 {object} getInvitesDTO // @Router /invites [get] // @Security Bearer -// @tags Invites +// @tags Invites,Statistics func (app *appContext) GetInvites(gc *gin.Context) { currentTime := time.Now() app.checkInvites() diff --git a/api-users.go b/api-users.go index 899ba18..51f59bd 100644 --- a/api-users.go +++ b/api-users.go @@ -911,7 +911,7 @@ func (app *appContext) userSummary(jfUser mediabrowser.User) respUser { // @Success 200 {object} PageCountDTO // @Router /users/count [get] // @Security Bearer -// @tags Activity +// @tags Activity,Statistics func (app *appContext) GetUserCount(gc *gin.Context) { resp := PageCountDTO{} users, err := app.jf.GetUsers(false) @@ -952,7 +952,7 @@ func (app *appContext) GetUsers(gc *gin.Context) { // @Failure 500 {object} stringResponse // @Router /users [post] // @Security Bearer -// @tags Users +// @tags Users,Statistics func (app *appContext) SearchUsers(gc *gin.Context) { req := ServerSearchReqDTO{} gc.BindJSON(&req) @@ -991,6 +991,38 @@ func (app *appContext) SearchUsers(gc *gin.Context) { gc.JSON(200, resp) } +// @Summary Get a count of users matching the search provided +// @Produce json +// @Param ServerSearchReqDTO body ServerSearchReqDTO true "search / pagination parameters" +// @Success 200 {object} PageCountDTO +// @Failure 500 {object} stringResponse +// @Router /users/count [post] +// @Security Bearer +// @tags Users,Statistics +func (app *appContext) GetFilteredUserCount(gc *gin.Context) { + req := ServerSearchReqDTO{} + gc.BindJSON(&req) + if req.SortByField == "" { + req.SortByField = USER_DEFAULT_SORT_FIELD + } + + var resp PageCountDTO + // No need to sort + userList, err := app.userCache.GetUserDTOs(app, false) + if err != nil { + app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) + respond(500, "Couldn't get users", gc) + return + } + if len(req.SearchTerms) != 0 || len(req.Queries) != 0 { + resp.Count = uint64(len(app.userCache.Filter(userList, req.SearchTerms, req.Queries))) + } else { + resp.Count = uint64(len(userList)) + } + + gc.JSON(200, resp) +} + // @Summary Set whether or not a user can access jfa-go. Redundant if the user is a Jellyfin admin. // @Produce json // @Param setAccountsAdminDTO body setAccountsAdminDTO true "Map of userIDs to whether or not they have access." diff --git a/main.go b/main.go index e94f8a6..bc909cb 100644 --- a/main.go +++ b/main.go @@ -757,6 +757,9 @@ func flagPassed(name string) (found bool) { // @tag.name Other // @tag.description Things that dont fit elsewhere. +// @tag.name Statistics +// @tag.description Routes that expose useful info/stats. + func printVersion() { tray := "" if TRAY { diff --git a/router.go b/router.go index e086ae6..6f113bb 100644 --- a/router.go +++ b/router.go @@ -201,6 +201,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) { api.GET(p+"/users", app.GetUsers) api.GET(p+"/users/count", app.GetUserCount) api.POST(p+"/users", app.SearchUsers) + api.POST(p+"/users/count", app.GetFilteredUserCount) api.POST(p+"/user", app.NewUserFromAdmin) api.POST(p+"/users/extend", app.ExtendExpiry) api.DELETE(p+"/users/:id/expiry", app.RemoveExpiry)