From 9f8b5cf94a254c73f1d4f6832b91c31232c835fa Mon Sep 17 00:00:00 2001 From: Carlos Maldonado Date: Sun, 1 Dec 2024 03:59:28 -0800 Subject: [PATCH 1/2] I created enrollment button, and tried to create unerollment but need help --- backend/internal/handlers/courses.go | 70 +++++++++++++++++++++++-- backend/internal/router/route.go | 1 + frontend/src/components/pages/Course.js | 70 +++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 3 deletions(-) diff --git a/backend/internal/handlers/courses.go b/backend/internal/handlers/courses.go index 4c999c7..98a5ea5 100644 --- a/backend/internal/handlers/courses.go +++ b/backend/internal/handlers/courses.go @@ -61,7 +61,7 @@ func Course(c *fiber.Ctx) error { Preload("Modules"). Preload("Modules.Content", func(db *gorm.DB) *gorm.DB { return db.Order("id ASC") - }). + }). Preload("Tags"). Where("id = ?", courseID). First(&course).Error; err != nil { @@ -223,6 +223,70 @@ func Enroll(c *fiber.Ctx) error { }) } +// Uneroll user into course +func Unenroll(c *fiber.Ctx) error { + user_id := c.Params("user_id") + course_id := c.Params("course_id") + + var user entity.Account + // Check if the user exists + if err := database.DB.Where("id = ?", user_id).First(&user).Error; err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"}) + } + + var course entity.Course + // Check if the course exists + if err := database.DB.Where("id = ?", course_id).First(&course).Error; err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Course not found"}) + } + + // Check if the user is enrolled in the course + if err := database.DB.Model(&user).Association("Courses").Find(&course); err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User is not enrolled in this course"}) + } + + // Unenroll user into course + if err := database.DB.Model(&user).Association("Courses").Delete(&course); err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Error unenrolling into course"}) + } + + return c.JSON(fiber.Map{ + "message": fmt.Sprintf("Successfully unenrolled user id %d in course %s", user.ID, course.Title), + }) +} + +func CheckEnrollmentStatus(c *fiber.Ctx) error { + user_id := c.Params("user_id") + course_id := c.Params("course_id") + + var user entity.Account + // Check if the user exists + if err := database.DB.Where("id = ?", user_id).First(&user).Error; err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"}) + } + + var course entity.Course + // Check if the course exists + if err := database.DB.Where("id = ?", course_id).First(&course).Error; err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Course not found"}) + } + + // Check if the user is enrolled in the course + isEnrolled := false + if err := database.DB.Table("enrollment"). + Where("account_id = ? AND course_id = ?", user_id, course_id). + Select("count(*) > 0"). + Scan(&isEnrolled).Error; err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Error checking enrollment status"}) + } + + // Return the enrollment status + return c.JSON(fiber.Map{ + "message": "Enrollment status checked successfully", + "isEnrolled": isEnrolled, + }) +} + // Create a module inside a course func CreateModule(c *fiber.Ctx) error { creator_id, err := strconv.Atoi(c.Params("creator_id")) @@ -372,7 +436,7 @@ func EditContent(c *fiber.Ctx) error { if err := os.Remove("./content" + path); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"message": err.Error()}) } - } else if !os.IsNotExist(err){ + } else if !os.IsNotExist(err) { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"message": err.Error()}) } @@ -480,7 +544,7 @@ func EditThumbnail(c *fiber.Ctx) error { if err := os.Remove(fmt.Sprintf("./content/%d/thumbnail.png", course_id)); err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"message": err.Error()}) } - } else if !os.IsNotExist(err){ + } else if !os.IsNotExist(err) { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"message": err.Error()}) } diff --git a/backend/internal/router/route.go b/backend/internal/router/route.go index 0a2da43..7a31f1a 100644 --- a/backend/internal/router/route.go +++ b/backend/internal/router/route.go @@ -92,4 +92,5 @@ func SetupRoutes(app *fiber.App) { app.Post("/edit-content/:creator_id/:content_id", handlers.EditContent) app.Post("/edit-thumbnail/:creator_id/:course_id", handlers.EditThumbnail) app.Post("/enroll/:user_id/:course_id", handlers.Enroll) + app.Delete("/unenroll/:user_id/:course_id", handlers.Unenroll) } diff --git a/frontend/src/components/pages/Course.js b/frontend/src/components/pages/Course.js index 707d372..3b9b127 100644 --- a/frontend/src/components/pages/Course.js +++ b/frontend/src/components/pages/Course.js @@ -10,6 +10,7 @@ export function Course() { const [userInfo, setUserInfo] = useState(null); const [error, setError] = useState(null); const [file, setFile] = useState(null); + const [isEnrolled, setIsEnrolled] = useState(false); const [newContentName, setNewContentName] = useState({ title: "", }); @@ -118,6 +119,67 @@ export function Course() { } }; + const handleEnroll = async () => { + const userId = Cookies.get('userId'); + + if (!userId) { + setError('User ID not found'); + return; + } + + try { + const response = await fetch(`http://localhost:4000/Enroll/${userId}/${courseID}`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + const data = await response.json(); + if (response.ok) { + Notiflix.Notify.success("Succesfully enrolled in the course!"); + setTimeout(() => { + window.location.reload(); + }, 500); + } else { + Notiflix.Notify.failure(data.message || "Enrollment failed"); + } + } catch (error) { + Notiflix.Notify.failure("Error occurred during enrollment"); + } + + }; + + const handleUnenroll = async () => { + const userId = Cookies.get('userId'); + + if (!userId) { + setError('User ID not found'); + return; + } + + try { + const response = await fetch(`http://localhost:4000/Unenroll/${userId}/${courseID}`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + }); + const data = await response.json(); + if (response.ok) { + Notiflix.Notify.success("Succesfully unenrolled in the course!"); + setTimeout(() => { + window.location.reload(); + }, 500); + } else { + Notiflix.Notify.failure(data.message || "Unenrollment failed"); + } + } catch (error) { + Notiflix.Notify.failure("Error occurred during Unenrollment"); + } + + }; + + useEffect(() => { const userId = Cookies.get('userId'); @@ -248,6 +310,14 @@ export function Course() {
{editThumbnail} {createButton} + {userInfo.role === "student" && ( + + )}
From 210043e774db168ad38888692ae630227e55de96 Mon Sep 17 00:00:00 2001 From: zachspang Date: Sun, 1 Dec 2024 08:49:10 -0800 Subject: [PATCH 2/2] Add isEnrolled handler --- backend/internal/handlers/courses.go | 24 ++++++++++++++++++++++++ backend/internal/router/route.go | 1 + frontend/src/components/pages/Course.js | 17 +++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/backend/internal/handlers/courses.go b/backend/internal/handlers/courses.go index 98a5ea5..0a12bfe 100644 --- a/backend/internal/handlers/courses.go +++ b/backend/internal/handlers/courses.go @@ -196,6 +196,30 @@ func CreateCourse(c *fiber.Ctx) error { }) } +// Returns a true if user is enrolled in course +func IsEnrolled(c *fiber.Ctx) error { + course_id := c.Params("course_id") + user_id := c.Params("user_id") + + var count int64 + + if err := database.DB.Table("enrollment").Where("account_id = ? AND course_id = ?", user_id, course_id).Count(&count).Error; err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Error retrieving courses"}) + } + + if count > 0 { + return c.JSON(fiber.Map{ + "message": "User is enrolled in this course", + "isEnrolled": true, + }) + } else { + return c.JSON(fiber.Map{ + "message": "User is not enrolled in this course", + "isEnrolled": false, + }) + } +} + // Enroll user into course func Enroll(c *fiber.Ctx) error { user_id := c.Params("user_id") diff --git a/backend/internal/router/route.go b/backend/internal/router/route.go index 7a31f1a..5d31828 100644 --- a/backend/internal/router/route.go +++ b/backend/internal/router/route.go @@ -91,6 +91,7 @@ func SetupRoutes(app *fiber.App) { app.Post("/delete-file/:creator_id/:content_id", handlers.DeleteFile) app.Post("/edit-content/:creator_id/:content_id", handlers.EditContent) app.Post("/edit-thumbnail/:creator_id/:course_id", handlers.EditThumbnail) + app.Get("/is-enrolled/:user_id/:course_id", handlers.IsEnrolled) app.Post("/enroll/:user_id/:course_id", handlers.Enroll) app.Delete("/unenroll/:user_id/:course_id", handlers.Unenroll) } diff --git a/frontend/src/components/pages/Course.js b/frontend/src/components/pages/Course.js index 3b9b127..ca12198 100644 --- a/frontend/src/components/pages/Course.js +++ b/frontend/src/components/pages/Course.js @@ -10,7 +10,7 @@ export function Course() { const [userInfo, setUserInfo] = useState(null); const [error, setError] = useState(null); const [file, setFile] = useState(null); - const [isEnrolled, setIsEnrolled] = useState(false); + const [isEnrolled, setIsEnrolled] = useState(null); const [newContentName, setNewContentName] = useState({ title: "", }); @@ -212,12 +212,25 @@ export function Course() { .catch((error) => setError(error.message)); } + async function fetchIsEnrolled() { + await fetch(`http://localhost:4000/is-enrolled/${userId}/${courseID}`) + .then((response) => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .then((data) => setIsEnrolled(data.isEnrolled)) + .catch((error) => setError(error.message)); + } + fetchCourse(); fetchUser(); + fetchIsEnrolled(); }, [courseID]); if (error) return

Error: {error}

; - if (!courseInfo || !userInfo) return

Loading...

; + if (!courseInfo || !userInfo || isEnrolled === null) return

Loading...

; var moduleList = []; //Push all modules into moduleList