Skip to content

Commit 37317e0

Browse files
remove concept of a GUEST user
1 parent 50f7fbd commit 37317e0

File tree

16 files changed

+94
-279
lines changed

16 files changed

+94
-279
lines changed

docs/api-reference/sourcebot-public.openapi.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,8 +1025,7 @@
10251025
"type": "string",
10261026
"enum": [
10271027
"OWNER",
1028-
"MEMBER",
1029-
"GUEST"
1028+
"MEMBER"
10301029
]
10311030
},
10321031
"createdAt": {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
Warnings:
3+
4+
- The values [GUEST] on the enum `OrgRole` will be removed. If these variants are still used in the database, this will fail.
5+
6+
*/
7+
8+
-- Remove the guest user and its membership (only holder of GUEST role)
9+
DELETE FROM "UserToOrg" WHERE "role" = 'GUEST';
10+
DELETE FROM "User" WHERE id = '1';
11+
12+
-- AlterEnum
13+
BEGIN;
14+
CREATE TYPE "OrgRole_new" AS ENUM ('OWNER', 'MEMBER');
15+
ALTER TABLE "UserToOrg" ALTER COLUMN "role" DROP DEFAULT;
16+
ALTER TABLE "UserToOrg" ALTER COLUMN "role" TYPE "OrgRole_new" USING ("role"::text::"OrgRole_new");
17+
ALTER TYPE "OrgRole" RENAME TO "OrgRole_old";
18+
ALTER TYPE "OrgRole_new" RENAME TO "OrgRole";
19+
DROP TYPE "OrgRole_old";
20+
ALTER TABLE "UserToOrg" ALTER COLUMN "role" SET DEFAULT 'MEMBER';
21+
COMMIT;

packages/db/prisma/schema.prisma

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,6 @@ model License {
311311
enum OrgRole {
312312
OWNER
313313
MEMBER
314-
GUEST
315314
}
316315

317316
model UserToOrg {

packages/web/src/actions.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -518,11 +518,6 @@ export const experimental_addGithubRepositoryByUrl = async (repositoryUrl: strin
518518
}
519519
}));
520520

