Skip to content

Commit 9c00d5b

Browse files
committed
add audit events
1 parent d591ab0 commit 9c00d5b

6 files changed

Lines changed: 307 additions & 1 deletion

File tree

server/app/admin_handler.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ func (a *App) SetPricesHandler(req *http.Request) (interface{}, Response) {
169169
a.config.PricesPerMonth.PublicIP = input.PublicIP
170170
}
171171

172+
if err := a.logVMsPriceUpdate(req, a.config.PricesPerMonth); err != nil {
173+
log.Error().Err(err).Send()
174+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
175+
}
176+
172177
return ResponseMsg{
173178
Message: "New prices are set",
174179
Data: nil,
@@ -314,6 +319,11 @@ func (a *App) DeleteAllDeploymentsHandler(req *http.Request) (interface{}, Respo
314319
}
315320
}
316321

322+
if err := a.logAllDeploymentsDelete(req); err != nil {
323+
log.Error().Err(err).Send()
324+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
325+
}
326+
317327
return ResponseMsg{
318328
Message: "Deployments are deleted successfully",
319329
}, Ok()
@@ -416,6 +426,11 @@ func (a *App) UpdateMaintenanceHandler(req *http.Request) (interface{}, Response
416426
return nil, InternalServerError(errors.New(internalServerErrorMsg))
417427
}
418428

429+
if err := a.logMaintenanceUpdate(req, input.ON); err != nil {
430+
log.Error().Err(err).Send()
431+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
432+
}
433+
419434
return ResponseMsg{
420435
Message: "Maintenance is updated successfully",
421436
Data: nil,
@@ -477,6 +492,11 @@ func (a *App) SetAdminHandler(req *http.Request) (interface{}, Response) {
477492
return nil, InternalServerError(errors.New(internalServerErrorMsg))
478493
}
479494

495+
if err := a.logAdminSet(req, user.ID.String(), input.Admin); err != nil {
496+
log.Error().Err(err).Send()
497+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
498+
}
499+
480500
return ResponseMsg{
481501
Message: "User is updated successfully",
482502
}, Ok()
@@ -537,6 +557,11 @@ func (a *App) CreateNewAnnouncementHandler(req *http.Request) (interface{}, Resp
537557
}
538558
}
539559

560+
if err := a.logAnnouncementCreate(req, adminAnnouncement.Subject); err != nil {
561+
log.Error().Err(err).Send()
562+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
563+
}
564+
540565
return ResponseMsg{
541566
Message: "new announcement is sent successfully",
542567
}, Created()
@@ -598,6 +623,11 @@ func (a *App) SendEmailHandler(req *http.Request) (interface{}, Response) {
598623
return nil, InternalServerError(errors.New(internalServerErrorMsg))
599624
}
600625

626+
if err := a.logEmailSent(req, user.ID.String(), emailUser.Subject); err != nil {
627+
log.Error().Err(err).Send()
628+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
629+
}
630+
601631
return ResponseMsg{
602632
Message: "new email is sent successfully",
603633
}, Created()
@@ -636,6 +666,11 @@ func (a *App) UpdateNextLaunchHandler(req *http.Request) (interface{}, Response)
636666
return nil, InternalServerError(errors.New(internalServerErrorMsg))
637667
}
638668

