181 lines
4.9 KiB
Go
181 lines
4.9 KiB
Go
package classrooms
|
|
|
|
import (
|
|
"boostai-backend/internal/handlers/api/shared"
|
|
"boostai-backend/internal/http/params"
|
|
"boostai-backend/internal/http/respond"
|
|
authmw "boostai-backend/internal/middleware"
|
|
"boostai-backend/internal/sqlc"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
type Handler struct {
|
|
queries *sqlc.Queries
|
|
}
|
|
|
|
type ClassroomResponse struct {
|
|
ID int64 `json:"id"`
|
|
TeacherID int64 `json:"teacher_id"`
|
|
Name string `json:"name"`
|
|
Code *string `json:"code,omitempty"`
|
|
Description *string `json:"description,omitempty"`
|
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
|
}
|
|
|
|
type StudentResponse struct {
|
|
ID int64 `json:"id"`
|
|
Email string `json:"email"`
|
|
Role string `json:"role"`
|
|
FullName string `json:"full_name"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedAt *time.Time `json:"created_at,omitempty"`
|
|
UpdatedAt *time.Time `json:"updated_at,omitempty"`
|
|
}
|
|
|
|
type createClassroomRequest struct {
|
|
TeacherID int64 `json:"teacher_id"`
|
|
Name string `json:"name"`
|
|
Code *string `json:"code"`
|
|
Description *string `json:"description"`
|
|
}
|
|
|
|
type addStudentToClassroomRequest struct {
|
|
StudentID int64 `json:"student_id"`
|
|
}
|
|
|
|
func NewHandler(queries *sqlc.Queries) *Handler {
|
|
return &Handler{queries: queries}
|
|
}
|
|
|
|
func (h *Handler) ListClassroomsByTeacher(c *fiber.Ctx) error {
|
|
teacherID, err := params.Int64PathParam(c, "teacherId")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ctx, cancel := shared.WithTimeout()
|
|
defer cancel()
|
|
|
|
classrooms, err := h.queries.ListClassroomsByTeacher(ctx, teacherID)
|
|
if err != nil {
|
|
return respond.DatabaseError(c, err)
|
|
}
|
|
|
|
items := make([]ClassroomResponse, 0, len(classrooms))
|
|
for _, classroom := range classrooms {
|
|
items = append(items, mapClassroom(classroom))
|
|
}
|
|
|
|
return c.JSON(shared.ListResponse[ClassroomResponse]{Data: items})
|
|
}
|
|
|
|
func (h *Handler) ListStudentsForClassroom(c *fiber.Ctx) error {
|
|
classroomID, err := params.Int64PathParam(c, "classroomId")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ctx, cancel := shared.WithTimeout()
|
|
defer cancel()
|
|
|
|
students, err := h.queries.ListStudentsForClassroom(ctx, classroomID)
|
|
if err != nil {
|
|
return respond.DatabaseError(c, err)
|
|
}
|
|
|
|
items := make([]StudentResponse, 0, len(students))
|
|
for _, student := range students {
|
|
items = append(items, mapStudent(student))
|
|
}
|
|
|
|
return c.JSON(shared.ListResponse[StudentResponse]{Data: items})
|
|
}
|
|
|
|
func (h *Handler) CreateClassroom(c *fiber.Ctx) error {
|
|
var req createClassroomRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "Unable to parse request body")
|
|
}
|
|
|
|
teacherID := authmw.CurrentUserID(c)
|
|
if teacherID == 0 || strings.TrimSpace(req.Name) == "" {
|
|
return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "teacher authentication and name are required")
|
|
}
|
|
|
|
ctx, cancel := shared.WithTimeout()
|
|
defer cancel()
|
|
|
|
classroom, err := h.queries.CreateClassroom(ctx, sqlc.CreateClassroomParams{
|
|
TeacherID: teacherID,
|
|
Name: strings.TrimSpace(req.Name),
|
|
Code: shared.NullableText(req.Code),
|
|
Description: shared.NullableText(req.Description),
|
|
})
|
|
if err != nil {
|
|
return respond.DatabaseError(c, err)
|
|
}
|
|
|
|
return c.Status(fiber.StatusCreated).JSON(mapClassroom(classroom))
|
|
}
|
|
|
|
func (h *Handler) AddStudentToClassroom(c *fiber.Ctx) error {
|
|
classroomID, err := params.Int64PathParam(c, "classroomId")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var req addStudentToClassroomRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "Unable to parse request body")
|
|
}
|
|
|
|
if req.StudentID == 0 {
|
|
return respond.Error(c, fiber.StatusBadRequest, "invalid_request", "student_id is required")
|
|
}
|
|
|
|
ctx, cancel := shared.WithTimeout()
|
|
defer cancel()
|
|
|
|
err = h.queries.AddStudentToClassroom(ctx, sqlc.AddStudentToClassroomParams{
|
|
ClassroomID: classroomID,
|
|
StudentID: req.StudentID,
|
|
})
|
|
if err != nil {
|
|
return respond.DatabaseError(c, err)
|
|
}
|
|
|
|
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
|
"status": "ok",
|
|
"classroom_id": classroomID,
|
|
"student_id": req.StudentID,
|
|
})
|
|
}
|
|
|
|
func mapClassroom(classroom sqlc.Classroom) ClassroomResponse {
|
|
return ClassroomResponse{
|
|
ID: classroom.ID,
|
|
TeacherID: classroom.TeacherID,
|
|
Name: classroom.Name,
|
|
Code: shared.TextPointer(classroom.Code),
|
|
Description: shared.TextPointer(classroom.Description),
|
|
CreatedAt: shared.TimePointer(classroom.CreatedAt),
|
|
UpdatedAt: shared.TimePointer(classroom.UpdatedAt),
|
|
}
|
|
}
|
|
|
|
func mapStudent(user sqlc.User) StudentResponse {
|
|
return StudentResponse{
|
|
ID: user.ID,
|
|
Email: user.Email,
|
|
Role: string(user.Role),
|
|
FullName: user.FullName,
|
|
IsActive: user.IsActive,
|
|
CreatedAt: shared.TimePointer(user.CreatedAt),
|
|
UpdatedAt: shared.TimePointer(user.UpdatedAt),
|
|
}
|
|
}
|