521-
export const getCurrentUserRole = async (): Promise<OrgRole | ServiceError> => sew(() =>
522-
withOptionalAuth(async ({ role }) => {
523-
return role;
524-
}));
525-
526521
export const createInvites = async (emails: string[]): Promise<{ success: boolean } | ServiceError> => sew(() =>
527522
withAuth(async ({ org, user, role, prisma }) =>
528523
withMinimumOrgRole(role, OrgRole.OWNER, async () => {
@@ -762,9 +757,6 @@ export const getOrgMembers = async () => sew(() =>
762757
const members = await prisma.userToOrg.findMany({
763758
where: {
764759
orgId: org.id,
765-
role: {
766-
not: OrgRole.GUEST,
767-
}
768760
},
769761
include: {
770762
user: true,

packages/web/src/app/(app)/repos/[id]/page.tsx

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import { getCurrentUserRole } from "@/actions"
2-
import { sew } from "@/middleware/sew"
31
import { Badge } from "@/components/ui/badge"
42
import { Button } from "@/components/ui/button"
53
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
64
import { Skeleton } from "@/components/ui/skeleton"
75
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
86
import { env } from "@sourcebot/shared"
9-
import { ServiceErrorException } from "@/lib/serviceError"
10-
import { cn, getCodeHostInfoForRepo, isServiceError } from "@/lib/utils"
11-
import { withOptionalAuth } from "@/middleware/withAuth"
7+
import { cn, getCodeHostInfoForRepo } from "@/lib/utils"
8+
import { authenticatedPage, type OptionalAuthOptions } from "@/middleware/authenticatedPage"
129
import { getConfigSettings, repoMetadataSchema } from "@sourcebot/shared"
1310
import { ExternalLink, Info } from "lucide-react"
1411
import Image from "next/image"
@@ -21,11 +18,27 @@ import { RepoBranchesTable } from "../components/repoBranchesTable"
2118
import { RepoJobsTable } from "../components/repoJobsTable"
2219
import { OrgRole } from "@sourcebot/db"
2320

24-
export default async function RepoDetailPage({ params }: { params: Promise<{ id: string }> }) {
25-
const { id } = await params
26-
const repo = await getRepoWithJobs(Number.parseInt(id))
27-
if (isServiceError(repo)) {
28-
throw new ServiceErrorException(repo);
21+
type RepoDetailPageProps = {
22+
params: Promise<{ id: string }>
23+
}
24+
25+
export default authenticatedPage<RepoDetailPageProps, OptionalAuthOptions>(async ({ org, role, prisma }, props) => {
26+
const { id } = await props.params;
27+
const repo = await prisma.repo.findUnique({
28+
where: {
29+
id: Number.parseInt(id),
30+
orgId: org.id,
31+
},
32+
include: {
33+
jobs: {
34+
orderBy: {
35+
createdAt: 'desc',
36+
},
37+
},
38+
},
39+
});
40+
if (!repo) {
41+
notFound();
2942
}
3043

3144
const codeHostInfo = getCodeHostInfoForRepo({
@@ -52,11 +65,6 @@ export default async function RepoDetailPage({ params }: { params: Promise<{ id:
5265

5366
const repoMetadata = repoMetadataSchema.parse(repo.metadata);
5467

55-
const userRole = await getCurrentUserRole();
56-
if (isServiceError(userRole)) {
57-
throw new ServiceErrorException(userRole);
58-
}
59-
6068
return (
6169
<>
6270
<div className="mb-6">
@@ -180,36 +188,11 @@ export default async function RepoDetailPage({ params }: { params: Promise<{ id:
180188
<RepoJobsTable
181189
data={repo.jobs}
182190
repoId={repo.id}
183-
isIndexButtonVisible={userRole === OrgRole.OWNER}
191+
isIndexButtonVisible={role === OrgRole.OWNER}
184192
/>
185193
</Suspense>
186194
</CardContent>
187195
</Card>
188196
</>
189-
)
190-
}
191-
192-
const getRepoWithJobs = async (repoId: number) => sew(() =>
193-
withOptionalAuth(async ({ prisma, org }) => {
194-
195-
const repo = await prisma.repo.findUnique({
196-
where: {
197-
id: repoId,
198-
orgId: org.id,
199-
},
200-
include: {
201-
jobs: {
202-
orderBy: {
203-
createdAt: 'desc'
204-
},
205-
}
206-
},
207-
});
208-
209-
if (!repo) {
210-
return notFound();
211-
}
212-
213-
return repo;
214-
})
215-
);
197+
);
198+
}, { allowAnonymous: true });

packages/web/src/app/api/(server)/ee/chat/[chatId]/searchMembers/route.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { apiHandler } from "@/lib/apiHandler";
2-
import { SOURCEBOT_GUEST_USER_ID } from "@/lib/constants";
32
import { ErrorCode } from "@/lib/errorCodes";
43
import { notFound, queryParamsSchemaValidationError, serviceErrorResponse } from "@/lib/serviceError";
54
import { isServiceError } from "@/lib/utils";
@@ -95,8 +94,6 @@ export const GET = apiHandler(async (
9594
const excludeUserIds = new Set([
9695
// Exclude the owner
9796
user.id,
98-
// ... and the guest user
99-
SOURCEBOT_GUEST_USER_ID,
10097
// ... as well as any existing
10198
...sharedWithUsers.map((s) => s.userId),
10299
]);

packages/web/src/ee/features/lighthouse/actions.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ export const createCheckoutSession = async (successUrl: string, cancelUrl: strin
100100
const memberCount = await prisma.userToOrg.count({
101101
where: {
102102
orgId: org.id,
103-
role: { not: "GUEST" },
104103
},
105104
});
106105

packages/web/src/ee/features/lighthouse/servicePing.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SINGLE_TENANT_ORG_ID, SOURCEBOT_GUEST_USER_ID } from "@/lib/constants";
1+
import { SINGLE_TENANT_ORG_ID } from "@/lib/constants";
22
import { isServiceError } from "@/lib/utils";
33
import { __unsafePrisma } from "@/prisma";
44
import { createLogger, decryptActivationCode, env, SOURCEBOT_VERSION } from "@sourcebot/shared";
@@ -18,9 +18,6 @@ export const syncWithLighthouse = async (orgId: number) => {
1818
const userCount = await __unsafePrisma.userToOrg.count({
1919
where: {
2020
orgId,
21-
userId: {
22-
not: SOURCEBOT_GUEST_USER_ID,
23-
}
2421
},
2522
});
2623

packages/web/src/initialize.ts

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,15 @@
1-
import { createGuestUser } from '@/lib/authUtils';
21
import { __unsafePrisma } from "@/prisma";
32
import { startServicePingCronJob } from '@/ee/features/lighthouse/servicePing';
4-
import { OrgRole } from '@sourcebot/db';
53
import { createLogger, env, loadConfig } from "@sourcebot/shared";
64
import { hasEntitlement } from '@/lib/entitlements';
7-
import { SINGLE_TENANT_ORG_ID, SOURCEBOT_GUEST_USER_ID } from './lib/constants';
8-
import { ServiceErrorException } from './lib/serviceError';
9-
import { getOrgMetadata, isServiceError } from './lib/utils';
5+
import { SINGLE_TENANT_ORG_ID } from './lib/constants';
6+
import { getOrgMetadata } from './lib/utils';
107

118
const logger = createLogger('web-initialize');
129

13-
const pruneOldGuestUser = async () => {
14-
// The old guest user doesn't have the GUEST role
15-
const guestUser = await __unsafePrisma.userToOrg.findUnique({
16-
where: {
17-
orgId_userId: {
18-
orgId: SINGLE_TENANT_ORG_ID,
19-
userId: SOURCEBOT_GUEST_USER_ID,
20-
},
21-
role: {
22-
not: OrgRole.GUEST,
23-
}
24-
},
25-
});
26-
27-
if (guestUser) {
28-
await __unsafePrisma.user.delete({
29-
where: {
30-
id: guestUser.userId,
31-
},
32-
});
33-
34-
logger.info(`Deleted old guest user ${guestUser.userId}`);
35-
}
36-
}
37-
3810
const init = async () => {
39-
// This is needed because v4 introduces the GUEST org role as well as making authentication required.
40-
// To keep things simple, we'll just delete the old guest user if it exists in the DB
41-
await pruneOldGuestUser();
42-
4311
const hasAnonymousAccessEntitlement = await hasEntitlement("anonymous-access");
44-
if (hasAnonymousAccessEntitlement) {
45-
const res = await createGuestUser();
46-
if (isServiceError(res)) {
47-
throw new ServiceErrorException(res);
48-
}
49-
} else {
12+
if (!hasAnonymousAccessEntitlement) {
5013
// If anonymous access entitlement is not enabled, set the flag to false in the org on init
5114
const org = await __unsafePrisma.org.findUnique({ where: { id: SINGLE_TENANT_ORG_ID } });
5215
if (org) {

packages/web/src/lib/authUtils.ts

Lines changed: 5 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import type { User as AuthJsUser } from "next-auth";
22
import { __unsafePrisma } from "@/prisma";
33
import { OrgRole } from "@sourcebot/db";
4-
import { SINGLE_TENANT_ORG_ID, SOURCEBOT_GUEST_USER_EMAIL, SOURCEBOT_GUEST_USER_ID, SOURCEBOT_SUPPORT_EMAIL } from "@/lib/constants";
5-
import { hasEntitlement } from "@/lib/entitlements";
4+
import { SINGLE_TENANT_ORG_ID } from "@/lib/constants";
65
import { isServiceError } from "@/lib/utils";
76
import { orgNotFound, ServiceError, userNotFound } from "@/lib/serviceError";
87
import { createLogger, getOfflineLicenseKey } from "@sourcebot/shared";
@@ -38,13 +37,7 @@ export const onCreateUser = async ({ user }: { user: AuthJsUser }) => {
3837
id: SINGLE_TENANT_ORG_ID,
3938
},
4039
include: {
41-
members: {
42-
where: {
43-
role: {
44-
not: OrgRole.GUEST,
45-
}
46-
}
47-
},
40+
members: true,
4841
}
4942
});
5043

@@ -67,8 +60,8 @@ export const onCreateUser = async ({ user }: { user: AuthJsUser }) => {
6760
throw new Error("Default org not found on single tenant user creation");
6861
}
6962

70-
// First (non-guest) user to sign up bootstraps the org as its OWNER. This
71-
// is how a fresh deployment gets its initial admin without manual setup.
63+
// First user to sign up bootstraps the org as its OWNER. This is how a
64+
// fresh deployment gets its initial admin without manual setup.
7265
const isFirstUser = defaultOrg.members.length === 0;
7366
if (isFirstUser) {
7467
await __unsafePrisma.$transaction(async (tx) => {
@@ -134,68 +127,6 @@ export const onCreateUser = async ({ user }: { user: AuthJsUser }) => {
134127
};
135128

136129

137-
export const createGuestUser = async (): Promise<ServiceError | boolean> => {
138-
const hasAnonymousAccessEntitlement = await hasEntitlement("anonymous-access");
139-
if (!hasAnonymousAccessEntitlement) {
140-
console.error(`Anonymous access isn't supported in your current plan. For support, contact ${SOURCEBOT_SUPPORT_EMAIL}.`);
141-
return {
142-
statusCode: StatusCodes.FORBIDDEN,
143-
errorCode: ErrorCode.INSUFFICIENT_PERMISSIONS,
144-
message: "Public access is not supported in your current plan",
145-
} satisfies ServiceError;
146-
}
147-
148-
const org = await __unsafePrisma.org.findUnique({
149-
where: { id: SINGLE_TENANT_ORG_ID },
150-
});
151-
if (!org) {
152-
return {
153-
statusCode: StatusCodes.NOT_FOUND,
154-
errorCode: ErrorCode.NOT_FOUND,
155-
message: "Organization not found",
156-
} satisfies ServiceError;
157-
}
158-
159-
const user = await __unsafePrisma.user.upsert({
160-
where: {
161-
id: SOURCEBOT_GUEST_USER_ID,
162-
},
163-
update: {},
164-
create: {
165-
id: SOURCEBOT_GUEST_USER_ID,
166-
name: "Guest",
167-
email: SOURCEBOT_GUEST_USER_EMAIL,
168-
},
169-
});
170-
171-
await __unsafePrisma.org.update({
172-
where: {
173-
id: org.id,
174-
},
175-
data: {
176-
members: {
177-
upsert: {
178-
where: {
179-
orgId_userId: {
180-
orgId: org.id,
181-
userId: user.id,
182-
},
183-
},
184-
update: {},
185-
create: {
186-
role: OrgRole.GUEST,
187-
user: {
188-
connect: { id: user.id },
189-
},
190-
},
191-
},
192-
},
193-
},
194-
});
195-
196-
return true;
197-
};
198-
199130
/**
200131
* Checks to see if the given organization has seat availability.
201132
* Seat availability is determined by the `seats` parameter in
@@ -207,13 +138,7 @@ export const orgHasAvailability = async (orgId: number): Promise<boolean> => {
207138
id: orgId,
208139
},
209140
include: {
210-
members: {
211-
where: {
212-
role: {
213-
not: OrgRole.GUEST
214-
}
215-
}
216-
},
141+
members: true,
217142
}
218143
});
219144

0 commit comments

Comments
 (0)