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,104 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"task/internal/sqlite"
|
||||
)
|
||||
|
||||
func TestProjectTokenBearerAuth(t *testing.T) {
|
||||
db, err := sqlite.Open(filepath.Join(t.TempDir(), "t.db"), []byte("secret"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
admin, err := db.CreateUser("admin", "pass", true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srv := New(db)
|
||||
handler := srv.Handler()
|
||||
|
||||
loginBody, _ := json.Marshal(map[string]string{"username": "admin", "password": "pass"})
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader(loginBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
cookie := rec.Result().Cookies()[0]
|
||||
|
||||
createBody, _ := json.Marshal(map[string]string{"name": "Demo"})
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/v1/projects", bytes.NewReader(createBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.AddCookie(cookie)
|
||||
rec = httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
var proj map[string]any
|
||||
_ = json.Unmarshal(rec.Body.Bytes(), &proj)
|
||||
pid := proj["id"].(string)
|
||||
|
||||
tokBody, _ := json.Marshal(map[string]string{"name": "tui", "scope": "write"})
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/v1/projects/"+pid+"/tokens", bytes.NewReader(tokBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.AddCookie(cookie)
|
||||
rec = httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Fatalf("create token %d %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var tok map[string]any
|
||||
_ = json.Unmarshal(rec.Body.Bytes(), &tok)
|
||||
raw := tok["token"].(string)
|
||||
if raw == "" {
|
||||
t.Fatal("expected raw token")
|
||||
}
|
||||
|
||||
ticketBody, _ := json.Marshal(map[string]string{"title": "Via token"})
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/v1/projects/"+pid+"/tickets", bytes.NewReader(ticketBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+raw)
|
||||
rec = httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusCreated {
|
||||
t.Fatalf("bearer create ticket %d %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
req = httptest.NewRequest(http.MethodGet, "/api/v1/projects/"+pid+"/tickets", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+raw)
|
||||
rec = httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("bearer list %d", rec.Code)
|
||||
}
|
||||
|
||||
// delete other user
|
||||
_, _ = db.CreateUser("bob", "x", false)
|
||||
users, _ := db.ListUsers()
|
||||
var bobID string
|
||||
for _, u := range users {
|
||||
if u.Username == "bob" {
|
||||
bobID = u.ID
|
||||
}
|
||||
}
|
||||
req = httptest.NewRequest(http.MethodDelete, "/api/v1/users/"+bobID, nil)
|
||||
req.AddCookie(cookie)
|
||||
rec = httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("delete user %d %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
patch, _ := json.Marshal(map[string]bool{"isAdmin": false})
|
||||
req = httptest.NewRequest(http.MethodPatch, "/api/v1/users/"+admin.ID, bytes.NewReader(patch))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.AddCookie(cookie)
|
||||
rec = httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, req)
|
||||
if rec.Code == http.StatusOK {
|
||||
t.Fatal("should not demote self")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user