Fix archiving and unarchiving functionality.

This commit is contained in:
2025-11-01 22:37:47 +00:00
parent 9dc01f925a
commit 61ad033520
8 changed files with 88 additions and 32 deletions

View File

@@ -21,6 +21,6 @@ type MessageService interface {
Archive(userID, id int64) error
//Restore()
//ToDo: implement
//Unarchive(userID, id int64) error
Unarchive(userID, id int64) error
//MarkRead(userID, id int64) error
}

View File

@@ -6,12 +6,14 @@ package accountMessageHandler
import (
"bytes"
"database/sql"
"errors"
"net/http"
"strconv"
templateHandlers "synlotto-website/internal/handlers/template"
templateHelpers "synlotto-website/internal/helpers/template"
errors "synlotto-website/internal/http/error"
httpErrors "synlotto-website/internal/http/error"
"synlotto-website/internal/logging"
"synlotto-website/internal/platform/bootstrap"
@@ -104,7 +106,7 @@ func (h *AccountMessageHandlers) ArchivePost(c *gin.Context) {
idStr := c.PostForm("id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil || id <= 0 {
errors.RenderStatus(c, sm, http.StatusBadRequest)
httpErrors.RenderStatus(c, sm, http.StatusBadRequest)
return
}
@@ -119,24 +121,32 @@ func (h *AccountMessageHandlers) ArchivePost(c *gin.Context) {
c.Redirect(http.StatusSeeOther, "/account/messages")
}
// POST /account/messages/restore
func (h *AccountMessageHandlers) RestorePost(c *gin.Context) {
// POST /account/messages/archived
func (h *AccountMessageHandlers) RestoreArchived(c *gin.Context) {
app := c.MustGet("app").(*bootstrap.App)
sm := app.SessionManager
//userID := mustUserID(c)
userID := mustUserID(c)
idStr := c.PostForm("id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil || id <= 0 {
errors.RenderStatus(c, sm, http.StatusBadRequest)
sm.Put(c.Request.Context(), "flash", "Invalid message id.")
c.Redirect(http.StatusSeeOther, "/account/messages/archive")
return
}
//
// if err := h.Svc.Unarchive(userID, id); err != nil {
// logging.Info("❌ Restore error: %v", err)
// sm.Put(c.Request.Context(), "flash", "Could not restore message.")
// } else {
// sm.Put(c.Request.Context(), "flash", "Message restored.")
// }
c.Redirect(http.StatusSeeOther, "/account/messages/archived")
if err := h.Svc.Unarchive(userID, id); err != nil {
logging.Info("❌ restore/unarchive error: %v", err)
// If no rows affected, show friendly flash; otherwise generic message.
if errors.Is(err, sql.ErrNoRows) {
sm.Put(c.Request.Context(), "flash", "Message not found or not permitted.")
} else {
sm.Put(c.Request.Context(), "flash", "Could not restore message.")
}
c.Redirect(http.StatusSeeOther, "/account/messages/archive")
return
}
sm.Put(c.Request.Context(), "flash", "Message restored.")
c.Redirect(http.StatusSeeOther, "/account/messages/archive")
}

View File

@@ -177,6 +177,6 @@ func RestoreMessageHandler(app *bootstrap.App) http.HandlerFunc {
templateHelpers.SetFlash(r, "Message restored.")
}
http.Redirect(w, r, "/account/messages/archived", http.StatusSeeOther)
http.Redirect(w, r, "/account/messages/archive", http.StatusSeeOther)
}
}

View File

@@ -71,7 +71,7 @@ func RegisterAccountRoutes(app *bootstrap.App) {
messages.POST("/send", msgH.SendPost)
messages.GET("/archive", msgH.ArchivedList) // view archived messages
messages.POST("/archive", msgH.ArchivePost) // archive a message
messages.POST("/restore", msgH.RestorePost)
messages.POST("/restore", msgH.RestoreArchived)
}
// Notifications (auth-required)

View File

@@ -1,6 +1,8 @@
package models
import "time"
import (
"time"
)
type Message struct {
ID int

View File

@@ -76,7 +76,8 @@ func (s *Service) ListArchived(userID int64) ([]domain.Message, error) {
defer cancel()
q := `
SELECT id, senderId, recipientId, subject, body, is_read, is_archived, created_at
SELECT id, senderId, recipientId, subject, body,
is_read, is_archived, created_at, archived_at
FROM user_messages
WHERE recipientId = ? AND is_archived = TRUE
ORDER BY created_at DESC`
@@ -91,11 +92,32 @@ func (s *Service) ListArchived(userID int64) ([]domain.Message, error) {
var out []domain.Message
for rows.Next() {
var m domain.Message
if err := rows.Scan(&m.ID, &m.SenderId, &m.RecipientId, &m.Subject, &m.Body, &m.IsRead, &m.IsArchived, &m.CreatedAt); err != nil {
var archived sql.NullTime
if err := rows.Scan(
&m.ID,
&m.SenderId,
&m.RecipientId,
&m.Subject,
&m.Body,
&m.IsRead,
&m.IsArchived,
&m.CreatedAt,
&archived,
); err != nil {
return nil, err
}
if archived.Valid {
t := archived.Time
m.ArchivedAt = &t
} else {
m.ArchivedAt = nil
}
out = append(out, m)
}
return out, rows.Err()
}
@@ -233,3 +255,25 @@ func intToStr(n int) string {
}
return string(b[i:])
}
func (s *Service) Unarchive(userID, id int64) error {
ctx, cancel := context.WithTimeout(context.Background(), s.Timeout)
defer cancel()
q := `
UPDATE user_messages
SET is_archived = 0, archived_at = NULL
WHERE id = ? AND recipientId = ?
`
q = s.bind(q)
res, err := s.DB.ExecContext(ctx, q, id, userID)
if err != nil {
return err
}
n, _ := res.RowsAffected()
if n == 0 {
return sql.ErrNoRows
}
return nil
}

View File

@@ -11,7 +11,7 @@
<p class="card-text">
<small class="text-muted">
Archived:
{{ if .ArchivedAt.Valid }}
{{ with .ArchivedAt }}
{{ .Format "02 Jan 2006 15:04" }}
{{ else }}
@@ -30,14 +30,14 @@
<!-- Pagination Controls (keep if your funcs exist) -->
<nav>
<ul class="pagination">
{{ if gt .Page 1 }}
{{ if gt .CurrentPage 1 }}
<li class="page-item">
<a class="page-link" href="?page={{ minus1 .Page }}">Previous</a>
<a class="page-link" href="?page={{ sub .CurrentPage 1 }}">Previous</a>
</li>
{{ end }}
{{ if .HasMore }}
{{ if lt .CurrentPage .TotalPages }}
<li class="page-item">
<a class="page-link" href="?page={{ plus1 .Page }}">Next</a>
<a class="page-link" href="?page={{ add .CurrentPage 1 }}">Next</a>
</li>
{{ end }}
</ul>

View File

@@ -7,7 +7,7 @@
{{ range .Messages }}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<a href="/account/messages/read?={{ .ID }}" class="fw-bold text-dark">{{ .Subject }}</a><br>
<a href="/account/messages/read?id={{ .ID }}" class="fw-bold text-dark">{{ .Subject }}</a><br>
<small class="text-muted">{{ .CreatedAt.Format "02 Jan 2006 15:04" }}</small>
</div>
<form method="POST" action="/account/messages/archive" class="m-0">