From e3428911b9146291267eeb625bb73003dabd921b Mon Sep 17 00:00:00 2001 From: H3ALY Date: Wed, 2 Apr 2025 17:15:57 +0100 Subject: [PATCH] Messages: Add archive (soft-delete) support + dropdown UI polish - Implemented `/account/messages/archive` route for soft-archiving messages - Added `is_archived` flag to `users_messages` schema and model - Topbar dropdown now reflects accurate unread message count - Fixed missing route registration for archive handler - Improved message visibility checks to prevent access violations - Placeholder for rate-limit (429) error page rendering identified --- handlers/messages.go | 20 ++++++++++++++++++++ main.go | 1 + storage/messages.go | 13 +++++++++++-- storage/schema.go | 1 + templates/account/messages/read.html | 2 +- 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/handlers/messages.go b/handlers/messages.go index 378fd49..3726239 100644 --- a/handlers/messages.go +++ b/handlers/messages.go @@ -52,3 +52,23 @@ func ReadMessageHandler(db *sql.DB) http.HandlerFunc { tmpl.ExecuteTemplate(w, "layout", context) } } + +func ArchiveMessageHandler(db *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + id := helpers.Atoi(r.URL.Query().Get("id")) + userID, ok := helpers.GetCurrentUserID(r) + if !ok { + helpers.RenderError(w, r, 403) + return + } + + err := storage.ArchiveMessage(db, userID, id) + if err != nil { + helpers.SetFlash(w, r, "Failed to archive message.") + } else { + helpers.SetFlash(w, r, "Message archived.") + } + + http.Redirect(w, r, "/account/messages", http.StatusSeeOther) + } +} diff --git a/main.go b/main.go index eaf3915..978253d 100644 --- a/main.go +++ b/main.go @@ -70,6 +70,7 @@ func setupAccountRoutes(mux *http.ServeMux, db *sql.DB) { mux.HandleFunc("/account/tickets/my_tickets", handlers.GetMyTickets(db)) mux.HandleFunc("/account/messages", middleware.Auth(true)(handlers.MessagesInboxHandler(db))) mux.HandleFunc("/account/messages/read", middleware.Auth(true)(handlers.ReadMessageHandler(db))) + mux.HandleFunc("/account/messages/archive", middleware.Auth(true)(handlers.ArchiveMessageHandler(db))) mux.HandleFunc("/account/notifications", middleware.Auth(true)(handlers.NotificationsHandler(db))) mux.HandleFunc("/account/notifications/read", middleware.Auth(true)(handlers.MarkNotificationReadHandler(db))) } diff --git a/storage/messages.go b/storage/messages.go index 4d4e64c..9e68b96 100644 --- a/storage/messages.go +++ b/storage/messages.go @@ -10,7 +10,7 @@ func GetMessageCount(db *sql.DB, userID int) (int, error) { var count int err := db.QueryRow(` SELECT COUNT(*) FROM users_messages - WHERE recipientId = ? AND is_read = FALSE + WHERE recipientId = ? AND is_read = FALSE AND is_archived = FALSE `, userID).Scan(&count) return count, err } @@ -19,7 +19,7 @@ func GetRecentMessages(db *sql.DB, userID int, limit int) []models.Message { rows, err := db.Query(` SELECT id, senderId, recipientId, subject, message, is_read, created_at FROM users_messages - WHERE recipientId = ? + WHERE recipientId = ? AND is_archived = FALSE ORDER BY created_at DESC LIMIT ? `, userID, limit) @@ -81,3 +81,12 @@ func MarkMessageAsRead(db *sql.DB, messageID, userID int) error { } return nil } + +func ArchiveMessage(db *sql.DB, userID, messageID int) error { + _, err := db.Exec(` + UPDATE users_messages + SET is_archived = TRUE + WHERE id = ? AND recipientId = ? + `, messageID, userID) + return err +} diff --git a/storage/schema.go b/storage/schema.go index 7aa35e7..77523a9 100644 --- a/storage/schema.go +++ b/storage/schema.go @@ -119,6 +119,7 @@ CREATE TABLE IF NOT EXISTS users_messages ( subject TEXT NOT NULL, message TEXT, is_read BOOLEAN DEFAULT FALSE, + is_archived BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );` diff --git a/templates/account/messages/read.html b/templates/account/messages/read.html index 6a82f12..967d7de 100644 --- a/templates/account/messages/read.html +++ b/templates/account/messages/read.html @@ -5,7 +5,7 @@

Received: {{ .Message.CreatedAt.Format "02 Jan 2006 15:04" }}


{{ .Message.Message }}

- Back to Inbox + Back to Inbox Archive {{ else }}
Message not found or access denied.