Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 49 additions & 23 deletions backend/controllers/get_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,69 @@ import (
"encoding/json"
"net/http"
"strconv"

"github.com/gorilla/sessions"
)

// SyncLogsHandler godoc
// @Summary Get sync logs
// @Description Fetch the latest sync operation logs
// @Description Fetch the latest sync operation logs for the authenticated user
// @Tags Logs
// @Accept json
// @Produce json
// @Param last query int false "Number of latest log entries to return (default: 100)"
// @Param last query int false "Number of latest log entries to return (default: 20, max: 20)"
// @Success 200 {array} models.LogEntry "List of log entries"
// @Failure 400 {string} string "Invalid last parameter"
// @Failure 401 {string} string "Authentication required"
// @Router /sync/logs [get]
func SyncLogsHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
return
}
func SyncLogsHandler(store *sessions.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
return
}

// Get the 'last' query parameter, default to 100
lastParam := r.URL.Query().Get("last")
last := 100
if lastParam != "" {
parsedLast, err := strconv.Atoi(lastParam)
if err != nil || parsedLast < 0 {
http.Error(w, "Invalid 'last' parameter", http.StatusBadRequest)
// Validate session - user must be authenticated to view logs
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, "Authentication required", http.StatusUnauthorized)
return
}
last = parsedLast
}

// Get the log store and retrieve logs
logStore := models.GetLogStore()
logs := logStore.GetLogs(last)
userInfo, ok := session.Values["user"].(map[string]interface{})
if !ok || userInfo == nil {
http.Error(w, "Authentication required", http.StatusUnauthorized)
return
}

// Get user's UUID to filter logs
userUUID, _ := userInfo["uuid"].(string)

// Get the 'last' query parameter, default to 20, max 20
const maxLogs = 20
lastParam := r.URL.Query().Get("last")
last := maxLogs
if lastParam != "" {
parsedLast, err := strconv.Atoi(lastParam)
if err != nil || parsedLast < 0 {
http.Error(w, "Invalid 'last' parameter", http.StatusBadRequest)
return
}
last = parsedLast
}
// Enforce hard cap to prevent resource exhaustion
if last > maxLogs {
last = maxLogs
}

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(logs); err != nil {
http.Error(w, "Failed to encode logs", http.StatusInternalServerError)
return
// Get the log store and retrieve logs filtered by user UUID
logStore := models.GetLogStore()
logs := logStore.GetLogsByUser(last, userUUID)

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(logs); err != nil {
http.Error(w, "Failed to encode logs", http.StatusInternalServerError)
return
}
}
}
2 changes: 1 addition & 1 deletion backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func main() {
mux.Handle("/modify-task", rateLimitedHandler(http.HandlerFunc(controllers.ModifyTaskHandler)))
mux.Handle("/complete-task", rateLimitedHandler(http.HandlerFunc(controllers.CompleteTaskHandler)))
mux.Handle("/delete-task", rateLimitedHandler(http.HandlerFunc(controllers.DeleteTaskHandler)))
mux.Handle("/sync/logs", rateLimitedHandler(http.HandlerFunc(controllers.SyncLogsHandler)))
mux.Handle("/sync/logs", rateLimitedHandler(controllers.SyncLogsHandler(store)))
mux.Handle("/complete-tasks", rateLimitedHandler(http.HandlerFunc(controllers.BulkCompleteTaskHandler)))
mux.Handle("/delete-tasks", rateLimitedHandler(http.HandlerFunc(controllers.BulkDeleteTaskHandler)))

Expand Down
27 changes: 27 additions & 0 deletions backend/models/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,30 @@ func (ls *LogStore) GetLogs(last int) []LogEntry {
}
return result
}

// GetLogsByUser returns the last N log entries for a specific user (filtered by SyncID/UUID)
func (ls *LogStore) GetLogsByUser(last int, userUUID string) []LogEntry {
ls.mu.RLock()
defer ls.mu.RUnlock()

// Filter entries by user UUID
var userEntries []LogEntry
for _, entry := range ls.entries {
if entry.SyncID == userUUID {
userEntries = append(userEntries, entry)
}
}

// Determine how many to return
count := last
if count <= 0 || count > len(userEntries) {
count = len(userEntries)
}

// Return last N entries in reverse order (newest first)
result := make([]LogEntry, count)
for i := 0; i < count; i++ {
result[i] = userEntries[len(userEntries)-1-i]
}
return result
}
Loading