rbac system first stage
This commit is contained in:
143
internal/db/auditlog.go
Normal file
143
internal/db/auditlog.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type AuditLog struct {
|
||||
bun.BaseModel `bun:"table:audit_log,alias:al"`
|
||||
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
UserID int `bun:"user_id,notnull"`
|
||||
Action string `bun:"action,notnull"`
|
||||
ResourceType string `bun:"resource_type,notnull"`
|
||||
ResourceID *string `bun:"resource_id"`
|
||||
Details json.RawMessage `bun:"details,type:jsonb"`
|
||||
IPAddress string `bun:"ip_address"`
|
||||
UserAgent string `bun:"user_agent"`
|
||||
Result string `bun:"result,notnull"` // success, denied, error
|
||||
ErrorMessage *string `bun:"error_message"`
|
||||
CreatedAt int64 `bun:"created_at,notnull"`
|
||||
|
||||
// Relations
|
||||
User *User `bun:"rel:belongs-to,join:user_id=id"`
|
||||
}
|
||||
|
||||
// TODO: add AuditLogs to match list style with PageOpts
|
||||
|
||||
// CreateAuditLog creates a new audit log entry
|
||||
func CreateAuditLog(ctx context.Context, tx bun.Tx, log *AuditLog) error {
|
||||
if log == nil {
|
||||
return errors.New("log cannot be nil")
|
||||
}
|
||||
|
||||
_, err := tx.NewInsert().
|
||||
Model(log).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "tx.NewInsert")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type AuditLogFilters struct {
|
||||
UserID *int
|
||||
Action *string
|
||||
ResourceType *string
|
||||
Result *string
|
||||
}
|
||||
|
||||
// GetAuditLogs retrieves audit logs with optional filters and pagination
|
||||
// TODO: change this to use db.PageOpts
|
||||
func GetAuditLogs(ctx context.Context, tx bun.Tx, limit, offset int, filters *AuditLogFilters) ([]*AuditLog, int, error) {
|
||||
query := tx.NewSelect().
|
||||
Model((*AuditLog)(nil)).
|
||||
Relation("User").
|
||||
Order("created_at DESC")
|
||||
|
||||
// Apply filters if provided
|
||||
if filters != nil {
|
||||
if filters.UserID != nil {
|
||||
query = query.Where("al.user_id = ?", *filters.UserID)
|
||||
}
|
||||
if filters.Action != nil {
|
||||
query = query.Where("al.action = ?", *filters.Action)
|
||||
}
|
||||
if filters.ResourceType != nil {
|
||||
query = query.Where("al.resource_type = ?", *filters.ResourceType)
|
||||
}
|
||||
if filters.Result != nil {
|
||||
query = query.Where("al.result = ?", *filters.Result)
|
||||
}
|
||||
}
|
||||
|
||||
// Get total count
|
||||
total, err := query.Count(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "query.Count")
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
var logs []*AuditLog
|
||||
err = query.
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Scan(ctx, &logs)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, 0, errors.Wrap(err, "query.Scan")
|
||||
}
|
||||
|
||||
return logs, total, nil
|
||||
}
|
||||
|
||||
// GetAuditLogsByUser retrieves audit logs for a specific user
|
||||
// TODO: change this to use db.PageOpts
|
||||
func GetAuditLogsByUser(ctx context.Context, tx bun.Tx, userID int, limit, offset int) ([]*AuditLog, int, error) {
|
||||
if userID <= 0 {
|
||||
return nil, 0, errors.New("userID must be positive")
|
||||
}
|
||||
|
||||
filters := &AuditLogFilters{
|
||||
UserID: &userID,
|
||||
}
|
||||
|
||||
return GetAuditLogs(ctx, tx, limit, offset, filters)
|
||||
}
|
||||
|
||||
// GetAuditLogsByAction retrieves audit logs for a specific action
|
||||
// TODO: change this to use db.PageOpts
|
||||
func GetAuditLogsByAction(ctx context.Context, tx bun.Tx, action string, limit, offset int) ([]*AuditLog, int, error) {
|
||||
if action == "" {
|
||||
return nil, 0, errors.New("action cannot be empty")
|
||||
}
|
||||
|
||||
filters := &AuditLogFilters{
|
||||
Action: &action,
|
||||
}
|
||||
|
||||
return GetAuditLogs(ctx, tx, limit, offset, filters)
|
||||
}
|
||||
|
||||
// CleanupOldAuditLogs deletes audit logs older than the specified timestamp
|
||||
func CleanupOldAuditLogs(ctx context.Context, tx bun.Tx, olderThan int64) (int, error) {
|
||||
result, err := tx.NewDelete().
|
||||
Model((*AuditLog)(nil)).
|
||||
Where("created_at < ?", olderThan).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "tx.NewDelete")
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "result.RowsAffected")
|
||||
}
|
||||
|
||||
return int(rowsAffected), nil
|
||||
}
|
||||
Reference in New Issue
Block a user