Files
upstream-gitea/routers/web/shared/audit/audit.go
upstream-mirror 52ae0c5802
Some checks failed
cache-seeder / prune (push) Has been skipped
cache-seeder / frontend (push) Failing after 3s
cache-seeder / python (push) Failing after 3s
cache-seeder / gobuild (push) Failing after 4s
cache-seeder / lint (bindata, lint-backend) (push) Failing after 3s
giteabot backport / giteabot (push) Has been skipped
giteabot / giteabot (push) Has been skipped
cache-prune / prune (push) Has been skipped
release-nightly-snapcraft / build-and-publish (ubuntu-24.04) (push) Has been cancelled
release-nightly-snapcraft / build-and-publish (ubuntu-24.04-arm) (push) Has been cancelled
release-nightly / nightly-binary (push) Has been cancelled
release-nightly / nightly-container (push) Has been cancelled
cron-renovate / cron-renovate (push) Has been skipped
snapshot of https://github.com/go-gitea/gitea.git (main, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:41:59 +05:00

106 lines
3.5 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package audit
import (
"maps"
"net/http"
"slices"
audit_model "gitea.dev/models/audit"
"gitea.dev/models/db"
user_model "gitea.dev/models/user"
"gitea.dev/modules/setting"
"gitea.dev/modules/templates"
"gitea.dev/modules/util"
"gitea.dev/services/audit"
"gitea.dev/services/context"
)
// ViewOptions configures a scoped audit log listing. The admin view leaves
// ScopeType empty to list every event; the user/org/repo views constrain the
// query to their own scope.
type ViewOptions struct {
Template templates.TplName
ScopeType audit_model.ScopeType
ScopeID int64
// PageData holds ctx.Data flags to enable for the active navigation tab.
PageData map[string]any
}
var filterableOrigins = []audit_model.Origin{audit_model.OriginUI, audit_model.OriginAPI, audit_model.OriginCLI, audit_model.OriginSystem}
// SearchOptionsFromRequest builds the event query from the request filters and
// publishes the applied values to ctx.Data so the filter form can render its
// current state. The listing and the export share it to stay in sync.
func SearchOptionsFromRequest(ctx *context.Context, scopeType audit_model.ScopeType, scopeID int64) *audit_model.EventSearchOptions {
// only the two known sort values are accepted, anything else falls back to the default
sort := util.Iif(audit_model.EventSort(ctx.FormString("sort")) == audit_model.SortTimestampAsc, audit_model.SortTimestampAsc, audit_model.SortTimestampDesc)
opts := &audit_model.EventSearchOptions{
Sort: sort,
ScopeType: scopeType,
ScopeID: scopeID,
}
if action := audit_model.Action(ctx.FormString("action")); action != "" {
if _, ok := audit_model.MessageTemplate(action); ok {
opts.Action = action
} else if audit_model.IsActionFilter(action) {
opts.ActionPrefix = action
}
}
if origin := audit_model.Origin(ctx.FormString("origin")); slices.Contains(filterableOrigins, origin) {
opts.Origin = origin
}
if actor := ctx.FormTrim("actor"); actor != "" {
u, err := user_model.GetUserByName(ctx, actor)
if err != nil {
opts.ActorID = -1 // an unknown actor matches nothing rather than everything
} else {
opts.ActorID = u.ID
}
}
ctx.Data["AuditSort"] = string(opts.Sort)
ctx.Data["AuditFilterAction"] = string(opts.Action)
if opts.ActionPrefix != "" {
ctx.Data["AuditFilterAction"] = string(opts.ActionPrefix)
}
ctx.Data["AuditFilterOrigin"] = string(opts.Origin)
ctx.Data["AuditFilterActor"] = ctx.FormTrim("actor")
ctx.Data["AuditActions"] = audit_model.ActionFilters()
ctx.Data["AuditOrigins"] = filterableOrigins
return opts
}
// View renders a paginated audit log listing shared by the admin, user, org and
// repo settings pages. Only the scope filter, template and page flags differ.
func View(ctx *context.Context, opts ViewOptions) {
ctx.Data["Title"] = ctx.Tr("audit.title")
ctx.Data["AuditRecordEnabled"] = setting.AuditRecordEnabled()
maps.Copy(ctx.Data, opts.PageData)
page := max(ctx.FormInt("page"), 1)
searchOpts := SearchOptionsFromRequest(ctx, opts.ScopeType, opts.ScopeID)
searchOpts.ListOptions = db.ListOptions{
Page: page,
PageSize: setting.UI.Admin.NoticePagingNum,
}
evs, total, err := audit.FindEvents(ctx, searchOpts)
if err != nil {
ctx.ServerError("FindEvents", err)
return
}
ctx.Data["AuditEvents"] = evs
ctx.Data["Page"] = context.NewPagerBuilder(ctx).TotalCount(total).PerPageLimit(setting.UI.Admin.NoticePagingNum).CurPage(page).Build()
ctx.HTML(http.StatusOK, opts.Template)
}