mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-06-29 04:47:45 +02:00
Harvey Tindall
2d83718f81
my initial intent before starting search was for it to be server-sided, considering this activity log could rack up 100s or 1000s of entries, and then I forgot and did it client-sided. this commit adds a feature to load more results when scrolled to the bottom, and when a search returns few or no results (this is limited, so it wont loop infinitely). Also finally got rid of the useless left column, since my ideas didn't match my implementation. also, sorting is only by date, can't be bothered with anything else.
171 lines
4.1 KiB
Go
171 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/timshannon/badgerhold/v4"
|
|
)
|
|
|
|
func stringToActivityType(v string) ActivityType {
|
|
switch v {
|
|
case "creation":
|
|
return ActivityCreation
|
|
case "deletion":
|
|
return ActivityDeletion
|
|
case "disabled":
|
|
return ActivityDisabled
|
|
case "enabled":
|
|
return ActivityEnabled
|
|
case "contactLinked":
|
|
return ActivityContactLinked
|
|
case "contactUnlinked":
|
|
return ActivityContactUnlinked
|
|
case "changePassword":
|
|
return ActivityChangePassword
|
|
case "resetPassword":
|
|
return ActivityResetPassword
|
|
case "createInvite":
|
|
return ActivityCreateInvite
|
|
case "deleteInvite":
|
|
return ActivityDeleteInvite
|
|
}
|
|
return ActivityUnknown
|
|
}
|
|
|
|
func activityTypeToString(v ActivityType) string {
|
|
switch v {
|
|
case ActivityCreation:
|
|
return "creation"
|
|
case ActivityDeletion:
|
|
return "deletion"
|
|
case ActivityDisabled:
|
|
return "disabled"
|
|
case ActivityEnabled:
|
|
return "enabled"
|
|
case ActivityContactLinked:
|
|
return "contactLinked"
|
|
case ActivityContactUnlinked:
|
|
return "contactUnlinked"
|
|
case ActivityChangePassword:
|
|
return "changePassword"
|
|
case ActivityResetPassword:
|
|
return "resetPassword"
|
|
case ActivityCreateInvite:
|
|
return "createInvite"
|
|
case ActivityDeleteInvite:
|
|
return "deleteInvite"
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func stringToActivitySource(v string) ActivitySource {
|
|
switch v {
|
|
case "user":
|
|
return ActivityUser
|
|
case "admin":
|
|
return ActivityAdmin
|
|
case "anon":
|
|
return ActivityAnon
|
|
case "daemon":
|
|
return ActivityDaemon
|
|
}
|
|
return ActivityAnon
|
|
}
|
|
|
|
func activitySourceToString(v ActivitySource) string {
|
|
switch v {
|
|
case ActivityUser:
|
|
return "user"
|
|
case ActivityAdmin:
|
|
return "admin"
|
|
case ActivityAnon:
|
|
return "anon"
|
|
case ActivityDaemon:
|
|
return "daemon"
|
|
}
|
|
return "anon"
|
|
}
|
|
|
|
// @Summary Get the requested set of activities, Paginated, filtered and sorted.
|
|
// @Produce json
|
|
// @Param GetActivitiesDTO body GetActivitiesDTO true "search parameters"
|
|
// @Success 200 {object} GetActivitiesRespDTO
|
|
// @Router /activity [post]
|
|
// @Security Bearer
|
|
// @tags Activity
|
|
func (app *appContext) GetActivities(gc *gin.Context) {
|
|
req := GetActivitiesDTO{}
|
|
gc.BindJSON(&req)
|
|
query := &badgerhold.Query{}
|
|
activityTypes := make([]interface{}, len(req.Type))
|
|
for i, v := range req.Type {
|
|
activityTypes[i] = stringToActivityType(v)
|
|
}
|
|
if len(activityTypes) != 0 {
|
|
query = badgerhold.Where("Type").In(activityTypes...)
|
|
}
|
|
|
|
if !req.Ascending {
|
|
query = query.Reverse()
|
|
}
|
|
|
|
query = query.SortBy("Time")
|
|
|
|
if req.Limit == 0 {
|
|
req.Limit = 10
|
|
}
|
|
|
|
query = query.Skip(req.Page * req.Limit).Limit(req.Limit)
|
|
|
|
var results []Activity
|
|
err := app.storage.db.Find(&results, query)
|
|
|
|
if err != nil {
|
|
app.err.Printf("Failed to read activities from DB: %v\n", err)
|
|
}
|
|
|
|
resp := GetActivitiesRespDTO{
|
|
Activities: make([]ActivityDTO, len(results)),
|
|
LastPage: len(results) != req.Limit,
|
|
}
|
|
|
|
for i, act := range results {
|
|
resp.Activities[i] = ActivityDTO{
|
|
ID: act.ID,
|
|
Type: activityTypeToString(act.Type),
|
|
UserID: act.UserID,
|
|
SourceType: activitySourceToString(act.SourceType),
|
|
Source: act.Source,
|
|
InviteCode: act.InviteCode,
|
|
Value: act.Value,
|
|
Time: act.Time.Unix(),
|
|
}
|
|
if act.Type == ActivityDeletion || act.Type == ActivityCreation {
|
|
resp.Activities[i].Username = act.Value
|
|
resp.Activities[i].Value = ""
|
|
} else if user, status, err := app.jf.UserByID(act.UserID, false); status == 200 && err == nil {
|
|
resp.Activities[i].Username = user.Name
|
|
}
|
|
|
|
if (act.SourceType == ActivityUser || act.SourceType == ActivityAdmin) && act.Source != "" {
|
|
user, status, err := app.jf.UserByID(act.Source, false)
|
|
if status == 200 && err == nil {
|
|
resp.Activities[i].SourceUsername = user.Name
|
|
}
|
|
}
|
|
}
|
|
|
|
gc.JSON(200, resp)
|
|
}
|
|
|
|
// @Summary Delete the activity with the given ID. No-op if non-existent, always succeeds.
|
|
// @Produce json
|
|
// @Param id path string true "ID of activity to delete"
|
|
// @Success 200 {object} boolResponse
|
|
// @Router /activity/{id} [delete]
|
|
// @Security Bearer
|
|
// @tags Activity
|
|
func (app *appContext) DeleteActivity(gc *gin.Context) {
|
|
app.storage.DeleteActivityKey(gc.Param("id"))
|
|
respondBool(200, true, gc)
|
|
}
|