Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
237 lines
8.0 KiB
Go
237 lines
8.0 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/breakpilot/school-service/internal/models"
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// ClassService handles class-related operations
|
|
type ClassService struct {
|
|
db *pgxpool.Pool
|
|
}
|
|
|
|
// NewClassService creates a new ClassService
|
|
func NewClassService(db *pgxpool.Pool) *ClassService {
|
|
return &ClassService{db: db}
|
|
}
|
|
|
|
// School Year Operations
|
|
|
|
// CreateSchoolYear creates a new school year
|
|
func (s *ClassService) CreateSchoolYear(ctx context.Context, teacherID string, req *models.CreateSchoolYearRequest) (*models.SchoolYear, error) {
|
|
startDate, _ := time.Parse("2006-01-02", req.StartDate)
|
|
endDate, _ := time.Parse("2006-01-02", req.EndDate)
|
|
|
|
// If this is current, unset other current years for this teacher
|
|
if req.IsCurrent {
|
|
s.db.Exec(ctx, `UPDATE school_years SET is_current = false WHERE teacher_id = $1`, teacherID)
|
|
}
|
|
|
|
var year models.SchoolYear
|
|
err := s.db.QueryRow(ctx, `
|
|
INSERT INTO school_years (teacher_id, name, start_date, end_date, is_current)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING id, name, start_date, end_date, is_current, teacher_id, created_at
|
|
`, teacherID, req.Name, startDate, endDate, req.IsCurrent).Scan(
|
|
&year.ID, &year.Name, &year.StartDate, &year.EndDate, &year.IsCurrent, &year.TeacherID, &year.CreatedAt,
|
|
)
|
|
return &year, err
|
|
}
|
|
|
|
// GetSchoolYears returns all school years for a teacher
|
|
func (s *ClassService) GetSchoolYears(ctx context.Context, teacherID string) ([]models.SchoolYear, error) {
|
|
rows, err := s.db.Query(ctx, `
|
|
SELECT id, name, start_date, end_date, is_current, teacher_id, created_at
|
|
FROM school_years
|
|
WHERE teacher_id = $1
|
|
ORDER BY start_date DESC
|
|
`, teacherID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var years []models.SchoolYear
|
|
for rows.Next() {
|
|
var y models.SchoolYear
|
|
if err := rows.Scan(&y.ID, &y.Name, &y.StartDate, &y.EndDate, &y.IsCurrent, &y.TeacherID, &y.CreatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
years = append(years, y)
|
|
}
|
|
return years, nil
|
|
}
|
|
|
|
// Class Operations
|
|
|
|
// CreateClass creates a new class
|
|
func (s *ClassService) CreateClass(ctx context.Context, teacherID string, req *models.CreateClassRequest) (*models.Class, error) {
|
|
var schoolYearID *uuid.UUID
|
|
if req.SchoolYearID != "" {
|
|
id, _ := uuid.Parse(req.SchoolYearID)
|
|
schoolYearID = &id
|
|
}
|
|
|
|
var class models.Class
|
|
err := s.db.QueryRow(ctx, `
|
|
INSERT INTO classes (teacher_id, school_year_id, name, grade_level, school_type, federal_state)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
RETURNING id, teacher_id, school_year_id, name, grade_level, school_type, federal_state, created_at
|
|
`, teacherID, schoolYearID, req.Name, req.GradeLevel, req.SchoolType, req.FederalState).Scan(
|
|
&class.ID, &class.TeacherID, &class.SchoolYearID, &class.Name, &class.GradeLevel, &class.SchoolType, &class.FederalState, &class.CreatedAt,
|
|
)
|
|
return &class, err
|
|
}
|
|
|
|
// GetClasses returns all classes for a teacher
|
|
func (s *ClassService) GetClasses(ctx context.Context, teacherID string) ([]models.Class, error) {
|
|
rows, err := s.db.Query(ctx, `
|
|
SELECT c.id, c.teacher_id, c.school_year_id, c.name, c.grade_level, c.school_type, c.federal_state, c.created_at,
|
|
COALESCE((SELECT COUNT(*) FROM students WHERE class_id = c.id), 0) as student_count
|
|
FROM classes c
|
|
WHERE c.teacher_id = $1
|
|
ORDER BY c.grade_level, c.name
|
|
`, teacherID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var classes []models.Class
|
|
for rows.Next() {
|
|
var c models.Class
|
|
if err := rows.Scan(&c.ID, &c.TeacherID, &c.SchoolYearID, &c.Name, &c.GradeLevel, &c.SchoolType, &c.FederalState, &c.CreatedAt, &c.StudentCount); err != nil {
|
|
return nil, err
|
|
}
|
|
classes = append(classes, c)
|
|
}
|
|
return classes, nil
|
|
}
|
|
|
|
// GetClass returns a single class
|
|
func (s *ClassService) GetClass(ctx context.Context, classID, teacherID string) (*models.Class, error) {
|
|
var class models.Class
|
|
err := s.db.QueryRow(ctx, `
|
|
SELECT c.id, c.teacher_id, c.school_year_id, c.name, c.grade_level, c.school_type, c.federal_state, c.created_at,
|
|
COALESCE((SELECT COUNT(*) FROM students WHERE class_id = c.id), 0) as student_count
|
|
FROM classes c
|
|
WHERE c.id = $1 AND c.teacher_id = $2
|
|
`, classID, teacherID).Scan(
|
|
&class.ID, &class.TeacherID, &class.SchoolYearID, &class.Name, &class.GradeLevel, &class.SchoolType, &class.FederalState, &class.CreatedAt, &class.StudentCount,
|
|
)
|
|
return &class, err
|
|
}
|
|
|
|
// DeleteClass deletes a class
|
|
func (s *ClassService) DeleteClass(ctx context.Context, classID, teacherID string) error {
|
|
_, err := s.db.Exec(ctx, `DELETE FROM classes WHERE id = $1 AND teacher_id = $2`, classID, teacherID)
|
|
return err
|
|
}
|
|
|
|
// Student Operations
|
|
|
|
// CreateStudent creates a new student
|
|
func (s *ClassService) CreateStudent(ctx context.Context, classID string, req *models.CreateStudentRequest) (*models.Student, error) {
|
|
var birthDate *time.Time
|
|
if req.BirthDate != "" {
|
|
t, _ := time.Parse("2006-01-02", req.BirthDate)
|
|
birthDate = &t
|
|
}
|
|
|
|
// Get school_id from class
|
|
var schoolID string
|
|
err := s.db.QueryRow(ctx, `SELECT school_id FROM classes WHERE id = $1`, classID).Scan(&schoolID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var student models.Student
|
|
err = s.db.QueryRow(ctx, `
|
|
INSERT INTO students (school_id, class_id, first_name, last_name, date_of_birth, student_number)
|
|
VALUES ($1, $2, $3, $4, $5, $6)
|
|
RETURNING id, class_id, first_name, last_name, date_of_birth, student_number, created_at
|
|
`, schoolID, classID, req.FirstName, req.LastName, birthDate, req.StudentNumber).Scan(
|
|
&student.ID, &student.ClassID, &student.FirstName, &student.LastName, &student.BirthDate, &student.StudentNumber, &student.CreatedAt,
|
|
)
|
|
return &student, err
|
|
}
|
|
|
|
// GetStudents returns all students in a class
|
|
func (s *ClassService) GetStudents(ctx context.Context, classID string) ([]models.Student, error) {
|
|
rows, err := s.db.Query(ctx, `
|
|
SELECT id, class_id, first_name, last_name, date_of_birth, student_number, created_at
|
|
FROM students
|
|
WHERE class_id = $1
|
|
ORDER BY last_name, first_name
|
|
`, classID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var students []models.Student
|
|
for rows.Next() {
|
|
var st models.Student
|
|
if err := rows.Scan(&st.ID, &st.ClassID, &st.FirstName, &st.LastName, &st.BirthDate, &st.StudentNumber, &st.CreatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
students = append(students, st)
|
|
}
|
|
return students, nil
|
|
}
|
|
|
|
// DeleteStudent deletes a student
|
|
func (s *ClassService) DeleteStudent(ctx context.Context, studentID string) error {
|
|
_, err := s.db.Exec(ctx, `DELETE FROM students WHERE id = $1`, studentID)
|
|
return err
|
|
}
|
|
|
|
// Subject Operations
|
|
|
|
// CreateSubject creates a new subject
|
|
func (s *ClassService) CreateSubject(ctx context.Context, teacherID string, req *models.CreateSubjectRequest) (*models.Subject, error) {
|
|
var subject models.Subject
|
|
err := s.db.QueryRow(ctx, `
|
|
INSERT INTO subjects (teacher_id, name, short_name, is_main_subject)
|
|
VALUES ($1, $2, $3, $4)
|
|
RETURNING id, teacher_id, name, short_name, is_main_subject, created_at
|
|
`, teacherID, req.Name, req.ShortName, req.IsMainSubject).Scan(
|
|
&subject.ID, &subject.TeacherID, &subject.Name, &subject.ShortName, &subject.IsMainSubject, &subject.CreatedAt,
|
|
)
|
|
return &subject, err
|
|
}
|
|
|
|
// GetSubjects returns all subjects for a teacher
|
|
func (s *ClassService) GetSubjects(ctx context.Context, teacherID string) ([]models.Subject, error) {
|
|
rows, err := s.db.Query(ctx, `
|
|
SELECT id, teacher_id, name, short_name, is_main_subject, created_at
|
|
FROM subjects
|
|
WHERE teacher_id = $1
|
|
ORDER BY name
|
|
`, teacherID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var subjects []models.Subject
|
|
for rows.Next() {
|
|
var subj models.Subject
|
|
if err := rows.Scan(&subj.ID, &subj.TeacherID, &subj.Name, &subj.ShortName, &subj.IsMainSubject, &subj.CreatedAt); err != nil {
|
|
return nil, err
|
|
}
|
|
subjects = append(subjects, subj)
|
|
}
|
|
return subjects, nil
|
|
}
|
|
|
|
// DeleteSubject deletes a subject
|
|
func (s *ClassService) DeleteSubject(ctx context.Context, subjectID, teacherID string) error {
|
|
_, err := s.db.Exec(ctx, `DELETE FROM subjects WHERE id = $1 AND teacher_id = $2`, subjectID, teacherID)
|
|
return err
|
|
}
|