forked from EduCraft/curriculum-project-hub
fix(admin): let project MANAGE holders list teams for grants
GET /teams was org-admin only while team-access mutations require project MANAGE, so members with MANAGE saw an empty grant picker. Open the read-only team list to any org member and load it in the project page whenever the actor can manage the project.
This commit is contained in:
@@ -45,22 +45,19 @@
|
|||||||
const [p, a] = await Promise.all([api.project(slug, projectId), api.teamAccess(slug, projectId)]);
|
const [p, a] = await Promise.all([api.project(slug, projectId), api.teamAccess(slug, projectId)]);
|
||||||
proj = p;
|
proj = p;
|
||||||
access = a.access;
|
access = a.access;
|
||||||
// Org-admin-only oversight sub-resources: sessions/teams/explorer are
|
// Team list is needed for grant UI whenever the actor has project MANAGE
|
||||||
// not available to member-level project MANAGE holders.
|
// (org admin or member). Sessions/explorer stay org-admin oversight only.
|
||||||
if (p.actorIsOrgAdmin) {
|
const needTeams = p.actorIsOrgAdmin === true || p.actorCanManageProject === true;
|
||||||
const [s, t, e] = await Promise.all([
|
const [s, t, e] = await Promise.all([
|
||||||
api.sessions(slug, projectId),
|
p.actorIsOrgAdmin ? api.sessions(slug, projectId) : Promise.resolve({ sessions: [] as SessionSummary[] }),
|
||||||
api.teams(slug),
|
needTeams ? api.teams(slug) : Promise.resolve({ teams: [] as TeamRow[] }),
|
||||||
api.explorer(slug),
|
p.actorIsOrgAdmin ? api.explorer(slug) : Promise.resolve(null as ExplorerData | null),
|
||||||
]);
|
]);
|
||||||
sessions = s.sessions;
|
sessions = s.sessions;
|
||||||
teams = t.teams;
|
teams = t.teams;
|
||||||
explorer = e;
|
explorer = e;
|
||||||
|
if (p.actorIsOrgAdmin) {
|
||||||
moveFolder = p.folderId ?? '';
|
moveFolder = p.folderId ?? '';
|
||||||
} else {
|
|
||||||
sessions = [];
|
|
||||||
teams = [];
|
|
||||||
explorer = null;
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err instanceof Error ? err.message : String(err);
|
error = err instanceof Error ? err.message : String(err);
|
||||||
|
|||||||
@@ -18,10 +18,16 @@ export async function registerTeamsRoutes(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const guardDeps: GuardDeps = { prisma: config.prisma, sessionSecret: config.sessionSecret };
|
const guardDeps: GuardDeps = { prisma: config.prisma, sessionSecret: config.sessionSecret };
|
||||||
|
|
||||||
|
// Read-only listing is open to any active org member so project MANAGE
|
||||||
|
// holders can pick a team when granting TEAM→PROJECT access (ADR-0004).
|
||||||
|
// Mutations below stay org-admin only.
|
||||||
app.get("/api/org/:orgSlug/teams", async (request, reply) => {
|
app.get("/api/org/:orgSlug/teams", async (request, reply) => {
|
||||||
try {
|
try {
|
||||||
const { orgSlug } = request.params as { orgSlug: string };
|
const { orgSlug } = request.params as { orgSlug: string };
|
||||||
const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
|
const auth = await requireOrgRole(request, reply, guardDeps, {
|
||||||
|
orgSlug,
|
||||||
|
roles: ["OWNER", "ADMIN", "MEMBER"],
|
||||||
|
});
|
||||||
if (auth === null) return;
|
if (auth === null) return;
|
||||||
return { teams: await listOrgTeams(config.prisma, auth.organization.id) };
|
return { teams: await listOrgTeams(config.prisma, auth.organization.id) };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user