This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/jacek/pamietnik/backend/internal/db"
|
||||
"github.com/jacek/pamietnik/backend/internal/domain"
|
||||
)
|
||||
@@ -34,6 +35,129 @@ func NewJournalHandler(store *db.JournalStore, uploadDir string) *JournalHandler
|
||||
return &JournalHandler{store: store, uploadDir: uploadDir}
|
||||
}
|
||||
|
||||
// HandleGetEditEntry renders the edit form for an existing entry.
|
||||
func (h *JournalHandler) HandleGetEditEntry(w http.ResponseWriter, r *http.Request) {
|
||||
userID := userIDFromContext(r.Context())
|
||||
entryID := chi.URLParam(r, "id")
|
||||
entry, err := h.store.GetEntry(r.Context(), entryID, userID)
|
||||
if err != nil {
|
||||
http.Error(w, "Eintrag nicht gefunden", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
render(w, "edit_entry.html", map[string]any{"Entry": entry})
|
||||
}
|
||||
|
||||
// HandleUpdateEntry handles POST /entries/{id} (multipart/form-data).
|
||||
func (h *JournalHandler) HandleUpdateEntry(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseMultipartForm(maxUploadSize); err != nil {
|
||||
http.Error(w, "Formular zu groß", http.StatusRequestEntityTooLarge)
|
||||
return
|
||||
}
|
||||
userID := userIDFromContext(r.Context())
|
||||
entryID := chi.URLParam(r, "id")
|
||||
|
||||
// Verify ownership first
|
||||
existing, err := h.store.GetEntry(r.Context(), entryID, userID)
|
||||
if err != nil {
|
||||
http.Error(w, "Eintrag nicht gefunden", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
entryTime := strings.TrimSpace(r.FormValue("time"))
|
||||
title := strings.TrimSpace(r.FormValue("title"))
|
||||
description := strings.TrimSpace(r.FormValue("description"))
|
||||
visibility := r.FormValue("visibility")
|
||||
if visibility != "public" && visibility != "private" {
|
||||
visibility = "private"
|
||||
}
|
||||
var hashtags []string
|
||||
if raw := strings.TrimSpace(r.FormValue("hashtags")); raw != "" {
|
||||
for _, tag := range strings.Split(raw, ",") {
|
||||
tag = strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(tag), "#"))
|
||||
if tag != "" {
|
||||
hashtags = append(hashtags, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry := domain.JournalEntry{
|
||||
EntryID: entryID,
|
||||
UserID: userID,
|
||||
EntryDate: existing.EntryDate,
|
||||
EntryTime: entryTime,
|
||||
Title: title,
|
||||
Description: description,
|
||||
Visibility: visibility,
|
||||
Hashtags: hashtags,
|
||||
}
|
||||
if lat := r.FormValue("lat"); lat != "" {
|
||||
var v float64
|
||||
if _, err := fmt.Sscanf(lat, "%f", &v); err == nil {
|
||||
entry.Lat = &v
|
||||
}
|
||||
}
|
||||
if lon := r.FormValue("lon"); lon != "" {
|
||||
var v float64
|
||||
if _, err := fmt.Sscanf(lon, "%f", &v); err == nil {
|
||||
entry.Lon = &v
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.store.UpdateEntry(r.Context(), entry); err != nil {
|
||||
http.Error(w, "Datenbankfehler", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle new image uploads
|
||||
if r.MultipartForm != nil && r.MultipartForm.File != nil {
|
||||
files := r.MultipartForm.File["images"]
|
||||
for _, fh := range files {
|
||||
if fh.Size == 0 || fh.Size > maxSingleImage {
|
||||
continue
|
||||
}
|
||||
f, err := fh.Open()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
buf := make([]byte, 512)
|
||||
n, _ := f.Read(buf)
|
||||
mime := http.DetectContentType(buf[:n])
|
||||
ext, ok := allowedMIME[mime]
|
||||
if !ok {
|
||||
f.Close()
|
||||
continue
|
||||
}
|
||||
filename := sanitizeFilename(entryID+"_"+fh.Filename) + ext
|
||||
destPath := filepath.Join(h.uploadDir, filename)
|
||||
out, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
continue
|
||||
}
|
||||
if _, err := out.Write(buf[:n]); err != nil {
|
||||
out.Close(); f.Close(); os.Remove(destPath)
|
||||
continue
|
||||
}
|
||||
if _, err := io.Copy(out, f); err != nil {
|
||||
out.Close(); f.Close(); os.Remove(destPath)
|
||||
continue
|
||||
}
|
||||
out.Close()
|
||||
f.Close()
|
||||
img := domain.JournalImage{
|
||||
EntryID: entryID, Filename: filename,
|
||||
OriginalName: fh.Filename, MimeType: mime, SizeBytes: fh.Size,
|
||||
}
|
||||
if _, err := h.store.InsertImage(r.Context(), img); err != nil {
|
||||
slog.Error("insert image", "entry_id", entryID, "err", err)
|
||||
os.Remove(destPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/days/"+existing.EntryDate, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// HandleCreateEntry handles POST /entries (multipart/form-data).
|
||||
func (h *JournalHandler) HandleCreateEntry(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseMultipartForm(maxUploadSize); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user