mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-05 13:29:44 +02:00
fix(handler): fix batch operations and error handling bugs (#779)
fix(handler): fix batch operations and error handling bugs
This commit is contained in:
@@ -412,7 +412,12 @@ func (h *Handler) GoogleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// Fetch user info from Google.
|
||||
userInfoReq, _ := http.NewRequestWithContext(r.Context(), http.MethodGet, "https://www.googleapis.com/oauth2/v2/userinfo", nil)
|
||||
userInfoReq, err := http.NewRequestWithContext(r.Context(), http.MethodGet, "https://www.googleapis.com/oauth2/v2/userinfo", nil)
|
||||
if err != nil {
|
||||
slog.Error("failed to create userinfo request", "error", err)
|
||||
writeError(w, http.StatusInternalServerError, "internal error")
|
||||
return
|
||||
}
|
||||
userInfoReq.Header.Set("Authorization", "Bearer "+gToken.AccessToken)
|
||||
|
||||
userInfoResp, err := http.DefaultClient.Do(userInfoReq)
|
||||
|
||||
@@ -1252,6 +1252,7 @@ func (h *Handler) BatchUpdateIssues(w http.ResponseWriter, r *http.Request) {
|
||||
AssigneeID: prevIssue.AssigneeID,
|
||||
DueDate: prevIssue.DueDate,
|
||||
ParentIssueID: prevIssue.ParentIssueID,
|
||||
ProjectID: prevIssue.ProjectID,
|
||||
}
|
||||
|
||||
if req.Updates.Title != nil {
|
||||
@@ -1295,6 +1296,33 @@ func (h *Handler) BatchUpdateIssues(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := rawUpdates["parent_issue_id"]; ok {
|
||||
if req.Updates.ParentIssueID != nil {
|
||||
newParentID := parseUUID(*req.Updates.ParentIssueID)
|
||||
// Cannot set self as parent.
|
||||
if uuidToString(newParentID) == issueID {
|
||||
continue
|
||||
}
|
||||
// Validate parent exists in the same workspace.
|
||||
if _, err := h.Queries.GetIssueInWorkspace(r.Context(), db.GetIssueInWorkspaceParams{
|
||||
ID: newParentID,
|
||||
WorkspaceID: prevIssue.WorkspaceID,
|
||||
}); err != nil {
|
||||
continue
|
||||
}
|
||||
params.ParentIssueID = newParentID
|
||||
} else {
|
||||
params.ParentIssueID = pgtype.UUID{Valid: false}
|
||||
}
|
||||
}
|
||||
if _, ok := rawUpdates["project_id"]; ok {
|
||||
if req.Updates.ProjectID != nil {
|
||||
params.ProjectID = parseUUID(*req.Updates.ProjectID)
|
||||
} else {
|
||||
params.ProjectID = pgtype.UUID{Valid: false}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce agent visibility for batch assignment.
|
||||
if req.Updates.AssigneeType != nil && *req.Updates.AssigneeType == "agent" && req.Updates.AssigneeID != nil {
|
||||
if ok, _ := h.canAssignAgent(r.Context(), r, *req.Updates.AssigneeID, workspaceID); !ok {
|
||||
@@ -1372,11 +1400,16 @@ func (h *Handler) BatchDeleteIssues(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
h.TaskService.CancelTasksForIssue(r.Context(), issue.ID)
|
||||
|
||||
if err := h.Queries.DeleteIssue(r.Context(), parseUUID(issueID)); err != nil {
|
||||
// Collect attachment URLs before CASCADE delete to clean up S3 objects.
|
||||
attachmentURLs, _ := h.Queries.ListAttachmentURLsByIssueOrComments(r.Context(), issue.ID)
|
||||
|
||||
if err := h.Queries.DeleteIssue(r.Context(), issue.ID); err != nil {
|
||||
slog.Warn("batch delete issue failed", "issue_id", issueID, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
h.deleteS3Objects(r.Context(), attachmentURLs)
|
||||
|
||||
actorType, actorID := h.resolveActor(r, userID, workspaceID)
|
||||
h.publish(protocol.EventIssueDeleted, workspaceID, actorType, actorID, map[string]any{"issue_id": issueID})
|
||||
deleted++
|
||||
|
||||
Reference in New Issue
Block a user