Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7898f40
revaming frontend completely
Jul 12, 2026
9297100
Updated TutorConnect backend and frontend
musharaftara123-spec Jul 12, 2026
81a026f
error handled
musharaftara123-spec Jul 12, 2026
ed95eeb
Wire up exam engine: student TestsPage, tutor TutorTestCompo, fix bro…
sundroosaahil Jul 12, 2026
4fa5e76
Add exam/result backend models and routes
sundroosaahil Jul 13, 2026
37b3f00
Fixed filename mismatch: Testspage.jsx -> TestsPage.jsx
sundroosaahil Jul 13, 2026
5d5c44a
Replace hardcoded localhost URLs with VITE_API_URL variable
sundroosaahil Jul 13, 2026
e863afd
fixed buttons (where upon clicking it didnt show tests ) minor chang…
sundroosaahil Jul 14, 2026
8099a5e
updated ui of student dashboard and tutor dashboard ,some things may…
sundroosaahil Jul 14, 2026
adce429
more changes to ui
sundroosaahil Jul 15, 2026
d60fc48
ui changes for student side
sundroosaahil Jul 18, 2026
1197fa3
updated the ui on tutor side
sundroosaahil Jul 19, 2026
385eb93
added admin panel
sundroosaahil Jul 20, 2026
2ac2ad4
Integrate admin panel: teacher approval routes, auth middleware, seed…
sundroosaahil Jul 20, 2026
66bff86
doubt section now shows doubts on tutor side
sundroosaahil Jul 20, 2026
610deb3
completed project
musharaftara123-spec Jul 21, 2026
b565f55
students can see best score
sundroosaahil Jul 21, 2026
4827a84
Merge branch 'ui-testing' of https://github.com/Adilrasheed1/Project …
sundroosaahil Jul 21, 2026
e24728c
fixed tutor side results
sundroosaahil Jul 21, 2026
f8d0147
filtering of tutors
Jul 26, 2026
444176c
minor changes in landing page
sundroosaahil Jul 26, 2026
6502e65
doubt entries
Jul 26, 2026
8101a5d
bss
Jul 26, 2026
d0f63e2
Merge branch 'ui-testing' of https://github.com/Adilrasheed1/Project …
sundroosaahil Jul 27, 2026
151e662
fix: resolve face-api.js build failure on Vite 8/Rolldown
sundroosaahil Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
Empty file removed backend/.env
Empty file.
2 changes: 2 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
.env
9 changes: 9 additions & 0 deletions backend/cloudinary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const cloudinary = require("cloudinary").v2;

cloudinary.config({
cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});

module.exports = cloudinary;
39 changes: 0 additions & 39 deletions backend/db/index.js

This file was deleted.

46 changes: 46 additions & 0 deletions backend/grandfatherTeachers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Run once, AFTER you've added the `status` field to Teacher.js
// and BEFORE any new teacher signs up under the new approval flow.
//
// This approves every teacher that already exists in the database,
// so only teachers who register from now on need admin approval.
//
// Usage:
// cd backend
// node grandfatherTeachers.js

require("dotenv").config();
const mongoose = require("mongoose");
const dns = require("node:dns");

// Same DNS fix used in index.js — required for MongoDB Atlas SRV lookups
// to resolve correctly on this network/machine.
dns.setServers(["8.8.8.8", "1.1.1.1"]);
dns.setDefaultResultOrder("ipv4first");

const Teacher = require("./models/Teacher");

async function run() {
await mongoose.connect(process.env.MONGO_URI, {
serverSelectionTimeoutMS: 10000,
family: 4,
});

const result = await Teacher.updateMany(
{}, // every existing teacher
{
status: "Approved",
isVerified: true,
reviewedAt: new Date(),
}
);

console.log(`✅ Grandfathered ${result.modifiedCount} existing teacher(s) as Approved.`);
console.log("Any teacher who signs up from now on will start as Pending and require admin approval.");

process.exit();
}

run().catch((err) => {
console.error("❌ Migration failed:", err);
process.exit(1);
});
58 changes: 39 additions & 19 deletions backend/index.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,51 @@
const express = require("express");
const cors = require("cors");
const http = require("http"); // 👈 add this
const mongoose = require("mongoose");
const http = require("http");
const bodyParser = require("body-parser");
require("dotenv").config();

const dns = require("node:dns");

dns.setServers(["8.8.8.8", "1.1.1.1"]);
dns.setDefaultResultOrder("ipv4first");

const app = express();
const server = http.createServer(app); // 👈 create HTTP server from express app
const server = http.createServer(app);

app.use(cors());
app.use(express.json());
app.use(bodyParser.json());
app.use("/api/auth", require("./routes/auth"));
app.use("/api/teacher-courses", require("./routes/teacherCourses"));
app.use("/api/courses", require("./routes/courses"));
app.use("/api/student", require("./routes/student"));
app.use("/api/orders", require("./routes/orders"));
// app.use("/api/doubts", require("./routes/doubts"));
app.use("/api/support", require("./routes/support"));
app.use("/api/admin-panel", require("./routes/adminPanel"));
// app.use("/api/admin", require("./routes/admin"));
// app.use("/api/tutor", require("./routes/tutor"));
// app.use("/api/user", require("./routes/user"));
app.use("/api/exam", require("./routes/exam"));
app.use("/api/result", require("./routes/result"));
app.use("/api/doubts", require("./routes/doubts"));

const adminRouter = require("./routes/admin");
const userRouter = require("./routes/user");
const doubtsRouter = require("./routes/doubts");
const tutorRouter = require("./routes/tutor");
const courseRouter = require('./routes/courses');

app.use("/admin", adminRouter);
app.use("/user", userRouter);
app.use("/doubts", doubtsRouter);
app.use("/tutor", tutorRouter);
app.use("/courses", courseRouter);

