181 lines
4.7 KiB
Go
181 lines
4.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"verstak/internal/core/activity"
|
|
"verstak/internal/core/nodes"
|
|
syncsvc "verstak/internal/core/sync"
|
|
)
|
|
|
|
func (a *App) ListNodesBySection(section string) ([]NodeDTO, error) {
|
|
list, err := a.nodes.ListRoots(false, section)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return toNodeDTOs(list), nil
|
|
}
|
|
|
|
func (a *App) ListChildren(parentID string) ([]NodeDTO, error) {
|
|
list, err := a.nodes.ListChildren(parentID, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return toNodeDTOs(list), nil
|
|
}
|
|
|
|
func (a *App) GetNodeDetail(nodeID string) (*NodeDTO, error) {
|
|
n, err := a.nodes.GetActive(nodeID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dto := toNodeDTO(n)
|
|
return &dto, nil
|
|
}
|
|
|
|
func (a *App) CreateNode(parentID, nodeType, title, section string) (*NodeDTO, error) {
|
|
if section == "today" || section == "inbox" {
|
|
return nil, fmt.Errorf("cannot create node with section %q", section)
|
|
}
|
|
n, err := a.nodes.Create(parentID, nodeType, title, section)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_ = a.activity.Record(n.ID, activity.TargetNode, n.ID, "", activity.TypeNodeCreated, title, "")
|
|
_ = a.sync.RecordOp(syncsvc.EntityNode, n.ID, syncsvc.OpCreate, nodePayload(n))
|
|
dto := toNodeDTO(n)
|
|
return &dto, nil
|
|
}
|
|
|
|
func (a *App) DeleteNode(id string) error {
|
|
n, err := a.nodes.GetActive(id)
|
|
if err != nil {
|
|
return a.nodes.SoftDelete(id)
|
|
}
|
|
pid := ""
|
|
if n.ParentID != nil {
|
|
pid = *n.ParentID
|
|
}
|
|
var entity string
|
|
var targetType string
|
|
var evType string
|
|
switch n.Type {
|
|
case nodes.TypeNote:
|
|
entity = syncsvc.EntityNote
|
|
targetType = activity.TargetNote
|
|
evType = activity.TypeNoteDeleted
|
|
case nodes.TypeFolder:
|
|
entity = syncsvc.EntityFolder
|
|
targetType = activity.TargetFolder
|
|
evType = activity.TypeFolderDeleted
|
|
case nodes.TypeFile:
|
|
entity = syncsvc.EntityFile
|
|
targetType = activity.TargetFile
|
|
evType = activity.TypeFileDeleted
|
|
default:
|
|
entity = syncsvc.EntityNode
|
|
targetType = activity.TargetNode
|
|
evType = activity.TypeNodeDeleted
|
|
}
|
|
_ = a.activity.Record(pid, targetType, id, "", evType, n.Title, "")
|
|
_ = a.sync.RecordOp(entity, id, syncsvc.OpDelete, nil)
|
|
return a.nodes.SoftDelete(id)
|
|
}
|
|
|
|
func (a *App) RenameNode(nodeID, newTitle string) error {
|
|
n, err := a.nodes.GetActive(nodeID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
oldTitle := n.Title
|
|
if err := a.nodes.UpdateTitle(nodeID, newTitle); err != nil {
|
|
return err
|
|
}
|
|
pid := ""
|
|
if n.ParentID != nil {
|
|
pid = *n.ParentID
|
|
}
|
|
var evType string
|
|
var targetType string
|
|
var syncEntity string
|
|
switch n.Type {
|
|
case nodes.TypeNote:
|
|
evType = activity.TypeNoteUpdated
|
|
targetType = activity.TargetNote
|
|
syncEntity = syncsvc.EntityNote
|
|
case nodes.TypeFile:
|
|
evType = activity.TypeFileRenamed
|
|
targetType = activity.TargetFile
|
|
syncEntity = syncsvc.EntityFile
|
|
case nodes.TypeFolder:
|
|
evType = activity.TypeFolderRenamed
|
|
targetType = activity.TargetFolder
|
|
syncEntity = syncsvc.EntityFolder
|
|
default:
|
|
evType = activity.TypeNodeUpdated
|
|
targetType = activity.TargetNode
|
|
syncEntity = syncsvc.EntityNode
|
|
}
|
|
_ = a.activity.Record(pid, targetType, nodeID, "", evType, newTitle, `{"from":"`+oldTitle+`","to":"`+newTitle+`"}`)
|
|
_ = a.sync.RecordOp(syncEntity, nodeID, syncsvc.OpUpdate, map[string]interface{}{
|
|
"title": newTitle,
|
|
"updated_at": time.Now().UTC().Format(time.RFC3339),
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (a *App) MoveNode(nodeID, newParentID string) error {
|
|
destChildren, err := a.nodes.ListChildren(newParentID, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
node, err := a.nodes.GetActive(nodeID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for i := range destChildren {
|
|
if destChildren[i].Title == node.Title {
|
|
newName := a.files.UniqueTitleCopy(newParentID, node.Title)
|
|
if err := a.nodes.UpdateTitle(nodeID, newName); err != nil {
|
|
return err
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if err := a.nodes.Move(nodeID, newParentID, 0); err != nil {
|
|
return err
|
|
}
|
|
pid := ""
|
|
if node.ParentID != nil {
|
|
pid = *node.ParentID
|
|
}
|
|
var targetType string
|
|
var evType string
|
|
var syncEntity string
|
|
switch node.Type {
|
|
case nodes.TypeNote:
|
|
targetType = activity.TargetNote
|
|
evType = activity.TypeNoteUpdated
|
|
syncEntity = syncsvc.EntityNote
|
|
case nodes.TypeFile:
|
|
targetType = activity.TargetFile
|
|
evType = activity.TypeFileMoved
|
|
syncEntity = syncsvc.EntityFile
|
|
case nodes.TypeFolder:
|
|
targetType = activity.TargetFolder
|
|
evType = activity.TypeFolderMoved
|
|
syncEntity = syncsvc.EntityFolder
|
|
default:
|
|
targetType = activity.TargetNode
|
|
evType = activity.TypeNodeUpdated
|
|
syncEntity = syncsvc.EntityNode
|
|
}
|
|
_ = a.activity.Record(pid, targetType, nodeID, "", evType, node.Title, `{"to":"`+newParentID+`"}`)
|
|
_ = a.sync.RecordOp(syncEntity, nodeID, syncsvc.OpMove, map[string]interface{}{
|
|
"parent_id": newParentID,
|
|
"updated_at": time.Now().UTC().Format(time.RFC3339),
|
|
})
|
|
return nil
|
|
}
|