CreateComment adds a new comment to an item. userID is the authenticated user authoring the comment (empty for agent/system comments); it's stored as the canonical author identity for the comment-edit permission check — the caller passes it explicitly rather than via the request body so it can't be
(workspaceID, itemID, userID string, input models.CommentCreate)
| 14 | // the caller passes it explicitly rather than via the request body so it |
| 15 | // can't be spoofed. |
| 16 | func (s *Store) CreateComment(workspaceID, itemID, userID string, input models.CommentCreate) (*models.Comment, error) { |
| 17 | id := newID() |
| 18 | ts := now() |
| 19 | |
| 20 | createdBy := input.CreatedBy |
| 21 | if createdBy == "" { |
| 22 | createdBy = "user" |
| 23 | } |
| 24 | source := input.Source |
| 25 | if source == "" { |
| 26 | source = "web" |
| 27 | } |
| 28 | author := input.Author |
| 29 | if author == "" { |
| 30 | author = createdBy |
| 31 | } |
| 32 | |
| 33 | _, err := s.db.Exec(s.q(` |
| 34 | INSERT INTO comments (id, item_id, workspace_id, author, user_id, body, created_by, source, activity_id, parent_id, created_at, updated_at) |
| 35 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`), |
| 36 | id, itemID, workspaceID, author, nilIfEmpty(userID), input.Body, createdBy, source, |
| 37 | nilIfEmpty(input.ActivityID), nilIfEmpty(input.ParentID), ts, ts, |
| 38 | ) |
| 39 | if err != nil { |
| 40 | return nil, fmt.Errorf("insert comment: %w", err) |
| 41 | } |
| 42 | |
| 43 | return s.GetComment(id) |
| 44 | } |
| 45 | |
| 46 | // UpdateComment replaces a comment's body and bumps updated_at. The |
| 47 | // comments_fts_update trigger re-indexes the new body. Returns |