Skip to content

Commit

Permalink
feat: Added cms-mobile routes (#1303)
Browse files Browse the repository at this point in the history
* add cms-mobile login route

* removed courses call while signing in

* added cms-mobile auth middleware

* feat: Added Courses API routes

* updated gitignore

* added search route

* feat: added middleware for mobile routes

* feat: corrected user Request type

* refactored search route

* added checks for user access for course collection and content

* minor fix

---------

Co-authored-by: rishavvajpayee <[email protected]>
  • Loading branch information
ItsFlash10 and rishavvajpayee authored Oct 24, 2024
1 parent 4b71e99 commit 90dad10
Show file tree
Hide file tree
Showing 8 changed files with 454 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ yarn-error.log*
# vercel
.vercel

#vs-code (debug config)
.vscode
launch.json

# typescript
*.tsbuildinfo
next-env.d.ts
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import db from '@/db';
import { NextRequest, NextResponse } from 'next/server';

async function checkUserContentAccess(userId: string, contentId: string) {
const userContent = await db.content.findFirst({
where: {
id: parseInt(contentId, 10),
courses: {
some: {
course: {
purchasedBy: {
some: {
userId,
},
},
},
},
},
},
});
return userContent !== null;
}

export async function GET(
req: NextRequest,
{ params }: { params: { contentId: string } },
) {
try {
const { contentId } = params;
const user = JSON.parse(req.headers.get('g') || '');
const userContentAccess = await checkUserContentAccess(user.id, contentId);
if (!userContentAccess) {
return NextResponse.json(
{ message: 'User does not have access to this content' },
{ status: 403 },
);
}
const contents = await db.content.findUnique({
where: {
id: parseInt(contentId, 10),
},
select: {
id: true,
type: true,
title: true,
hidden: true,
description: true,
thumbnail: true,
parentId: true,
createdAt: true,
notionMetadataId: true,
commentsCount: true,
VideoMetadata: true,
NotionMetadata: true,
},
});
return NextResponse.json({
message: 'Content fetched successfully',
data: contents,
});
} catch (error) {
console.log(error);
return NextResponse.json(
{ message: 'Error fetching Content', error },
{ status: 500 },
);
}
}
62 changes: 62 additions & 0 deletions src/app/api/mobile/courses/[courseId]/[collectionId]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import db from '@/db';
import { NextRequest, NextResponse } from 'next/server';

async function checkUserCollectionAccess(userId: string, collectionId: string) {
const userCollection = await db.content.findFirst({
where: {
id: parseInt(collectionId, 10),
courses: {
some: {
course: {
purchasedBy: {
some: {
userId,
},
},
},
},
},
},
});

return userCollection !== null;
}

export async function GET(
request: NextRequest,
{ params }: { params: { collectionId: string } },
) {
try {
const user = JSON.parse(request.headers.get('g') || '');
if (!user) {
return NextResponse.json({ message: 'User not found' }, { status: 401 });
}

const { collectionId } = params;
const userHasCollectionAccess = await checkUserCollectionAccess(
user.id,
collectionId,
);
if (!userHasCollectionAccess) {
return NextResponse.json(
{ message: 'User does not have access to this collection' },
{ status: 403 },
);
}
const collectionData = await db.content.findMany({
where: {
parentId: parseInt(collectionId, 10),
},
});
return NextResponse.json({
message: 'Collection Data fetched successfully',
data: collectionData,
});
} catch (error) {
console.log(error);
return NextResponse.json(
{ message: 'Error fetching user courses', error },
{ status: 500 },
);
}
}
52 changes: 52 additions & 0 deletions src/app/api/mobile/courses/[courseId]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import db from '@/db';
import { NextResponse, NextRequest } from 'next/server';

async function checkUserCourseAccess(userId: string, courseId: string) {
const userCourse = await db.course.findFirst({
where: {
purchasedBy: {
some: {
userId,
},
},
id: parseInt(courseId, 10),
},
});

return userCourse !== null;
}

export async function GET(
request: NextRequest,
{ params }: { params: { courseId: string } },
) {
try {
const user: { id: string } = JSON.parse(request.headers.get('g') || '');
const { courseId } = params;

const userCourseAccess = await checkUserCourseAccess(user.id, courseId);
if (!userCourseAccess) {
return NextResponse.json(
{ message: 'User does not have access to this course' },
{ status: 403 },
);
}
const folderContents = await db.content.findMany({
where: {
id: parseInt(courseId, 10),
type: 'folder',
},
});

return NextResponse.json({
message: 'Courses Data fetched successfully',
data: folderContents,
});
} catch (error) {
console.log(error);
return NextResponse.json(
{ message: 'Error fetching user courses', error },
{ status: 500 },
);
}
}
33 changes: 33 additions & 0 deletions src/app/api/mobile/courses/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import db from '@/db';
import { NextResponse, NextRequest } from 'next/server';

export async function GET(req: NextRequest) {
try {
const user = JSON.parse(req.headers.get('g') || '');
if (!user) {
return NextResponse.json({ message: 'User Not Found' }, { status: 400 });
}
const userCourses = await db.course.findMany({
where: {
purchasedBy: {
some: {
user: {
email: user.email,
},
},
},
},
});

return NextResponse.json({
message: 'User courses fetched successfully',
data: userCourses,
});
} catch (error) {
console.log(error);
return NextResponse.json(
{ message: 'Error fetching user courses', error },
{ status: 500 },
);
}
}
84 changes: 84 additions & 0 deletions src/app/api/mobile/search/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { cache } from '@/db/Cache';
import db from '@/db';
import { CourseContent } from '@prisma/client';
import Fuse from 'fuse.js';
import { NextRequest, NextResponse } from 'next/server';

export type TSearchedVideos = {
id: number;
parentId: number | null;
title: string;
} & {
parent: { courses: CourseContent[] } | null;
};

const fuzzySearch = (videos: TSearchedVideos[], searchQuery: string) => {
const searchedVideos = new Fuse(videos, {
minMatchCharLength: 3,
keys: ['title'],
}).search(searchQuery);

return searchedVideos.map((video) => video.item);
};

export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const searchQuery = searchParams.get('q');
const user = JSON.parse(request.headers.get('g') || '');

if (!user) {
return NextResponse.json({ message: 'User Not Found' }, { status: 400 });
}

if (searchQuery && searchQuery.length > 2) {
const value: TSearchedVideos[] = await cache.get(
'getAllVideosForSearch',
[],
);

if (value) {
return NextResponse.json(fuzzySearch(value, searchQuery));
}

const allVideos = await db.content.findMany({
where: {
type: 'video',
hidden: false,
parent: {
courses: {
some: {
course: {
purchasedBy: {
some: {
userId: user.id,
},
},
},
},
},
},
},
select: {
id: true,
parentId: true,
title: true,
parent: {
select: {
courses: true,
},
},
},
});

cache.set('getAllVideosForSearch', [], allVideos, 24 * 60 * 60);

return NextResponse.json(fuzzySearch(allVideos, searchQuery));
}
} catch (err) {
return NextResponse.json(
{ message: 'Error fetching search results', err },
{ status: 500 },
);
}
}
Loading

0 comments on commit 90dad10

Please sign in to comment.