453 lines
12 KiB
Go
453 lines
12 KiB
Go
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",
|
|
})
|
|
}
|