Skip to content

Commit

Permalink
Merge branch 'master' into deployment-enhancement
Browse files Browse the repository at this point in the history
  • Loading branch information
yhtMinceraft1010X committed Oct 15, 2023
2 parents 8d34e87 + 1833e41 commit 421f62b
Show file tree
Hide file tree
Showing 25 changed files with 507 additions and 152 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ env:
FIREBASE_SERVICE_ACCOUNT_PROD: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_PROD }}
PRISMA_DATABASE_URL_PROD: ${{ secrets.PRISMA_DATABASE_URL_PROD }}
MONGO_ATLAS_URL_PROD: ${{ secrets.MONGO_ATLAS_URL_PROD }}
FRONTEND_FIREBASE_CONFIG_PROD: ${{ secrets.FRONTEND_FIREBASE_CONFIG_PROD }}

jobs:
setup-build-publish-deploy:
Expand Down Expand Up @@ -70,7 +71,9 @@ jobs:
kubectl create secret generic prisma-database-url \
--from-literal=prisma-database-url=$PRISMA_DATABASE_URL_PROD
kubectl create secret generic mongo-atlas-url \
--from-literal=mongo-atlas-url =$MONGO_ATLAS_URL_PROD
--from-literal=mongo-atlas-url=$MONGO_ATLAS_URL_PROD
kubectl create secret generic frontend-firebase-config \
--from-literal=frontend-firebase-config=$FRONTEND_FIREBASE_CONFIG_PROD
# Deploy the Docker images to the GKE cluster
- name: Deploy production application
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,22 @@ your services / frontend.
├── /deployment
│ ├── /docker
│ └── /kubernetes
├── .env (not in git)
├── .env.firebase_emulators_test (not in git)
└── README.md (and other root-level files & docs)
```
### Getting Started - Local Development:
1. Ensure that you have an `.env` file at the root directory with the following variables:
```bash
PRISMA_DATABASE_URL=<redacted>
MONGO_ATLAS_URL=<redacted>
FIREBASE_SERVICE_ACCOUNT=<redacted>
NEXT_PUBLIC_FRONTEND_FIREBASE_CONFIG={"apiKey": <redacted>,"authDomain": <redacted>,"projectId": <redacted>,"storageBucket": <redacted>,"messagingSenderId": <redacted>,"appId": <redacted>}
```
Note: For `NEXT_PUBLIC_FRONTEND_FIREBASE_CONFIG`, the JSON should not have newlines since Next.js may not process it correctly.
1. **Installing secret detection hooks:** From the root directory, run:
```bash
pip install pre-commit
Expand Down
7 changes: 5 additions & 2 deletions deployment/gke-prod-manifests/frontend-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ spec:
- env:
- name: GATEWAY_ADDRESS
value: "http://gateway:4000/"
- name: FIREBASE_CONFIG_FILEPATH
value: "./firebase_config_prod.json"
- name: NEXT_PUBLIC_FRONTEND_FIREBASE_CONFIG
valueFrom:
secretKeyRef:
name: frontend-firebase-config
key: frontend-firebase-config
- image: asia-southeast1-docker.pkg.dev/peerprep-group11-dev/codeparty-prod-images/frontend:latest
name: frontend
ports:
Expand Down
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ services:
container_name: frontend
ports:
- "3000:3000"
environment:
GATEWAY_ADDRESS: "http://localhost:4000/"
NEXT_PUBLIC_FRONTEND_FIREBASE_CONFIG: ${NEXT_PUBLIC_FRONTEND_FIREBASE_CONFIG}
2 changes: 1 addition & 1 deletion frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ yarn
First, run the development server:

