Add restore functionality for archived messages
- Added `RestoreMessageHandler` and route at `/account/messages/restore` - Updated `users_messages` table to support `archived_at` reset - Added restore button to archived messages template - Ensures archived messages can be moved back into inbox
This commit is contained in:
@@ -11,13 +11,37 @@ import (
|
||||
|
||||
func MessagesInboxHandler(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
userID, ok := helpers.GetCurrentUserID(r)
|
||||
if !ok {
|
||||
helpers.RenderError(w, r, 403)
|
||||
return
|
||||
}
|
||||
|
||||
page := helpers.Atoi(r.URL.Query().Get("page"))
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
perPage := 10
|
||||
|
||||
totalCount := storage.GetInboxMessageCount(db, userID)
|
||||
totalPages := (totalCount + perPage - 1) / perPage
|
||||
if totalPages == 0 {
|
||||
totalPages = 1
|
||||
}
|
||||
|
||||
messages := storage.GetInboxMessages(db, userID, page, perPage)
|
||||
|
||||
data := BuildTemplateData(db, w, r)
|
||||
context := helpers.TemplateContext(w, r, data)
|
||||
|
||||
context["Messages"] = messages
|
||||
context["CurrentPage"] = page
|
||||
context["TotalPages"] = totalPages
|
||||
context["PageRange"] = helpers.PageRange(page, totalPages)
|
||||
|
||||
tmpl := helpers.LoadTemplateFiles("messages.html", "templates/account/messages/index.html")
|
||||
|
||||
err := tmpl.ExecuteTemplate(w, "layout", context)
|
||||
if err != nil {
|
||||
if err := tmpl.ExecuteTemplate(w, "layout", context); err != nil {
|
||||
helpers.RenderError(w, r, 500)
|
||||
}
|
||||
}
|
||||
@@ -136,3 +160,23 @@ func SendMessageHandler(db *sql.DB) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RestoreMessageHandler(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.RestoreMessage(db, userID, id)
|
||||
if err != nil {
|
||||
helpers.SetFlash(w, r, "Failed to restore message.")
|
||||
} else {
|
||||
helpers.SetFlash(w, r, "Message restored.")
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/account/messages/archived", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,3 +16,11 @@ func GetTotalPages(db *sql.DB, tableName, whereClause string, args []interface{}
|
||||
}
|
||||
return totalPages, totalCount
|
||||
}
|
||||
|
||||
func MakePageRange(current, total int) []int {
|
||||
var pages []int
|
||||
for i := 1; i <= total; i++ {
|
||||
pages = append(pages, i)
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ func TemplateFuncs() template.FuncMap {
|
||||
},
|
||||
"mul": func(a, b int) int { return a * b },
|
||||
"add": func(a, b int) int { return a + b },
|
||||
"sub": func(a, b int) int { return a - b },
|
||||
"min": func(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
@@ -66,6 +67,7 @@ func TemplateFuncs() template.FuncMap {
|
||||
}
|
||||
return s[:max] + "..."
|
||||
},
|
||||
"PageRange": PageRange,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,3 +117,11 @@ func rangeClass(n int) string {
|
||||
return "50-plus"
|
||||
}
|
||||
}
|
||||
|
||||
func PageRange(current, total int) []int {
|
||||
var pages []int
|
||||
for i := 1; i <= total; i++ {
|
||||
pages = append(pages, i)
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
1
main.go
1
main.go
@@ -72,6 +72,7 @@ func setupAccountRoutes(mux *http.ServeMux, db *sql.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/messages/archived", middleware.Auth(true)(handlers.ArchivedMessagesHandler(db)))
|
||||
mux.HandleFunc("/account/messages/restore", middleware.Auth(true)(handlers.RestoreMessageHandler(db)))
|
||||
mux.HandleFunc("/account/messages/send", middleware.Auth(true)(handlers.SendMessageHandler(db)))
|
||||
mux.HandleFunc("/account/notifications", middleware.Auth(true)(handlers.NotificationsHandler(db)))
|
||||
mux.HandleFunc("/account/notifications/read", middleware.Auth(true)(handlers.MarkNotificationReadHandler(db)))
|
||||
|
||||
@@ -127,3 +127,52 @@ func GetArchivedMessages(db *sql.DB, userID int, page, perPage int) []models.Mes
|
||||
}
|
||||
return messages
|
||||
}
|
||||
|
||||
func GetInboxMessages(db *sql.DB, userID int, page, perPage int) []models.Message {
|
||||
offset := (page - 1) * perPage
|
||||
rows, err := db.Query(`
|
||||
SELECT id, senderId, recipientId, subject, message, is_read, created_at
|
||||
FROM users_messages
|
||||
WHERE recipientId = ? AND is_archived = FALSE
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`, userID, perPage, offset)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var messages []models.Message
|
||||
for rows.Next() {
|
||||
var m models.Message
|
||||
err := rows.Scan(
|
||||
&m.ID, &m.SenderId, &m.RecipientId,
|
||||
&m.Subject, &m.Message, &m.IsRead, &m.CreatedAt,
|
||||
)
|
||||
if err == nil {
|
||||
messages = append(messages, m)
|
||||
}
|
||||
}
|
||||
return messages
|
||||
}
|
||||
|
||||
func GetInboxMessageCount(db *sql.DB, userID int) int {
|
||||
var count int
|
||||
err := db.QueryRow(`
|
||||
SELECT COUNT(*) FROM users_messages
|
||||
WHERE recipientId = ? AND is_archived = FALSE
|
||||
`, userID).Scan(&count)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func RestoreMessage(db *sql.DB, userID, messageID int) error {
|
||||
_, err := db.Exec(`
|
||||
UPDATE users_messages
|
||||
SET is_archived = FALSE, archived_at = NULL
|
||||
WHERE id = ? AND recipientId = ?
|
||||
`, messageID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" action="/account/messages/restore" class="m-0">
|
||||
{{ $.CSRFField }}
|
||||
<input type="hidden" name="id" value="{{ .ID }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-success">Restore</button>
|
||||
</form>
|
||||
{{ end }}
|
||||
|
||||
<!-- Pagination Controls -->
|
||||
@@ -10,7 +10,7 @@
|
||||
<br>
|
||||
<small class="text-muted">{{ .CreatedAt.Format "02 Jan 2006 15:04" }}</small>
|
||||
</div>
|
||||
<form method="POST" action="/account/messages/archive" class="m-0">
|
||||
<form method="POST" action="/account/messages/archive?id={{ .ID }}" class="m-0">
|
||||
{{ $.CSRFField }}
|
||||
<input type="hidden" name="id" value="{{ .ID }}">
|
||||
<button type="submit" class="btn btn-sm btn-outline-secondary">Archive</button>
|
||||
@@ -18,34 +18,37 @@
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
<!-- Pagination -->
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
{{ if gt .CurrentPage 1 }}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ sub .CurrentPage 1 }}">Previous</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
|
||||
<!-- Pagination -->
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
{{ if gt .CurrentPage 1 }}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ sub .CurrentPage 1 }}">Previous</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
{{ range $i := .PageRange }}
|
||||
<li class="page-item {{ if eq $i $.CurrentPage }}active{{ end }}">
|
||||
<a class="page-link" href="?page={{ $i }}">{{ $i }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
|
||||
{{ range $i := .PageRange }}
|
||||
<li class="page-item {{ if eq $i $.CurrentPage }}active{{ end }}">
|
||||
<a class="page-link" href="?page={{ $i }}">{{ $i }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
{{ if lt .CurrentPage .TotalPages }}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ add .CurrentPage 1 }}">Next</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{{ if lt .CurrentPage .TotalPages }}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ add .CurrentPage 1 }}">Next</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{{ else }}
|
||||
<div class="alert alert-info">No messages found.</div>
|
||||
{{ end }}
|
||||
|
||||
<a href="/account/messages/send" class="btn btn-primary mt-3">Compose Message</a>
|
||||
<div class="mt-3">
|
||||
<a href="/account/messages/send" class="btn btn-primary">Compose Message</a>
|
||||
<a href="/account/messages/archived" class="btn btn-outline-secondary ms-2">View Archived</a>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
{{ if not .Notifications }}
|
||||
<li class="text-center text-muted py-2">No notifications</li>
|
||||
{{ end }}
|
||||
@@ -103,6 +103,7 @@
|
||||
{{ else }}
|
||||
<li class="text-center text-muted py-2">No messages</li>
|
||||
{{ end }}
|
||||
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li class="text-center"><a href="/account/messages" class="dropdown-item">View all messages</a></li>
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user