Skip to content

Commit 8f34dd7

Browse files
improve redemption flow
1 parent b8ae015 commit 8f34dd7

File tree

4 files changed

+24
-34
lines changed

4 files changed

+24
-34
lines changed

packages/web/src/actions.ts

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getAuditService } from "@/ee/features/audit/factory";
44
import { env, getSMTPConnectionURL } from "@sourcebot/shared";
55
import { addUserToOrganization, orgHasAvailability } from "@/lib/authUtils";
66
import { ErrorCode } from "@/lib/errorCodes";
7-
import { notFound, orgNotFound, ServiceError } from "@/lib/serviceError";
7+
import { notAuthenticated, notFound, orgNotFound, ServiceError } from "@/lib/serviceError";
88
import { getOrgMetadata, isHttpError, isServiceError } from "@/lib/utils";
99
import { __unsafePrisma } from "@/prisma";
1010
import { render } from "@react-email/components";
@@ -24,7 +24,7 @@ import JoinRequestApprovedEmail from "./emails/joinRequestApprovedEmail";
2424
import JoinRequestSubmittedEmail from "./emails/joinRequestSubmittedEmail";
2525
import { AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME, MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, SINGLE_TENANT_ORG_ID, SOURCEBOT_SUPPORT_EMAIL } from "./lib/constants";
2626
import { RepositoryQuery } from "./lib/types";
27-
import { withAuth, withOptionalAuth } from "./middleware/withAuth";
27+
import { getAuthenticatedUser, withAuth, withOptionalAuth } from "./middleware/withAuth";
2828
import { withMinimumOrgRole } from "./middleware/withMinimumOrgRole";
2929
import { getBrowsePath } from "./app/(app)/browse/hooks/utils";
3030
import { sew } from "@/middleware/sew";
@@ -817,17 +817,14 @@ export const getOrgAccountRequests = async () => sew(() =>
817817
}));
818818
}));
819819

