Skip to content
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
13 changes: 0 additions & 13 deletions server/models/Questions.ts

This file was deleted.

12 changes: 0 additions & 12 deletions server/models/User.ts

This file was deleted.

13 changes: 13 additions & 0 deletions server/src/models/Questions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import mongoose, { Schema, Document } from "mongoose";

export interface IQuestion extends Document {
prompt: string;
difficulty: "easy" | "medium" | "hard";
}

const QuestionSchema: Schema = new Schema({
prompt: { type: String, required: true },
difficulty: { type: String, enum: ["easy", "medium", "hard"], required: true },
});

export const Question = mongoose.model<IQuestion>("Question", QuestionSchema);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express from 'express';
import type { Request, Response } from 'express';
import { OpenAI } from 'openai';
import { PromptBuilder } from '../src/utils/PromptBuilder';
import { PromptBuilder } from '../../utils/PromptBuilder';
import dotenv from 'dotenv';

dotenv.config();
Expand Down
2 changes: 1 addition & 1 deletion server/index.ts → server/src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express from 'express';
import dotenv from 'dotenv';
import cors from 'cors';
import openaiRoutes from './routes/openai';
import openaiRoutes from './api/openai';

dotenv.config();

Expand Down
27 changes: 27 additions & 0 deletions server/src/seeds/seed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import mongoose from "mongoose";
import dotenv from "dotenv";
import User from "../models/User";
// import { Question } from "../models/Question";

dotenv.config();

async function seedDatabase() {
await mongoose.connect(process.env.MONGODB_URI!);

// Wipe collections
await User.deleteMany({});

// Seed data
await User.create({ username: "playerOne", email: "player@example.com", password: "123456" });
// await Question.insertMany([
// { prompt: "Explain closures in JavaScript", difficulty: "hard" },
// { prompt: "What is a component in React?", difficulty: "easy" }
// ]);

console.log("🌱 Seeding complete!");
mongoose.connection.close();
}

seedDatabase().catch((error) => {
console.error("Error seeding database:", error);
});
63 changes: 41 additions & 22 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,54 @@ import typeDefs from './schemas/typeDefs';
import resolvers from './schemas/resolvers';
import { authenticateToken } from './utils/auth';


// Extend the Request interface to include the user property
declare global {
namespace Express {
interface Request {
user?: any; // Replace 'any' with the appropriate type for your user object
}
}
}

dotenv.config();

const startServer = async () => {
const app = express();
const PORT = process.env.PORT || 3001;
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! });

// Middleware
app.use(cors());
app.use(express.json());
app.use(express.static('public')); // serve generated mp3 files
app.use(authenticateToken);
// Create a new instance of an Apollo server with the GraphQL schema
const startApolloServer = async () => {
const server = new ApolloServer({
typeDefs,
resolvers,
});

// Apollo Server setup
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }: { req: Request }) => ({ user: req.user }),
});
await server.start();
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(express.static('public')); // serve generated mp3 file
app.use('/graphql', expressMiddleware(server as any,
{
context: authenticateToken as any
}
));

// if we're in production, serve client/build as static assets
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(dirname, '../client/build')));

app.get('*', (_req: Request, res: Response) => {
res.sendFile(path.join(dirname, '../client/dist/index.html'));
});
}

await server.start();
server.applyMiddleware({ app, path: '/graphql' });
// Start the server
app.listen(PORT, () => {
console.log(`✅ Server is running on http://localhost:${PORT}`);
console.log(`✅ GraphQL endpoint is available at http://localhost:${PORT}/graphql`);
});
};

// TTS Route for Dr. Dan
app.post('/api/tts', async (req: Request, res: Response) => {
Expand All @@ -58,11 +84,4 @@ dotenv.config();
res.send('🎙️ Codezilla server is up!');
});

// Start the server
app.listen(PORT, () => {
console.log(`✅ Server is running on http://localhost:${PORT}`);
console.log(`✅ GraphQL endpoint is available at http://localhost:${PORT}/graphql`);
});
};

startServer();
startApolloServer();
77 changes: 44 additions & 33 deletions server/src/utils/auth.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,67 @@
import type { Request, Response, NextFunction} from 'express';
import jwt from 'jsonwebtoken';

import dotenv from 'dotenv';

dotenv.config();

interface JwtPayload {
_id: unknown;
username: string;
email: string;
exp?: number; // Optional expiration field
}

export const authMiddleware = ({ req }: { req: any }) => {
const authHeader = req.headers.authorization;

declare global {
namespace Express {
interface Request {
user?: JwtPayload;
}
}
}
if (authHeader) {
const token = authHeader.split(' ')[1];
const secretKey = process.env.JWT_SECRET_KEY || '';

export const authenticateToken = (req: Request, res: Response, next: NextFunction) => {
const authHeader = req.headers.authorization || '';
console.log('Token received:', token); // Log the token

if (!authHeader) {
return res.status(401).json({ error: 'Authorization header is missing' });
}
try {
const decoded = jwt.decode(token) as JwtPayload | null;

const token = authHeader.split(' ')[1];
const secretKey = process.env.JWT_SECRET_KEY;
if (!decoded || !decoded.exp) {
throw new Error('Token does not contain expiration date');
}

if (!secretKey) {
console.error('JWT_SECRET_KEY is not defined in the environment variables');
return res.status(500).json({ error: 'Internal server error' });
}
const currentTime = Math.floor(Date.now() / 1000);
if (decoded.exp < currentTime) {
throw new Error('Token has expired');
}

jwt.verify(token, secretKey, (err, user) => {
if (err) {
console.error('JWT verification failed:', err.message);
return res.status(403).json({ error: 'Invalid or expired token' });
const user = jwt.verify(token, secretKey) as JwtPayload;
return { user };
} catch (err) {
console.error('Invalid token:', err);
throw new Error('Invalid token');
}
}

req.user = user as JwtPayload;
next();
});
return { user: null };
};
export const signToken = (username: string, email: string, _id: unknown) => {
const payload = { username, email, _id };
const secretKey = process.env.JWT_SECRET_KEY;

if (!secretKey) {
throw new Error('JWT_SECRET_KEY is not defined in the environment variables');
export const authenticateToken = (token: string) => {
const secretKey = process.env.JWT_SECRET_KEY || '';

if (!token) {
throw new Error('No token provided');
}

try {
const user = jwt.verify(token, secretKey) as JwtPayload;
return user;
} catch (err) {
console.error('Invalid token:', err);
throw new Error('Invalid or expired token');
}
};

return jwt.sign(payload, secretKey, { expiresIn: '1h' });
export const signToken = (username: string, email: string, _id: unknown) => {
const payload = { username, email, _id };
const secretKey = process.env.JWT_SECRET_KEY || '';
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
console.log('Generated Token:', token);
return token;
};