package main import ( "verstak/internal/core/activity" "verstak/internal/core/files" "verstak/internal/core/nodes" syncsvc "verstak/internal/core/sync" ) func (a *App) ListFiles(nodeID string) ([]FileDTO, error) { records, err := a.files.ListByNode(nodeID) if err != nil { return nil, err } result := make([]FileDTO, len(records)) for i := range records { rec := &records[i] result[i] = FileDTO{ ID: rec.ID, NodeID: rec.NodeID, Name: rec.Filename, Path: rec.Path, Size: rec.Size, Mime: rec.MIME, IsDir: rec.MIME == "inode/directory", Missing: rec.Missing, } } return result, nil } func (a *App) ListItems(nodeID string) ([]FileTreeItemDTO, error) { children, err := a.nodes.ListChildren(nodeID, false) if err != nil { return nil, err } result := make([]FileTreeItemDTO, 0, len(children)) for i := range children { if children[i].Type != nodes.TypeFolder && children[i].Type != nodes.TypeFile { continue } item := FileTreeItemDTO{ ID: children[i].ID, Name: children[i].Title, Type: children[i].Type, } if children[i].Type == nodes.TypeFolder { kids, _ := a.nodes.ListChildren(children[i].ID, false) item.HasKids = len(kids) > 0 } else if children[i].Type == nodes.TypeFile { records, _ := a.files.ListByNode(children[i].ID) if len(records) > 0 { item.FileID = records[0].ID item.Size = records[0].Size item.Mime = records[0].MIME } } result = append(result, item) } return result, nil } func (a *App) AddPathCopy(nodeID, sourcePath string) ([]NodeDTO, error) { nodes, err := a.files.AddPathCopy(nodeID, sourcePath) if err != nil { return nil, err } for _, n := range nodes { _ = a.activity.Record(nodeID, activity.TargetFile, n.ID, "", activity.TypeFileAdded, n.Title, `{"source":"`+sourcePath+`"}`) _ = a.sync.RecordOp(syncsvc.EntityFile, n.ID, syncsvc.OpCreate, a.filePayload(&n)) } return toNodeDTOs(nodes), nil } func (a *App) AddPathLink(nodeID, sourcePath string) ([]NodeDTO, error) { nodes, err := a.files.AddPathLink(nodeID, sourcePath) if err != nil { return nil, err } for _, n := range nodes { _ = a.activity.Record(nodeID, activity.TargetFile, n.ID, "", activity.TypeFileAdded, n.Title, `{"source":"`+sourcePath+`"}`) _ = a.sync.RecordOp(syncsvc.EntityFile, n.ID, syncsvc.OpCreate, a.filePayload(&n)) } return toNodeDTOs(nodes), nil } func (a *App) DeleteFileOrFolder(nodeID string) error { n, err := a.nodes.GetActive(nodeID) if err == nil { pid := "" if n.ParentID != nil { pid = *n.ParentID } evType := activity.TypeFileDeleted targetType := activity.TargetFile if n.Type == nodes.TypeFolder { evType = activity.TypeFolderDeleted targetType = activity.TargetFolder } _ = a.activity.Record(pid, targetType, nodeID, "", evType, n.Title, "") syncEntity := syncsvc.EntityFile if n.Type == nodes.TypeFolder { syncEntity = syncsvc.EntityFolder } _ = a.sync.RecordOp(syncEntity, nodeID, syncsvc.OpDelete, nil) } return a.files.DeleteNodeAndChildren(nodeID) } func (a *App) CreateEmptyFile(parentID, filename string) (*NodeDTO, error) { node, err := a.files.CreateEmptyFile(parentID, filename) if err != nil { return nil, err } _ = a.activity.Record(parentID, activity.TargetFile, node.ID, "", activity.TypeFileAdded, filename, "") _ = a.sync.RecordOp(syncsvc.EntityFile, node.ID, syncsvc.OpCreate, a.filePayload(node)) dto := toNodeDTO(node) return &dto, nil } func (a *App) DuplicateNode(nodeID string) (*NodeDTO, error) { node, err := a.files.Duplicate(nodeID) if err != nil { return nil, err } n, err2 := a.nodes.GetActive(nodeID) pid := "" if err2 == nil && n.ParentID != nil { pid = *n.ParentID } _ = a.activity.Record(pid, activity.TargetFile, node.ID, "", activity.TypeFileCopied, node.Title, "") _ = a.sync.RecordOp(syncsvc.EntityFile, node.ID, syncsvc.OpCreate, a.filePayload(node)) dto := toNodeDTO(node) return &dto, nil } func (a *App) ValidateName(name string) error { return files.ValidateName(name) } func (a *App) PreviewImport(sourcePath string) (*files.ImportSummary, error) { return a.files.PreviewImport(sourcePath) }