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 == "" {
|
||||
ErrorResponse(w, http.StatusBadRequest, "invalid_body", "name and parent_id required"); return
|
||||
}
|
||||
projectKey, err := lib.DeriveProjectKey(h.Cfg.MasterKey, projectID)
|
||||
if err != nil { ErrorResponse(w, http.StatusInternalServerError, "internal", "key error"); return }
|
||||
|
||||
var parentDepth int
|
||||
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()
|
||||
secID := uuid.New().String()
|
||||
parent, err := lib.EntryByID(h.DB, h.Cfg, body.ParentID)
|
||||
if err != nil || parent == nil {
|
||||
ErrorResponse(w, http.StatusBadRequest, "invalid_parent", "Parent entry not found"); return
|
||||
}
|
||||
siblings, _ := lib.EntriesByParent(h.DB, h.Cfg, body.ParentID)
|
||||
name := strings.TrimSpace(body.Name)
|
||||
secData := lib.SectionData{Name: name}
|
||||
secDataJSON, _ := json.Marshal(secData)
|
||||
sumPacked, _ := lib.Pack(projectKey, name)
|
||||
dataPacked, _ := lib.Pack(projectKey, string(secDataJSON))
|
||||
|
||||
_, err = h.DB.Conn.Exec(
|
||||
`INSERT INTO entries (entry_id, project_id, parent_id, type, depth, sort_order,
|
||||
search_key, search_key2, summary, data, stage,
|
||||
assignee_id, return_to_id, origin_id, version, deleted_at, deleted_by, key_version, created_at, updated_at, created_by)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
||||
secID, projectID, body.ParentID, lib.TypeSection, parentDepth+1, maxSort+1000,
|
||||
nil, nil, sumPacked, dataPacked, lib.StagePreDataroom,
|
||||
"", "", "", 1, nil, nil, 1, now, now, actorID,
|
||||
)
|
||||
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})
|
||||
entry := &lib.Entry{
|
||||
ProjectID: projectID,
|
||||
ParentID: body.ParentID,
|
||||
Type: lib.TypeSection,
|
||||
Depth: parent.Depth + 1,
|
||||
SortOrder: (len(siblings) + 1) * 1000,
|
||||
SummaryText: name,
|
||||
DataText: string(secDataJSON),
|
||||
Stage: lib.StagePreDataroom,
|
||||
}
|
||||
if err := lib.EntryWrite(h.DB, h.Cfg, actorID, entry); err != nil {
|
||||
ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create section"); return
|
||||
}
|
||||
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.
|
||||
|
|
@ -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 == "" {
|
||||
ErrorResponse(w, http.StatusBadRequest, "invalid_body", "title and parent_id required"); return
|
||||
}
|
||||
projectKey, err := lib.DeriveProjectKey(h.Cfg.MasterKey, projectID)
|
||||
if err != nil { ErrorResponse(w, http.StatusInternalServerError, "internal", "key error"); return }
|
||||
|
||||
// Determine depth from parent
|
||||
var parentDepth int
|
||||
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()
|
||||
parent, err := lib.EntryByID(h.DB, h.Cfg, body.ParentID)
|
||||
if err != nil || parent == nil {
|
||||
ErrorResponse(w, http.StatusBadRequest, "invalid_parent", "Parent entry not found"); return
|
||||
}
|
||||
siblings, _ := lib.EntriesByParent(h.DB, h.Cfg, body.ParentID)
|
||||
title := strings.TrimSpace(body.Title)
|
||||
reqData := lib.RequestData{Title: title, Status: "open", Priority: "medium"}
|
||||
reqDataJSON, _ := json.Marshal(reqData)
|
||||
sumPacked, _ := lib.Pack(projectKey, title)
|
||||
dataPacked, _ := lib.Pack(projectKey, string(reqDataJSON))
|
||||
|
||||
_, err = h.DB.Conn.Exec(
|
||||
`INSERT INTO entries (entry_id, project_id, parent_id, type, depth, sort_order,
|
||||
search_key, search_key2, summary, data, stage,
|
||||
assignee_id, return_to_id, origin_id, version, deleted_at, deleted_by, key_version, created_at, updated_at, created_by)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
||||
reqID, projectID, body.ParentID, lib.TypeRequest, parentDepth+1, maxSort+100,
|
||||
nil, nil, sumPacked, dataPacked, lib.StagePreDataroom,
|
||||
"", "", "", 1, nil, nil, 1, now, now, actorID,
|
||||
)
|
||||
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})
|
||||
entry := &lib.Entry{
|
||||
ProjectID: projectID,
|
||||
ParentID: body.ParentID,
|
||||
Type: lib.TypeRequest,
|
||||
Depth: parent.Depth + 1,
|
||||
SortOrder: (len(siblings) + 1) * 100,
|
||||
SummaryText: title,
|
||||
DataText: string(reqDataJSON),
|
||||
Stage: lib.StagePreDataroom,
|
||||
}
|
||||
if err := lib.EntryWrite(h.DB, h.Cfg, actorID, entry); err != nil {
|
||||
ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create request"); return
|
||||
}
|
||||
JSONResponse(w, http.StatusOK, map[string]any{"entry_id": entry.EntryID, "title": title})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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)
|
||||
requestListID := uuid.New().String()
|
||||
|
||||
// Compute sort_order: place after last existing list
|
||||
var maxSort int
|
||||
h.DB.Conn.QueryRow(
|
||||
`SELECT COALESCE(MAX(sort_order),0) FROM entries WHERE project_id=? AND type='request_list' AND deleted_at IS NULL`, projectID,
|
||||
).Scan(&maxSort)
|
||||
sortOrder := maxSort + 1000
|
||||
|
||||
// Sort after existing lists: use sibling count * 1000
|
||||
siblings, _ := lib.EntriesByParent(h.DB, h.Cfg, projectID)
|
||||
listCount := 0
|
||||
for _, s := range siblings {
|
||||
if s.Type == lib.TypeRequestList {
|
||||
listCount++
|
||||
}
|
||||
}
|
||||
rlData := lib.RequestListData{Name: listName}
|
||||
rlDataJSON, _ := json.Marshal(rlData)
|
||||
rlSummaryPacked, _ := lib.Pack(projectKey, listName)
|
||||
rlDataPacked, _ := lib.Pack(projectKey, string(rlDataJSON))
|
||||
|
||||
_, err = h.DB.Conn.Exec(
|
||||
`INSERT INTO entries (entry_id, project_id, parent_id, type, depth, sort_order,
|
||||
search_key, search_key2, summary, data, stage,
|
||||
assignee_id, return_to_id, origin_id,
|
||||
version, deleted_at, deleted_by, key_version,
|
||||
created_at, updated_at, created_by)
|
||||
VALUES (?,?,?,?,?,?, ?,?,?,?,?, ?,?,?, ?,?,?,?, ?,?,?)`,
|
||||
requestListID, projectID, projectID, lib.TypeRequestList, 1, sortOrder,
|
||||
nil, nil, rlSummaryPacked, rlDataPacked, lib.StagePreDataroom,
|
||||
"", "", "",
|
||||
1, nil, nil, 1,
|
||||
now, now, actorID,
|
||||
)
|
||||
if err != nil {
|
||||
entry := &lib.Entry{
|
||||
ProjectID: projectID,
|
||||
ParentID: projectID,
|
||||
Type: lib.TypeRequestList,
|
||||
Depth: 1,
|
||||
SortOrder: (listCount + 1) * 1000,
|
||||
SummaryText: listName,
|
||||
DataText: string(rlDataJSON),
|
||||
Stage: lib.StagePreDataroom,
|
||||
}
|
||||
if err := lib.EntryWrite(h.DB, h.Cfg, actorID, entry); err != nil {
|
||||
ErrorResponse(w, http.StatusInternalServerError, "internal", "Failed to create request list")
|
||||
return
|
||||
}
|
||||
|
||||
JSONResponse(w, http.StatusOK, map[string]any{
|
||||
"entry_id": requestListID,
|
||||
"entry_id": entry.EntryID,
|
||||
"name": listName,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue