feat(env): Update environment configuration and enhance email functionality

- Renamed DATABASE_URL to POSTGRES_URL in .env.example for clarity.
- Added SMTP configuration for email sending, including host, port, user, password, and from address.
- Updated package.json to include new dependencies for email handling and UI components.
- Modified middleware to handle public and protected routes more effectively.
- Enhanced API routes for studies to support user roles and permissions.
- Updated database schema to include invitations and user roles related to studies.
- Improved user permissions handling in the permissions module.
- Added new utility functions for managing user roles and study access.
This commit is contained in:
2024-12-03 23:02:23 -05:00
parent 3a955a0568
commit 3ec8b2fe46
28 changed files with 1775 additions and 121 deletions

View File

@@ -0,0 +1,64 @@
import { eq, and, gt } from "drizzle-orm";
import { NextResponse } from "next/server";
import { auth } from "@clerk/nextjs/server";
import { db } from "~/db";
import { invitationsTable, userRolesTable } from "~/db/schema";
export async function POST(
request: Request,
{ params }: { params: { token: string } }
) {
const { userId } = await auth();
if (!userId) {
return new NextResponse("Unauthorized", { status: 401 });
}
try {
const { token } = params;
// Find the invitation
const [invitation] = await db
.select()
.from(invitationsTable)
.where(
and(
eq(invitationsTable.token, token),
eq(invitationsTable.accepted, false),
gt(invitationsTable.expiresAt, new Date())
)
)
.limit(1);
if (!invitation) {
return new NextResponse(
"Invitation not found or has expired",
{ status: 404 }
);
}
// Start a transaction
await db.transaction(async (tx) => {
// Mark invitation as accepted
await tx
.update(invitationsTable)
.set({ accepted: true })
.where(eq(invitationsTable.id, invitation.id));
// Assign role to user for this specific study
await tx
.insert(userRolesTable)
.values({
userId,
roleId: invitation.roleId,
studyId: invitation.studyId,
})
.onConflictDoNothing();
});
return new NextResponse("Invitation accepted", { status: 200 });
} catch (error) {
console.error("Error accepting invitation:", error);
return new NextResponse("Internal Server Error", { status: 500 });
}
}