820-
export const createAccountRequest = async (userId: string) => sew(async () => {
821-
const user = await __unsafePrisma.user.findUnique({
822-
where: {
823-
id: userId,
824-
},
825-
});
826-
827-
if (!user) {
828-
return notFound("User not found");
820+
export const createAccountRequest = async () => sew(async () => {
821+
const authResult = await getAuthenticatedUser();
822+
if (!authResult) {
823+
return notAuthenticated();
829824
}
830825

826+
const { user } = authResult;
827+
831828
const org = await __unsafePrisma.org.findUnique({
832829
where: {
833830
id: SINGLE_TENANT_ORG_ID,
@@ -841,14 +838,14 @@ export const createAccountRequest = async (userId: string) => sew(async () => {
841838
const existingRequest = await __unsafePrisma.accountRequest.findUnique({
842839
where: {
843840
requestedById_orgId: {
844-
requestedById: userId,
841+
requestedById: user.id,
845842
orgId: org.id,
846843
},
847844
},
848845
});
849846

850847
if (existingRequest) {
851-
logger.warn(`User ${userId} already has an account request for org ${org.id}. Skipping account request creation.`);
848+
logger.warn(`User ${user.id} already has an account request for org ${org.id}. Skipping account request creation.`);
852849
return {
853850
success: true,
854851
existingRequest: true,
@@ -858,7 +855,7 @@ export const createAccountRequest = async (userId: string) => sew(async () => {
858855
if (!existingRequest) {
859856
await __unsafePrisma.accountRequest.create({
860857
data: {
861-
requestedById: userId,
858+
requestedById: user.id,
862859
orgId: org.id,
863860
},
864861
});
@@ -869,7 +866,7 @@ export const createAccountRequest = async (userId: string) => sew(async () => {
869866
// on user creation (the header isn't set when next-auth calls onCreateUser for some reason)
870867
const deploymentUrl = env.AUTH_URL;
871868

872-
const owner = await __unsafePrisma.user.findFirst({
869+
const owners = await __unsafePrisma.user.findMany({
873870
where: {
874871
orgs: {
875872
some: {
@@ -880,8 +877,8 @@ export const createAccountRequest = async (userId: string) => sew(async () => {
880877
},
881878
});
882879

883-
if (!owner) {
884-
logger.error(`Failed to find owner for org ${org.id} when drafting email for account request from ${userId}`);
880+
if (owners.length === 0) {
881+
logger.error(`Failed to find any owners for org ${org.id} when drafting email for account request from ${user.id}`);
885882
} else {
886883
const html = await render(JoinRequestSubmittedEmail({
887884
baseUrl: deploymentUrl,
@@ -894,9 +891,13 @@ export const createAccountRequest = async (userId: string) => sew(async () => {
894891
orgImageUrl: org.imageUrl ?? undefined,
895892
}));
896893

894+
const ownerEmails = owners
895+
.map((owner) => owner.email)
896+
.filter((email): email is string => email !== null);
897+
897898
const transport = createTransport(smtpConnectionUrl);
898899
const result = await transport.sendMail({
899-
to: owner.email!,
900+
to: ownerEmails,
900901
from: env.EMAIL_FROM_ADDRESS,
901902
subject: `New account request for ${org.name} on Sourcebot`,
902903
html,
@@ -905,7 +906,7 @@ export const createAccountRequest = async (userId: string) => sew(async () => {
905906

906907
const failed = result.rejected.concat(result.pending).filter(Boolean);
907908
if (failed.length > 0) {
908-
logger.error(`Failed to send account request email to ${owner.email}: ${failed}`);
909+
logger.error(`Failed to send account request email to ${ownerEmails.join(', ')}: ${failed}`);
909910
}
910911
}
911912
} else {

packages/web/src/app/(app)/components/submitAccountRequestButton.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,15 @@ import { createAccountRequest } from "@/actions"
88
import { isServiceError } from "@/lib/utils"
99
import { useRouter } from "next/navigation"
1010

11-
interface SubmitButtonProps {
12-
userId: string
13-
}
1411

15-
export function SubmitAccountRequestButton({ userId }: SubmitButtonProps) {
12+
export function SubmitAccountRequestButton() {
1613
const { toast } = useToast()
1714
const router = useRouter()
1815
const [isSubmitting, setIsSubmitting] = useState(false)
1916

2017
const handleSubmit = async () => {
2118
setIsSubmitting(true)
22-
const result = await createAccountRequest(userId)
19+
const result = await createAccountRequest()
2320
if (!isServiceError(result)) {
2421
if (result.existingRequest) {
2522
toast({

packages/web/src/app/(app)/components/submitJoinRequest.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"
22
import { SourcebotLogo } from "@/app/components/sourcebotLogo"
3-
import { auth } from "@/auth"
43
import { SubmitAccountRequestButton } from "./submitAccountRequestButton"
54

65
export const SubmitJoinRequest = async () => {
7-
const session = await auth()
8-
const userId = session?.user?.id
9-
10-
if (!userId) {
11-
return null
12-
}
13-
146
return (
157
<div className="min-h-screen bg-[var(--background)] flex items-center justify-center p-6">
168
<LogoutEscapeHatch className="absolute top-0 right-0 p-6" />
@@ -41,7 +33,7 @@ export const SubmitJoinRequest = async () => {
4133

4234
<div className="space-y-4">
4335
<div className="flex justify-center">
44-
<SubmitAccountRequestButton userId={userId} />
36+
<SubmitAccountRequestButton />
4537
</div>
4638
</div>
4739
</div>

packages/web/src/emails/joinRequestSubmittedEmail.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const JoinRequestSubmittedEmail = ({
3535
orgImageUrl,
3636
}: JoinRequestSubmittedEmailProps) => {
3737
const previewText = `${requestor.name ?? requestor.email} has requested to join ${orgName} on Sourcebot`;
38-
const reviewLink = `${baseUrl}/settings/members`;
38+
const reviewLink = `${baseUrl}/settings/members?tab=requests`;
3939

4040
return (
4141
<Html>

0 commit comments

Comments
 (0)