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
This commit is contained in:
@@ -52,3 +52,23 @@ func ReadMessageHandler(db *sql.DB) http.HandlerFunc {
|
|||||||
tmpl.ExecuteTemplate(w, "layout", context)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
1
main.go
1
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/tickets/my_tickets", handlers.GetMyTickets(db))
|
||||||
mux.HandleFunc("/account/messages", middleware.Auth(true)(handlers.MessagesInboxHandler(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/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", middleware.Auth(true)(handlers.NotificationsHandler(db)))
|
||||||
mux.HandleFunc("/account/notifications/read", middleware.Auth(true)(handlers.MarkNotificationReadHandler(db)))
|
mux.HandleFunc("/account/notifications/read", middleware.Auth(true)(handlers.MarkNotificationReadHandler(db)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ func GetMessageCount(db *sql.DB, userID int) (int, error) {
|
|||||||
var count int
|
var count int
|
||||||
err := db.QueryRow(`
|
err := db.QueryRow(`
|
||||||
SELECT COUNT(*) FROM users_messages
|
SELECT COUNT(*) FROM users_messages
|
||||||
WHERE recipientId = ? AND is_read = FALSE
|
WHERE recipientId = ? AND is_read = FALSE AND is_archived = FALSE
|
||||||
`, userID).Scan(&count)
|
`, userID).Scan(&count)
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ func GetRecentMessages(db *sql.DB, userID int, limit int) []models.Message {
|
|||||||
rows, err := db.Query(`
|
rows, err := db.Query(`
|
||||||
SELECT id, senderId, recipientId, subject, message, is_read, created_at
|
SELECT id, senderId, recipientId, subject, message, is_read, created_at
|
||||||
FROM users_messages
|
FROM users_messages
|
||||||
WHERE recipientId = ?
|
WHERE recipientId = ? AND is_archived = FALSE
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
`, userID, limit)
|
`, userID, limit)
|
||||||
@@ -81,3 +81,12 @@ func MarkMessageAsRead(db *sql.DB, messageID, userID int) error {
|
|||||||
}
|
}
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ CREATE TABLE IF NOT EXISTS users_messages (
|
|||||||
subject TEXT NOT NULL,
|
subject TEXT NOT NULL,
|
||||||
message TEXT,
|
message TEXT,
|
||||||
is_read BOOLEAN DEFAULT FALSE,
|
is_read BOOLEAN DEFAULT FALSE,
|
||||||
|
is_archived BOOLEAN DEFAULT FALSE,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);`
|
);`
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<p class="text-muted">Received: {{ .Message.CreatedAt.Format "02 Jan 2006 15:04" }}</p>
|
<p class="text-muted">Received: {{ .Message.CreatedAt.Format "02 Jan 2006 15:04" }}</p>
|
||||||
<hr>
|
<hr>
|
||||||
<p>{{ .Message.Message }}</p>
|
<p>{{ .Message.Message }}</p>
|
||||||
<a href="/account/messages" class="btn btn-secondary mt-4">Back to Inbox</a>
|
<a href="/account/messages" class="btn btn-secondary mt-4">Back to Inbox</a> <a href="/account/messages/archive?id={{ .Message.ID }}" class="btn btn-outline-danger mt-3">Archive</a>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<div class="alert alert-danger text-center">
|
<div class="alert alert-danger text-center">
|
||||||
Message not found or access denied.
|
Message not found or access denied.
|
||||||
|
|||||||
Reference in New Issue
Block a user