mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
add get users and delete user endpoints
This commit is contained in:
parent
5b1caae854
commit
10969707bc
2 changed files with 174 additions and 0 deletions
93
packages/web/src/app/api/(server)/ee/user/route.ts
Normal file
93
packages/web/src/app/api/(server)/ee/user/route.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
'use server';
|
||||||
|
|
||||||
|
import { withAuthV2, withMinimumOrgRole } from "@/withAuthV2";
|
||||||
|
import { OrgRole } from "@sourcebot/db";
|
||||||
|
import { isServiceError } from "@/lib/utils";
|
||||||
|
import { serviceErrorResponse, missingQueryParam, notFound } from "@/lib/serviceError";
|
||||||
|
import { createLogger } from "@sourcebot/logger";
|
||||||
|
import { NextRequest } from "next/server";
|
||||||
|
import { StatusCodes } from "http-status-codes";
|
||||||
|
import { ErrorCode } from "@/lib/errorCodes";
|
||||||
|
import { getAuditService } from "@/ee/features/audit/factory";
|
||||||
|
|
||||||
|
const logger = createLogger('ee-user-api');
|
||||||
|
const auditService = getAuditService();
|
||||||
|
|
||||||
|
export const DELETE = async (request: NextRequest) => {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const userId = url.searchParams.get('userId');
|
||||||
|
|
||||||
|
if (!userId) {
|
||||||
|
return serviceErrorResponse(missingQueryParam('userId'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await withAuthV2(async ({ org, role, user: currentUser, prisma }) => {
|
||||||
|
return withMinimumOrgRole(role, OrgRole.OWNER, async () => {
|
||||||
|
try {
|
||||||
|
if (currentUser.id === userId) {
|
||||||
|
return {
|
||||||
|
statusCode: StatusCodes.BAD_REQUEST,
|
||||||
|
errorCode: ErrorCode.INVALID_REQUEST_BODY,
|
||||||
|
message: 'Cannot delete your own user account',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetUser = await prisma.user.findUnique({
|
||||||
|
where: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!targetUser) {
|
||||||
|
return notFound('User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
await auditService.createAudit({
|
||||||
|
action: "user.delete",
|
||||||
|
actor: {
|
||||||
|
id: currentUser.id,
|
||||||
|
type: "user"
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
id: userId,
|
||||||
|
type: "user"
|
||||||
|
},
|
||||||
|
orgId: org.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete the user (cascade will handle all related records)
|
||||||
|
await prisma.user.delete({
|
||||||
|
where: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info('User deleted successfully', {
|
||||||
|
deletedUserId: userId,
|
||||||
|
deletedByUserId: currentUser.id,
|
||||||
|
orgId: org.id
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'User deleted successfully'
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error deleting user', { error, userId });
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isServiceError(result)) {
|
||||||
|
return serviceErrorResponse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.json(result, { status: StatusCodes.OK });
|
||||||
|
};
|
||||||
|
|
||||||
81
packages/web/src/app/api/(server)/ee/users/route.ts
Normal file
81
packages/web/src/app/api/(server)/ee/users/route.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
'use server';
|
||||||
|
|
||||||
|
import { withAuthV2, withMinimumOrgRole } from "@/withAuthV2";
|
||||||
|
import { OrgRole } from "@sourcebot/db";
|
||||||
|
import { isServiceError } from "@/lib/utils";
|
||||||
|
import { serviceErrorResponse } from "@/lib/serviceError";
|
||||||
|
import { createLogger } from "@sourcebot/logger";
|
||||||
|
import { getAuditService } from "@/ee/features/audit/factory";
|
||||||
|
|
||||||
|
const logger = createLogger('ee-users-api');
|
||||||
|
const auditService = getAuditService();
|
||||||
|
|
||||||
|
export const GET = async () => {
|
||||||
|
const result = await withAuthV2(async ({ prisma, org, role, user }) => {
|
||||||
|
return withMinimumOrgRole(role, OrgRole.OWNER, async () => {
|
||||||
|
try {
|
||||||
|
const memberships = await prisma.userToOrg.findMany({
|
||||||
|
where: {
|
||||||
|
orgId: org.id,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
user: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const usersWithActivity = await Promise.all(
|
||||||
|
memberships.map(async (membership) => {
|
||||||
|
const lastActivity = await prisma.audit.findFirst({
|
||||||
|
where: {
|
||||||
|
actorId: membership.user.id,
|
||||||
|
actorType: 'user',
|
||||||
|
orgId: org.id,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
timestamp: 'desc',
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
timestamp: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: membership.user.id,
|
||||||
|
name: membership.user.name,
|
||||||
|
email: membership.user.email,
|
||||||
|
role: membership.role,
|
||||||
|
createdAt: membership.user.createdAt,
|
||||||
|
lastActivityAt: lastActivity?.timestamp ?? null,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
await auditService.createAudit({
|
||||||
|
action: "user.list",
|
||||||
|
actor: {
|
||||||
|
id: user.id,
|
||||||
|
type: "user"
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
id: org.id.toString(),
|
||||||
|
type: "org"
|
||||||
|
},
|
||||||
|
orgId: org.id
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.info('Fetched users list', { count: usersWithActivity.length });
|
||||||
|
return usersWithActivity;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error fetching users', { error });
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isServiceError(result)) {
|
||||||
|
return serviceErrorResponse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.json(result);
|
||||||
|
};
|
||||||
|
|
||||||
Loading…
Reference in a new issue