package web import ( "context" "io" "log/slog" "net/http" "net/url" "strings" "testing" "time" "gitea.mynodes.xyz/ilker/llmgw/internal/store" ) // fakeOrgEditor is fakeOrgs that also changes: u1 administers Acme, u4 // manages it, and what each change did is written down. type fakeOrgEditor struct { fakeOrgs admins map[string]string // org -> admin user id did []string revoked []string } func (f *fakeOrgEditor) ManagesOrg(_ context.Context, user, org string) (bool, error) { return f.admins[org] == user || f.managers[org] == user, nil } func (f *fakeOrgEditor) ManagedOrgs(ctx context.Context, user string) ([]store.Org, error) { var out []store.Org for _, o := range []store.Org{{ID: "org-a", Name: "Acme"}, {ID: "org-s", Name: "Scania"}} { if ok, _ := f.ManagesOrg(ctx, user, o.ID); ok { out = append(out, o) } } return out, nil } func (f *fakeOrgEditor) AdministersOrg(_ context.Context, user, org string) (bool, error) { return f.admins[org] == user, nil } func (f *fakeOrgEditor) UserByEmail(_ context.Context, email string) (store.User, error) { switch email { case "new@acme": return store.User{ID: "u5", Email: email, State: store.UserActive}, nil case "waiting@acme": return store.User{ID: "u6", Email: email, State: store.UserPending}, nil } return store.User{}, store.ErrNotFound } func (f *fakeOrgEditor) CreateTeam(_ context.Context, org, name string) (string, error) { f.did = append(f.did, "team "+org+" "+name) return "t9", nil } func (f *fakeOrgEditor) CreateProject(_ context.Context, team, name string) (string, error) { f.did = append(f.did, "project "+team+" "+name) return "p9", nil } func (f *fakeOrgEditor) RenameTeam(_ context.Context, id, name string) error { f.did = append(f.did, "rename team "+id+" "+name) return nil } func (f *fakeOrgEditor) RenameProject(_ context.Context, id, name string) error { f.did = append(f.did, "rename project "+id+" "+name) return nil } func (f *fakeOrgEditor) DeleteTeam(_ context.Context, id string) error { f.did = append(f.did, "delete team "+id) return nil } func (f *fakeOrgEditor) DeleteProject(_ context.Context, id string) error { f.did = append(f.did, "delete project "+id) return nil } func (f *fakeOrgEditor) AddMembership(_ context.Context, user string, scope store.Scope, id, role, _ string, _ time.Time) error { f.did = append(f.did, "join "+user+" "+string(scope)+":"+id+" "+role) return nil } func (f *fakeOrgEditor) RemoveMembership(_ context.Context, user string, scope store.Scope, id string, _ time.Time) (int, error) { f.did = append(f.did, "leave "+user+" "+string(scope)+":"+id) return 0, nil } func (f *fakeOrgEditor) AllKeys(context.Context) ([]store.KeyRow, error) { return []store.KeyRow{ {Key: store.Key{ID: "k-acme", Prefix: "sk-a", ProjectID: "p1"}, ProjectPath: "Acme / ml / training"}, {Key: store.Key{ID: "k-scania", Prefix: "sk-s", ProjectID: "p-s"}}, }, nil } func (f *fakeOrgEditor) RevokeKey(_ context.Context, id string, _ time.Time) error { f.revoked = append(f.revoked, id) return nil } func orgAdminPage(t *testing.T, user store.User) (*http.ServeMux, *fakeOrgEditor) { t.Helper() f := &fakeOrgEditor{ fakeOrgs: fakeOrgs{managers: map[string]string{"org-a": "u4"}}, admins: map[string]string{"org-a": "u1"}, } p := NewAccountPages(fakeAccounts{user: user}, nil, nil, "v0", slog.New(slog.NewTextHandler(io.Discard, nil))) mux := http.NewServeMux() p.RegisterOrgPages(mux, f, nil) return mux, f } func form(kv ...string) url.Values { v := url.Values{"csrf": {"tok"}} for i := 0; i+1 < len(kv); i += 2 { v.Set(kv[i], kv[i+1]) } return v } func TestAnOrganizationsAdminIsGivenTheFormsAndAManagerIsNot(t *testing.T) { admin, _ := orgAdminPage(t, store.User{ID: "u1", Email: "boss@acme"}) body := mirrorGet(t, admin, "/org/org-a").Body.String() for _, want := range []string{`action="/org/org-a/teams"`, `action="/org/org-a/members"`, `action="/org/org-a/keys/k-acme/revoke"`, "sk-a"} { if !strings.Contains(body, want) { t.Errorf("the admin's page lacks %q", want) } } if strings.Contains(body, "k-scania") { t.Error("a key of another organization is on the page") } manager, f := orgAdminPage(t, store.User{ID: "u4", Email: "watch@acme"}) w := mirrorGet(t, manager, "/org/org-a") if w.Code != http.StatusOK { t.Fatalf("the manager lost their page: %d", w.Code) } if strings.Contains(w.Body.String(), "