mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
feat(groups): host-based forge sources with optional display name
- forgeSources entries are now { host, type, name? }: the repository URL's
hostname is matched case-insensitively against host (github.com for GitHub,
distinct hosts for multiple Gitea instances); the footer label is the
optional name, falling back to the host
- GroupEditor renders one row per source: host input + type select + optional
display name (grid layout); hostname validation mirrors the server
- fix: apiFetch sends Content-Type: application/json — h3's readBody only
parses JSON bodies with that header, so every PUT/POST from the refactored
console arrived as a raw string and failed with 'groups must be an array'
- hardening: readJsonBody (admin + actions) JSON-parses string bodies so curl
and older clients without the content-type header still work
- regression test: groups PUT without content-type + forgeSources round-trip
- docs: groups.md/message-format.md (en/zh), AGENTS.md, config.example.yaml
This commit is contained in:
parent
17d10db845
commit
3f6f7f17b5
19 changed files with 469 additions and 108 deletions
|
|
@ -1,5 +1,10 @@
|
|||
import { describe, it, expect } from "bun:test";
|
||||
import { adminGroupRename, adminGroupRoutesGet, adminApiMe } from "../server/lib/web/admin";
|
||||
import {
|
||||
adminGroupRename,
|
||||
adminGroupRoutesGet,
|
||||
adminApiGroupsPut,
|
||||
adminApiMe,
|
||||
} from "../server/lib/web/admin";
|
||||
import { createAdminSession, adminCookie } from "../server/lib/web/session";
|
||||
import { loadGroups } from "../server/lib/web/groups";
|
||||
import { loadRoutes } from "../server/lib/config";
|
||||
|
|
@ -116,6 +121,46 @@ describe("admin handlers (h3)", () => {
|
|||
expect(await listInvites(kv, "old-team")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("accepts a groups PUT without the application/json content-type", async () => {
|
||||
const kv = createMockKV();
|
||||
await kv.put(
|
||||
"config:groups",
|
||||
JSON.stringify([
|
||||
{ id: "team", name: "Team", adminIds: [], members: [{ login: "alice", role: "owner" }] },
|
||||
]),
|
||||
);
|
||||
const env = createEnv({ KV: kv });
|
||||
const sessionId = await createAdminSession(kv, "1001", "alice");
|
||||
|
||||
// The console's fetch helper always declares application/json, but curl
|
||||
// and older clients may omit it — h3's readBody then returns the raw
|
||||
// string, which used to fail validation with "groups must be an array".
|
||||
const event = makeEvent("/api/groups", {
|
||||
method: "PUT",
|
||||
headers: { cookie: adminCookie(sessionId) },
|
||||
body: JSON.stringify({
|
||||
groups: [
|
||||
{
|
||||
id: "team",
|
||||
name: "Team",
|
||||
adminIds: [],
|
||||
members: [{ login: "alice", role: "owner" }],
|
||||
forgeSources: [{ host: "git.example.com", type: "gitea", name: "内网 Gitea" }],
|
||||
},
|
||||
],
|
||||
}),
|
||||
env,
|
||||
});
|
||||
const result = (await adminApiGroupsPut(event)) as { ok?: boolean };
|
||||
expect(responseStatus(event)).toBe(200);
|
||||
expect(result.ok).toBe(true);
|
||||
const groups = await loadGroups(kv);
|
||||
expect(groups).toHaveLength(1);
|
||||
expect(groups[0]!.forgeSources).toEqual([
|
||||
{ host: "git.example.com", type: "gitea", name: "内网 Gitea" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("forbids non-owner members from renaming", async () => {
|
||||
const kv = createMockKV();
|
||||
await kv.put(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue