209 lines
5.9 KiB
Go
209 lines
5.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"Yimaru-Backend/internal/domain"
|
|
"encoding/json"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
type activityLogRes struct {
|
|
ID int64 `json:"id"`
|
|
ActorID *int64 `json:"actor_id,omitempty"`
|
|
ActorRole *string `json:"actor_role,omitempty"`
|
|
Action string `json:"action"`
|
|
ResourceType string `json:"resource_type"`
|
|
ResourceID *int64 `json:"resource_id,omitempty"`
|
|
Message *string `json:"message,omitempty"`
|
|
Metadata json.RawMessage `json:"metadata"`
|
|
IPAddress *string `json:"ip_address,omitempty"`
|
|
UserAgent *string `json:"user_agent,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type activityLogListRes struct {
|
|
Logs []activityLogRes `json:"logs"`
|
|
TotalCount int64 `json:"total_count"`
|
|
Limit int32 `json:"limit"`
|
|
Offset int32 `json:"offset"`
|
|
}
|
|
|
|
// GetActivityLogs godoc
|
|
// @Summary Get activity logs
|
|
// @Description Returns a filtered, paginated list of activity logs
|
|
// @Tags activity-logs
|
|
// @Produce json
|
|
// @Param actor_id query int false "Filter by actor ID"
|
|
// @Param action query string false "Filter by action"
|
|
// @Param resource_type query string false "Filter by resource type"
|
|
// @Param resource_id query int false "Filter by resource ID"
|
|
// @Param after query string false "Filter logs after this RFC3339 timestamp"
|
|
// @Param before query string false "Filter logs before this RFC3339 timestamp"
|
|
// @Param limit query int false "Limit" default(20)
|
|
// @Param offset query int false "Offset" default(0)
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/activity-logs [get]
|
|
func (h *Handler) GetActivityLogs(c *fiber.Ctx) error {
|
|
var filter domain.ActivityLogFilter
|
|
|
|
if v := c.Query("actor_id"); v != "" {
|
|
id, err := strconv.ParseInt(v, 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid actor_id parameter",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
filter.ActorID = &id
|
|
}
|
|
|
|
if v := c.Query("action"); v != "" {
|
|
filter.Action = &v
|
|
}
|
|
|
|
if v := c.Query("resource_type"); v != "" {
|
|
filter.ResourceType = &v
|
|
}
|
|
|
|
if v := c.Query("resource_id"); v != "" {
|
|
id, err := strconv.ParseInt(v, 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid resource_id parameter",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
filter.ResourceID = &id
|
|
}
|
|
|
|
if v := c.Query("after"); v != "" {
|
|
t, err := time.Parse(time.RFC3339, v)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid after parameter, expected RFC3339 format",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
filter.After = &t
|
|
}
|
|
|
|
if v := c.Query("before"); v != "" {
|
|
t, err := time.Parse(time.RFC3339, v)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid before parameter, expected RFC3339 format",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
filter.Before = &t
|
|
}
|
|
|
|
limitStr := c.Query("limit", "20")
|
|
limit, err := strconv.Atoi(limitStr)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid limit parameter",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
if limit > 100 {
|
|
limit = 100
|
|
}
|
|
filter.Limit = int32(limit)
|
|
|
|
offsetStr := c.Query("offset", "0")
|
|
offset, err := strconv.Atoi(offsetStr)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid offset parameter",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
filter.Offset = int32(offset)
|
|
|
|
logs, totalCount, err := h.activityLogSvc.List(c.Context(), filter)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to retrieve activity logs",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
var logResponses []activityLogRes
|
|
for _, l := range logs {
|
|
logResponses = append(logResponses, activityLogRes{
|
|
ID: l.ID,
|
|
ActorID: l.ActorID,
|
|
ActorRole: l.ActorRole,
|
|
Action: l.Action,
|
|
ResourceType: l.ResourceType,
|
|
ResourceID: l.ResourceID,
|
|
Message: l.Message,
|
|
Metadata: l.Metadata,
|
|
IPAddress: l.IPAddress,
|
|
UserAgent: l.UserAgent,
|
|
CreatedAt: l.CreatedAt,
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Activity logs retrieved successfully",
|
|
Data: activityLogListRes{
|
|
Logs: logResponses,
|
|
TotalCount: totalCount,
|
|
Limit: int32(limit),
|
|
Offset: int32(offset),
|
|
},
|
|
})
|
|
}
|
|
|
|
// GetActivityLogByID godoc
|
|
// @Summary Get activity log by ID
|
|
// @Description Returns a single activity log entry by its ID
|
|
// @Tags activity-logs
|
|
// @Produce json
|
|
// @Param id path int true "Activity Log ID"
|
|
// @Success 200 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 404 {object} domain.ErrorResponse
|
|
// @Router /api/v1/activity-logs/{id} [get]
|
|
func (h *Handler) GetActivityLogByID(c *fiber.Ctx) error {
|
|
idStr := c.Params("id")
|
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid activity log ID",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
l, err := h.activityLogSvc.GetByID(c.Context(), id)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{
|
|
Message: "Activity log not found",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.JSON(domain.Response{
|
|
Message: "Activity log retrieved successfully",
|
|
Data: activityLogRes{
|
|
ID: l.ID,
|
|
ActorID: l.ActorID,
|
|
ActorRole: l.ActorRole,
|
|
Action: l.Action,
|
|
ResourceType: l.ResourceType,
|
|
ResourceID: l.ResourceID,
|
|
Message: l.Message,
|
|
Metadata: l.Metadata,
|
|
IPAddress: l.IPAddress,
|
|
UserAgent: l.UserAgent,
|
|
CreatedAt: l.CreatedAt,
|
|
},
|
|
})
|
|
}
|