669+
if err := a.logNextLaunchUpdate(req, input.Launched); err != nil {
670+
log.Error().Err(err).Send()
671+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
672+
}
673+
639674
return ResponseMsg{
640675
Message: "Next Launch is updated successfully",
641676
Data: nil,

server/app/app.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ func (a *App) registerHandlers() {
119119
invoiceRouter := authRouter.PathPrefix("/invoice").Subrouter()
120120
cardRouter := userRouter.PathPrefix("/card").Subrouter()
121121
logRouter := userRouter.PathPrefix("/log").Subrouter()
122+
eventRouter := userRouter.PathPrefix("/event").Subrouter()
122123
notificationRouter := authRouter.PathPrefix("/notification").Subrouter()
123124
vmRouter := authRouter.PathPrefix("/vm").Subrouter()
124125
k8sRouter := authRouter.PathPrefix("/k8s").Subrouter()
@@ -159,6 +160,8 @@ func (a *App) registerHandlers() {
159160

160161
logRouter.HandleFunc("", WrapFunc(a.ListLogsHandler)).Methods("GET", "OPTIONS")
161162

163+
eventRouter.HandleFunc("", WrapFunc(a.ListEventsHandler)).Methods("GET", "OPTIONS")
164+
162165
invoiceRouter.HandleFunc("", WrapFunc(a.ListInvoicesHandler)).Methods("GET", "OPTIONS")
163166
invoiceRouter.HandleFunc("/{id}", WrapFunc(a.GetInvoiceHandler)).Methods("GET", "OPTIONS")
164167
invoiceRouter.HandleFunc("/download/{id}", WrapFunc(a.DownloadInvoiceHandler)).Methods("GET", "OPTIONS")

server/app/audit_handler.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,37 @@ func (a *App) ListLogsHandler(req *http.Request) (interface{}, Response) {
4242
Data: logs,
4343
}, Ok()
4444
}
45+
46+
// Example endpoint: List user's events
47+
// @Summary List user's events
48+
// @Description List user's events
49+
// @Tags Audit
50+
// @Accept json
51+
// @Produce json
52+
// @Security BearerAuth
53+
// @Success 200 {object} []models.AuditEvent
54+
// @Failure 400 {object} Response
55+
// @Failure 401 {object} Response
56+
// @Failure 404 {object} Response
57+
// @Failure 500 {object} Response
58+
// @Router /user/event [get]
59+
func (a *App) ListEventsHandler(req *http.Request) (interface{}, Response) {
60+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
61+
62+
events, err := a.db.GetUserEvents(userID)
63+
if err == gorm.ErrRecordNotFound || len(events) == 0 {
64+
return ResponseMsg{
65+
Message: "no events found",
66+
Data: events,
67+
}, Ok()
68+
}
69+
if err != nil {
70+
log.Error().Err(err).Send()
71+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
72+
}
73+
74+
return ResponseMsg{
75+
Message: "Events are found",
76+
Data: events,
77+
}, Ok()
78+
}

server/app/events.go

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package app
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"time"
7+
8+
"github.com/codescalers/cloud4students/internal"
9+
"github.com/codescalers/cloud4students/middlewares"
10+
"github.com/codescalers/cloud4students/models"
11+
"github.com/pkg/errors"
12+
)
13+
14+
func (a *App) logInvoicePayment(userID, currency string, invoiceTotal float64, paymentDetails models.PaymentDetails) error {
15+
event := models.AuditEvent{
16+
UserID: userID,
17+
Action: "pay_invoice",
18+
Role: "User",
19+
Timestamp: time.Now(),
20+
Metadata: fmt.Sprintf(
21+
"Invoice %v with value: %v %v is paid using: {balance: %v, vouchers: %v, card:%v}",
22+
paymentDetails.InvoiceID, invoiceTotal, currency,
23+
paymentDetails.Balance, paymentDetails.VoucherBalance, paymentDetails.Card,
24+
),
25+
}
26+
27+
if err := a.db.CreateAuditEvent(&event); err != nil {
28+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
29+
}
30+
31+
return nil
32+
}
33+
34+
func (a *App) logInvoicePDFUpdate(req *http.Request, invoiceID int) error {
35+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
36+
37+
event := models.AuditEvent{
38+
UserID: userID,
39+
Action: "update_invoice",
40+
Role: "User",
41+
Timestamp: time.Now(),
42+
Metadata: fmt.Sprintf("Invoice %v pdf data is updated", invoiceID),
43+
}
44+
45+
if err := a.db.CreateAuditEvent(&event); err != nil {
46+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
47+
}
48+
49+
return nil
50+
}
51+
52+
func (a *App) logInvoiceDownload(req *http.Request, invoiceID int) error {
53+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
54+
55+
event := models.AuditEvent{
56+
UserID: userID,
57+
Action: "download_invoice",
58+
Role: "User",
59+
Timestamp: time.Now(),
60+
Metadata: fmt.Sprintf("Invoice %v is downloaded", invoiceID),
61+
}
62+
63+
if err := a.db.CreateAuditEvent(&event); err != nil {
64+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
65+
}
66+
67+
return nil
68+
}
69+
70+
func (a *App) logEmailSent(req *http.Request, targetUserID, subject string) error {
71+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
72+
73+
event := models.AuditEvent{
74+
UserID: userID,
75+
Action: "send_email",
76+
Role: "Admin",
77+
Timestamp: time.Now(),
78+
Metadata: fmt.Sprintf("An email is sent to: %v, with subject: %v", targetUserID, subject),
79+
}
80+
81+
if err := a.db.CreateAuditEvent(&event); err != nil {
82+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
83+
}
84+
85+
return nil
86+
}
87+
88+
func (a *App) logAnnouncementCreate(req *http.Request, subject string) error {
89+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
90+
91+
event := models.AuditEvent{
92+
UserID: userID,
93+
Action: "create_announcement",
94+
Role: "Admin",
95+
Timestamp: time.Now(),
96+
Metadata: fmt.Sprintf("An announcement is created with subject: %v", subject),
97+
}
98+
99+
if err := a.db.CreateAuditEvent(&event); err != nil {
100+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
101+
}
102+
103+
return nil
104+
}
105+
106+
func (a *App) logAdminSet(req *http.Request, adminID string, admin bool) error {
107+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
108+
109+
metaData := fmt.Sprintf("A new admin %v is added", adminID)
110+
if !admin {
111+
metaData = fmt.Sprintf("An admin %v is removed", adminID)
112+
}
113+
114+
event := models.AuditEvent{
115+
UserID: userID,
116+
Action: "set_admin",
117+
Role: "Admin",
118+
Timestamp: time.Now(),
119+
Metadata: metaData,
120+
}
121+
122+
if err := a.db.CreateAuditEvent(&event); err != nil {
123+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
124+
}
125+
126+
return nil
127+
}
128+
129+
func (a *App) logNextLaunchUpdate(req *http.Request, on bool) error {
130+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
131+
132+
event := models.AuditEvent{
133+
UserID: userID,
134+
Action: "update_next_launch",
135+
Role: "Admin",
136+
Timestamp: time.Now(),
137+
Metadata: fmt.Sprintf("Next launch value is updated to: %v", on),
138+
}
139+
140+
if err := a.db.CreateAuditEvent(&event); err != nil {
141+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
142+
}
143+
144+
return nil
145+
}
146+
147+
func (a *App) logMaintenanceUpdate(req *http.Request, on bool) error {
148+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
149+
150+
event := models.AuditEvent{
151+
UserID: userID,
152+
Action: "update_maintenance",
153+
Role: "Admin",
154+
Timestamp: time.Now(),
155+
Metadata: fmt.Sprintf("Maintenance value is updated to: %v", on),
156+
}
157+
158+
if err := a.db.CreateAuditEvent(&event); err != nil {
159+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
160+
}
161+
162+
return nil
163+
}
164+
165+
func (a *App) logAllDeploymentsDelete(req *http.Request) error {
166+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
167+
168+
event := models.AuditEvent{
169+
UserID: userID,
170+
Action: "delete_all_deployments",
171+
Role: "Admin",
172+
Timestamp: time.Now(),
173+
Metadata: "All virtual machines are deleted",
174+
}
175+
176+
if err := a.db.CreateAuditEvent(&event); err != nil {
177+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
178+
}
179+
180+
return nil
181+
}
182+
183+
func (a *App) logVMsPriceUpdate(req *http.Request, prices internal.Prices) error {
184+
userID := req.Context().Value(middlewares.UserIDKey("UserID")).(string)
185+
186+
event := models.AuditEvent{
187+
UserID: userID,
188+
Action: "update_vms_prices",
189+
Role: "Admin",
190+
Timestamp: time.Now(),
191+
Metadata: fmt.Sprintf(
192+
"Virtual machines prices are updated {small: %v, medium: %v, large: %v, public IPs: %v}",
193+
prices.SmallVM, prices.MediumVM, prices.LargeVM, prices.PublicIP,
194+
),
195+
}
196+
197+
if err := a.db.CreateAuditEvent(&event); err != nil {
198+
return errors.Wrapf(err, "Failed to log audit event: %s", event.Action)
199+
}
200+
201+
return nil
202+
}

server/app/invoice_handler.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,22 @@ func (a *App) DownloadInvoiceHandler(req *http.Request) (interface{}, Response)
174174
log.Error().Err(err).Send()
175175
return nil, InternalServerError(errors.New(internalServerErrorMsg))
176176
}
177+
178+
if err := a.logInvoicePDFUpdate(req, invoice.ID); err != nil {
179+
log.Error().Err(err).Send()
180+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
181+
}
177182
}
178183

179184
if userID != invoice.UserID {
180185
return nil, NotFound(errors.New("invoice is not found"))
181186
}
182187

188+
if err := a.logInvoiceDownload(req, invoice.ID); err != nil {
189+
log.Error().Err(err).Send()
190+
return nil, InternalServerError(errors.New(internalServerErrorMsg))
191+
}
192+
183193
return invoice.FileData, Ok().
184194
WithHeader("Content-Disposition", fmt.Sprintf("attachment; filename=%s", fmt.Sprintf("invoice-%s-%d.pdf", invoice.UserID, invoice.ID))).
185195
WithHeader("Content-Type", "application/pdf")
@@ -689,6 +699,11 @@ func (a *App) payInvoice(user *models.User, cardPaymentID string, method method,
689699
return InternalServerError(errors.New(internalServerErrorMsg))
690700
}
691701

702+
if err := a.logInvoicePayment(user.ID.String(), a.config.Currency, invoiceTotal, paymentDetails); err != nil {
703+
log.Error().Err(err).Send()
704+
return InternalServerError(errors.New(internalServerErrorMsg))
705+
}
706+
692707
return nil
693708
}
694709

0 commit comments

Comments
 (0)