-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IMPLEMENT THE COURSE CRUD LOGIC (#8)
* Add Course and UserCourse entities, integrate relationships, update auth middleware for CRUD operations, implement course routes, controller, and service * updated the config file * Updated the couseEntity to have Course video record stored * resoved the dotenv issue * updated the inport of entities in the connfig file * updated inport in the jobService * updated naming convention conflic resolve * adjusted the server file and config * resolved the conflict between App.js and Server.js
- Loading branch information
1 parent
890ff1c
commit 2095750
Showing
12 changed files
with
560 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,25 @@ | ||
import { DataSource } from 'typeorm'; | ||
import User from '../entities/user.entity.js'; | ||
import Job from '../entities/job.entity.js'; | ||
import dotenv from "dotenv" | ||
import { DataSource } from "typeorm"; | ||
import { Course } from "../entities/course.entity.js" | ||
import { UserCourse } from "../entities/userCourse.entity.js" | ||
import UserEntity from "../entities/user.entity.js"; | ||
import Job from "../entities/job.entity.js"; | ||
|
||
dotenv.config() | ||
|
||
const AppDataSource = new DataSource({ | ||
type: 'postgres', | ||
host: process.env.DB_HOST || 'localhost', | ||
port: parseInt(process.env.DB_PORT || '5432'), | ||
type: "postgres", | ||
host: process.env.DB_HOST, | ||
port: Number.parseInt(process.env.DB_PORT), | ||
username: process.env.DB_USER, | ||
password: process.env.DB_PASSWORD, | ||
database: process.env.DB_NAME, | ||
synchronize: true, | ||
dropSchema: false, | ||
logging: false, | ||
entities: [User, Job], | ||
logging: true, | ||
entities: [UserEntity, Course, UserCourse, Job], | ||
subscribers: [], | ||
migrations: [], | ||
}); | ||
}) | ||
|
||
export default AppDataSource; | ||
|
||
export default AppDataSource; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { CourseService } from "../services/courseServices.js" | ||
import courseValidation from "../validation/course.validation.js" | ||
|
||
class CourseController { | ||
async createCourse(req, res) { | ||
try { | ||
const { error, value } = courseValidation.createCourse.validate(req.body) | ||
if (error) { | ||
return res.status(400).json({ message: error.details[0].message }) | ||
} | ||
|
||
const course = await CourseService.createCourse(value) | ||
res.status(201).json(course) | ||
} catch (error) { | ||
if (error.message === "Course already exists") { | ||
res.status(409).json({ message: error.message }) | ||
} else { | ||
res.status(400).json({ message: "Error creating course", error: error.message }) | ||
} | ||
} | ||
} | ||
|
||
async getAllCourses(req, res) { | ||
try { | ||
const courses = await CourseService.getAllCourses() | ||
res.json(courses) | ||
} catch (error) { | ||
res.status(500).json({ message: "Error fetching courses", error: error.message }) | ||
} | ||
} | ||
|
||
async getCourseById(req, res) { | ||
try { | ||
const { error, value } = courseValidation.courseIdParam.validate({ id: req.params.id }) | ||
if (error) { | ||
return res.status(400).json({ message: error.details[0].message }) | ||
} | ||
|
||
const course = await CourseService.getCourseById(value.id) | ||
if (course) { | ||
res.json(course) | ||
} else { | ||
res.status(404).json({ message: "Course not found" }) | ||
} | ||
} catch (error) { | ||
res.status(500).json({ message: "Error fetching course", error: error.message }) | ||
} | ||
} | ||
|
||
async updateCourse(req, res) { | ||
try { | ||
const idValidation = courseValidation.courseIdParam.validate({ id: req.params.id }) | ||
if (idValidation.error) { | ||
return res.status(400).json({ message: idValidation.error.details[0].message }) | ||
} | ||
|
||
const { error, value } = courseValidation.updateCourse.validate(req.body) | ||
if (error) { | ||
return res.status(400).json({ message: error.details[0].message }) | ||
} | ||
|
||
const course = await CourseService.updateCourse(idValidation.value.id, value) | ||
if (course) { | ||
res.json(course) | ||
} else { | ||
res.status(404).json({ message: "Course not found" }) | ||
} | ||
} catch (error) { | ||
if (error.message === "Course already exists") { | ||
res.status(409).json({ message: error.message }) | ||
} else { | ||
res.status(400).json({ message: "Error updating course", error: error.message }) | ||
} | ||
} | ||
} | ||
|
||
async deleteCourse(req, res) { | ||
try { | ||
const { error, value } = courseValidation.courseIdParam.validate({ id: req.params.id }) | ||
if (error) { | ||
return res.status(400).json({ message: error.details[0].message }) | ||
} | ||
|
||
await CourseService.deleteCourse(value.id) | ||
res.status(204).send() | ||
} catch (error) { | ||
if (error.message === "Course not found") { | ||
res.status(404).json({ message: error.message }) | ||
} else { | ||
res.status(500).json({ message: "Error deleting course", error: error.message }) | ||
} | ||
} | ||
} | ||
|
||
async updateCourseVideo(req, res) { | ||
try { | ||
const { error: idError, value: idValue } = courseValidation.courseIdParam.validate({ id: req.params.id }) | ||
if (idError) { | ||
return res.status(400).json({ message: idError.details[0].message }) | ||
} | ||
|
||
if (!req.file) { | ||
return res.status(400).json({ message: "No video file uploaded" }) | ||
} | ||
|
||
const videoUrl = `/uploads/courses/videos/${req.file.filename}` | ||
|
||
const { error, value } = courseValidation.updateCourseVideo.validate({ videoUrl }) | ||
if (error) { | ||
return res.status(400).json({ message: error.details[0].message }) | ||
} | ||
|
||
const updatedCourse = await CourseService.updateCourseVideo(idValue.id, value.videoUrl) | ||
if (updatedCourse) { | ||
res.json(updatedCourse) | ||
} else { | ||
res.status(404).json({ message: "Course not found" }) | ||
} | ||
} catch (error) { | ||
res.status(500).json({ message: "Error updating course video", error: error.message }) | ||
} | ||
} | ||
} | ||
|
||
export default new CourseController() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { EntitySchema } from "typeorm" | ||
|
||
export const Course = new EntitySchema({ | ||
name: "Course", | ||
tableName: "courses", | ||
columns: { | ||
id: { | ||
type: "int", | ||
primary: true, | ||
generated: true, | ||
}, | ||
title: { | ||
type: "varchar", | ||
unique: true, | ||
nullable: false, | ||
}, | ||
description: { | ||
type: "text", | ||
nullable: true, | ||
}, | ||
instructorId: { | ||
type: "int", | ||
nullable: false, | ||
}, | ||
level: { | ||
type: "varchar", | ||
nullable: true, | ||
}, | ||
duration: { | ||
type: "int", | ||
nullable: true, | ||
}, | ||
videoUrl: { | ||
type: "varchar", | ||
nullable: true, | ||
}, | ||
createdAt: { | ||
type: "timestamp", | ||
createDate: true, | ||
}, | ||
}, | ||
relations: { | ||
users: { | ||
type: "many-to-many", | ||
target: "UserEntity", | ||
joinTable: { | ||
name: "user_courses", | ||
joinColumn: { | ||
name: "courseId", | ||
referencedColumnName: "id", | ||
}, | ||
inverseJoinColumn: { | ||
name: "userId", | ||
referencedColumnName: "id", | ||
}, | ||
}, | ||
}, | ||
userCourses: { | ||
type: "one-to-many", | ||
target: "UserCourse", | ||
inverseSide: "course", | ||
}, | ||
}, | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { EntitySchema } from "typeorm" | ||
|
||
export const UserCourse = new EntitySchema({ | ||
name: "UserCourse", | ||
tableName: "user_courses", | ||
columns: { | ||
userId: { | ||
primary: true, | ||
type: "int", | ||
}, | ||
courseId: { | ||
primary: true, | ||
type: "int", | ||
}, | ||
progress: { | ||
type: "int", | ||
default: 0, | ||
}, | ||
enrollmentDate: { | ||
type: "timestamp", | ||
createDate: true, | ||
}, | ||
}, | ||
relations: { | ||
user: { | ||
type: "many-to-one", | ||
target: "User", | ||
joinColumn: { | ||
name: "userId", | ||
referencedColumnName: "id", | ||
}, | ||
onDelete: "CASCADE", | ||
}, | ||
course: { | ||
type: "many-to-one", | ||
target: "Course", | ||
joinColumn: { | ||
name: "courseId", | ||
referencedColumnName: "id", | ||
}, | ||
onDelete: "CASCADE", | ||
}, | ||
}, | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
@baseUrl = http://localhost:3000/api/courses | ||
|
||
### Create a new course | ||
POST {{baseUrl}} | ||
Content-Type: application/json | ||
|
||
{ | ||
"title": "Advance Blockchain", | ||
"description": "Learn the basics of blockchain technology", | ||
"instructorId": 1, | ||
"level": "beginner", | ||
"duration": 5 | ||
} | ||
|
||
### Get all courses | ||
GET {{baseUrl}} | ||
|
||
### Get a specific course | ||
GET {{baseUrl}}/1 | ||
|
||
### Update a course | ||
PUT {{baseUrl}}/1 | ||
Content-Type: application/json | ||
{ | ||
"title": "Advanced Blockchain Concepts", | ||
"description": "Dive deeper into blockchain technology and its applications" | ||
} | ||
|
||
### Delete a course | ||
DELETE {{baseUrl}}/4 | ||
|
||
### Create another course | ||
POST {{baseUrl}} | ||
Content-Type: application/json | ||
|
||
{ | ||
"title": "Advance Smart Contract Development", | ||
"description": "Learn how to create and deploy smart contracts on blockchain platforms", | ||
"instructorId": 2, | ||
"level": "beginner", | ||
"duration": 5 | ||
} | ||
|
||
### Get all courses after operations | ||
GET {{baseUrl}} | ||
|
Oops, something went wrong.