```bash
yarn dev
yarn dev:local
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev:local": "dotenv -e ../.env -- yarn dev",
"dev": "next dev",
"build": "next build",
"start": "next start -H 0.0.0.0",
Expand Down
9 changes: 1 addition & 8 deletions frontend/src/firebase-client/firebase_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

// Firebase configuration
/**
* How to use:
* - For dev, just leave FIREBASE_CONFIG_FILEPATH empty
* - For prod or simulated prod, pass in the filepath to the env variable
*/
const firebaseConfigFile = process.env.FIREBASE_CONFIG_FILEPATH || "./firebase_config_dev.json"

const firebaseConfig = require(firebaseConfigFile);
const firebaseConfig = JSON.parse(process.env.NEXT_PUBLIC_FRONTEND_FIREBASE_CONFIG as string)

// Initialize Firebase
const app = initializeApp(firebaseConfig);
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/firebase-client/firebase_config_dev.json

This file was deleted.

3 changes: 3 additions & 0 deletions frontend/src/hooks/useCollaboration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum SocketEvents {
ROOM_UPDATE = "api/collaboration-service/room/update",
ROOM_SAVE = "api/collaboration-service/room/save",
ROOM_LOAD = "api/collaboration-service/room/load",
QUESTION_SET = "api/collaboration-service/question/set",
}

var vers = 0;
Expand All @@ -33,12 +34,14 @@ const useCollaboration = ({ roomId, userId }: UseCollaborationProps) => {
const prevTextRef = useRef<string>(text);
const awaitingAck = useRef<boolean>(false); // ack from sending update
const awaitingSync = useRef<boolean>(false); // synced with server
const questionId = "1";

useEffect(() => {
const socketConnection = io("http://localhost:5003/");
setSocket(socketConnection);

socketConnection.emit(SocketEvents.ROOM_JOIN, roomId, userId);
socketConnection.emit(SocketEvents.QUESTION_SET, questionId);

socketConnection.on(
SocketEvents.ROOM_UPDATE,
Expand Down
30 changes: 24 additions & 6 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,40 @@ model Match {
}

model AppUser {
uid String @id
uid String @id
displayName String?
photoUrl String?
matchDifficulty Int?
matchProgrammingLanguage String?
attempts Attempt[]
}

model Room {
room_id String @id
users String[] // Array of user_id strings
status EnumRoomStatus
text String
saved_text String?
room_id String @id
active_users String[] // Array of user_id strings still active
users String[] // Array of user_id strings
status EnumRoomStatus
text String
saved_text String?
question_id String?
attempt Attempt? @relation(fields: [attempt_id], references: [id])
attempt_id String? @unique
}

enum EnumRoomStatus {
active
inactive
}

model Attempt {
id String @id @default(uuid())
users AppUser[]
question_id String
answer String?
solved Boolean @default(false)
time_created DateTime @default(now())
time_saved_at DateTime @default(now()) // when answers are updated
time_updated DateTime @updatedAt // any field change
room_id String? // may be inactive
room Room?
}
12 changes: 8 additions & 4 deletions services/admin-service/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import express, {Express} from 'express';
import express, { Express } from "express";
import swaggerUi from "swagger-ui-express";
import swaggerFile from "../openapiDoc.json";

const app: Express = express();

const port : number = parseInt(process.env.PORT || "5005");
const port: number = parseInt(process.env.PORT || "5005");

import router from './routes/index';
import router from "./routes/index";

app.use('/api/admin-service', router);
app.use("/api/admin-service", router);

app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerFile));

app.listen(port, () => {
console.log(`⚡️[server]: Server is running at http://localhost:${port}`);
Expand Down
1 change: 1 addition & 0 deletions services/admin-service/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"target": "es2016",
"module": "commonjs",
"rootDir": "./src",
"resolveJsonModule": true,
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
Expand Down
119 changes: 112 additions & 7 deletions services/collaboration-service/src/db/prisma-db.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PrismaClient, Room } from "@prisma/client";
import { AppUser, PrismaClient, Room } from "@prisma/client";

const prisma = new PrismaClient();

Expand Down Expand Up @@ -56,32 +56,137 @@ export async function updateRoomStatus(room_id: string): Promise<void> {
});
if (!room) return;

if (room.users.length === 0) {
if (room.active_users.length === 0) {
room.status = "inactive";
saveAttempt(room_id);
} else {
room.status = "active";
}
await prisma.room.update({
where: {
room_id: room_id,
},
data: {
status: room.status,
},
});
}

export async function saveAttempt(room_id: string): Promise<void> {
const room = await prisma.room.findUnique({
where: {
room_id: room_id,
},
});

const attempt_id = room!.attempt_id;
const answer = room!.text;
const question_id = room!.question_id ?? "";

const users: AppUser[] = await prisma.appUser.findMany({
where: {
uid: {
in: room!.users,
},
},
});

if (attempt_id) {
await prisma.attempt.update({
where: {
id: attempt_id,
},
data: {
users: {
connect: users.map((user) => ({
uid: user.uid as string,
})),
},
answer: answer,
time_saved_at: new Date(),
},
});
return;
}

await prisma.attempt.create({
data: {
users: {
connect: users.map((user) => ({
uid: user.uid as string,
})),
},
question_id: question_id,
answer: answer,
room_id: room_id,
room: {
connect: {
room_id: room_id,
},
},
},
});
}

export async function setRoomQuestion(
room_id: string,
question_id: string
): Promise<void> {
await prisma.room.update({
where: {
room_id: room_id,
},
data: {
question_id: question_id,
},
});
}

export async function createOrUpdateRoomWithUser(
room_id: string,
user_id: string
): Promise<void> {
let users: string[] = [];
let active_users: string[] = [];
const room = await prisma.room.findUnique({
where: {
room_id: room_id,
},
select: {
users: true,
active_users: true,
},
});
if (room) {
users = room.users;
active_users = room.active_users;
if (users.indexOf(user_id) === -1) {
users.push(user_id);
}
if (active_users.indexOf(user_id) === -1) {
active_users.push(user_id);
}
}

await prisma.room.upsert({
where: {
room_id: room_id,
},
update: {
status: "active",
users: {
push: user_id,
set: users,
},
active_users: {
set: active_users,
},
},
create: {
room_id: room_id,
text: "",
status: "active",
users: [user_id],
active_users: [user_id],
},
});
}
Expand Down Expand Up @@ -127,18 +232,18 @@ export async function removeUserFromRoom(

if (!existingRoom) return;

const userIndex = existingRoom.users.indexOf(user_id);
const userIndex = existingRoom.active_users.indexOf(user_id);

if (userIndex > -1) {
existingRoom.users.splice(userIndex, 1);
existingRoom.active_users.splice(userIndex, 1);

await prisma.room.update({
where: {
room_id: room_id,
},
data: {
users: {
set: existingRoom.users,
active_users: {
set: existingRoom.active_users,
},
},
});
Expand Down
Loading

0 comments on commit 421f62b

Please sign in to comment.