Introduces the web backend (auth, RBAC, project tokens, revisions), YouTrack-or-taskmaster backend choice in the TUI, and a first-pass embedded Svelte UI. The frontend is functional but needs a major rework. Co-authored-by: Cursor <cursoragent@cursor.com>
73 lines
1.7 KiB
Go
73 lines
1.7 KiB
Go
package server
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"task/internal/project"
|
|
"task/internal/ticket"
|
|
)
|
|
|
|
// ImportJSONDataDir copies projects/tickets/time from a local JSON DataDir into SQLite.
|
|
func (s *Server) ImportJSONDataDir(dataDir string, ownerUserID string) error {
|
|
ps := project.NewDirStore(dataDir)
|
|
ts := ticket.NewJSONStore(dataDir)
|
|
timeStore := ticket.NewJSONTimeStore(dataDir)
|
|
|
|
projects, err := ps.List()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, p := range projects {
|
|
if err := s.Projects.Ensure(p.ID); err != nil {
|
|
return fmt.Errorf("project %s: %w", p.ID, err)
|
|
}
|
|
if ownerUserID != "" {
|
|
_ = s.DB.SetMember(p.ID, ownerUserID, "owner")
|
|
}
|
|
meta, err := ps.LoadMeta(p.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if meta.YouTrack != nil && meta.YouTrack.Configured() {
|
|
if err := s.Projects.SaveMeta(p.ID, meta); err != nil {
|
|
return fmt.Errorf("meta %s: %w", p.ID, err)
|
|
}
|
|
}
|
|
tickets, err := ts.List(p.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, t := range tickets {
|
|
if _, err := s.Tickets.Get(t.ID); err == nil {
|
|
continue // already imported
|
|
}
|
|
if _, err := s.Tickets.Create(t); err != nil {
|
|
return fmt.Errorf("ticket %s: %w", t.ID, err)
|
|
}
|
|
_, _ = s.DB.AppendRevision("ticket", t.ID, p.ID, "import", ownerUserID, t)
|
|
}
|
|
}
|
|
|
|
entries, err := timeStore.List()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
existing, _ := s.Times.List()
|
|
have := map[string]bool{}
|
|
for _, e := range existing {
|
|
have[e.ID] = true
|
|
}
|
|
for _, e := range entries {
|
|
if have[e.ID] {
|
|
continue
|
|
}
|
|
if _, err := s.Times.Create(e); err != nil {
|
|
return fmt.Errorf("time %s: %w", e.ID, err)
|
|
}
|
|
}
|
|
if active, err := timeStore.LoadActiveTimer(); err == nil && active != nil {
|
|
_ = s.Times.SaveActiveTimer(active)
|
|
}
|
|
return nil
|
|
}
|