feat(api): add endpoint to list guest photos
* implement handleListPhotos to retrieve uploaded photos * create PhotoFileRecord struct for photo data * add fetchGuestPhotos function in the UI * display guest photos in the photo upload page * remove index.html as it is no longer needed * add calendar functionality to download wedding event
This commit is contained in:
@@ -36,6 +36,7 @@ func (s *Server) Routes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("GET /api/config", s.handleConfig)
|
||||
mux.HandleFunc("POST /api/rsvp", s.handleRSVP)
|
||||
mux.HandleFunc("GET /api/guests", s.handleGuestList)
|
||||
mux.HandleFunc("GET /api/photos", s.handleListPhotos)
|
||||
mux.HandleFunc("POST /api/photos/upload", s.handlePhotoUpload)
|
||||
}
|
||||
|
||||
@@ -146,6 +147,27 @@ func (s *Server) handleGuestList(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
type photoResponse struct {
|
||||
URL string `json:"url"`
|
||||
UploaderName string `json:"uploaderName"`
|
||||
}
|
||||
|
||||
func (s *Server) handleListPhotos(w http.ResponseWriter, r *http.Request) {
|
||||
files, err := s.store.ListPhotoFiles()
|
||||
if err != nil {
|
||||
log.Printf("photos: list failed: %v", err)
|
||||
writeError(w, http.StatusInternalServerError, "could not load photos")
|
||||
return
|
||||
}
|
||||
|
||||
out := make([]photoResponse, 0, len(files))
|
||||
for _, f := range files {
|
||||
out = append(out, photoResponse{URL: f.URL, UploaderName: f.UploaderName})
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]any{"photos": out})
|
||||
}
|
||||
|
||||
var allowedImageTypes = map[string]bool{
|
||||
"image/jpeg": true,
|
||||
"image/png": true,
|
||||
@@ -155,11 +177,6 @@ var allowedImageTypes = map[string]bool{
|
||||
}
|
||||
|
||||
func (s *Server) handlePhotoUpload(w http.ResponseWriter, r *http.Request) {
|
||||
if time.Now().Before(s.cfg.Wedding.Date) {
|
||||
writeError(w, http.StatusForbidden, "photo uploads open on the wedding day")
|
||||
return
|
||||
}
|
||||
|
||||
maxTotalBytes := int64(s.cfg.Upload.MaxSizeMB) * int64(s.cfg.Upload.MaxFiles) * 1024 * 1024
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxTotalBytes+1<<20)
|
||||
|
||||
|
||||
@@ -159,6 +159,36 @@ func (s *Store) CreatePhotoUpload(u PhotoUpload) (int64, error) {
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
type PhotoFileRecord struct {
|
||||
URL string
|
||||
UploaderName string
|
||||
}
|
||||
|
||||
// ListPhotoFiles returns every uploaded photo, most recent first.
|
||||
func (s *Store) ListPhotoFiles() ([]PhotoFileRecord, error) {
|
||||
rows, err := s.db.Query(
|
||||
`SELECT f.url, u.name
|
||||
FROM photo_files f
|
||||
JOIN photo_uploads u ON u.id = f.upload_id
|
||||
ORDER BY f.created_at DESC, f.id DESC
|
||||
LIMIT 200`,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var out []PhotoFileRecord
|
||||
for rows.Next() {
|
||||
var rec PhotoFileRecord
|
||||
if err := rows.Scan(&rec.URL, &rec.UploaderName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, rec)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (s *Store) AddPhotoFiles(uploadID int64, files []PhotoFile) error {
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user