// 👇 pass the server to your WebSocket setup
require('./server')(server);

const port = process.env.PORT || 3000;
server.listen(port, () => {
console.log(`Server running on port ${port}`);
});
mongoose
.connect(process.env.MONGO_URI, {
serverSelectionTimeoutMS: 10000,
family: 4,
})
.then(() => {
console.log("✅ Connected to MongoDB successfully!");

server.listen(process.env.PORT || 3000, () => {
console.log(`🚀 Server running on port ${process.env.PORT || 3000}`);
});
})
.catch((err) => {
console.error("❌ MongoDB connection error:");
console.error(err);
});
24 changes: 24 additions & 0 deletions backend/middlewares/adminPanelAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const jwt = require("jsonwebtoken");

const adminPanelAuth = (req, res, next) => {
const token = req.headers.authorization?.split(" ")[1];

if (!token) {
return res.status(401).json({ message: "No token provided" });
}

try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);

if (decoded.role !== "admin") {
return res.status(403).json({ message: "Admin access only" });
}

req.user = decoded;
next();
} catch {
return res.status(401).json({ message: "Invalid token" });
}
};

module.exports = adminPanelAuth;
11 changes: 11 additions & 0 deletions backend/models/AdminUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const mongoose = require("mongoose");

const adminUserSchema = new mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
name: { type: String, default: "Admin" },
role: { type: String, default: "admin" },
createdAt: { type: Date, default: Date.now },
});

module.exports = mongoose.model("AdminUser", adminUserSchema);
29 changes: 29 additions & 0 deletions backend/models/Courses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const mongoose = require("mongoose");

const noteSchema = new mongoose.Schema({
title: { type: String },
fileUrl: { type: String },
}, { _id: false });

const lectureSchema = new mongoose.Schema({
title: { type: String },
videoUrl: { type: String },
notes: [noteSchema], // <-- notes now live under their lecture
}, { _id: false });

const courseSchema = new mongoose.Schema({
title: { type: String, required: true },
subject: { type: String, required: true },
description: { type: String },
price: { type: Number, required: true },
tutor: { type: String, required: true },
tutorId: { type: mongoose.Schema.Types.ObjectId, ref: "Teacher" },
thumbnailUrl: { type: String },
lectures: [lectureSchema],
rating: { type: Number, default: 0 },
students: { type: Number, default: 0 },
color: { type: String, default: "#4FB88A" },
createdAt: { type: Date, default: Date.now },
});

module.exports = mongoose.model("Course", courseSchema);
19 changes: 19 additions & 0 deletions backend/models/Doubts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const mongoose = require("mongoose");

const doubtSchema = new mongoose.Schema(
{
title: { type: String, required: true },
description: { type: String, required: true },
subject: { type: String, required: true },
image: { type: String, default: "" },
status: {
type: String,
enum: ["pending", "resolved"],
default: "pending",
},
},
{ timestamps: true }
);

const Doubts = mongoose.model("Doubts", doubtSchema);
module.exports = { Doubts };
20 changes: 20 additions & 0 deletions backend/models/Exam.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const mongoose = require("mongoose");

const questionSchema = new mongoose.Schema({
question: { type: String },
options: [String],
answer: { type: String }
}, { _id: false });

const examSchema = new mongoose.Schema({
name: { type: String, required: true },
subject: { type: String },
type: { type: String, default: "normal" }, // "normal" or "proctored"
duration: { type: Number },
color: { type: String },
questions: [questionSchema],
createdAt: { type: Date, default: Date.now },
createdBy: { type: String }
});

module.exports = mongoose.model("Exam", examSchema);
32 changes: 32 additions & 0 deletions backend/models/Order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const mongoose = require("mongoose");

const orderSchema = new mongoose.Schema({
student: {
type: mongoose.Schema.Types.ObjectId,
ref: "Student",
required: true,
},

course: {
type: mongoose.Schema.Types.ObjectId,
ref: "Course",
required: true,
},

amount: {
type: Number,
required: true,
},

paymentStatus: {
type: String,
default: "Completed",
},

purchasedAt: {
type: Date,
default: Date.now,
},
});

module.exports = mongoose.model("Order", orderSchema);
22 changes: 22 additions & 0 deletions backend/models/Result.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const mongoose = require("mongoose");

const violationSchema = new mongoose.Schema({
type: { type: String },
time: { type: String },
deduction: { type: Number }
}, { _id: false });

const resultSchema = new mongoose.Schema({
examId: { type: String },
examName: { type: String },
studentUsername: { type: String },
examScore: { type: Number },
integrityScore: { type: Number },
finalScore: { type: Number },
totalMarks: { type: Number },
examType: { type: String },
violations: [violationSchema],
submittedAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model("Result", resultSchema);
50 changes: 50 additions & 0 deletions backend/models/Student.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const mongoose = require("mongoose");

const enrolledCourseSchema = new mongoose.Schema({
course: {
type: mongoose.Schema.Types.ObjectId,
ref: "Course",
},

progress: {
type: Number,
default: 0,
},

completedLectures: [
{
type: Number,
},
],

enrolledAt: {
type: Date,
default: Date.now,
},
});

const studentSchema = new mongoose.Schema({
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true },
phone: { type: String },
dob: { type: String },
gender: { type: String },
grade: { type: String },
board: { type: String },
school: { type: String },
city: { type: String },
state: { type: String },
password: { type: String, required: true },
role: { type: String, default: "student" },

isBlocked: { type: Boolean, default: false },
blockedAt: { type: Date },
blockReason: { type: String, default: "" },

enrolledCourses: [enrolledCourseSchema],

createdAt: { type: Date, default: Date.now },
});

module.exports = mongoose.model("Student", studentSchema);
Loading