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
2 changes: 1 addition & 1 deletion app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default function AboutPage() {
<div className="grid grid-cols-2 md:grid-cols-4 gap-8 text-center">
{[
{ value: "20K+", label: "Community Members" },
{ value: "800+", label: "Engineers Trained" },
{ value: "1600+", label: "Engineers Trained" },
{ value: "200+", label: "Sessions Delivered" },
{ value: "100%", label: "Free Forever" },
].map((stat, i) => (
Expand Down
85 changes: 83 additions & 2 deletions app/api/dsoc/applications/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,47 @@ import connectDB from '@/lib/db';
import { DSOCApplication } from '@/models/DSOCApplication';
import { DSOCProject } from '@/models/DSOCProject';
import { DSOCMentee } from '@/models/DSOCMentee';
import jwt from 'jsonwebtoken';

async function getMentorFromToken(request: NextRequest) {
const token = request.cookies.get('dsoc-mentor-token')?.value;
if (!token) return null;

try {
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as { id: string; role: string };
if (decoded.role !== 'dsoc-mentor') return null;
return decoded.id;
} catch {
return null;
}
}

async function getAdminFromToken(request: NextRequest) {
const token = request.cookies.get('admin-token')?.value;
if (!token) return null;

try {
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as { id?: string };
return decoded.id || null;
} catch {
return null;
}
}

function hasMentorAccess(
mentorId: string,
project: { mentors?: Array<{ _id?: string } | string> } | null
) {
if (!project || !Array.isArray(project.mentors)) return false;

return project.mentors.some((mentor) => {
if (!mentor) return false;
if (typeof mentor === 'string') return mentor === mentorId;
if (mentor._id) return mentor._id.toString() === mentorId;
const asAny = mentor as { toString?: () => string };
return asAny.toString?.() === mentorId;
});
}

// GET single application
export async function GET(
Expand All @@ -12,6 +53,15 @@ export async function GET(
try {
await connectDB();
const { id } = await params;

const mentorId = await getMentorFromToken(request);
const adminId = await getAdminFromToken(request);
if (!mentorId && !adminId) {
return NextResponse.json(
{ success: false, error: 'Unauthorized' },
{ status: 401 }
);
}

const application = await DSOCApplication.findById(id)
.populate('project', 'title organization status mentors')
Expand All @@ -24,6 +74,16 @@ export async function GET(
{ status: 404 }
);
}

if (mentorId) {
const project = application.project as { mentors?: Array<{ _id?: string } | string> } | null;
if (!hasMentorAccess(mentorId, project)) {
return NextResponse.json(
{ success: false, error: 'Forbidden' },
{ status: 403 }
);
}
}

return NextResponse.json({
success: true,
Expand All @@ -46,8 +106,16 @@ export async function PUT(
try {
await connectDB();
const { id } = await params;

// TODO: Add mentor/admin authentication check

const mentorId = await getMentorFromToken(request);
const adminId = await getAdminFromToken(request);
if (!mentorId && !adminId) {
return NextResponse.json(
{ success: false, error: 'Unauthorized' },
{ status: 401 }
);
}

const body = await request.json();
const { status, mentorNotes, adminNotes, score } = body;

Expand All @@ -59,6 +127,19 @@ export async function PUT(
{ status: 404 }
);
}

if (mentorId) {
const project = await DSOCProject.findById(application.project)
.select('mentors')
.lean();

if (!project || !hasMentorAccess(mentorId, project)) {
return NextResponse.json(
{ success: false, error: 'Forbidden' },
{ status: 403 }
);
}
}

// Update application
if (status) application.status = status;
Expand Down
52 changes: 46 additions & 6 deletions app/api/dsoc/applications/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ async function getMenteeFromToken(request: NextRequest) {
}
}

// Helper to get mentor from token
async function getMentorFromToken(request: NextRequest) {
const token = request.cookies.get('dsoc-mentor-token')?.value;
if (!token) return null;

try {
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as { id: string; role: string };
if (decoded.role !== 'dsoc-mentor') return null;
return decoded.id;
} catch {
return null;
}
}

// GET all applications (with filters)
export async function GET(request: NextRequest) {
try {
Expand All @@ -26,15 +40,41 @@ export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const projectId = searchParams.get('project');
const status = searchParams.get('status');
const menteeId = await getMenteeFromToken(request);
const mentorOnly = searchParams.get('mentor') === 'true';
const menteeOnly = searchParams.get('my') === 'true';
const menteeId = menteeOnly ? await getMenteeFromToken(request) : null;

const query: any = {};

if (projectId) query.project = projectId;
if (status) query.status = status;
if (menteeId && searchParams.get('my') === 'true') {
query.mentee = menteeId;

if (mentorOnly) {
const mentorId = await getMentorFromToken(request);
if (!mentorId) {
return NextResponse.json(
{ success: false, error: 'Unauthorized' },
{ status: 401 }
);
}

const mentorProjects = await DSOCProject.find({ mentors: mentorId })
.select('_id')
.lean();

const mentorProjectIds = mentorProjects.map((project) => project._id.toString());

if (projectId) {
if (!mentorProjectIds.includes(projectId)) {
return NextResponse.json({ success: true, data: [] });
}
query.project = projectId;
} else {
query.project = { $in: mentorProjectIds };
}
} else {
if (projectId) query.project = projectId;
if (menteeId) query.mentee = menteeId;
}

if (status) query.status = status;

const applications = await DSOCApplication.find(query)
.populate('project', 'title organization status')
Expand Down
45 changes: 45 additions & 0 deletions app/api/dsoc/mentor/me/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { NextRequest, NextResponse } from 'next/server';
import connectDB from '@/lib/db';
import { DSOCMentor } from '@/models/DSOCMentor';
import jwt from 'jsonwebtoken';

export async function GET(request: NextRequest) {
try {
await connectDB();

const token = request.cookies.get('dsoc-mentor-token')?.value;
if (!token) {
return NextResponse.json({ success: false }, { status: 200 });
}

const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as {
id: string;
role: string;
};

if (decoded.role !== 'dsoc-mentor') {
return NextResponse.json({ success: false }, { status: 200 });
}

const mentor = await DSOCMentor.findById(decoded.id)
.select('_id name email username isActive')
.lean();

if (!mentor || !mentor.isActive) {
return NextResponse.json({ success: false }, { status: 200 });
}

return NextResponse.json({
success: true,
data: {
id: mentor._id,
name: mentor.name,
email: mentor.email,
username: mentor.username,
},
});
} catch (error) {
console.error('Error checking DSOC mentor session:', error);
return NextResponse.json({ success: false }, { status: 200 });
}
}
26 changes: 26 additions & 0 deletions app/api/dsoc/projects/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ import { NextRequest, NextResponse } from 'next/server';
import connectDB from '@/lib/db';
import '@/models/DSOCMentor';
import { DSOCProject } from '@/models/DSOCProject';
import jwt from 'jsonwebtoken';

async function getMentorFromToken(request: NextRequest) {
const token = request.cookies.get('dsoc-mentor-token')?.value;
if (!token) return null;

try {
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as { id: string; role: string };
if (decoded.role !== 'dsoc-mentor') return null;
return decoded.id;
} catch {
return null;
}
}

// GET all projects with filtering
export async function GET(request: NextRequest) {
Expand All @@ -16,10 +30,22 @@ export async function GET(request: NextRequest) {
const search = searchParams.get('search');
const limit = parseInt(searchParams.get('limit') || '50');
const page = parseInt(searchParams.get('page') || '1');
const mentorOnly = searchParams.get('mentor') === 'true';

// Build query
const query: any = { isActive: true };

if (mentorOnly) {
const mentorId = await getMentorFromToken(request);
if (!mentorId) {
return NextResponse.json(
{ success: false, error: 'Unauthorized' },
{ status: 401 }
);
}
query.mentors = mentorId;
}

if (status) query.status = status;
if (difficulty) query.difficulty = difficulty;
if (technology) query.technologies = { $in: [technology] };
Expand Down
Loading
Loading