fix: CreateSection/CreateRequest/CreateRequestList now use lib.EntryWrite — no more raw DB calls in handlers
This commit is contained in:
parent
eb37f682eb
commit
ec0b60d44c
145
api/handlers.go
145
api/handlers.go
|
|
@ -2057,35 +2057,28 @@ func (h *Handlers) CreateSection(w http.ResponseWriter, r *http.Request) {
|
||||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil || strings.TrimSpace(body.Name) == "" || body.ParentID == "" {
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil || strings.TrimSpace(body.Name) == "" || body.ParentID == "" {
|
||||||
ErrorResponse(w, http.StatusBadRequest, "invalid_body", "name and parent_id required"); return
|
ErrorResponse(w, http.StatusBadRequest, "invalid_body", "name and parent_id required"); return
|
||||||
}
|
}
|
||||||
projectKey, err := lib.DeriveProjectKey(h.Cfg.MasterKey, projectID)
|
parent, err := lib.EntryByID(h.DB, h.Cfg, body.ParentID)
|
||||||
if err != nil { ErrorResponse(w, http.StatusInternalServerError, "internal", "key error"); return }
|
if err != nil || parent == nil {
|
||||||
|
ErrorResponse(w, http.StatusBadRequest, "invalid_parent", "Parent entry not found"); return
|
||||||
var parentDepth int
|
}
|
||||||
h.DB.Conn.QueryRow(`SELECT depth FROM entries WHERE entry_id=?`, body.ParentID).Scan(&parentDepth)
|
siblings, _ := lib.EntriesByParent(h.DB, h.Cfg, body.ParentID)
|
||||||
var maxSort int
|
|
||||||
h.DB.Conn.QueryRow(
|
|
||||||
`SELECT COALESCE(MAX(sort_order),0) FROM entries WHERE parent_id=? AND deleted_at IS NULL`, body.ParentID,
|
|
||||||
).Scan(&maxSort)
|
|
||||||
|
|
||||||
now := time.Now().UnixMilli()
|
|
||||||
secID := uuid.New().String()
|
|
||||||
name := strings.TrimSpace(body.Name)
|
name := strings.TrimSpace(body.Name)
|
||||||
secData := lib.SectionData{Name: name}
|
secData := lib.SectionData{Name: name}
|
||||||
secDataJSON, _ := json.Marshal(secData)
|
secDataJSON, _ := json.Marshal(secData)
|
||||||
sumPacked, _ := lib.Pack(projectKey, name)
|
entry := &lib.Entry{
|
||||||
dataPacked, _ := lib.Pack(projectKey, string(secDataJSON))
|
ProjectID: projectID,
|
||||||
|
ParentID: body.ParentID,
|
||||||
_, err = h.DB.Conn.Exec(
|
Type: lib.TypeSection,
|
||||||
`INSERT INTO entries (entry_id, project_id, parent_id, type, depth, sort_order,
|
Depth: parent.Depth + 1,
|
||||||
search_key, search_key2, summary, data, stage,
|
SortOrder: (len(siblings) + 1) * 1000,
|
||||||
assignee_id, return_to_id, origin_id, version, deleted_at, deleted_by, key_version, created_at, updated_at, created_by)
|
SummaryText: name,
|
||||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
DataText: string(secDataJSON),
|
||||||
secID, projectID, body.ParentID, lib.TypeSection, parentDepth+1, maxSort+1000,
|
Stage: lib.StagePreDataroom,
|
||||||
nil, nil, sumPacked, dataPacked, lib.StagePreDataroom,
|
}
|
||||||
"", "", "", 1, nil, nil, 1, now, now, actorID,
|
if err := lib.EntryWrite(h.DB, h.Cfg, actorID, entry); err != nil {
|
||||||
)
|
ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create section"); return
|
||||||
if err != nil { ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create section"); return }
|
}
|
||||||
JSONResponse(w, http.StatusOK, map[string]any{"entry_id": secID, "name": name})
|
JSONResponse(w, http.StatusOK, map[string]any{"entry_id": entry.EntryID, "name": name})
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRequest creates a new blank request under a section or request_list.
|
// CreateRequest creates a new blank request under a section or request_list.
|
||||||
|
|
@ -2102,36 +2095,28 @@ func (h *Handlers) CreateRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil || strings.TrimSpace(body.Title) == "" || body.ParentID == "" {
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil || strings.TrimSpace(body.Title) == "" || body.ParentID == "" {
|
||||||
ErrorResponse(w, http.StatusBadRequest, "invalid_body", "title and parent_id required"); return
|
ErrorResponse(w, http.StatusBadRequest, "invalid_body", "title and parent_id required"); return
|
||||||
}
|
}
|
||||||
projectKey, err := lib.DeriveProjectKey(h.Cfg.MasterKey, projectID)
|
parent, err := lib.EntryByID(h.DB, h.Cfg, body.ParentID)
|
||||||
if err != nil { ErrorResponse(w, http.StatusInternalServerError, "internal", "key error"); return }
|
if err != nil || parent == nil {
|
||||||
|
ErrorResponse(w, http.StatusBadRequest, "invalid_parent", "Parent entry not found"); return
|
||||||
// Determine depth from parent
|
}
|
||||||
var parentDepth int
|
siblings, _ := lib.EntriesByParent(h.DB, h.Cfg, body.ParentID)
|
||||||
h.DB.Conn.QueryRow(`SELECT depth FROM entries WHERE entry_id=?`, body.ParentID).Scan(&parentDepth)
|
|
||||||
var maxSort int
|
|
||||||
h.DB.Conn.QueryRow(
|
|
||||||
`SELECT COALESCE(MAX(sort_order),0) FROM entries WHERE parent_id=? AND deleted_at IS NULL`, body.ParentID,
|
|
||||||
).Scan(&maxSort)
|
|
||||||
|
|
||||||
now := time.Now().UnixMilli()
|
|
||||||
reqID := uuid.New().String()
|
|
||||||
title := strings.TrimSpace(body.Title)
|
title := strings.TrimSpace(body.Title)
|
||||||
reqData := lib.RequestData{Title: title, Status: "open", Priority: "medium"}
|
reqData := lib.RequestData{Title: title, Status: "open", Priority: "medium"}
|
||||||
reqDataJSON, _ := json.Marshal(reqData)
|
reqDataJSON, _ := json.Marshal(reqData)
|
||||||
sumPacked, _ := lib.Pack(projectKey, title)
|
entry := &lib.Entry{
|
||||||
dataPacked, _ := lib.Pack(projectKey, string(reqDataJSON))
|
ProjectID: projectID,
|
||||||
|
ParentID: body.ParentID,
|
||||||
_, err = h.DB.Conn.Exec(
|
Type: lib.TypeRequest,
|
||||||
`INSERT INTO entries (entry_id, project_id, parent_id, type, depth, sort_order,
|
Depth: parent.Depth + 1,
|
||||||
search_key, search_key2, summary, data, stage,
|
SortOrder: (len(siblings) + 1) * 100,
|
||||||
assignee_id, return_to_id, origin_id, version, deleted_at, deleted_by, key_version, created_at, updated_at, created_by)
|
SummaryText: title,
|
||||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
DataText: string(reqDataJSON),
|
||||||
reqID, projectID, body.ParentID, lib.TypeRequest, parentDepth+1, maxSort+100,
|
Stage: lib.StagePreDataroom,
|
||||||
nil, nil, sumPacked, dataPacked, lib.StagePreDataroom,
|
}
|
||||||
"", "", "", 1, nil, nil, 1, now, now, actorID,
|
if err := lib.EntryWrite(h.DB, h.Cfg, actorID, entry); err != nil {
|
||||||
)
|
ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create request"); return
|
||||||
if err != nil { ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create request"); return }
|
}
|
||||||
JSONResponse(w, http.StatusOK, map[string]any{"entry_id": reqID, "title": title})
|
JSONResponse(w, http.StatusOK, map[string]any{"entry_id": entry.EntryID, "title": title})
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRequestList creates a new empty request list for a project.
|
// CreateRequestList creates a new empty request list for a project.
|
||||||
|
|
@ -2152,48 +2137,34 @@ func (h *Handlers) CreateRequestList(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
projectKey, err := lib.DeriveProjectKey(h.Cfg.MasterKey, projectID)
|
|
||||||
if err != nil {
|
|
||||||
ErrorResponse(w, http.StatusInternalServerError, "internal", "Could not derive project key")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
now := time.Now().UnixMilli()
|
|
||||||
listName := strings.TrimSpace(body.Name)
|
listName := strings.TrimSpace(body.Name)
|
||||||
requestListID := uuid.New().String()
|
// Sort after existing lists: use sibling count * 1000
|
||||||
|
siblings, _ := lib.EntriesByParent(h.DB, h.Cfg, projectID)
|
||||||
// Compute sort_order: place after last existing list
|
listCount := 0
|
||||||
var maxSort int
|
for _, s := range siblings {
|
||||||
h.DB.Conn.QueryRow(
|
if s.Type == lib.TypeRequestList {
|
||||||
`SELECT COALESCE(MAX(sort_order),0) FROM entries WHERE project_id=? AND type='request_list' AND deleted_at IS NULL`, projectID,
|
listCount++
|
||||||
).Scan(&maxSort)
|
}
|
||||||
sortOrder := maxSort + 1000
|
}
|
||||||
|
|
||||||
rlData := lib.RequestListData{Name: listName}
|
rlData := lib.RequestListData{Name: listName}
|
||||||
rlDataJSON, _ := json.Marshal(rlData)
|
rlDataJSON, _ := json.Marshal(rlData)
|
||||||
rlSummaryPacked, _ := lib.Pack(projectKey, listName)
|
entry := &lib.Entry{
|
||||||
rlDataPacked, _ := lib.Pack(projectKey, string(rlDataJSON))
|
ProjectID: projectID,
|
||||||
|
ParentID: projectID,
|
||||||
_, err = h.DB.Conn.Exec(
|
Type: lib.TypeRequestList,
|
||||||
`INSERT INTO entries (entry_id, project_id, parent_id, type, depth, sort_order,
|
Depth: 1,
|
||||||
search_key, search_key2, summary, data, stage,
|
SortOrder: (listCount + 1) * 1000,
|
||||||
assignee_id, return_to_id, origin_id,
|
SummaryText: listName,
|
||||||
version, deleted_at, deleted_by, key_version,
|
DataText: string(rlDataJSON),
|
||||||
created_at, updated_at, created_by)
|
Stage: lib.StagePreDataroom,
|
||||||
VALUES (?,?,?,?,?,?, ?,?,?,?,?, ?,?,?, ?,?,?,?, ?,?,?)`,
|
}
|
||||||
requestListID, projectID, projectID, lib.TypeRequestList, 1, sortOrder,
|
if err := lib.EntryWrite(h.DB, h.Cfg, actorID, entry); err != nil {
|
||||||
nil, nil, rlSummaryPacked, rlDataPacked, lib.StagePreDataroom,
|
|
||||||
"", "", "",
|
|
||||||
1, nil, nil, 1,
|
|
||||||
now, now, actorID,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create request list")
|
ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create request list")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONResponse(w, http.StatusOK, map[string]any{
|
JSONResponse(w, http.StatusOK, map[string]any{
|
||||||
"entry_id": requestListID,
|
"entry_id": entry.EntryID,
|
||||||
"name": listName,
|
"name": listName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue