package orm import ( "fmt" "net/http" "strconv" "time" "gogs.carduccidante.edu.it/karmen/core/renderer" ) type Teacher struct { Credential IsCoordinator bool `gorm:"-"` IsMinuter bool `gorm:"-"` Classes []*Class Students []*Student Subjects []*Subject Activities []*Activity Departments []*Department Groups []*Group `gorm:"many2many:group_teachers"` Coordinator []*Class Minuter []*Class SubjectsByClass map[uint][]*Subject `gorm:"-"` Hours int ActualHours int `gorm:"-"` } var ( selectUniqueTeacherClasses = ` SELECT DISTINCT classes.* FROM activities INNER JOIN classes on classes.id=activities.class_id WHERE (activities.teacher_id=? OR activities.supply_teacher_id=?)` selectUniqueTeacherSubjects = ` SELECT DISTINCT subjects.* FROM activities INNER JOIN subjects on subjects.id=activities.subject_id WHERE (activities.teacher_id=? OR activities.supply_teacher_id=?)` selectUniqueTeacherStudents = ` SELECT DISTINCT students.* FROM activities INNER JOIN students on students.id=activities.student_id WHERE (activities.teacher_id=? OR activities.supply_teacher_id=?)` selectUniqueTeacherSubjectsByClass = ` SELECT subjects.* FROM activities INNER JOIN subjects on subjects.id=activities.subject_id WHERE (activities.teacher_id=? OR activities.supply_teacher_id=?) AND (activities.class_id=?) ` selectSupplyTeachers = ` SELECT teachers.*,1 as supply FROM activities INNER JOIN teachers on teachers.id=activities.teacher_id WHERE supply_teacher_id <> 0 ORDER BY surname,name ` countActualTeacherHours = ` SELECT sum(hours) as actual_hours FROM activities WHERE (teacher_id=? OR supply_teacher_id=?); ` ) func (t *Teacher) GetID() uint { return t.ID } func (t *Teacher) String() string { return fmt.Sprintf("%s %s", t.Surname, t.Name) } func (t *Teacher) Create(args map[string]string, r *http.Request) (interface{}, error) { if r.Method == "GET" { return nil, nil } else { teacher := new(Teacher) err := renderer.Decode(teacher, r) if err != nil { return nil, err } teacher, err = CreateTeacher(teacher) if err != nil { return nil, err } return teacher, nil } } func (t *Teacher) Read(args map[string]string, r *http.Request) (interface{}, error) { var teacher Teacher id := args["id"] if err := DB().Preload("Groups").Where("id = ?", id).Find(&teacher).Error; err != nil { return nil, err } if err := DB().Raw(selectUniqueTeacherClasses, id, id).Scan(&teacher.Classes).Error; err != nil { return nil, err } if err := DB().Raw(selectUniqueTeacherSubjects, id, id).Scan(&teacher.Subjects).Error; err != nil { return nil, err } if err := DB().Raw(selectUniqueTeacherStudents, id, id).Scan(&teacher.Students).Error; err != nil { return nil, err } var result struct { ActualHours int } if err := DB().Raw(countActualTeacherHours, id, id).Scan(&result).Error; err != nil { return nil, err } teacher.ActualHours = result.ActualHours if err := DB().Preload("SupplyTeacher").Preload("Teacher").Preload("Subject").Preload("Student").Preload("Class").Where("teacher_id=? OR supply_teacher_id=?", id, id).Find(&teacher.Activities).Error; err != nil { return nil, err } coordClasses, err := teacher.CoordinatorClasses() if err != nil { return nil, err } minuterClasses, err := teacher.MinuterClasses() if err != nil { return nil, err } teacher.IsCoordinator, teacher.IsMinuter = len(coordClasses) > 0, len(minuterClasses) > 0 teacher.Coordinator, teacher.Minuter = coordClasses, minuterClasses return &teacher, nil } func (t *Teacher) ReadAll(args map[string]string, r *http.Request) (interface{}, error) { var teachers []*Teacher if err := DB().Order("surname,name").Find(&teachers).Error; err != nil { return nil, err } for _, teacher := range teachers { teacher.GetClasses() } for _, teacher := range teachers { teacher.GetSubjects() } for _, teacher := range teachers { teacher.GetStudents() } for _, teacher := range teachers { teacher.GetActivities() } for _, teacher := range teachers { teacher.SubjectsByClass = make(map[uint][]*Subject) for _, c := range teacher.Classes { subjects, err := teacher.GetSubjectsByClassID(strconv.Itoa(int(c.ID))) if err != nil { return nil, err } teacher.SubjectsByClass[c.ID] = subjects } coordClasses, err := teacher.CoordinatorClasses() if err != nil { return nil, err } minuterClasses, err := teacher.MinuterClasses() if err != nil { return nil, err } teacher.Coordinator, teacher.Minuter = coordClasses, minuterClasses } return teachers, nil } func (t *Teacher) Update(args map[string]string, r *http.Request) (interface{}, error) { if r.Method == "GET" { return t.Read(args, r) } else { teacher, err := t.Read(args, nil) if err != nil { return nil, err } // FIXME: Should not be hard set. teacher.(*Teacher).Regenerate = false // FIXME: Should not be hard set. teacher.(*Teacher).Exclude = false // FIXME: Should not be hard set. teacher.(*Teacher).NotInvited = false if len(args["DateFrom"]) == 0 { // FIXME: Should not be hard set. teacher.(*Teacher).DateFrom = time.Time{} } if len(args["DateTo"]) == 0 { // FIXME: Should not be hard set. teacher.(*Teacher).DateTo = time.Time{} } err = renderer.Decode(teacher, r) if err != nil { return nil, err } _, err = SaveTeacher(teacher) if err != nil { return nil, err } teacher, err = t.Read(args, nil) if err != nil { return nil, err } return teacher.(*Teacher), nil } } func (t *Teacher) Delete(args map[string]string, r *http.Request) (interface{}, error) { teacher, err := t.Read(args, nil) if err != nil { return nil, err } if err := DB().Unscoped().Delete(teacher.(*Teacher)).Error; err != nil { return nil, err } return teacher.(*Teacher), nil } func SaveTeacher(teacher interface{}) (interface{}, error) { if err := DB().Omit("Classes", "Subjects", "Activities").Save(teacher).Error; err != nil { return nil, err } return teacher, nil } func CreateTeacher(teacher *Teacher) (*Teacher, error) { var teachers []*Teacher if err := DB().Where("name=? AND surname=?", teacher.Name, teacher.Surname).Find(&teachers).Error; err != nil { return nil, err } if len(teachers) > 0 { return nil, fmt.Errorf("Teacher %s already exists!", teacher.CompleteName()) } if err := DB().Create(teacher).Error; err != nil { return nil, err } return teacher, nil } func (t *Teacher) GetClasses() ([]*Class, error) { if err := DB().Raw(selectUniqueTeacherClasses, t.ID, t.ID).Scan(&t.Classes).Error; err != nil { return nil, err } return t.Classes, nil } func (t *Teacher) GetSubjects() ([]*Subject, error) { if err := DB().Raw(selectUniqueTeacherSubjects, t.ID, t.ID).Scan(&t.Subjects).Error; err != nil { return nil, err } return t.Subjects, nil } func (t *Teacher) GetStudents() ([]*Student, error) { if err := DB().Raw(selectUniqueTeacherStudents, t.ID, t.ID).Scan(&t.Students).Error; err != nil { return nil, err } return t.Students, nil } func (t *Teacher) GetActivities() ([]*Activity, error) { if err := DB().Preload("SupplyTeacher").Preload("Teacher").Preload("Subject").Preload("Class").Preload("Student").Where("teacher_id=? OR supply_teacher_id=?", t.ID, t.ID).Find(&t.Activities).Error; err != nil { return nil, err } return t.Activities, nil } func (t *Teacher) GetActivitiesByClass(id string) ([]*Activity, error) { if err := DB().Preload("Teacher").Where("class_id=? AND (teacher_id=? or supply_teacher_id=?)", id, t.ID, t.ID).Find(&t.Activities).Error; err != nil { return nil, err } return t.Activities, nil } func (t *Teacher) GetSubjectsByClassID(id string) ([]*Subject, error) { if err := DB().Raw(selectUniqueTeacherSubjectsByClass, t.ID, t.ID, id).Scan(&t.Subjects).Error; err != nil { return nil, err } return t.Subjects, nil } func (t *Teacher) CoordinatorClasses() ([]*Class, error) { var output []*Class classes, err := t.GetClasses() if err != nil { return nil, err } for _, class := range classes { if class.CoordinatorID == t.ID { output = append(output, class) } } return output, nil } func (t *Teacher) MinuterClasses() ([]*Class, error) { var output []*Class classes, err := t.GetClasses() if err != nil { return nil, err } for _, class := range classes { if class.MinuterID == t.ID { output = append(output, class) } } return output, nil } func (t Teacher) IsCoordinatorInClass(className string) bool { var classes []Class if err := DB().Model(t).Where("name = ?", className).Related(&classes, "Classes").Error; err != nil { panic(err) } for _, class := range classes { if class.CoordinatorID == t.ID { return true } } return false } func (t *Teacher) CompleteName() string { return fmt.Sprintf("%s %s", t.Name, t.Surname) } func (t *Teacher) RestAPIPath() string { return "teachers" }