feat: implement single POST upsert API with automatic ID generation

- Replace separate POST/PUT endpoints with unified POST upsert
- Add automatic content ID generation from element context when no ID provided
- Implement version history preservation before content updates
- Add element context support for backend ID generation
- Update frontend to use single endpoint for all content operations
- Enhanced demo site with latest database content including proper content IDs
This commit is contained in:
2025-09-11 16:36:42 +02:00
parent 2ce37874ff
commit 3db1340cce
8 changed files with 65 additions and 177 deletions

View File

@@ -252,68 +252,6 @@ func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request) {
}
userID := userInfo.ID
var content interface{}
var err error
switch h.database.GetDBType() {
case "sqlite3":
content, err = h.database.GetSQLiteQueries().CreateContent(context.Background(), sqlite.CreateContentParams{
ID: contentID,
SiteID: siteID,
Value: req.Value,
Type: req.Type,
LastEditedBy: userID,
})
case "postgresql":
content, err = h.database.GetPostgreSQLQueries().CreateContent(context.Background(), postgresql.CreateContentParams{
ID: contentID,
SiteID: siteID,
Value: req.Value,
Type: req.Type,
LastEditedBy: userID,
})
default:
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("Failed to create content: %v", err), http.StatusInternalServerError)
return
}
item := h.convertToAPIContent(content)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(item)
}
// UpdateContent handles PUT /api/content/{id} with upsert functionality
func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
contentID := vars["id"]
siteID := r.URL.Query().Get("site_id")
if siteID == "" {
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
return
}
var req UpdateContentRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// Extract user from request using authentication service
userInfo, authErr := h.authService.ExtractUserFromRequest(r)
if authErr != nil {
http.Error(w, fmt.Sprintf("Authentication error: %v", authErr), http.StatusUnauthorized)
return
}
userID := userInfo.ID
// Check if content exists for version history (non-blocking)
var existingContent interface{}
var contentExists bool
@@ -350,13 +288,12 @@ func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
contentType = "text" // default type for new content
}
// Perform upsert operation
var upsertedContent interface{}
var content interface{}
var err error
switch h.database.GetDBType() {
case "sqlite3":
upsertedContent, err = h.database.GetSQLiteQueries().UpsertContent(context.Background(), sqlite.UpsertContentParams{
content, err = h.database.GetSQLiteQueries().UpsertContent(context.Background(), sqlite.UpsertContentParams{
ID: contentID,
SiteID: siteID,
Value: req.Value,
@@ -364,7 +301,7 @@ func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
LastEditedBy: userID,
})
case "postgresql":
upsertedContent, err = h.database.GetPostgreSQLQueries().UpsertContent(context.Background(), postgresql.UpsertContentParams{
content, err = h.database.GetPostgreSQLQueries().UpsertContent(context.Background(), postgresql.UpsertContentParams{
ID: contentID,
SiteID: siteID,
Value: req.Value,
@@ -381,7 +318,7 @@ func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
return
}
item := h.convertToAPIContent(upsertedContent)
item := h.convertToAPIContent(content)
// Trigger file enhancement if site is registered for auto-enhancement
if h.siteManager != nil && h.siteManager.IsAutoEnhanceEnabled(siteID) {
@@ -395,6 +332,7 @@ func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(item)
}