Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `wa_user_created` PostHog event fired on successful user sign-up. [#933](https://github.com/sourcebot-dev/sourcebot/pull/933)
- Added `wa_askgh_login_wall_prompted` PostHog event fired when an unauthenticated user attempts to ask a question on Ask GitHub. [#933](https://github.com/sourcebot-dev/sourcebot/pull/933)
- Added Bitbucket Server (Data Center) OAuth 2.0 SSO identity provider support (`provider: "bitbucket-server"`). [#934](https://github.com/sourcebot-dev/sourcebot/pull/934)
- Added `GET /api/ee/user` endpoint that returns the authenticated owner's user info (name, email, createdAt, updatedAt). [#940](https://github.com/sourcebot-dev/sourcebot/pull/940)

### Changed
- Hide version upgrade toast for askgithub deployment (`EXPERIMENT_ASK_GH_ENABLED`). [#931](https://github.com/sourcebot-dev/sourcebot/pull/931)
Expand Down
5 changes: 4 additions & 1 deletion packages/shared/src/entitlements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ const entitlements = [
"analytics",
"permission-syncing",
"github-app",
"chat-sharing"
"chat-sharing",
"org-management"
] as const;
export type Entitlement = (typeof entitlements)[number];

Expand All @@ -56,6 +57,7 @@ const entitlementsByPlan: Record<Plan, Entitlement[]> = {
"permission-syncing",
"github-app",
"chat-sharing",
"org-management",
],
"self-hosted:enterprise-unlimited": [
"anonymous-access",
Expand All @@ -67,6 +69,7 @@ const entitlementsByPlan: Record<Plan, Entitlement[]> = {
"permission-syncing",
"github-app",
"chat-sharing",
"org-management",
],
} as const;

Expand Down
65 changes: 64 additions & 1 deletion packages/web/src/app/api/(server)/ee/user/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,76 @@ import { serviceErrorResponse, missingQueryParam, notFound } from "@/lib/service
import { isServiceError } from "@/lib/utils";
import { withAuthV2, withMinimumOrgRole } from "@/withAuthV2";
import { OrgRole } from "@sourcebot/db";
import { createLogger } from "@sourcebot/shared";
import { createLogger, hasEntitlement } from "@sourcebot/shared";
import { StatusCodes } from "http-status-codes";
import { NextRequest } from "next/server";

const logger = createLogger('ee-user-api');
const auditService = getAuditService();

export const GET = apiHandler(async (request: NextRequest) => {
if (!hasEntitlement('org-management')) {
return serviceErrorResponse({
statusCode: StatusCodes.FORBIDDEN,
errorCode: ErrorCode.INSUFFICIENT_PERMISSIONS,
message: "Organization management is not enabled for your license",
});
}

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, prisma }) => {
return withMinimumOrgRole(role, OrgRole.OWNER, async () => {
try {
const userData = await prisma.user.findUnique({
where: {
id: userId,
},
select: {
name: true,
email: true,
createdAt: true,
updatedAt: true,
},
});

if (!userData) {
return notFound('User not found');
}
Comment thread
msukkari marked this conversation as resolved.

await auditService.createAudit({
action: "user.read",
actor: {
id: user.id,
type: "user"
},
target: {
id: userId,
type: "user"
},
orgId: org.id,
});

return userData;
} catch (error) {
logger.error('Error fetching user info', { error, userId });
throw error;
}
});
});

if (isServiceError(result)) {
return serviceErrorResponse(result);
}

return Response.json(result, { status: StatusCodes.OK });
});

export const DELETE = apiHandler(async (request: NextRequest) => {
const url = new URL(request.url);
const userId = url.searchParams.get('userId');
Expand Down
12 changes: 11 additions & 1 deletion packages/web/src/app/api/(server)/ee/users/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,22 @@ import { serviceErrorResponse } from "@/lib/serviceError";
import { isServiceError } from "@/lib/utils";
import { withAuthV2, withMinimumOrgRole } from "@/withAuthV2";
import { OrgRole } from "@sourcebot/db";
import { createLogger } from "@sourcebot/shared";
import { createLogger, hasEntitlement } from "@sourcebot/shared";
import { StatusCodes } from "http-status-codes";
import { ErrorCode } from "@/lib/errorCodes";

const logger = createLogger('ee-users-api');
const auditService = getAuditService();

export const GET = apiHandler(async () => {
if (!hasEntitlement('org-management')) {
return serviceErrorResponse({
statusCode: StatusCodes.FORBIDDEN,
errorCode: ErrorCode.INSUFFICIENT_PERMISSIONS,
message: "Organization management is not enabled for your license",
});
}

const result = await withAuthV2(async ({ prisma, org, role, user }) => {
return withMinimumOrgRole(role, OrgRole.OWNER, async () => {
try {
Expand Down