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
62 changes: 61 additions & 1 deletion src/controllers/course.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ export const publishLesson = catchAsync(async (req: Request, res: Response, next
});

// unpublish lesson
export const unPublishLesson = catchAsync(async (req: Request, res: Response, next: NextFunction) => {
export const unpublishLesson = catchAsync(async (req: Request, res: Response, next: NextFunction) => {
const courseId = req.params.id;

if (!courseId) {
Expand Down Expand Up @@ -2584,3 +2584,63 @@ export const checkCoursePurchased = catchAsync(async (req: Request, res: Respons
isPurchased
});
});

export const getPublishedCoursesForAdmin = catchAsync(async (req: Request, res: Response, next: NextFunction) => {
const { search, level, sortBy = 'createdAt', sortOrder = 'desc' } = req.query;

// Build query for published courses
const query: any = { isPublished: true };

// Add search filter
if (search) {
query.$or = [
{ name: { $regex: search as string, $options: 'i' } },
{ subTitle: { $regex: search as string, $options: 'i' } },
{ description: { $regex: search as string, $options: 'i' } }
];
}

// Add level filter
if (level) {
query.level = level;
}

// Build sort object
const sort: any = {};
sort[sortBy as string] = sortOrder === 'desc' ? -1 : 1;

// Get all published courses with populate necessary fields
const courses = await CourseModel.find(query)
.populate('authorId', 'name email avatar profession')
.populate('category', 'name')
.populate('subCategory', 'name')
.populate('level', 'name')
.sort(sort)
.lean();

// Calculate additional stats for each course
const coursesWithStats = await Promise.all(
courses.map(async (course) => {
// Count lessons
const sectionIds = course.sections || [];
const lessonsCount = await LessonModel.countDocuments({ sectionId: { $in: sectionIds } });

// Calculate duration in hours
const durationInMinutes = course.duration || 0;
const durationInHours = (durationInMinutes / 60).toFixed(1);

return {
...course,
lessonsCount,
durationInHours: `${durationInHours} hours`,
totalSections: sectionIds.length
};
})
);

res.status(200).json({
success: true,
data: coursesWithStats,
totalCourses: coursesWithStats.length
});
});
121 changes: 118 additions & 3 deletions src/routes/course.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
getSignatureForDelete,
deleteLesson,
publishLesson,
unPublishLesson,
unpublishLesson,
publishSection,
unpublishSection,
deleteSection,
Expand All @@ -40,7 +40,8 @@ import {
getInstructorCourseStats,
getLatestCourseStatus,
getTopViewing,
getAllAssignedCoursesOfUser
getAllAssignedCoursesOfUser,
getPublishedCoursesForAdmin
} from '../controllers/course.controller';
import { getUserInfo, updateAccessToken } from '../controllers/user.controller';
import { createSection, updateSection } from '../controllers/section.controller';
Expand Down Expand Up @@ -914,7 +915,7 @@ router.put('/publish-lesson/:id', isAuthenticated, updateAccessToken, publishLes
* 401:
* description: Not authenticated
*/
router.put('/unpublish-lesson/:id', isAuthenticated, updateAccessToken, unPublishLesson);
router.put('/unpublish-lesson/:id', isAuthenticated, updateAccessToken, unpublishLesson);

/**
* @swagger
Expand Down Expand Up @@ -1041,4 +1042,118 @@ router.get(
getLatestCourseStatus
);

/**
* @swagger
* /api/courses/admin/published:
* get:
* summary: Get all published courses for admin
* tags: [Courses]
* security:
* - bearerAuth: []
* parameters:
* - in: query
* name: search
* schema:
* type: string
* description: Search term for course name, subtitle, or description
* - in: query
* name: level
* schema:
* type: string
* description: Level ID to filter by
* - in: query
* name: sortBy
* schema:
* type: string
* enum: [createdAt, name, price, rating, purchased]
* default: createdAt
* description: Field to sort by
* - in: query
* name: sortOrder
* schema:
* type: string
* enum: [asc, desc]
* default: desc
* description: Sort order
* responses:
* 200:
* description: List of all published courses
* content:
* application/json:
* schema:
* type: object
* properties:
* success:
* type: boolean
* data:
* type: array
* items:
* type: object
* properties:
* _id:
* type: string
* name:
* type: string
* subTitle:
* type: string
* price:
* type: number
* isFree:
* type: boolean
* rating:
* type: number
* purchased:
* type: number
* lessonsCount:
* type: number
* durationInHours:
* type: string
* totalSections:
* type: number
* authorId:
* type: object
* properties:
* name:
* type: string
* email:
* type: string
* avatar:
* type: string
* profession:
* type: string
* category:
* type: object
* properties:
* name:
* type: string
* subCategory:
* type: object
* properties:
* name:
* type: string
* level:
* type: object
* properties:
* name:
* type: string
* createdAt:
* type: string
* updatedAt:
* type: string
* totalCourses:
* type: number
* description: Total number of published courses
* 401:
* description: Not authenticated
* 403:
* description: Not authorized (admin role required)
*/
router.get(
'/admin/published',
updateAccessToken,
isAuthenticated,
authorizeRoles('admin'),
getPublishedCoursesForAdmin
);

export = router;