Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync Upstream #163

Merged
merged 5 commits into from
Apr 14, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions .github/workflows/unit-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ jobs:
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }}
GOOGLE_BASEFOLDER: ${{ secrets.GOOGLE_BASEFOLDER }}
GOOGLE_CLIENT_EMAIL: ${{ secrets.GOOGLE_CLIENT_EMAIL }}
GOOGLE_PRIVATE_KEY: ${{ secrets.GOOGLE_PRIVATE_KEY }}
6 changes: 5 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ model Senior {
firstname String
lastname String
location String
dateCreated DateTime @default(now())
description String
StudentIDs String[] @db.ObjectId
Students User[] @relation(fields: [StudentIDs], references: [id])
Expand Down Expand Up @@ -132,10 +133,13 @@ model Chapter {
id String @id @default(auto()) @map("_id") @db.ObjectId
chapterName String
location String
chapterFolder String @default("")
dateCreated DateTime @default(now())
students User[]
seniors Senior[]

// Google Drive API related fields
chapterFolder String @default("")
permissions String[]
}

model Resource {
Expand Down
Binary file added public/landing/about/parallel_stories1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/about/parallel_stories2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/about/parallel_stories3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/about/sundaes_sundays.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/about/their_lives_reflected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/arielle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/katie.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/meet_tlp1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/meet_tlp2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/meet_tlp3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/our_team.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/press1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/press2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/landing/team/wanda.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 1 addition & 8 deletions src/app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,9 @@ import NextAuth, { NextAuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";

const GOOGLE_API_SCOPE = [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.appdata",
"https://www.googleapis.com/auth/drive.appfolder",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive.resource",
"https://www.googleapis.com/auth/documents",
"https://www.googleapis.com/auth/documents.readonly",
"openid",
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
"openid",
];

export const authOptions: NextAuthOptions = {
Expand Down
35 changes: 35 additions & 0 deletions src/app/api/chapter/[chapterId]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { NextResponse } from "next/server";
import { withSessionAndRole } from "@server/decorator";
import { prisma } from "@server/db/client";
import { driveV3 } from "@server/service";

export const DELETE = withSessionAndRole(["ADMIN"], async ({ params }) => {
// TODO
// 1. Implement route.client.ts
// 2. Implement route.schema.ts
// 3. Finish deleting chapter
// 4. Add it to AdminHomePage

const chapterId = params.params.chapterId;
const chapter = await prisma.chapter.findUnique({
where: {
id: chapterId,
},
});

if (chapter == null) {
// If no ID is found, chapter has been deleted by another admin.
return NextResponse.json("ok");
}

await Promise.allSettled(
chapter.permissions.map((permissionId) =>
driveV3.permissions.delete({
fileId: chapter.chapterFolder,
permissionId: permissionId,
})
)
);

return NextResponse.json("ok");
});
10 changes: 3 additions & 7 deletions src/app/api/file/[fileId]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ import { FileResponse } from "./route.schema";
import { File } from "@server/model";
import { prisma } from "@server/db/client";
import { withSession } from "@server/decorator";
import { createDriveService } from "@server/service";
import { driveV3 } from "@server/service";
import moment from "moment";

export const PATCH = withSession(async (request) => {
const service = await createDriveService(request.session.user.id);

const body = await request.req.json();
const nextParams: { fileId: string } = request.params.params;
const { fileId } = nextParams;
Expand Down Expand Up @@ -97,7 +95,7 @@ export const PATCH = withSession(async (request) => {
resource: body,
};

await service.files.update(fileUpdateData);
await driveV3.files.update(fileUpdateData);

const file = await prisma.file.findFirst({
where: {
Expand Down Expand Up @@ -131,8 +129,6 @@ export const PATCH = withSession(async (request) => {
});

export const DELETE = withSession(async (request) => {
const service = await createDriveService(request.session.user.id);

const nextParams: { fileId: string } = request.params.params;
const { fileId } = nextParams;

Expand Down Expand Up @@ -192,7 +188,7 @@ export const DELETE = withSession(async (request) => {
);
}

await service.files.delete({
await driveV3.files.delete({
fileId: fileId,
});

Expand Down
10 changes: 3 additions & 7 deletions src/app/api/file/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@ import { FileResponse } from "./route.schema";
import { File } from "@server/model";
import { prisma } from "@server/db/client";
import { withSession } from "@server/decorator";
import { createDriveService } from "@server/service";
import { driveV3 } from "@server/service";
import moment from "moment";

export const POST = withSession(async (request) => {
const service = await createDriveService(request.session.user.id);

const body = await request.req.json();
const fileRequest = File.safeParse(body);

if (!fileRequest.success) {
console.log(fileRequest.error);
return NextResponse.json(
FileResponse.parse({
code: "INVALID_REQUEST",
Expand Down Expand Up @@ -83,10 +80,9 @@ export const POST = withSession(async (request) => {
};

// NOTE: File will still be created on Drive even if it fails on MongoDB
const file = await service.files.create(fileCreateData);

// TOOD(nickbar01234) - Handle failure
const file = await driveV3.files.create(fileCreateData);
const googleFileId = file.data.id;

// If the data is valid, save it to the database via prisma client
await prisma.file.create({
data: {
Expand Down
7 changes: 3 additions & 4 deletions src/app/api/handle-chapter-request/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import {
HandleChapterRequestResponse,
} from "./route.schema";
import { withSession } from "@server/decorator";
import { createDriveService } from "@server/service";
import { driveV3 } from "@server/service";
import { env } from "@env/server.mjs";
import { prisma } from "@server/db/client";

export const POST = withSession(async ({ req, session }) => {
export const POST = withSession(async ({ req }) => {
const handleChapterRequest = HandleChapterRequest.safeParse(await req.json());
if (!handleChapterRequest.success) {
return NextResponse.json(
Expand Down Expand Up @@ -73,8 +73,7 @@ export const POST = withSession(async ({ req, session }) => {
fields: "id",
};

const service = await createDriveService(session.user.id);
const file = await service.files.create(fileCreateData);
const file = await driveV3.files.create(fileCreateData);
const googleFolderId = file.data.id as string;

await prisma.chapter.update({
Expand Down
9 changes: 4 additions & 5 deletions src/app/api/senior/route.client.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { TypedRequest } from "@server/type";
import { seniorPostResponse, IPostSeniorRequestSchema } from "./route.schema";

interface IPostSeniorRequest extends Omit<RequestInit, "body"> {
body: IPostSeniorRequestSchema;
}

export const postSenior = async (request: IPostSeniorRequest) => {
export const postSenior = async (
request: TypedRequest<IPostSeniorRequestSchema>
) => {
const { body, ...options } = request;

const response = await fetch(`/api/senior/`, {
Expand Down
8 changes: 2 additions & 6 deletions src/app/api/senior/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { withSessionAndRole } from "@server/decorator";
import { NextResponse } from "next/server";
import { seniorPostResponse, postSeniorSchema } from "./route.schema";
import { prisma } from "@server/db/client";
import { createDriveService } from "@server/service";
import { driveV3 } from "@server/service";

// @TODO - Use google drive service to create folder
export const POST = withSessionAndRole(
Expand Down Expand Up @@ -83,11 +83,7 @@ export const POST = withSessionAndRole(
fields: "id",
};

const service = await createDriveService(session.user.id);

const file = await (service as NonNullable<typeof service>).files.create(
fileCreateData
);
const file = await driveV3.files.create(fileCreateData);
const googleFolderId = (file as any).data.id;

await prisma.senior.update({
Expand Down
21 changes: 17 additions & 4 deletions src/app/api/user-request/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "./route.schema";
import { prisma } from "@server/db/client";
import { withSession } from "@server/decorator/index";
import { createDriveService } from "@server/service";
import { driveV3 } from "@server/service";

export const POST = withSession(async ({ req, session }) => {
try {
Expand Down Expand Up @@ -194,7 +194,6 @@ export const PATCH = withSession(async ({ req, session }) => {

// Next, share the folder with the user that is accepted
const shareFolder = async (folderId: string, userEmail: string) => {
const service = await createDriveService(session.user.id);
// Define the permission
const permission = {
type: "user",
Expand All @@ -203,13 +202,27 @@ export const PATCH = withSession(async ({ req, session }) => {
};

// Share the folder
await service.permissions.create({
return await driveV3.permissions.create({
fileId: folderId,
sendNotificationEmail: false,
requestBody: permission,
});
};
// Since we use Google login, they must have an email
await shareFolder(folderId, chapterRequest.user.email ?? "");
const permission = await shareFolder(
folderId,
chapterRequest.user.email ?? ""
);
// TODO(nickbar01234) - Handle failure
const permissionId = permission.data.id as string;
await prisma.chapter.update({
where: { id: chapterRequest.chapterId },
data: {
permissions: {
push: permissionId,
},
},
});
// We update the chapter ID second to allow the user to rejoin in the case that shareFolder fails midway
await prisma.user.update({
where: { id: chapterRequest.uid },
Expand Down
7 changes: 1 addition & 6 deletions src/app/private/chapter-leader/seniors/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ const UserSeniorsPage = async () => {
const seniors = chapter?.seniors.sort(compareSenior) ?? [];
const students = chapter?.students ?? [];

return (
<>
<div className="mb-6 text-2xl">Seniors {`(${seniors.length})`}</div>
<SeniorView seniors={seniors} students={students} />
</>
);
return <SeniorView seniors={seniors} students={students} />;
};

export default UserSeniorsPage;
54 changes: 29 additions & 25 deletions src/app/private/user/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,40 @@ import { getServerSessionOrRedirect } from "@server/utils";

const UserHomePage = async () => {
const session = await getServerSessionOrRedirect();
const chapter = await prisma.chapter.findFirstOrThrow({
where: {
id: session.user?.ChapterID ?? "",
},
include: {
students: {
where: {
OR: [
{
position: {
not: "",
if (session.user?.ChapterID != null) {
const chapter = await prisma.chapter.findFirstOrThrow({
where: {
id: session.user?.ChapterID ?? "",
},
include: {
students: {
where: {
OR: [
{
position: {
not: "",
},
},
{
role: "CHAPTER_LEADER",
},
},
{
role: "CHAPTER_LEADER",
},
],
],
},
},
},
},
});
const resources = await prisma.resource.findMany({
where: {
access: {
isEmpty: true,
});
const resources = await prisma.resource.findMany({
where: {
access: {
isEmpty: true,
},
},
},
});
});

return <DisplayChapterInfo chapter={chapter} resources={resources} />;
return <DisplayChapterInfo chapter={chapter} resources={resources} />;
} else {
return null;
}
};

export default UserHomePage;
Loading
Loading