- Add ProcessingIssuesHandler with List and GetStats methods - Add AdminProcessingIssues template for issues dashboard - Display error/warning/info stats cards - Sort issues by severity and creation date - Add dismiss functionality for warnings and info items - Add navigate to media item functionality - Show issue type, description, and media details
140 lines
4.2 KiB
Go
140 lines
4.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bookhoard/internal/database"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/labstack/echo/v5"
|
|
)
|
|
|
|
type ProcessingIssuesHandler struct {
|
|
db *database.Queries
|
|
}
|
|
|
|
func NewProcessingIssuesHandler(db *database.Queries) *ProcessingIssuesHandler {
|
|
return &ProcessingIssuesHandler{db: db}
|
|
}
|
|
|
|
type ProcessingIssueResponse struct {
|
|
ID string `json:"id"`
|
|
MediaItemID string `json:"media_item_id"`
|
|
Title string `json:"title"`
|
|
FilePath string `json:"file_path"`
|
|
FormatGroup string `json:"format_group"`
|
|
LibraryTypeName string `json:"library_type_name"`
|
|
IssueType string `json:"issue_type"`
|
|
IssueDescription string `json:"issue_description"`
|
|
Severity string `json:"severity"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
type ProcessingIssueStats struct {
|
|
ErrorCount int64 `json:"error_count"`
|
|
WarningCount int64 `json:"warning_count"`
|
|
InfoCount int64 `json:"info_count"`
|
|
}
|
|
|
|
// ListProcessingIssues returns all processing issues for a library
|
|
func (h *ProcessingIssuesHandler) ListProcessingIssues(c *echo.Context) error {
|
|
libraryID, err := uuid.Parse(c.Param("libraryId"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid library ID"})
|
|
}
|
|
|
|
issues, err := h.db.ListProcessingIssuesByLibrary(
|
|
c.Request().Context(),
|
|
pgtype.UUID{Bytes: libraryID, Valid: true},
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to fetch issues"})
|
|
}
|
|
|
|
response := make([]ProcessingIssueResponse, len(issues))
|
|
for i, issue := range issues {
|
|
response[i] = ProcessingIssueResponse{
|
|
ID: issue.ID.String(),
|
|
MediaItemID: issue.MediaItemID.String(),
|
|
Title: issue.Title,
|
|
FilePath: issue.FilePath,
|
|
FormatGroup: issue.FormatGroup,
|
|
LibraryTypeName: issue.LibraryTypeName,
|
|
IssueType: issue.IssueType,
|
|
IssueDescription: issue.IssueDescription,
|
|
Severity: issue.Severity,
|
|
CreatedAt: issue.CreatedAt.Time,
|
|
}
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// GetProcessingIssueStats returns statistics about processing issues
|
|
func (h *ProcessingIssuesHandler) GetProcessingIssueStats(c *echo.Context) error {
|
|
libraryID, err := uuid.Parse(c.Param("libraryId"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid library ID"})
|
|
}
|
|
|
|
stats, err := h.db.GetProcessingIssueStats(
|
|
c.Request().Context(),
|
|
pgtype.UUID{Bytes: libraryID, Valid: true},
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to fetch stats"})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, ProcessingIssueStats{
|
|
ErrorCount: stats.ErrorCount,
|
|
WarningCount: stats.WarningCount,
|
|
InfoCount: stats.InfoCount,
|
|
})
|
|
}
|
|
|
|
// ResolveProcessingIssue marks an issue as resolved
|
|
func (h *ProcessingIssuesHandler) ResolveProcessingIssue(c *echo.Context) error {
|
|
issueID, err := uuid.Parse(c.Param("issueId"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid issue ID"})
|
|
}
|
|
|
|
mediaItemID, err := uuid.Parse(c.Param("mediaItemId"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid media item ID"})
|
|
}
|
|
|
|
_, err = h.db.ResolveProcessingIssue(
|
|
c.Request().Context(),
|
|
issueID,
|
|
pgtype.UUID{Bytes: mediaItemID, Valid: true},
|
|
)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to resolve issue"})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, map[string]interface{}{
|
|
"success": true,
|
|
"message": "Issue marked as resolved",
|
|
})
|
|
}
|
|
|
|
// DeleteProcessingIssue permanently deletes an issue record
|
|
func (h *ProcessingIssuesHandler) DeleteProcessingIssue(c *echo.Context) error {
|
|
issueID, err := uuid.Parse(c.Param("issueId"))
|
|
if err != nil {
|
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid issue ID"})
|
|
}
|
|
|
|
_, err = h.db.DeleteProcessingIssue(c.Request().Context(), issueID)
|
|
if err != nil {
|
|
return c.JSON(http.StatusInternalServerError, map[string]string{"error": "Failed to delete issue"})
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, map[string]interface{}{
|
|
"success": true,
|
|
"message": "Issue deleted",
|
|
})
|
|
}
|