Boost Azure Demo
This commit is contained in:
180
Backend/internal/handlers/api/classrooms/handler.go
Normal file
180
Backend/internal/handlers/api/classrooms/handler.go
Normal file
@@ -0,0 +1,180 @@
|
||||
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),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user