The suggestion + feedback handlers wrote to legacy public-schema tables (`patholo_link_suggestions`, `patholo_link_feedback`) via Supabase PostgREST. The patHoLo→Paliad rebrand moved those tables into the paliad schema as `paliad.link_suggestions` / `paliad.link_feedback` — PostgREST is not configured to expose paliad on the youpc Supabase, so all three callsites 500'd in prod. Replace the PostgREST integration with a new LinkService backed by the same sqlx pool every other paliad service uses. Schema-qualified table names work directly via DATABASE_URL, the inconsistent supabaseInsert/Count helpers go away, and the suggestion/feedback handlers now use requireDB for clean 503s when the pool isn't wired. handleSuggestionCount keeps its tolerant 0-on-error behaviour so the admin badge never blocks page render. When DATABASE_URL is unset the count endpoint returns 0 instead of 503 — knowledge-platform-only deployments still serve the Link Hub page. Flagged in t-paliad-074 (F-12).
78 lines
2.4 KiB
Go
78 lines
2.4 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
)
|
|
|
|
// LinkService persists user-submitted Link Hub suggestions and feedback into
|
|
// paliad.link_suggestions / paliad.link_feedback. The earlier implementation
|
|
// posted these via Supabase PostgREST against a public-schema patholo_link_*
|
|
// table; that surface no longer exists after the rebrand to paliad schema, so
|
|
// writes go through the same sqlx pool every other paliad service uses.
|
|
type LinkService struct {
|
|
db *sqlx.DB
|
|
}
|
|
|
|
func NewLinkService(db *sqlx.DB) *LinkService {
|
|
return &LinkService{db: db}
|
|
}
|
|
|
|
// LinkSuggestionInput is the payload of a /api/links/suggest call.
|
|
// Description and SuggestedBy are optional — empty strings hit the column
|
|
// defaults set in the migration.
|
|
type LinkSuggestionInput struct {
|
|
Title string
|
|
URL string
|
|
Category string
|
|
Description string
|
|
SuggestedBy string
|
|
}
|
|
|
|
// InsertSuggestion creates a row with status='pending' so admins can triage
|
|
// before promoting the link into the curated hub.
|
|
func (s *LinkService) InsertSuggestion(ctx context.Context, in LinkSuggestionInput) error {
|
|
const q = `INSERT INTO paliad.link_suggestions
|
|
(title, url, category, description, suggested_by, status)
|
|
VALUES ($1, $2, $3, $4, $5, 'pending')`
|
|
if _, err := s.db.ExecContext(ctx, q,
|
|
in.Title, in.URL, in.Category, in.Description, in.SuggestedBy,
|
|
); err != nil {
|
|
return fmt.Errorf("insert link suggestion: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// LinkFeedbackInput is the payload of a /api/links/feedback call.
|
|
type LinkFeedbackInput struct {
|
|
LinkID string
|
|
FeedbackType string
|
|
Message string
|
|
SubmittedBy string
|
|
}
|
|
|
|
func (s *LinkService) InsertFeedback(ctx context.Context, in LinkFeedbackInput) error {
|
|
const q = `INSERT INTO paliad.link_feedback
|
|
(link_id, feedback_type, message, submitted_by)
|
|
VALUES ($1, $2, $3, $4)`
|
|
if _, err := s.db.ExecContext(ctx, q,
|
|
in.LinkID, in.FeedbackType, in.Message, in.SubmittedBy,
|
|
); err != nil {
|
|
return fmt.Errorf("insert link feedback: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// CountPendingSuggestions powers the admin badge on the Link Hub.
|
|
func (s *LinkService) CountPendingSuggestions(ctx context.Context) (int, error) {
|
|
var n int
|
|
if err := s.db.GetContext(ctx, &n,
|
|
`SELECT count(*) FROM paliad.link_suggestions WHERE status = 'pending'`,
|
|
); err != nil {
|
|
return 0, fmt.Errorf("count pending link suggestions: %w", err)
|
|
}
|
|
return n, nil
|
|
}
|