Format the repository with Prettier
CI has been running `prettier --check` against a tree that was never formatted, so the check reported 63 files and failed every run. Nothing here is a behaviour change: `pnpm lint` and the four typecheck builds pass exactly as before. conduit-bringup-artifacts is added to .prettierignore instead. Those files are captured bring-up reports, not maintained sources; reflowing them would only churn a record of what happened.
This commit is contained in:
@@ -174,104 +174,117 @@ export default async function organizationRoutes(app: FastifyInstance) {
|
||||
});
|
||||
|
||||
// POST /api/organizations/:orgId/members — invite by email
|
||||
app.post('/:orgId/members', { schema: { ...OrgIdParamSchema, ...AddMemberSchema } }, async (request, reply) => {
|
||||
const { orgId } = request.params as { orgId: string };
|
||||
await requirePermission(request, orgId, 'org.members');
|
||||
app.post(
|
||||
'/:orgId/members',
|
||||
{ schema: { ...OrgIdParamSchema, ...AddMemberSchema } },
|
||||
async (request, reply) => {
|
||||
const { orgId } = request.params as { orgId: string };
|
||||
await requirePermission(request, orgId, 'org.members');
|
||||
|
||||
const { email, role } = request.body as { email: string; role: 'admin' | 'user' };
|
||||
const { email, role } = request.body as { email: string; role: 'admin' | 'user' };
|
||||
|
||||
const user = await app.db.query.users.findFirst({
|
||||
where: eq(users.email, email),
|
||||
});
|
||||
if (!user) throw AppError.notFound('User with this email not found');
|
||||
const user = await app.db.query.users.findFirst({
|
||||
where: eq(users.email, email),
|
||||
});
|
||||
if (!user) throw AppError.notFound('User with this email not found');
|
||||
|
||||
const existing = await app.db.query.organizationMembers.findFirst({
|
||||
where: and(
|
||||
eq(organizationMembers.organizationId, orgId),
|
||||
eq(organizationMembers.userId, user.id),
|
||||
),
|
||||
});
|
||||
if (existing) throw AppError.conflict('User is already a member');
|
||||
const existing = await app.db.query.organizationMembers.findFirst({
|
||||
where: and(
|
||||
eq(organizationMembers.organizationId, orgId),
|
||||
eq(organizationMembers.userId, user.id),
|
||||
),
|
||||
});
|
||||
if (existing) throw AppError.conflict('User is already a member');
|
||||
|
||||
const [member] = await app.db
|
||||
.insert(organizationMembers)
|
||||
.values({
|
||||
const [member] = await app.db
|
||||
.insert(organizationMembers)
|
||||
.values({
|
||||
organizationId: orgId,
|
||||
userId: user.id,
|
||||
role,
|
||||
})
|
||||
.returning();
|
||||
|
||||
await createAuditLog(app.db, request, {
|
||||
organizationId: orgId,
|
||||
userId: user.id,
|
||||
role,
|
||||
})
|
||||
.returning();
|
||||
action: 'member.add',
|
||||
metadata: { userId: user.id, email, role },
|
||||
});
|
||||
|
||||
await createAuditLog(app.db, request, {
|
||||
organizationId: orgId,
|
||||
action: 'member.add',
|
||||
metadata: { userId: user.id, email, role },
|
||||
});
|
||||
|
||||
return reply.code(201).send(member);
|
||||
});
|
||||
return reply.code(201).send(member);
|
||||
},
|
||||
);
|
||||
|
||||
// PATCH /api/organizations/:orgId/members/:memberId
|
||||
app.patch('/:orgId/members/:memberId', { schema: { ...MemberIdParamSchema, ...UpdateMemberSchema } }, async (request) => {
|
||||
const { orgId, memberId } = request.params as { orgId: string; memberId: string };
|
||||
await requirePermission(request, orgId, 'org.members');
|
||||
app.patch(
|
||||
'/:orgId/members/:memberId',
|
||||
{ schema: { ...MemberIdParamSchema, ...UpdateMemberSchema } },
|
||||
async (request) => {
|
||||
const { orgId, memberId } = request.params as { orgId: string; memberId: string };
|
||||
await requirePermission(request, orgId, 'org.members');
|
||||
|
||||
const body = request.body as { role?: 'admin' | 'user'; customPermissions?: Record<string, boolean> };
|
||||
const body = request.body as {
|
||||
role?: 'admin' | 'user';
|
||||
customPermissions?: Record<string, boolean>;
|
||||
};
|
||||
|
||||
const [updated] = await app.db
|
||||
.update(organizationMembers)
|
||||
.set(body)
|
||||
.where(and(
|
||||
eq(organizationMembers.id, memberId),
|
||||
eq(organizationMembers.organizationId, orgId),
|
||||
))
|
||||
.returning();
|
||||
const [updated] = await app.db
|
||||
.update(organizationMembers)
|
||||
.set(body)
|
||||
.where(
|
||||
and(eq(organizationMembers.id, memberId), eq(organizationMembers.organizationId, orgId)),
|
||||
)
|
||||
.returning();
|
||||
|
||||
if (!updated) throw AppError.notFound('Member not found');
|
||||
if (!updated) throw AppError.notFound('Member not found');
|
||||
|
||||
await createAuditLog(app.db, request, {
|
||||
organizationId: orgId,
|
||||
action: 'member.update',
|
||||
metadata: { memberId, ...body },
|
||||
});
|
||||
await createAuditLog(app.db, request, {
|
||||
organizationId: orgId,
|
||||
action: 'member.update',
|
||||
metadata: { memberId, ...body },
|
||||
});
|
||||
|
||||
return updated;
|
||||
});
|
||||
return updated;
|
||||
},
|
||||
);
|
||||
|
||||
// DELETE /api/organizations/:orgId/members/:memberId
|
||||
app.delete('/:orgId/members/:memberId', { schema: MemberIdParamSchema }, async (request, reply) => {
|
||||
const { orgId, memberId } = request.params as { orgId: string; memberId: string };
|
||||
await requirePermission(request, orgId, 'org.members');
|
||||
app.delete(
|
||||
'/:orgId/members/:memberId',
|
||||
{ schema: MemberIdParamSchema },
|
||||
async (request, reply) => {
|
||||
const { orgId, memberId } = request.params as { orgId: string; memberId: string };
|
||||
await requirePermission(request, orgId, 'org.members');
|
||||
|
||||
const member = await app.db.query.organizationMembers.findFirst({
|
||||
where: and(
|
||||
eq(organizationMembers.id, memberId),
|
||||
eq(organizationMembers.organizationId, orgId),
|
||||
),
|
||||
});
|
||||
if (!member) throw AppError.notFound('Member not found');
|
||||
const member = await app.db.query.organizationMembers.findFirst({
|
||||
where: and(
|
||||
eq(organizationMembers.id, memberId),
|
||||
eq(organizationMembers.organizationId, orgId),
|
||||
),
|
||||
});
|
||||
if (!member) throw AppError.notFound('Member not found');
|
||||
|
||||
// Cannot remove org owner
|
||||
const org = await app.db.query.organizations.findFirst({
|
||||
where: eq(organizations.id, orgId),
|
||||
});
|
||||
if (org && member.userId === org.ownerId) {
|
||||
throw AppError.badRequest('Cannot remove the organization owner');
|
||||
}
|
||||
// Cannot remove org owner
|
||||
const org = await app.db.query.organizations.findFirst({
|
||||
where: eq(organizations.id, orgId),
|
||||
});
|
||||
if (org && member.userId === org.ownerId) {
|
||||
throw AppError.badRequest('Cannot remove the organization owner');
|
||||
}
|
||||
|
||||
await app.db
|
||||
.delete(organizationMembers)
|
||||
.where(and(
|
||||
eq(organizationMembers.id, memberId),
|
||||
eq(organizationMembers.organizationId, orgId),
|
||||
));
|
||||
await app.db
|
||||
.delete(organizationMembers)
|
||||
.where(
|
||||
and(eq(organizationMembers.id, memberId), eq(organizationMembers.organizationId, orgId)),
|
||||
);
|
||||
|
||||
await createAuditLog(app.db, request, {
|
||||
organizationId: orgId,
|
||||
action: 'member.remove',
|
||||
metadata: { memberId, userId: member.userId },
|
||||
});
|
||||
await createAuditLog(app.db, request, {
|
||||
organizationId: orgId,
|
||||
action: 'member.remove',
|
||||
metadata: { memberId, userId: member.userId },
|
||||
});
|
||||
|
||||
return reply.code(204).send();
|
||||
});
|
||||
return reply.code(204).send();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user