mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 22:37:03 +00:00
41be1bf113
* feat(apps): human-facing JSON names the app that wrote an item, comment or version (TASK-3413, SPEC-6 U9c) Items (the creating app), comments and version rows carry via_app (the install id) and via_app_name (the bot's name, else the origin; kept after uninstall) on the web API, the MCP get / list summary / history summary projections, and the TS types, with WorkspaceApp naming the members apps array. ToolSurface 0.65, additive. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(apps): attribution on search, /changes, playbook show and restore; chunked lookup (codex r1 on U9c) Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(apps): attribution on the role board, a comment edit's response and the account export (codex r2 on U9c) Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * docs: README tool catalog at v0.65 (TASK-3413) Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
84 lines
2.1 KiB
Go
84 lines
2.1 KiB
Go
package server
|
|
|
|
import (
|
|
"log/slog"
|
|
|
|
"github.com/PerpetualSoftware/pad/internal/models"
|
|
)
|
|
|
|
// App attribution on human-facing JSON (SPEC-6 U9c, TASK-3413): via_app and
|
|
// via_app_name on items (the creating app), comments and version rows, read
|
|
// in one batch per response. A lookup failure leaves the fields absent and
|
|
// is logged: the label is a decoration, and the response is not refused
|
|
// for it.
|
|
|
|
func (s *Server) hydrateItemsAppAttribution(items []models.Item) {
|
|
if len(items) == 0 {
|
|
return
|
|
}
|
|
ids := make([]string, len(items))
|
|
for i := range items {
|
|
ids[i] = items[i].ID
|
|
}
|
|
attr, err := s.store.ItemsCreatedViaApp(ids)
|
|
if err != nil {
|
|
slog.Error("app attribution: items", "error", err)
|
|
return
|
|
}
|
|
for i := range items {
|
|
if a, ok := attr[items[i].ID]; ok {
|
|
items[i].ViaApp, items[i].ViaAppName = a.InstallID, a.Name
|
|
}
|
|
}
|
|
}
|
|
|
|
// hydrateItemAppAttribution is hydrateItemsAppAttribution for one item.
|
|
func (s *Server) hydrateItemAppAttribution(item *models.Item) {
|
|
if item == nil {
|
|
return
|
|
}
|
|
one := []models.Item{*item}
|
|
s.hydrateItemsAppAttribution(one)
|
|
item.ViaApp, item.ViaAppName = one[0].ViaApp, one[0].ViaAppName
|
|
}
|
|
|
|
func (s *Server) hydrateCommentsAppAttribution(comments []models.Comment) {
|
|
if len(comments) == 0 {
|
|
return
|
|
}
|
|
ids := make([]string, len(comments))
|
|
for i := range comments {
|
|
ids[i] = comments[i].ID
|
|
}
|
|
attr, err := s.store.CommentsViaApp(ids)
|
|
if err != nil {
|
|
slog.Error("app attribution: comments", "error", err)
|
|
return
|
|
}
|
|
for i := range comments {
|
|
if a, ok := attr[comments[i].ID]; ok {
|
|
comments[i].ViaApp, comments[i].ViaAppName = a.InstallID, a.Name
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Server) hydrateVersionsAppAttribution(versions []models.Version) {
|
|
if len(versions) == 0 {
|
|
return
|
|
}
|
|
ids := make([]string, len(versions))
|
|
for i := range versions {
|
|
ids[i] = versions[i].ID
|
|
}
|
|
attr, err := s.store.VersionsViaApp(ids)
|
|
if err != nil {
|
|
slog.Error("app attribution: versions", "error", err)
|
|
return
|
|
}
|
|
for i := range versions {
|
|
if a, ok := attr[versions[i].ID]; ok {
|
|
versions[i].ViaApp, versions[i].ViaAppName = a.InstallID, a.Name
|
|
}
|
|
}
|
|
}
|