Files
BoostAI/Backend/internal/handlers/api/classrooms/handler.go
2026-05-25 17:05:06 +01:00

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),
}
}