Add tm_server with SQLite, Svelte UI, and task-master TUI sync.
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>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"task/internal/ticket"
|
||||
)
|
||||
|
||||
func TestStoresRoundTrip(t *testing.T) {
|
||||
db, err := Open(filepath.Join(t.TempDir(), "test.db"), []byte("test-secret"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
ps := NewProjectStore(db)
|
||||
if err := ps.Ensure("inbox"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ts := NewTicketStore(db)
|
||||
created, err := ts.Create(ticket.Ticket{Title: "Hello", ProjectID: "inbox", Status: ticket.StatusTodo})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := ts.Get(created.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.Title != "Hello" {
|
||||
t.Fatalf("title=%q", got.Title)
|
||||
}
|
||||
got.Title = "Updated"
|
||||
if err := ts.Update(got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ts.MarkSynced(got.ID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
synced, _ := ts.Get(got.ID)
|
||||
if synced.SyncedAt.IsZero() || !synced.SyncedAt.Equal(synced.UpdatedAt) {
|
||||
t.Fatalf("syncedAt=%v updatedAt=%v", synced.SyncedAt, synced.UpdatedAt)
|
||||
}
|
||||
|
||||
timeStore := NewTimeStore(db)
|
||||
_, err = timeStore.Create(ticket.TimeEntry{
|
||||
TicketID: created.ID,
|
||||
ProjectID: "inbox",
|
||||
Duration: time.Hour,
|
||||
Source: ticket.SourceManual,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sum, err := timeStore.SumByTicket(created.ID)
|
||||
if err != nil || sum != time.Hour {
|
||||
t.Fatalf("sum=%v err=%v", sum, err)
|
||||
}
|
||||
|
||||
u, err := db.CreateUser("admin", "secret", true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
token, _, err := db.CreateSession(u.ID, time.Hour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
me, err := db.UserFromSession(token)
|
||||
if err != nil || me.Username != "admin" {
|
||||
t.Fatalf("session user=%v err=%v", me, err)
|
||||
}
|
||||
if err := db.SetMember("inbox", u.ID, RoleOwner); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
role, _ := db.MemberRole("inbox", u.ID)
|
||||
if role != RoleOwner {
|
||||
t.Fatalf("role=%s", role)
|
||||
}
|
||||
|
||||
_, err = db.AppendRevision("ticket", created.ID, "inbox", "update", u.ID, synced)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
revs, err := db.ListRevisions("ticket", created.ID)
|
||||
if err != nil || len(revs) != 1 {
|
||||
t.Fatalf("revs=%v err=%v", revs, err)
|
||||
}
|
||||
|
||||
conn, err := db.CreateConnection("YT", "youtrack", "https://yt.example", "instance", "tok-123", u.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
loaded, err := db.GetConnection(conn.ID)
|
||||
if err != nil || loaded.Token != "tok-123" {
|
||||
t.Fatalf("token=%q err=%v", loaded.Token, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user