package lessons import ( "errors" "fmt" "time" "git.ex.umbach.dev/LMS/libcore/models" "github.com/gofiber/fiber/v2" "github.com/google/uuid" "gorm.io/gorm" "lms.de/backend/modules/database" "lms.de/backend/modules/structs" "lms.de/backend/modules/utils" "lms.de/backend/socketclients" ) func GetQuestions(c *fiber.Ctx) error { // swagger:operation GET /v1/lessons/{lessonId}/questions questions getQuestions // --- // summary: Get questions // produces: // - application/json // responses: // '200': // description: Questions // schema: // "$ref": "#/definitions/QuestionsResponse" // '500': // description: Failed to get questions var params structs.LessonIdParam if err := c.ParamsParser(¶ms); err != nil { return c.SendStatus(fiber.StatusBadRequest) } // check if lesson belongs to organization var lesson models.Lesson if err := database.DB.Model(&models.Lesson{}). Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)). First(&lesson).Error; err != nil { return c.JSON([]models.Question{}) } // get questions var questions []models.Question if err := database.DB.Model(&models.Question{}). Where("lesson_id = ?", params.LessonId). Find(&questions).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return c.SendStatus(fiber.StatusNotFound) } } // get all questions liked by user var likedQuestions []string if err := database.DB.Model(&models.QuestionLike{}). Where("creator_user_id = ?", c.Locals("userId").(string)). Pluck("question_id", &likedQuestions).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return c.SendStatus(fiber.StatusInternalServerError) } } /* var questionLikes []models.QuestionLike if err := database.DB.Model(&models.QuestionLike{}). Where("creator_user_id = ?", c.Locals("userId").(string)). Find(&questionLikes).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return c.SendStatus(fiber.StatusInternalServerError) } } var likedQuestions []string for _, questionLike := range questionLikes { likedQuestions = append(likedQuestions, questionLike.QuestionId) } */ return c.JSON(structs.QuestionsResponse{ Questions: questions, LikedQuestions: likedQuestions, }) } func CreateQuestion(c *fiber.Ctx) error { // swagger:operation POST /v1/lessons/{lessonId}/questions question createQuestion // --- // summary: Create question // consumes: // - application/json // produces: // - application/json // parameters: // - name: body // in: body // schema: // "$ref": "#/definitions/CreateQuestionRequest" // responses: // '200': // description: Question created successfully // schema: // type: string // '400': // description: Invalid request body // '500': // description: Failed to create question var params structs.LessonIdParam if err := c.ParamsParser(¶ms); err != nil { return c.SendStatus(fiber.StatusBadRequest) } var body structs.CreateQuestionRequest if err := c.BodyParser(&body); err != nil { return c.SendStatus(fiber.StatusBadRequest) } // check if lesson belongs to organization var lesson models.Lesson if err := database.DB.Model(&models.Lesson{}). Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)). First(&lesson).Error; err != nil { return c.SendStatus(fiber.StatusNotFound) } // create question question := models.Question{ Id: uuid.New().String(), LessonId: params.LessonId, Message: body.Message, Likes: 0, CreatorUserId: c.Locals("userId").(string), CreatedAt: time.Now(), } if err := database.DB.Create(&question).Error; err != nil { return c.SendStatus(fiber.StatusInternalServerError) } socketclients.BroadcastMessageToTopic( c.Locals("organizationId").(string), utils.SubscribedTopicLessonsId(params.LessonId), structs.SendSocketMessage{ Cmd: utils.SendCmdLessonQuestionCreated, Body: question, }, ) return c.JSON(fiber.Map{ "status": "success", }) } func CreateQuestionReply(c *fiber.Ctx) error { // swagger:operation POST /v1/lessons/{lessonId}/questions/{questionId}/reply question createQuestionReply // --- // summary: Create question reply // consumes: // - application/json // produces: // - application/json // parameters: // - name: body // in: body // schema: // "$ref": "#/definitions/CreateQuestionRequest" // responses: // '200': // description: Question reply created successfully // schema: // type: string // '400': // description: Invalid request body // '500': // description: Failed to create question reply var params structs.LessonIdQuestionIdParam if err := c.ParamsParser(¶ms); err != nil { return c.SendStatus(fiber.StatusBadRequest) } var body structs.CreateQuestionRequest if err := c.BodyParser(&body); err != nil { return c.SendStatus(fiber.StatusBadRequest) } // check if lesson belongs to organization var lesson models.Lesson if err := database.DB.Model(&models.Lesson{}). Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)). First(&lesson).Error; err != nil { return c.SendStatus(fiber.StatusNotFound) } // check if question belongs to lesson var question models.Question if err := database.DB.Model(&models.Question{}). Where("id = ? AND lesson_id = ?", params.QuestionId, params.LessonId). First(&question).Error; err != nil { return c.SendStatus(fiber.StatusNotFound) } // create question reply question = models.Question{ Id: uuid.New().String(), LessonId: params.LessonId, QuestionId: params.QuestionId, ReplyId: params.QuestionId, Message: body.Message, Likes: 0, CreatorUserId: c.Locals("userId").(string), } if err := database.DB.Create(&question).Error; err != nil { return c.SendStatus(fiber.StatusInternalServerError) } socketclients.BroadcastMessageToTopic( c.Locals("organizationId").(string), utils.SubscribedTopicLessonsId(params.LessonId), structs.SendSocketMessage{ Cmd: utils.SendCmdLessonQuestionCreated, Body: question, }, ) return c.JSON(fiber.Map{ "status": "success", }) } func LikeQuestion(c *fiber.Ctx) error { // swagger:operation POST /v1/lessons/{lessonId}/questions/{questionId}/likes question likeQuestion // --- // summary: Like question // produces: // - application/json // responses: // '200': // description: Question liked successfully // schema: // type: string // '500': // description: Failed to like question var params structs.LessonIdQuestionIdParam if err := c.ParamsParser(¶ms); err != nil { return c.SendStatus(fiber.StatusBadRequest) } // check if lesson belongs to organization var lesson models.Lesson if err := database.DB.Model(&models.Lesson{}). Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)). First(&lesson).Error; err != nil { fmt.Println("lesson not found") return c.SendStatus(fiber.StatusNotFound) } // check if question belongs to lesson var question models.Question if err := database.DB.Model(&models.Question{}). Where("id = ? AND lesson_id = ?", params.QuestionId, params.LessonId). First(&question).Error; err != nil { fmt.Println("question not found") return c.SendStatus(fiber.StatusNotFound) } // check if user already liked question var questionLike models.QuestionLike if err := database.DB.Model(&models.QuestionLike{}). Where("question_id = ? AND creator_user_id = ?", params.QuestionId, c.Locals("userId").(string)). First(&questionLike).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return c.SendStatus(fiber.StatusInternalServerError) } } if questionLike.Id != "" { fmt.Println("question already liked") return c.SendStatus(fiber.StatusConflict) } // like question questionLike = models.QuestionLike{ Id: uuid.New().String(), QuestionId: params.QuestionId, CreatorUserId: c.Locals("userId").(string), CreatedAt: time.Now(), } if err := database.DB.Create(&questionLike).Error; err != nil { return c.SendStatus(fiber.StatusInternalServerError) } // update question likes if err := database.DB.Model(&models.Question{}). Where("id = ?", params.QuestionId). Update("likes", gorm.Expr("likes + 1")).Error; err != nil { return c.SendStatus(fiber.StatusInternalServerError) } // send message to user clients who liked the question socketclients.SendMessageToUserWithTopic( c.Locals("userId").(string), utils.SubscribedTopicLessonsId(params.LessonId), structs.SendSocketMessage{ Cmd: utils.SendCmdLessonQuestionLiked, Body: question.Id, }, ) // inform all users about the like socketclients.BroadcastMessageToTopic( c.Locals("userId").(string), utils.SubscribedTopicLessonsId(params.LessonId), structs.SendSocketMessage{ Cmd: utils.SendCmdLessonQuestionCountUpLikes, Body: question.Id, }, ) return c.JSON(fiber.Map{ "status": "success", }) } func DislikeQuestion(c *fiber.Ctx) error { // swagger:operation DELETE /v1/lessons/{lessonId}/questions/{questionId}/likes question dislikeQuestion // --- // summary: Dislike question // produces: // - application/json // responses: // '200': // description: Question disliked successfully // schema: // type: string // '500': // description: Failed to dislike question var params structs.LessonIdQuestionIdParam if err := c.ParamsParser(¶ms); err != nil { return c.SendStatus(fiber.StatusBadRequest) } // check if lesson belongs to organization var lesson models.Lesson if err := database.DB.Model(&models.Lesson{}). Where("id = ? AND organization_id = ?", params.LessonId, c.Locals("organizationId").(string)). First(&lesson).Error; err != nil { return c.SendStatus(fiber.StatusNotFound) } // check if question belongs to lesson var question models.Question if err := database.DB.Model(&models.Question{}). Where("id = ? AND lesson_id = ?", params.QuestionId, params.LessonId). First(&question).Error; err != nil { return c.SendStatus(fiber.StatusNotFound) } // check if user already liked question var questionLike models.QuestionLike if err := database.DB.Model(&models.QuestionLike{}). Where("question_id = ? AND creator_user_id = ?", params.QuestionId, c.Locals("userId").(string)). First(&questionLike).Error; err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return c.SendStatus(fiber.StatusInternalServerError) } } if questionLike.Id == "" { return c.SendStatus(fiber.StatusConflict) } // dislike question if err := database.DB.Delete(&questionLike).Error; err != nil { return c.SendStatus(fiber.StatusInternalServerError) } // update question likes if err := database.DB.Model(&models.Question{}). Where("id = ?", params.QuestionId). Update("likes", gorm.Expr("likes - 1")).Error; err != nil { return c.SendStatus(fiber.StatusInternalServerError) } // send message to user clients who disliked the question socketclients.SendMessageToUserWithTopic( c.Locals("userId").(string), utils.SubscribedTopicLessonsId(params.LessonId), structs.SendSocketMessage{ Cmd: utils.SendCmdLessonQuestionDisliked, Body: question.Id, }, ) // inform all users about the dislike socketclients.BroadcastMessageToTopic( c.Locals("userId").(string), utils.SubscribedTopicLessonsId(params.LessonId), structs.SendSocketMessage{ Cmd: utils.SendCmdLessonQuestionCountDownLikes, Body: question.Id, }, ) return c.JSON(fiber.Map{ "status": "success", }) }