199 lines
5.3 KiB
Go
199 lines
5.3 KiB
Go
package main
|
|
|
|
import "fmt"
|
|
|
|
type InboxNodeDTO struct {
|
|
NodeDTO
|
|
CaptureKind string `json:"captureKind"`
|
|
CaptureSource string `json:"captureSource"`
|
|
CaptureStatus string `json:"captureStatus"`
|
|
CaptureContextType string `json:"captureContextType"`
|
|
CaptureContextNodeID string `json:"captureContextNodeId"`
|
|
CaptureContextSection string `json:"captureContextSection"`
|
|
SuggestedTargetNodeID string `json:"suggestedTargetNodeId"`
|
|
CaptureContextLabel string `json:"captureContextLabel"`
|
|
SuggestedTargetLabel string `json:"suggestedTargetLabel"`
|
|
CapturedAt string `json:"capturedAt"`
|
|
SourceKind string `json:"sourceKind"`
|
|
URL string `json:"url,omitempty"`
|
|
Hostname string `json:"hostname,omitempty"`
|
|
}
|
|
|
|
func (a *App) ListInboxNodes() ([]InboxNodeDTO, error) {
|
|
if err := a.requireVault(); err != nil {
|
|
return nil, err
|
|
}
|
|
list, err := a.nodes.ListInboxRoots(false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dtos := make([]InboxNodeDTO, 0, len(list))
|
|
for _, n := range list {
|
|
dto, err := a.inboxNodeDTO(&n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dtos = append(dtos, *dto)
|
|
}
|
|
for i := range dtos {
|
|
n, err := a.nodes.CountChildren(dtos[i].ID, "case", "client", "project", "folder", "document", "recipe")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dtos[i].HasChildren = n > 0
|
|
}
|
|
return dtos, nil
|
|
}
|
|
|
|
func (a *App) ListInboxNodesForTarget(nodeID string) ([]InboxNodeDTO, error) {
|
|
if err := a.requireVault(); err != nil {
|
|
return nil, err
|
|
}
|
|
if nodeID == "" {
|
|
return []InboxNodeDTO{}, nil
|
|
}
|
|
list, err := a.ListInboxNodes()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := make([]InboxNodeDTO, 0, len(list))
|
|
for _, item := range list {
|
|
if item.CaptureContextNodeID == nodeID || item.SuggestedTargetNodeID == nodeID {
|
|
out = append(out, item)
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (a *App) AssignInboxNode(nodeID, targetParentID string) (*NodeDTO, error) {
|
|
return a.ResolveInboxNode(nodeID, targetParentID)
|
|
}
|
|
|
|
func (a *App) ResolveInboxNodeHere(nodeID string) (*NodeDTO, error) {
|
|
if err := a.requireVault(); err != nil {
|
|
return nil, err
|
|
}
|
|
dto, err := a.inboxNodeByID(nodeID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if dto.SuggestedTargetNodeID == "" {
|
|
return nil, fmt.Errorf("suggested target is required")
|
|
}
|
|
return a.ResolveInboxNode(nodeID, dto.SuggestedTargetNodeID)
|
|
}
|
|
|
|
func (a *App) ResolveInboxNode(nodeID, targetParentID string) (*NodeDTO, error) {
|
|
if err := a.requireVault(); err != nil {
|
|
return nil, err
|
|
}
|
|
if !a.isInboxCaptureNode(nodeID) {
|
|
return nil, fmt.Errorf("node is not an inbox artifact")
|
|
}
|
|
if targetParentID == "" {
|
|
return nil, fmt.Errorf("target parent is required")
|
|
}
|
|
sourceKind := a.captureMeta(nodeID, "capture.source_kind")
|
|
if sourceKind == "" {
|
|
sourceKind = a.captureMeta(nodeID, "capture.kind")
|
|
}
|
|
if sourceKind == "url" {
|
|
if err := a.resolveURLInboxNode(nodeID, targetParentID); err != nil {
|
|
return nil, err
|
|
}
|
|
return a.GetNodeDetail(targetParentID)
|
|
}
|
|
if err := a.MoveNode(nodeID, targetParentID); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := a.clearCaptureMeta(nodeID); err != nil {
|
|
return nil, err
|
|
}
|
|
dto, err := a.GetNodeDetail(nodeID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return dto, nil
|
|
}
|
|
|
|
func (a *App) inboxNodeByID(nodeID string) (*InboxNodeDTO, error) {
|
|
n, err := a.nodes.GetActive(nodeID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return a.inboxNodeDTO(n)
|
|
}
|
|
|
|
func (a *App) resolveURLInboxNode(nodeID, targetParentID string) error {
|
|
if _, err := a.nodes.GetActive(targetParentID); err != nil {
|
|
return fmt.Errorf("target parent not found: %w", err)
|
|
}
|
|
rawURL := a.captureMeta(nodeID, "capture.url")
|
|
if rawURL == "" {
|
|
return fmt.Errorf("captured url is missing")
|
|
}
|
|
title := a.captureMeta(nodeID, "capture.title")
|
|
if title == "" {
|
|
if n, err := a.nodes.GetActive(nodeID); err == nil {
|
|
title = n.Title
|
|
}
|
|
}
|
|
source := a.captureMeta(nodeID, "capture.source")
|
|
capturedAt := a.captureMeta(nodeID, "capture.created_at")
|
|
if _, err := a.createResolvedLink(targetParentID, rawURL, title, "", source, capturedAt); err != nil {
|
|
return err
|
|
}
|
|
if err := a.DeleteNode(nodeID); err != nil {
|
|
return err
|
|
}
|
|
return a.clearCaptureMeta(nodeID)
|
|
}
|
|
|
|
func (a *App) DeleteInboxNode(nodeID string) error {
|
|
if err := a.requireVault(); err != nil {
|
|
return err
|
|
}
|
|
if !a.isInboxCaptureNode(nodeID) {
|
|
return fmt.Errorf("node is not an inbox artifact")
|
|
}
|
|
if err := a.DeleteNode(nodeID); err != nil {
|
|
return err
|
|
}
|
|
return a.clearCaptureMeta(nodeID)
|
|
}
|
|
|
|
func (a *App) filterInboxCaptureNodes(list []NodeDTO) []NodeDTO {
|
|
out := make([]NodeDTO, 0, len(list))
|
|
for _, item := range list {
|
|
if !a.isInboxCaptureNode(item.ID) {
|
|
out = append(out, item)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (a *App) isInboxCaptureNode(nodeID string) bool {
|
|
v, ok, err := a.nodes.MetaGet(nodeID, "capture.inbox")
|
|
if err != nil || !ok || v != "true" {
|
|
return false
|
|
}
|
|
status, ok, err := a.nodes.MetaGet(nodeID, "capture.status")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return !ok || status == "" || status == "unresolved"
|
|
}
|
|
|
|
func (a *App) clearCaptureMeta(nodeID string) error {
|
|
_, err := a.db.Exec(`DELETE FROM node_meta WHERE node_id = ? AND key LIKE 'capture.%'`, nodeID)
|
|
return err
|
|
}
|
|
|
|
func (a *App) captureMeta(nodeID, key string) string {
|
|
v, ok, err := a.nodes.MetaGet(nodeID, key)
|
|
if err != nil || !ok {
|
|
return ""
|
|
}
|
|
return v
|
|
}
|