Merge branch 'main' into feature/deployment-yoshi
This commit is contained in:
commit
1aa82a7355
55 changed files with 7981 additions and 10 deletions
70
.dockerignore
Normal file
70
.dockerignore
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Node.js dependencies
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Environment and secrets
|
||||
.env*
|
||||
*.env
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
config.local.*
|
||||
*.local.yml
|
||||
|
||||
# Version control
|
||||
.git/
|
||||
.gitignore
|
||||
.svn/
|
||||
.hg/
|
||||
|
||||
# IDE/editor files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Build and output directories
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
.local/
|
||||
local/
|
||||
|
||||
# Test and debug artifacts
|
||||
test/
|
||||
tests/
|
||||
debug/
|
||||
*.log
|
||||
|
||||
# Documentation
|
||||
README*
|
||||
*.md
|
||||
docs/
|
||||
|
||||
# Docker and Compose files
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
|
||||
# Project-specific
|
||||
fly.toml
|
||||
|
||||
# Prisma generated files (if any)
|
||||
prisma/migrations/
|
||||
|
||||
# Miscellaneous
|
||||
*.bak
|
||||
*.old
|
||||
*.orig
|
||||
|
||||
# Exclude lock files (do NOT ignore them)
|
||||
# package-lock.json
|
||||
# yarn.lock
|
||||
# pnpm-lock.yaml
|
||||
|
||||
# Exclude gradle/maven/go/python/java patterns not relevant to Node.js
|
||||
# (No __pycache__, *.pyc, *.pyo, .pytest_cache, .coverage, /vendor/, *.test, .go-cache, target/, *.class, .gradle/)
|
||||
1
README.md
Normal file
1
README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
## Running the Project with Docker
|
||||
40
assignment-db-service/.dockerignore
Normal file
40
assignment-db-service/.dockerignore
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Node.js specific
|
||||
**node_modules/
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
|
||||
# Environment and secrets
|
||||
.env*
|
||||
*.env
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
|
||||
# Development artifacts
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Version control
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
README*
|
||||
|
||||
# Docker files
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
|
||||
# Project-specific
|
||||
package-lock.json
|
||||
|
|
@ -4,7 +4,9 @@
|
|||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||
|
||||
# DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
|
||||
# DATABASE_URL="postgres://postgres:w2eSd47GJEdqvMf@snakebyte.internal:5432"
|
||||
DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable
|
||||
#use this when testing local, remmber to run the proxy command
|
||||
# DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@localhost:15432/postgres?schema=public"
|
||||
|
||||
DATABASE_URL="postgres://postgres:wly9H8gjjmxYfg1@bytecamp-db.flycast:5432?sslmode=disable"
|
||||
# DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable
|
||||
NODE_PORT=3000
|
||||
20
assignment-db-service/Dockerfile
Normal file
20
assignment-db-service/Dockerfile
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
RUN apt-get update -y && apt-get install -y openssl && npm install && npx prisma generate
|
||||
|
||||
# Copy the application source code
|
||||
COPY --link . .
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 3000
|
||||
|
||||
# Define the command to run the application
|
||||
CMD ["node", "app.js"]
|
||||
29
assignment-db-service/DockerfileDEV
Normal file
29
assignment-db-service/DockerfileDEV
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Then copy the rest of the application code
|
||||
COPY . .
|
||||
|
||||
# Install build tools (needed for bcrypt native bindings)
|
||||
RUN apt-get update -y && apt-get install -y build-essential python3 openssl
|
||||
|
||||
# Copy only package files first (faster caching)
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install && npx prisma generate
|
||||
|
||||
# Rebuild bcrypt specifically (optional if clean install is guaranteed)
|
||||
# RUN npm rebuild bcrypt --build-from-source
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 3200
|
||||
|
||||
# Start the application
|
||||
CMD ["node", "app.js"]
|
||||
163
assignment-db-service/app.js
Normal file
163
assignment-db-service/app.js
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
const express = require("express");
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
const app = express();
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const port = process.env.NODE_PORT || 3000;
|
||||
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
//function to conver req.body to assignment
|
||||
function convertToAssignment(req) {
|
||||
const {
|
||||
campid,
|
||||
programid,
|
||||
studentname,
|
||||
snakegameid,
|
||||
originalfile,
|
||||
editablefile,
|
||||
assignmenturl,
|
||||
password,
|
||||
instructorid
|
||||
} = req.body;
|
||||
|
||||
// const hashedPassword = await bcrypt.hash(Password, 10);
|
||||
return {
|
||||
campid: campid,
|
||||
programid: programid,
|
||||
studentname: studentname,
|
||||
snakegameid: snakegameid,
|
||||
originalfile: originalfile,
|
||||
editablefile: editablefile,
|
||||
assignmenturl: assignmenturl,
|
||||
// passwordhash: hashedpassword,
|
||||
passwordhash: password,
|
||||
instructorid: instructorid,
|
||||
};
|
||||
}
|
||||
|
||||
// Create Assignment
|
||||
app.post("/assignments", async (req, res) => {
|
||||
try {
|
||||
console.log("Request body:", req.body);
|
||||
|
||||
// const {
|
||||
// campid,
|
||||
// programid,
|
||||
// studentname,
|
||||
// snakegameid,
|
||||
// originalfile,
|
||||
// editablefile,
|
||||
// assignmenturl,
|
||||
// password,
|
||||
// instructorid
|
||||
// } = req.body;
|
||||
|
||||
// const hashedPassword = await bcrypt.hash(Password, 10);
|
||||
const newAssignment = await prisma.assignments.create({
|
||||
data: {
|
||||
...convertToAssignment(req)
|
||||
},
|
||||
});
|
||||
|
||||
console.log("Assignment created successfully:", newAssignment);
|
||||
|
||||
res.json({
|
||||
message: "Assignment created successfully",
|
||||
assignment: newAssignment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error creating assignment:", err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Get Assignments by InstructorID
|
||||
app.get("/assignments/instructor/:instructorId", async (req, res) => {
|
||||
try {
|
||||
const { instructorId } = req.params;
|
||||
console.log("InstructorID:", instructorId);
|
||||
const assignments = await prisma.assignments.findMany({
|
||||
where: { instructorid: parseInt(instructorId) },
|
||||
});
|
||||
|
||||
if (assignments.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ message: "No assignments found for this instructor" });
|
||||
}
|
||||
|
||||
res.json(assignments);
|
||||
} catch (err) {
|
||||
console.error("Error fetching assignments:", err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Read Assignment
|
||||
app.get("/assignments/:id", async (req, res) => {
|
||||
try {
|
||||
const assignment = await prisma.assignments.findUnique({
|
||||
where: { assignmentid: parseInt(req.params.id) },
|
||||
});
|
||||
|
||||
if (!assignment) {
|
||||
return res.status(404).json({ message: "Assignment not found" });
|
||||
}
|
||||
|
||||
res.json(assignment);
|
||||
} catch (err) {
|
||||
console.error("Error fetching assignment:", err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Update Assignment
|
||||
app.put("/assignments/:id", async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const data = req.body;
|
||||
|
||||
if (data.password) {
|
||||
// data.passwordhash = await bcrypt.hash(data.Password, 10);
|
||||
data.passwordhash = data.password;
|
||||
delete data.password;
|
||||
}
|
||||
|
||||
const updatedAssignment = await prisma.assignments.update({
|
||||
where: { assignmentid: parseInt(id) },
|
||||
data,
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: "Assignment updated successfully",
|
||||
assignment: updatedAssignment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error updating assignment:", err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Delete Assignment
|
||||
app.delete("/assignments/:id", async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
await prisma.assignments.delete({
|
||||
where: { assignmentid: parseInt(id) },
|
||||
});
|
||||
|
||||
res.json({ message: "Assignment deleted successfully" });
|
||||
} catch (err) {
|
||||
console.error("Error deleting assignment:", err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server running at http://localhost:${port}`);
|
||||
});
|
||||
12
assignment-db-service/dev.env
Normal file
12
assignment-db-service/dev.env
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Environment variables declared in this file are automatically made available to Prisma.
|
||||
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
|
||||
|
||||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||
|
||||
#use this when testing local, remmber to run the proxy command
|
||||
DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@host.docker.internal:15432/postgres?schema=public"
|
||||
|
||||
# DATABASE_URL="postgres://postgres:wly9H8gjjmxYfg1@bytecamp-db.flycast:5432?sslmode=disable"
|
||||
# DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable
|
||||
NODE_PORT=3200
|
||||
32
assignment-db-service/fly.toml
Normal file
32
assignment-db-service/fly.toml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# fly.toml app configuration file generated for db-assignment-service on 2025-04-24T11:13:50-07:00
|
||||
#
|
||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||
#
|
||||
|
||||
app = 'db-assignment-service'
|
||||
primary_region = 'sea'
|
||||
|
||||
[build]
|
||||
|
||||
[http_service]
|
||||
internal_port = 3000
|
||||
force_https = true
|
||||
auto_stop_machines = 'stop'
|
||||
auto_start_machines = true
|
||||
min_machines_running = 0
|
||||
processes = ['app']
|
||||
|
||||
[[services]]
|
||||
protocol = 'tcp'
|
||||
internal_port = 3000
|
||||
ports = []
|
||||
|
||||
[services.concurrency]
|
||||
type = 'requests'
|
||||
hard_limit = 1000
|
||||
soft_limit = 500
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
1738
assignment-db-service/package-lock.json
generated
Normal file
1738
assignment-db-service/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
13
assignment-db-service/package.json
Normal file
13
assignment-db-service/package.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.1.0",
|
||||
"bcrypt": "^5.1.1",
|
||||
"express": "^5.1.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"prisma": "^6.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev": "nodemon app.js"
|
||||
}
|
||||
}
|
||||
22
assignment-db-service/prisma/schema.prisma
Normal file
22
assignment-db-service/prisma/schema.prisma
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "windows"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model assignments {
|
||||
assignmentid Int @id @default(autoincrement())
|
||||
campid Int?
|
||||
programid Int?
|
||||
studentname String?
|
||||
snakegameid String?
|
||||
originalfile String?
|
||||
editablefile String?
|
||||
assignmenturl String?
|
||||
passwordhash String? // store bcrypt hash
|
||||
instructorid Int?
|
||||
}
|
||||
4
assignment-db-service/readme.md
Normal file
4
assignment-db-service/readme.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# database microservice
|
||||
- store database tables
|
||||
- issue and re-issue auth tokens (jwt)
|
||||
- handle password reset into db
|
||||
40
assignment-service/.dockerignore
Normal file
40
assignment-service/.dockerignore
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Node.js specific
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
|
||||
# Environment and secrets
|
||||
.env*
|
||||
*.env
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
|
||||
# Development artifacts
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Version control
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
README*
|
||||
|
||||
# Docker files
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
|
||||
# Project-specific
|
||||
package-lock.json
|
||||
2
assignment-service/.env
Normal file
2
assignment-service/.env
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#DB_ASSIGNMENT_SERVICE_URL = "http://localhost:3000"
|
||||
DB_ASSIGNMENT_SERVICE_URL = "http://db-assignment-service.internal:3000"
|
||||
23
assignment-service/Dockerfile
Normal file
23
assignment-service/Dockerfile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
|
||||
# Install dependencies using npm ci for deterministic builds
|
||||
# RUN --mount=type=cache,target=/root/.npm npm ci --production
|
||||
|
||||
# Copy the application source code
|
||||
COPY --link . .
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8080
|
||||
|
||||
# Define the command to run the application
|
||||
CMD ["node", "server.js"]
|
||||
20
assignment-service/DockerfileDEV
Normal file
20
assignment-service/DockerfileDEV
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
|
||||
# Install dependencies using npm ci for deterministic builds
|
||||
# RUN --mount=type=cache,target=/root/.npm npm ci --production
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8082
|
||||
|
||||
# Define the command to run the application
|
||||
CMD ["node", "server.js"]
|
||||
33
assignment-service/README.md
Normal file
33
assignment-service/README.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Running the Project with Docker
|
||||
|
||||
This section provides instructions to build and run the project using Docker.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ensure Docker and Docker Compose are installed on your system.
|
||||
- The project requires Node.js version `22.13.1` as specified in the Dockerfile.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- If applicable, create a `.env` file in the project root directory to define environment variables. Uncomment the `env_file` line in the `docker-compose.yml` file to enable this.
|
||||
|
||||
## Build and Run Instructions
|
||||
|
||||
1. Build the Docker image and start the services:
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
2. Access the application at `http://localhost:8080`.
|
||||
|
||||
## Configuration
|
||||
|
||||
- The application runs with a non-root user for enhanced security.
|
||||
- The `NODE_ENV` is set to `production` and `NODE_OPTIONS` is configured for optimized memory usage.
|
||||
|
||||
## Exposed Ports
|
||||
|
||||
- The application service exposes port `8080` to the host system.
|
||||
|
||||
For further details, refer to the provided `Dockerfile` and `docker-compose.yml` files.
|
||||
5
assignment-service/dev.env
Normal file
5
assignment-service/dev.env
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#DB_ASSIGNMENT_SERVICE_URL="http://localhost:3000"
|
||||
DB_ASSIGNMENT_SERVICE_URL="http://js-assignment-db-service:3200"
|
||||
AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42"
|
||||
ACCEPTED_ORIGINS=http://localhost:3000,http://localhost:8081,http://localhost:3001,http://localhost:5173
|
||||
PORT=8082
|
||||
42
assignment-service/fly.toml
Normal file
42
assignment-service/fly.toml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# fly.toml app configuration file generated for assignment-service on 2025-04-24T11:48:54-07:00
|
||||
#
|
||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||
#
|
||||
|
||||
app = 'assignment-service'
|
||||
primary_region = 'sea'
|
||||
|
||||
[build]
|
||||
|
||||
[env]
|
||||
PORT = '8080'
|
||||
|
||||
[http_service]
|
||||
internal_port = 8080
|
||||
force_https = true
|
||||
auto_stop_machines = 'stop'
|
||||
auto_start_machines = true
|
||||
min_machines_running = 0
|
||||
processes = ['app']
|
||||
|
||||
[[services]]
|
||||
protocol = 'tcp'
|
||||
internal_port = 8080
|
||||
|
||||
[[services.ports]]
|
||||
port = 80
|
||||
handlers = ['http']
|
||||
|
||||
[[services.ports]]
|
||||
port = 443
|
||||
handlers = ['tls', 'http']
|
||||
|
||||
[[services.tcp_checks]]
|
||||
interval = '10s'
|
||||
timeout = '2s'
|
||||
grace_period = '5s'
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
2043
assignment-service/package-lock.json
generated
Normal file
2043
assignment-service/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
21
assignment-service/package.json
Normal file
21
assignment-service/package.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "auth-service",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"dev": "nodemon server.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"axios": "^1.8.4",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "^1.18.1",
|
||||
"nodemon": "^3.1.9",
|
||||
"passport": "^0.7.0"
|
||||
}
|
||||
}
|
||||
82
assignment-service/routes/InstructorRouter.js
Normal file
82
assignment-service/routes/InstructorRouter.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
const intructorRouter = require("express").Router();
|
||||
const passport = require("passport");
|
||||
const axios = require("axios");
|
||||
|
||||
const DB_ASSIGNMENT_SERVICE_URL = process.env.DB_ASSIGNMENT_SERVICE_URL || "http://localhost:3000";
|
||||
console.log("DB_ASSIGNMENT_SERVICE_URL:", DB_ASSIGNMENT_SERVICE_URL);
|
||||
|
||||
// This endpoint is for instructors to create a new assignment
|
||||
intructorRouter.post("/create",
|
||||
// passport.authenticate("jwt", { session: false }),
|
||||
async (req, res) => {
|
||||
try {
|
||||
console.log("Creating a new assignment with data:", req.body);
|
||||
const response = await axios.post(`${DB_ASSIGNMENT_SERVICE_URL}/assignments`, req.body);
|
||||
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
|
||||
res.status(response.status).json(response.data);
|
||||
} catch (error) {
|
||||
console.error("Error creating assignment:", error.message);
|
||||
res.status(error.response?.status || 500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// This endpoint is for instructors to get details of a specific assignment
|
||||
intructorRouter.get("/details/:id", async (req, res) => {
|
||||
try {
|
||||
const assignmentId = req.params.id;
|
||||
console.log("Fetching details for assignmentId:", assignmentId);
|
||||
const response = await axios.get(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`);
|
||||
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
|
||||
res.status(response.status).json(response.data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching assignment details:", error.message);
|
||||
res.status(error.response?.status || 500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// This endpoint is for instructors to get a list of assignments they have created
|
||||
intructorRouter.get("/list/:id", async (req, res) => {
|
||||
// if (req.isAuthenticated()) {
|
||||
try {
|
||||
const instructorId = req.params.id;
|
||||
console.log("Fetching assignments for instructorId:", instructorId);
|
||||
// const instructorId = req.user.userid; // Assuming req.user contains the authenticated user
|
||||
const response = await axios.get(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/instructor/${instructorId}`);
|
||||
console.log("Response from DB_ASSIGNMENT_SERVICE_URL:", response.data);
|
||||
res.status(response.status).json(response.data);
|
||||
} catch (error) {
|
||||
res.status(error.response?.status || 500).json({ error: error.message });
|
||||
}
|
||||
// } else {
|
||||
// return res.status(401).json({ error: "Not authenticated" });
|
||||
// }
|
||||
|
||||
});
|
||||
|
||||
// This endpoint is for instructors to update an assignment
|
||||
intructorRouter.put("/update/:id",
|
||||
// passport.authenticate("jwt", { session: false }),
|
||||
async (req, res) => {
|
||||
try {
|
||||
const assignmentId = req.params.id;
|
||||
const response = await axios.put(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`, req.body);
|
||||
res.status(response.status).json(response.data);
|
||||
} catch (error) {
|
||||
res.status(error.response?.status || 500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// This endpoint is for instructors to delete an assignment
|
||||
intructorRouter.delete("/delete/:id",
|
||||
// passport.authenticate("jwt", { session: false }),
|
||||
async (req, res) => {
|
||||
try {
|
||||
const assignmentId = req.params.id;
|
||||
const response = await axios.delete(`${DB_ASSIGNMENT_SERVICE_URL}/assignments/${assignmentId}`);
|
||||
res.status(response.status).json(response.data);
|
||||
} catch (error) {
|
||||
res.status(error.response?.status || 500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = intructorRouter;
|
||||
13
assignment-service/routes/StudentRouter.js
Normal file
13
assignment-service/routes/StudentRouter.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const studentRouter = require("express").Router();
|
||||
const passport = require("passport");
|
||||
const axios = require("axios");
|
||||
|
||||
studentRouter.post("/save", (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
studentRouter.post("/deploy", (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
module.exports = studentRouter;
|
||||
41
assignment-service/server.js
Normal file
41
assignment-service/server.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
require('dotenv').config();
|
||||
const cors = require("cors");
|
||||
const passport = require("passport");
|
||||
const session = require("express-session");
|
||||
|
||||
const express = require("express");
|
||||
const instructorRouter = require("./routes/InstructorRouter");
|
||||
const studentRouter = require("./routes/StudentRouter");
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
|
||||
// app.use(
|
||||
// session({
|
||||
// secret: process.env.AUTH_SESSION_KEY,
|
||||
// resave: false,
|
||||
// saveUninitialized: false,
|
||||
// cookie: {
|
||||
// maxAge: 24 * 60 * 60 * 1000, // 1 day
|
||||
// },
|
||||
// })
|
||||
// );
|
||||
|
||||
// app.use(passport.initialize());
|
||||
// app.use(passport.session());
|
||||
|
||||
// app.use(
|
||||
// cors({
|
||||
// origin: process.env.ACCEPTED_ORIGINS.split(","),
|
||||
// methods: ["GET", "POST"],
|
||||
// credentials: true,
|
||||
// })
|
||||
// )
|
||||
|
||||
app.use("/instructor", instructorRouter);
|
||||
app.use("/student", studentRouter);
|
||||
|
||||
const port = process.env.PORT || 8080;
|
||||
app.listen(port, () => console.log(`Listening on port ${port}...`));
|
||||
40
auth-service/.dockerignore
Normal file
40
auth-service/.dockerignore
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Node.js specific
|
||||
**node_modules/
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
|
||||
# Environment and secrets
|
||||
.env*
|
||||
*.env
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
|
||||
# Development artifacts
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Version control
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
README*
|
||||
|
||||
# Docker files
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
|
||||
# Project-specific
|
||||
package-lock.json
|
||||
11
auth-service/.env
Normal file
11
auth-service/.env
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
GOOGLE_CLIENT_ID = "485880105639-1in8tvb6ondnn198rasuj2d8ank06ntp.apps.googleusercontent.com"
|
||||
GOOGLE_CLIENT_SECRET = "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"
|
||||
GOOGLE_CALLBACK_URL = "https://byte-camp-auth-service.fly.dev/auth/google/callback"
|
||||
LOGIN_REDIRECT_URL = "https://bytecamp-web.fly.dev/"
|
||||
ACCEPTED_ORIGINS ="https://bytecamp-web.fly.dev,https://byte-camp-auth-service.fly.dev"
|
||||
#DB_USER_SERVICE_URL = "http://localhost:3000/"
|
||||
DB_USER_SERVICE_URL = "http://db-user-service.internal:3000/"
|
||||
AUTH_SESSION_KEY = "f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42"
|
||||
|
||||
# fly secrets set GOOGLE_CALLBACK_URL=https://byte-camp-auth-service.fly.dev/auth/google/callback
|
||||
#fly secrets set GOOGLE_CLIENT_ID=485880105639-1in8tvb6ondnn198rasuj2d8ank06ntp.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=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 LOGIN_REDIRECT_URL=https://bytecamp-web.fly.dev/ DB_USER_SERVICE_URL=https://db-user-service.fly.dev:3000/ AUTH_SESSION_KEY=f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42
|
||||
23
auth-service/Dockerfile
Normal file
23
auth-service/Dockerfile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
|
||||
# Install dependencies using npm ci for deterministic builds
|
||||
# RUN --mount=type=cache,target=/root/.npm npm ci --production
|
||||
|
||||
# Copy the application source code
|
||||
COPY --link . .
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8080
|
||||
|
||||
# Define the command to run the application
|
||||
CMD ["node", "server.js"]
|
||||
20
auth-service/DockerfileDEV
Normal file
20
auth-service/DockerfileDEV
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
|
||||
# Install dependencies using npm ci for deterministic builds
|
||||
# RUN --mount=type=cache,target=/root/.npm npm ci --production
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8080
|
||||
|
||||
# Define the command to run the application
|
||||
CMD ["node", "server.js"]
|
||||
33
auth-service/README.md
Normal file
33
auth-service/README.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Running the Project with Docker
|
||||
|
||||
This section provides instructions to build and run the project using Docker.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Ensure Docker and Docker Compose are installed on your system.
|
||||
- The project requires Node.js version `22.13.1` as specified in the Dockerfile.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- If applicable, create a `.env` file in the project root directory to define environment variables. Uncomment the `env_file` line in the `docker-compose.yml` file to enable this.
|
||||
|
||||
## Build and Run Instructions
|
||||
|
||||
1. Build the Docker image and start the services:
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
2. Access the application at `http://localhost:8080`.
|
||||
|
||||
## Configuration
|
||||
|
||||
- The application runs with a non-root user for enhanced security.
|
||||
- The `NODE_ENV` is set to `production` and `NODE_OPTIONS` is configured for optimized memory usage.
|
||||
|
||||
## Exposed Ports
|
||||
|
||||
- The application service exposes port `8080` to the host system.
|
||||
|
||||
For further details, refer to the provided `Dockerfile` and `docker-compose.yml` files.
|
||||
8
auth-service/dev.env
Normal file
8
auth-service/dev.env
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
GOOGLE_CLIENT_ID="485880105639-1in8tvb6ondnn198rasuj2d8ank06ntp.apps.googleusercontent.com"
|
||||
GOOGLE_CLIENT_SECRET="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"
|
||||
GOOGLE_CALLBACK_URL="http://localhost:8080/auth/google/callback"
|
||||
LOGIN_REDIRECT_URL="http://localhost:5173/"
|
||||
ACCEPTED_ORIGINS=http://localhost:3000,http://localhost:8081,http://localhost:3001,http://localhost:5173
|
||||
DB_USER_SERVICE_URL="http://js-user-db-service:3100/"
|
||||
AUTH_SESSION_KEY="f3f4d8e6b17a4b3abdc8e9a2c0457aaf91c0d5f6e3b7a9c8df624bd71ea35f42"
|
||||
PORT=8080
|
||||
42
auth-service/fly.toml
Normal file
42
auth-service/fly.toml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# fly.toml app configuration file generated for byte-camp-auth-service on 2025-04-21T14:38:25-07:00
|
||||
#
|
||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||
#
|
||||
|
||||
app = 'byte-camp-auth-service'
|
||||
primary_region = 'sea'
|
||||
|
||||
[build]
|
||||
|
||||
[env]
|
||||
PORT = '8080'
|
||||
|
||||
[http_service]
|
||||
internal_port = 8080
|
||||
force_https = true
|
||||
auto_stop_machines = 'stop'
|
||||
auto_start_machines = true
|
||||
min_machines_running = 0
|
||||
processes = ['app']
|
||||
|
||||
[[services]]
|
||||
protocol = 'tcp'
|
||||
internal_port = 8080
|
||||
|
||||
[[services.ports]]
|
||||
port = 80
|
||||
handlers = ['http']
|
||||
|
||||
[[services.ports]]
|
||||
port = 443
|
||||
handlers = ['tls', 'http']
|
||||
|
||||
[[services.tcp_checks]]
|
||||
interval = '10s'
|
||||
timeout = '2s'
|
||||
grace_period = '5s'
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
1555
auth-service/package-lock.json
generated
Normal file
1555
auth-service/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
22
auth-service/package.json
Normal file
22
auth-service/package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "auth-service",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"dev": "nodemon server.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"axios": "^1.8.4",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.5.0",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "^1.18.1",
|
||||
"nodemon": "^3.1.9",
|
||||
"passport": "^0.7.0",
|
||||
"passport-google-oauth20": "^2.0.0"
|
||||
}
|
||||
}
|
||||
36
auth-service/passport.js
Normal file
36
auth-service/passport.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
require('dotenv').config();
|
||||
|
||||
const GoogleStrategy = require("passport-google-oauth20").Strategy;
|
||||
const passport = require("passport");
|
||||
|
||||
passport.use(
|
||||
new GoogleStrategy(
|
||||
{
|
||||
clientID: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
callbackURL: process.env.GOOGLE_CALLBACK_URL,
|
||||
scope: ["profile", "email"],
|
||||
},
|
||||
function (accessToken, refreshToken, profile, callback) {
|
||||
|
||||
// Save the user info to your DB here if still not yet saved
|
||||
// Example of what profile might contain:
|
||||
// {
|
||||
// "id": "112233445566778899",
|
||||
// "displayName": "John Doe",
|
||||
// "emails": [{ "value": "john.doe@gmail.com" }],
|
||||
// "photos": [{ "value": "https://.../photo.jpg" }]
|
||||
// }
|
||||
|
||||
callback(null, profile);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
passport.serializeUser((user, done) => {
|
||||
done(null, user);
|
||||
});
|
||||
|
||||
passport.deserializeUser((user, done) => {
|
||||
done(null,user);
|
||||
});
|
||||
60
auth-service/routes/auth.js
Normal file
60
auth-service/routes/auth.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
const router = require("express").Router();
|
||||
const passport = require("passport");
|
||||
const axios = require("axios");
|
||||
|
||||
router.get(
|
||||
"/google/callback",
|
||||
passport.authenticate("google", {
|
||||
successRedirect: "/auth/google/login",
|
||||
failureRedirect: "/auth/login/failed",
|
||||
})
|
||||
);
|
||||
|
||||
router.get("/current_user", (req, res) => {
|
||||
if (req.isAuthenticated()) {
|
||||
console.log("Authenticated user:", req.user);
|
||||
res.json(req.user);
|
||||
} else {
|
||||
console.log("User not authenticated");
|
||||
res.status(401).json({ error: "Not authenticated" });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/google/login", (req, res) => {
|
||||
if (req.user) {
|
||||
console.log(`${process.env.DB_USER_SERVICE_URL}instructor/register-user`);
|
||||
axios
|
||||
.post(`${process.env.DB_USER_SERVICE_URL}instructor/register-user`, {
|
||||
user: req.user,
|
||||
})
|
||||
.then((response) => {
|
||||
req.user.userId = response.data.user.userid;
|
||||
console.log("User ID:", response.data.user.userid);
|
||||
req.user.role = "instructor";
|
||||
console.log("User registration response:", response.data);
|
||||
res.redirect(process.env.LOGIN_REDIRECT_URL);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error registering user:", error.message);
|
||||
res.status(500).json({ error: true, message: "User login failed" });
|
||||
});
|
||||
} else {
|
||||
res.status(403).json({ error: true, message: "Not Authorized" });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/login/failed", (req, res) => {
|
||||
res.status(401).json({
|
||||
error: true,
|
||||
message: "Log in failure",
|
||||
});
|
||||
});
|
||||
|
||||
router.get("/google", passport.authenticate("google", ["profile", "email"]));
|
||||
|
||||
router.get("/logout", (req, res) => {
|
||||
req.logOut();
|
||||
res.redirect(process.env.LOGIN_REDIRECT_URL);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
37
auth-service/server.js
Normal file
37
auth-service/server.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
require('dotenv').config();
|
||||
|
||||
const cors = require("cors");
|
||||
const express = require("express");
|
||||
const passport = require("passport");
|
||||
const passportSetup = require("./passport");
|
||||
const authRoute = require("./routes/auth");
|
||||
const session = require("express-session");
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(
|
||||
session({
|
||||
secret: process.env.AUTH_SESSION_KEY,
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
maxAge: 24 * 60 * 60 * 1000, // 1 day
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
app.use(passport.initialize());
|
||||
app.use(passport.session());
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: process.env.ACCEPTED_ORIGINS.split(","),
|
||||
methods: ["GET", "POST"],
|
||||
credentials: true,
|
||||
})
|
||||
)
|
||||
|
||||
app.use("/auth", authRoute);
|
||||
|
||||
const port = process.env.PORT || 8080;
|
||||
app.listen(port, () => console.log(`Listening on port ${port}...`));
|
||||
64
compose.yaml
Normal file
64
compose.yaml
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
js-assignment-db-service:
|
||||
build:
|
||||
context: ./assignment-db-service
|
||||
dockerfile: DockerfileDEV
|
||||
container_name: js-assignment-db-service
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
ports:
|
||||
- "3200:3200" # Expose port to the same host
|
||||
env_file:
|
||||
- ./assignment-db-service/dev.env
|
||||
networks:
|
||||
- backend
|
||||
|
||||
js-assignment-service:
|
||||
build:
|
||||
context: ./assignment-service
|
||||
dockerfile: DockerfileDEV
|
||||
container_name: js-assignment-service
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
ports:
|
||||
- "8082:8082" # Expose port to the same host
|
||||
env_file:
|
||||
- ./assignment-service/dev.env
|
||||
depends_on:
|
||||
- js-assignment-db-service
|
||||
networks:
|
||||
- backend
|
||||
|
||||
js-auth-service:
|
||||
build:
|
||||
context: ./auth-service
|
||||
dockerfile: DockerfileDEV
|
||||
container_name: js-auth-service
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
ports:
|
||||
- "8080:8080" # Expose port to the same host
|
||||
env_file:
|
||||
- ./auth-service/dev.env
|
||||
networks:
|
||||
- backend
|
||||
|
||||
js-user-db-service:
|
||||
build:
|
||||
context: ./user-db-service
|
||||
dockerfile: DockerfileDEV
|
||||
container_name: js-user-db-service
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
ports:
|
||||
- "3100:3100" # Expose port to the same host
|
||||
env_file:
|
||||
- ./user-db-service/dev.env
|
||||
networks:
|
||||
- backend
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: bridge
|
||||
|
|
@ -1 +0,0 @@
|
|||
PORT=3000
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
DATABASE_SERVICE_URL=""
|
||||
FRONTEND_SERVICE_URL=""
|
||||
UPLOADER_SERVICE_URL=""
|
||||
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
FLY_API_BASE_URL=https://api.fly.io
|
||||
FLY_API_TOKEN=your-api-token
|
||||
40
user-db-service/.dockerignore
Normal file
40
user-db-service/.dockerignore
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Node.js specific
|
||||
**node_modules/
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
|
||||
# Environment and secrets
|
||||
.env*
|
||||
*.env
|
||||
*.pem
|
||||
*.key
|
||||
*.crt
|
||||
|
||||
# Development artifacts
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Version control
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Temporary files
|
||||
tmp/
|
||||
temp/
|
||||
*.tmp
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
README*
|
||||
|
||||
# Docker files
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
|
||||
# Project-specific
|
||||
package-lock.json
|
||||
12
user-db-service/.env
Normal file
12
user-db-service/.env
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Environment variables declared in this file are automatically made available to Prisma.
|
||||
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
|
||||
|
||||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||
|
||||
#use this when testing local, remmber to run the proxy command
|
||||
# DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@localhost:15432/postgres?schema=public"
|
||||
|
||||
DATABASE_URL="postgres://postgres:wly9H8gjjmxYfg1@bytecamp-db.flycast:5432?sslmode=disable"
|
||||
# DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable
|
||||
NODE_PORT=3000
|
||||
20
user-db-service/Dockerfile
Normal file
20
user-db-service/Dockerfile
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
RUN apt-get update -y && apt-get install -y openssl && npm install && npx prisma generate
|
||||
|
||||
# Copy the application source code
|
||||
COPY --link . .
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 3000
|
||||
|
||||
# Define the command to run the application
|
||||
CMD ["node", "app.js"]
|
||||
17
user-db-service/DockerfileDEV
Normal file
17
user-db-service/DockerfileDEV
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
|
||||
# Use the official Node.js image as the base image
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
RUN apt-get update -y && apt-get install -y openssl && npm install && npx prisma generate
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 3100
|
||||
|
||||
# Define the command to run the application
|
||||
CMD ["node", "app.js"]
|
||||
24
user-db-service/app.js
Normal file
24
user-db-service/app.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
const express = require('express');
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const app = express();
|
||||
|
||||
const adminRouter = require("./routes/AdminRouter");
|
||||
const instructorRouter = require("./routes/InstructorRouter");
|
||||
const studentRouter = require("./routes/StudentRouter");
|
||||
|
||||
// require('dotenv').config(); // prisma client already loads .env apparently, double check before deploying
|
||||
const port = process.env.NODE_PORT; // Use env for port
|
||||
console.log('NODE_PORT:', port);
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
//use routes of other pages
|
||||
app.use("/student", studentRouter);
|
||||
app.use("/admin", adminRouter);
|
||||
app.use("/instructor", instructorRouter);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server running at http://localhost:${port}`);
|
||||
});
|
||||
12
user-db-service/dev.env
Normal file
12
user-db-service/dev.env
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Environment variables declared in this file are automatically made available to Prisma.
|
||||
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
|
||||
|
||||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||
|
||||
#use this when testing local, remmber to run the proxy command
|
||||
DATABASE_URL="postgresql://postgres:wly9H8gjjmxYfg1@host.docker.internal:15432/postgres?schema=public"
|
||||
|
||||
# DATABASE_URL="postgres://postgres:wly9H8gjjmxYfg1@bytecamp-db.flycast:5432?sslmode=disable"
|
||||
# DATABASE_URL=postgres://snakebyte:zVB7lgOiKr89dq6@localhost:5432/snakebyte?sslmode=disable
|
||||
NODE_PORT=3100
|
||||
45
user-db-service/fly.toml
Normal file
45
user-db-service/fly.toml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# fly.toml file for a Node.js service that connects to an external Postgres DB
|
||||
|
||||
app = "db-user-service"
|
||||
primary_region = "sea"
|
||||
|
||||
[build]
|
||||
# Only needed if you're using a Dockerfile — can be empty if using buildpacks or Node preset
|
||||
|
||||
#[env]
|
||||
#NODE_ENV = "production"
|
||||
#DATABASE_URL = "postgresql://user:password@hostname:port/dbname"
|
||||
# you can also leave DATABASE_URL unset here and use secrets instead
|
||||
|
||||
# Removed the [http_service] section to disable public HTTP/HTTPS access
|
||||
# [http_service]
|
||||
# internal_port = 3000
|
||||
# force_https = true
|
||||
# auto_stop_machines = true
|
||||
# auto_start_machines = true
|
||||
# min_machines_running = 0
|
||||
# processes = ["app"]
|
||||
|
||||
[[services]]
|
||||
protocol = "tcp"
|
||||
internal_port = 3000
|
||||
internal_only = true # Makes this service only accessible internally
|
||||
|
||||
# Removed public port exposure
|
||||
# [[services.ports]]
|
||||
# port = 80
|
||||
# handlers = ["http"]
|
||||
|
||||
# [[services.ports]]
|
||||
# port = 443
|
||||
# handlers = ["tls", "http"]
|
||||
|
||||
[services.concurrency]
|
||||
type = "requests"
|
||||
hard_limit = 1000
|
||||
soft_limit = 500
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
cpu_kind = "shared"
|
||||
cpus = 1
|
||||
1217
user-db-service/package-lock.json
generated
Normal file
1217
user-db-service/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
12
user-db-service/package.json
Normal file
12
user-db-service/package.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.1.0",
|
||||
"express": "^5.1.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"prisma": "^6.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev": "nodemon app.js"
|
||||
}
|
||||
}
|
||||
19
user-db-service/prisma/schema.prisma
Normal file
19
user-db-service/prisma/schema.prisma
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "windows"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model users {
|
||||
userid Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
name String?
|
||||
password String?
|
||||
role String?
|
||||
googleid String?
|
||||
logintype String?
|
||||
}
|
||||
4
user-db-service/readme.md
Normal file
4
user-db-service/readme.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# database microservice
|
||||
- store database tables
|
||||
- issue and re-issue auth tokens (jwt)
|
||||
- handle password reset into db
|
||||
25
user-db-service/routes/AdminRouter.js
Normal file
25
user-db-service/routes/AdminRouter.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
const express = require("express");
|
||||
const adminRouter = express.Router();
|
||||
|
||||
// Endpoint to fetch custom query (avoid raw queries if possible)
|
||||
adminRouter.get('/query', async (req, res) => {
|
||||
// double check if user is admin first from jwt
|
||||
const query = req.body.query
|
||||
const response = prisma.$queryRaw`${query}`;
|
||||
res.status(400).json({ error: 'Custom queries are not supported.' });
|
||||
});
|
||||
|
||||
// Fetch top users (update logic as per your requirements)
|
||||
adminRouter.get('/update', async (req, res) => {
|
||||
try {
|
||||
const users = await prisma.user.findMany({
|
||||
orderBy: { username: 'asc' }, // Example sorting
|
||||
});
|
||||
res.json(users);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = adminRouter;
|
||||
52
user-db-service/routes/InstructorRouter.js
Normal file
52
user-db-service/routes/InstructorRouter.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
const express = require("express");
|
||||
const instructorRouter = express.Router();
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// For new users sign-up via Google oAuth:
|
||||
instructorRouter.post("/register-user", async (req, res) => {
|
||||
try {
|
||||
console.log("Received request to register user");
|
||||
|
||||
const { id, displayName, emails } = req.body.user;
|
||||
console.log("User details from request:", { id, displayName, emails });
|
||||
|
||||
const email = emails[0].value;
|
||||
console.log("Extracted email:", email);
|
||||
|
||||
// Check if user exists
|
||||
const user = await prisma.users.findFirst({
|
||||
where: {
|
||||
email: {
|
||||
equals: email,
|
||||
mode: "insensitive",
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log("User lookup result:", user);
|
||||
|
||||
// if it is a new user, insert it into the DB
|
||||
if (!user) {
|
||||
console.log("User does not exist, creating new user");
|
||||
const newUser = await prisma.users.create({
|
||||
data: {
|
||||
name: displayName,
|
||||
email: email,
|
||||
role: "instructor",
|
||||
googleid: id,
|
||||
logintype: "google",
|
||||
},
|
||||
});
|
||||
console.log("New user created:", newUser);
|
||||
res.json({ message: "User added successfully", user: newUser });
|
||||
} else {
|
||||
console.log("User already exists:", user);
|
||||
res.json({ message: "User exist", user: user });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error during user registration:", err.message);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = instructorRouter;
|
||||
17
user-db-service/routes/StudentRouter.js
Normal file
17
user-db-service/routes/StudentRouter.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
const express = require("express");
|
||||
const studenRouter = express.Router();
|
||||
|
||||
// Add a new student
|
||||
studenRouter.post('/add-user', async (req, res) => {
|
||||
try {
|
||||
const { username, email } = req.body;
|
||||
const newUser = await prisma.user.create({
|
||||
data: { username, email },
|
||||
});
|
||||
res.json({ message: 'User added successfully', user: newUser });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = studenRouter;
|
||||
Loading…
Add table
Add a link
Reference in a new issue