@@ -14,42 +14,114 @@ func (c *TasksController) GetAvailableTasks(ctx *gin.Context) ...
1414
15153. We document all routes with Swagger in the following format:
1616
17- // SignIn
18- // @Summary Authenticate a user
19- // @Description Authenticate a user with email and password
20- // @Tags users
17+ package audit_logs
18+
19+ import (
20+ "net/http"
21+
22+ user_models "logbull/internal/features/users/models"
23+
24+ "github.com/gin-gonic/gin"
25+ "github.com/google/uuid"
26+ )
27+
28+ type AuditLogController struct {
29+ auditLogService *AuditLogService
30+ }
31+
32+ func (c *AuditLogController) RegisterRoutes(router *gin.RouterGroup) {
33+ // All audit log endpoints require authentication (handled in main.go)
34+ auditRoutes := router.Group("/audit-logs")
35+
36+ auditRoutes.GET("/global", c.GetGlobalAuditLogs)
37+ auditRoutes.GET("/users/:userId", c.GetUserAuditLogs)
38+ }
39+
40+ // GetGlobalAuditLogs
41+ // @Summary Get global audit logs (ADMIN only)
42+ // @Description Retrieve all audit logs across the system
43+ // @Tags audit-logs
2144// @Accept json
2245// @Produce json
23- // @Param request body SignInRequest true "User signin data"
24- // @Success 200 {object} SignInResponse
25- // @Failure 400
26- // @Router /users/signin [post]
46+ // @Security BearerAuth
47+ // @Param limit query int false "Limit number of results" default(100)
48+ // @Param offset query int false "Offset for pagination" default(0)
49+ // @Param beforeDate query string false "Filter logs created before this date (RFC3339 format)" format(date-time)
50+ // @Success 200 {object} GetAuditLogsResponse
51+ // @Failure 401 {object} map[string]string
52+ // @Failure 403 {object} map[string]string
53+ // @Router /audit-logs/global [get]
54+ func (c *AuditLogController) GetGlobalAuditLogs(ctx *gin.Context) {
55+ user, isOk := ctx.MustGet("user").(*user_models.User)
56+ if !isOk {
57+ ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user type in context"})
58+ return
59+ }
2760
28- Do not forget to write docs.
29- You can avoid description if it is useless.
30- Specify particular acceping \ producing models
61+ request := &GetAuditLogsRequest{}
62+ if err := ctx.ShouldBindQuery(request); err != nil {
63+ ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid query parameters"})
64+ return
65+ }
3166
32- 4. All controllers should have RegisterRoutes method which receives
33- RouterGroup (always put this routes on the top of file under controller definition)
67+ response, err := c.auditLogService.GetGlobalAuditLogs(user, request)
68+ if err != nil {
69+ if err.Error() == "only administrators can view global audit logs" {
70+ ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
71+ return
72+ }
73+ ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve audit logs"})
74+ return
75+ }
3476
35- Example:
36-
37- func (c *OrderController) RegisterRoutes(router *gin.RouterGroup) {
38- router.POST("/bots/users/orders/generate", c.GenerateOrder)
39- router.POST("/bots/users/orders/generate-by-admin", c.GenerateOrderByAdmin)
40- router.GET("/bots/users/orders/mark-as-paid-by-admin", c.MarkOrderAsPaidByAdmin)
41- router.GET("/bots/users/orders/payments-by-bot", c.GetOrderPaymentsByBot)
42- router.GET("/bots/users/orders/payments-by-user", c.GetOrderPaymentsByUser)
43- router.GET("/bots/users/orders/orders-by-user-for-admin", c.GetOrdersByUserForAdmin)
44- router.POST("/bots/users/orders/orders-by-user-for-user", c.GetOrdersByUserForUser)
45- router.POST("/bots/users/orders/order", c.GetOrder)
46- router.POST("/bots/users/orders/cancel-subscription-by-user", c.CancelSubscriptionByUser)
47- router.GET("/bots/users/orders/cancel-subscription-by-admin", c.CancelSubscriptionByAdmin)
48- router.GET(
49- "/bots/users/orders/cancel-subscriptions-by-payment-option",
50- c.CancelSubscriptionsByPaymentOption,
51- )
77+ ctx.JSON(http.StatusOK, response)
5278}
5379
54- 5. Check that use use valid .Query("param") and .Param("param") methods.
55- If route does not have param - use .Query("query")
80+ // GetUserAuditLogs
81+ // @Summary Get user audit logs
82+ // @Description Retrieve audit logs for a specific user
83+ // @Tags audit-logs
84+ // @Accept json
85+ // @Produce json
86+ // @Security BearerAuth
87+ // @Param userId path string true "User ID"
88+ // @Param limit query int false "Limit number of results" default(100)
89+ // @Param offset query int false "Offset for pagination" default(0)
90+ // @Param beforeDate query string false "Filter logs created before this date (RFC3339 format)" format(date-time)
91+ // @Success 200 {object} GetAuditLogsResponse
92+ // @Failure 400 {object} map[string]string
93+ // @Failure 401 {object} map[string]string
94+ // @Failure 403 {object} map[string]string
95+ // @Router /audit-logs/users/{userId} [get]
96+ func (c *AuditLogController) GetUserAuditLogs(ctx *gin.Context) {
97+ user, isOk := ctx.MustGet("user").(*user_models.User)
98+ if !isOk {
99+ ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user type in context"})
100+ return
101+ }
102+
103+ userIDStr := ctx.Param("userId")
104+ targetUserID, err := uuid.Parse(userIDStr)
105+ if err != nil {
106+ ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
107+ return
108+ }
109+
110+ request := &GetAuditLogsRequest{}
111+ if err := ctx.ShouldBindQuery(request); err != nil {
112+ ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid query parameters"})
113+ return
114+ }
115+
116+ response, err := c.auditLogService.GetUserAuditLogs(targetUserID, user, request)
117+ if err != nil {
118+ if err.Error() == "insufficient permissions to view user audit logs" {
119+ ctx.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
120+ return
121+ }
122+ ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve audit logs"})
123+ return
124+ }
125+
126+ ctx.JSON(http.StatusOK, response)
127+ }
0 commit comments