diff --git a/config/config.go b/config/config.go index 1a98a5c..1eba4b1 100644 --- a/config/config.go +++ b/config/config.go @@ -51,14 +51,12 @@ type Config struct { func ReadConfigFile(filename string, conf *Config) error { configData, err := ioutil.ReadFile(filename) if err != nil { - err = fmt.Errorf("Error reading config file: %w", err) - log.Println(err.Error()) + log.Printf("Error reading config file: %s", err.Error()) return err } err = json.Unmarshal(configData, conf) if err != nil { - err = fmt.Errorf("Error parsing config file as json: %w", err) - log.Println(err.Error()) + log.Printf("Error parsing config file as json: %s", err.Error()) return err } return validateConfig(conf) diff --git a/controllers/addOfficeHourHandler.go b/controllers/addOfficeHourHandler.go index a99a40a..1bdaf5d 100644 --- a/controllers/addOfficeHourHandler.go +++ b/controllers/addOfficeHourHandler.go @@ -2,12 +2,10 @@ package controllers import ( "fmt" - "log" "net/http" "net/mail" "officeHours/config" "officeHours/models" - "officeHours/templating" "strconv" "strings" ) @@ -150,19 +148,12 @@ func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Requ id, err := b.officeHourRepo.Add(officeHour) if err != nil { w.WriteHeader(http.StatusInternalServerError) - templating.ServeTemplate(w, "addFailure", err) + b.serveTemplate(w, "addFailure", err) return } - officeHour, err = b.officeHourRepo.FindById(id) - if err != nil { - log.Printf("Error finding new office hour by id %d: %s", id, err.Error()) - } - _, err = b.requestRepo.Add(officeHour, models.RequestActivate) - if err != nil { - log.Printf("Error adding request: %s", err.Error()) - } - templating.ServeTemplate(w, "addSuccess", nil) - + officeHour, _ = b.officeHourRepo.FindById(id) + b.requestRepo.Add(officeHour, models.RequestActivate) + b.serveTemplate(w, "addSuccess", nil) } } @@ -173,5 +164,5 @@ func (b *BaseHandler) writeAddOfficeHourMask(w http.ResponseWriter, req *http.Re if len(data.Errors) != 0 { w.WriteHeader(http.StatusBadRequest) } - templating.ServeTemplate(w, "addMask", data) + b.serveTemplate(w, "addMask", data) } diff --git a/controllers/confirmRequestHandler.go b/controllers/confirmRequestHandler.go index 98a485d..7f2060f 100644 --- a/controllers/confirmRequestHandler.go +++ b/controllers/confirmRequestHandler.go @@ -2,7 +2,6 @@ package controllers import ( "net/http" - "officeHours/templating" ) func (b *BaseHandler) ConfirmRequestHandler(w http.ResponseWriter, req *http.Request) { @@ -10,17 +9,15 @@ func (b *BaseHandler) ConfirmRequestHandler(w http.ResponseWriter, req *http.Req request, err := b.requestRepo.FindBySecret(secret) if err != nil { - // TODO: header 404 - templating.ServeTemplate(w, "requestNotFound", nil) + b.serveTemplate(w, "requestNotFound", nil) return } err = b.requestRepo.Execute(request) if err != nil { - // TODO: write header 500 - templating.ServeTemplate(w, "executeFailure", err.Error()) + b.serveTemplate(w, "executeFailure", err.Error()) return } - templating.ServeTemplate(w, "executeSuccess", nil) + b.serveTemplate(w, "executeSuccess", nil) } diff --git a/controllers/deleteOfficeHourHandler.go b/controllers/deleteOfficeHourHandler.go index f694872..233dc34 100644 --- a/controllers/deleteOfficeHourHandler.go +++ b/controllers/deleteOfficeHourHandler.go @@ -4,13 +4,10 @@ package controllers import ( "net/http" "officeHours/models" - "officeHours/templating" "strconv" ) func (b *BaseHandler) DeleteOfficeHourHandler(w http.ResponseWriter, req *http.Request) { - // TODO: error handling here is by no means sufficient, furthermore - // 400 BadRequest is for technically wrong stuff (most promimently GET instead of POST) if req.FormValue("id") != "" { id, err := strconv.Atoi(req.FormValue("id")) if err != nil { @@ -21,7 +18,7 @@ func (b *BaseHandler) DeleteOfficeHourHandler(w http.ResponseWriter, req *http.R w.WriteHeader(http.StatusBadRequest) } _, err = b.requestRepo.Add(officeHour, models.RequestDelete) - templating.ServeTemplate(w, "deleteSuccess", nil) + b.serveTemplate(w, "deleteSuccess", nil) } else { officeHours, _ := b.officeHourRepo.GetAll(true) timetable, slots := b.GetTimetable(officeHours) diff --git a/controllers/getHandlers.go b/controllers/getHandlers.go index 5bdc516..50d055e 100644 --- a/controllers/getHandlers.go +++ b/controllers/getHandlers.go @@ -2,10 +2,8 @@ package controllers import ( "html/template" - "log" "net/http" "officeHours/models" - "officeHours/templating" "strconv" ) @@ -20,10 +18,7 @@ func (b *BaseHandler) GetByRoomHandler(w http.ResponseWriter, req *http.Request) b.RootHandler(w, req) return } - officeHours, err := b.officeHourRepo.FindByRoom(room, true) - if err != nil { - log.Printf("Error getting office hours for room %s: %s", room.Name, err.Error()) - } + officeHours, _ := b.officeHourRepo.FindByRoom(room, true) timetable, slots := b.GetTimetable(officeHours) b.writeTimetablePage(w, req, b.printTimetable(timetable, slots, false)) } @@ -39,10 +34,7 @@ func (b *BaseHandler) GetByCourseHandler(w http.ResponseWriter, req *http.Reques b.RootHandler(w, req) return } - officeHours, err := b.officeHourRepo.FindByCourse(course, true) - if err != nil { - log.Printf("Error getting office hours for course %s: %s", course.Name, err.Error()) - } + officeHours, _ := b.officeHourRepo.FindByCourse(course, true) timetable, slots := b.GetTimetable(officeHours) b.writeTimetablePage(w, req, b.printTimetable(timetable, slots, false)) } @@ -59,5 +51,5 @@ func (b *BaseHandler) writeTimetablePage(w http.ResponseWriter, req *http.Reques SelectedRoom int SelectedCourse int }{courses, rooms, timetable, selectedRoom, selectedCourse} - templating.ServeTemplate(w, "index", data) + b.serveTemplate(w, "index", data) } diff --git a/controllers/templates.go b/controllers/templates.go new file mode 100644 index 0000000..7dd1a78 --- /dev/null +++ b/controllers/templates.go @@ -0,0 +1,60 @@ +package controllers + +import ( + "fmt" + "html/template" + "log" + "net/http" + "officeHours/models" + "os" +) + +var funcs = template.FuncMap{ + "DayName": models.DayName, + "divide": func(i int, j int) int { return i / j }, +} +var baseTemplate = template.Must(template.ParseFiles("templates/base.html")).New("base.html").Funcs(funcs) + +// Execute a rendered full HTML page. +// +// If you just want to fill a template snippet, use the RawTemplates object. +// +// Parameters: +// - name is the name of the template file inside templates/, without .html suffix. +// - data is passed through to the template +func (b *BaseHandler) serveTemplate(w http.ResponseWriter, name string, data any) { + full_name := "templates/" + name + ".html" + // check that template exists + info, err := os.Stat(full_name) + if (err != nil && os.IsNotExist(err)) || info.IsDir() { + errMsg := fmt.Sprintf("Template %s nicht gefunden", full_name) + log.Println(errMsg) + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(errMsg)) + return + } + + tmpl, err := baseTemplate.ParseFiles(full_name) + if err != nil { + errMsg := fmt.Sprintf("Template %s konnte nicht geparst werden : %s", full_name, err.Error()) + log.Println(errMsg) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(errMsg)) + return + } + // TODO: cache templates in parsed state, but not executed + err = template.Must(tmpl.Clone()).Execute(w, data) + if err != nil { + errMsg := fmt.Sprintf("Template %s konnte nicht ausgeführt werden : %s", full_name, err.Error()) + log.Println(errMsg) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(errMsg)) + return + } +} + +// standalone templates that should not be wrapped into the base.html +var RawTemplates = template.Must(template.New("").Funcs(funcs).ParseFiles( + "templates/confirmationMail", + "templates/td.html", + "templates/officeHourTable.html")) diff --git a/controllers/timetable.go b/controllers/timetable.go index b1d5eb1..7162026 100644 --- a/controllers/timetable.go +++ b/controllers/timetable.go @@ -5,9 +5,7 @@ import ( "bytes" "fmt" "html/template" - "log" "officeHours/models" - "officeHours/templating" ) func (b *BaseHandler) GetTimetable(officeHours []models.OfficeHour) (timetable map[models.Date]map[int]models.OfficeHour, slots []int) { @@ -86,12 +84,7 @@ func (b *BaseHandler) printTimetable(timetable map[models.Date]map[int]models.Of MinuteGranularity int DeleteIcons bool }{OfficeHour: current, MinuteGranularity: b.config.Date.MinuteGranularity, DeleteIcons: deleteIcons} - err := templating.WriteTemplate(&celldata, "td", data) - if err != nil { - err = fmt.Errorf("writing table cell failed:\n%w", err) - log.Println(err.Error()) - // TODO: better error wrapping up to top-level request handler - } + RawTemplates.ExecuteTemplate(&celldata, "td.html", data) tableBody += celldata.String() } } else { @@ -123,11 +116,6 @@ func (b *BaseHandler) printTimetable(timetable map[models.Date]map[int]models.Of slots[4], template.HTML(tableBody), } - err := templating.WriteTemplate(&table, "officeHourTable", tableData) - if err != nil { - err = fmt.Errorf("writing table failed:\n%w", err) - log.Println(err.Error()) - // TODO: better error wrapping up to top-level request handler - } + RawTemplates.ExecuteTemplate(&table, "officeHourTable.html", tableData) return template.HTML(table.String()) } diff --git a/main.go b/main.go index 00423f5..67e773e 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,6 @@ import ( "officeHours/controllers" "officeHours/repositories" "officeHours/sqldb" - "officeHours/templating" "os" ) @@ -20,7 +19,6 @@ func main() { if e == nil { log.SetOutput(logwriter) } - configFile := flag.String( "config", "config/config.json", @@ -39,17 +37,8 @@ func main() { // serve static files staticHandler := http.FileServer(http.Dir("./static")) - // parse templates - if err = templating.InitTemplates(); err != nil { - log.Print(err.Error()) - log.Fatal(">>>\nFatal error occurred, aborting program\n<<<\n") - } - // database connection - db, err := sqldb.Connect(conf) - if err != nil { - log.Print(err.Error()) - log.Fatal(">>>\nFatal error occurred, aborting program\n<<<\n") - } + + db := sqldb.Connect(conf) // Create repos roomRepo := repositories.NewRoomRepo(db) courseRepo := repositories.NewCourseRepo(db) diff --git a/repositories/course.go b/repositories/course.go index e721130..68dd801 100644 --- a/repositories/course.go +++ b/repositories/course.go @@ -3,9 +3,6 @@ package repositories import ( "database/sql" - "errors" - "fmt" - "log" "officeHours/models" ) @@ -20,17 +17,26 @@ func NewCourseRepo(db *sql.DB) *CourseRepo { } func (r *CourseRepo) FindByName(name string) (models.Course, error) { - return r.getFromRow(r.db.QueryRow("SELECT * FROM course WHERE name=?", name)) + row := r.db.QueryRow("SELECT * FROM course WHERE name=?", name) + var course models.Course + if err := row.Scan(&course.Id, &course.Name); err != nil { + return models.Course{}, err + } + return course, nil } func (r *CourseRepo) FindById(id int) (models.Course, error) { - return r.getFromRow(r.db.QueryRow("SELECT * FROM course WHERE id=?", id)) + row := r.db.QueryRow("SELECT * FROM course WHERE id=?", id) + var course models.Course + if err := row.Scan(&course.Id, &course.Name); err != nil { + return models.Course{}, err + } + return course, nil } func (r *CourseRepo) GetAll() ([]models.Course, error) { rows, err := r.db.Query("SELECT * FROM course") if err != nil { - log.Printf("Error getting all courses: %s", err.Error()) return nil, err } defer rows.Close() @@ -43,22 +49,9 @@ func (r *CourseRepo) getFromRows(rows *sql.Rows) ([]models.Course, error) { for rows.Next() { var course models.Course if err := rows.Scan(&course.Id, &course.Name); err != nil { - log.Printf("Error scanning course row: %s", err.Error()) return courses, err } courses = append(courses, course) } return courses, nil } - -func (r *CourseRepo) getFromRow(row *sql.Row) (models.Course, error) { - var course models.Course - if err := row.Scan(&course.Id, &course.Name); err != nil { - err = fmt.Errorf("Error getting course row: %w", err) - if !errors.Is(err, sql.ErrNoRows) { - log.Printf(err.Error()) - } - return models.Course{}, err - } - return course, nil -} diff --git a/repositories/officeHour.go b/repositories/officeHour.go index e92093f..dae2213 100644 --- a/repositories/officeHour.go +++ b/repositories/officeHour.go @@ -3,9 +3,7 @@ package repositories import ( "database/sql" - "errors" "fmt" - "log" "officeHours/config" "officeHours/models" ) @@ -37,11 +35,7 @@ func (r *OfficeHourRepo) GetAll(activeOnly bool) ([]models.OfficeHour, error) { rows, err = r.db.Query("SELECT * FROM officeHour") } if err != nil { - err = fmt.Errorf("Error getting all officeHours from database: %w", err) - if !errors.Is(err, sql.ErrNoRows) { - log.Println(err.Error()) - } - return nil, err + return nil, fmt.Errorf("Error getting all officeHours from database: %s", err.Error()) } defer rows.Close() return r.getFromRows(rows) @@ -55,14 +49,10 @@ func (r *OfficeHourRepo) FindByCourse(course models.Course, activeOnly bool) ([] } else { rows, err = r.db.Query("SELECT * FROM officeHour WHERE course=?", course.Id) } - defer rows.Close() if err != nil { - err = fmt.Errorf("Error getting officeHours by course from database: %w", err) - if !errors.Is(err, sql.ErrNoRows) { - log.Println(err.Error()) - } - return nil, err + return nil, fmt.Errorf("Error getting officeHours by course from database: %s", err.Error()) } + defer rows.Close() return r.getFromRows(rows) } @@ -75,11 +65,7 @@ func (r *OfficeHourRepo) FindByRoom(room models.Room, activeOnly bool) ([]models rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=?", room.Id) } if err != nil { - err = fmt.Errorf("Error getting officeHours by room from database: %w", err) - if !errors.Is(err, sql.ErrNoRows) { - log.Println(err.Error()) - } - return nil, err + return nil, fmt.Errorf("Error getting officeHours by room from database: %s", err.Error()) } defer rows.Close() return r.getFromRows(rows) @@ -89,16 +75,11 @@ func (r *OfficeHourRepo) FindById(id int) (models.OfficeHour, error) { return r.getFromRow(r.db.QueryRow("SELECT * FROM officeHour WHERE id=?", id)) } -func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (int, error) { +func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (id int, err error) { // Find correct tutor or add if not existent - _, err := r.tutorRepo.Add(officeHour.Tutor) - if err != nil { - return 0, err - } + r.tutorRepo.Add(officeHour.Tutor) officeHour.Tutor, err = r.tutorRepo.FindByNameAndEmail(officeHour.Tutor.Name, officeHour.Tutor.Email) if err != nil { - err = fmt.Errorf("Newly added tutor not found: %w", err) - log.Println(err.Error()) return 0, err } @@ -130,19 +111,14 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (int, error) { officeHour.Info, officeHour.Active, officeHour.Duration) - id, lastInsertIdErr := sqlResult.LastInsertId() - if lastInsertIdErr != nil { - log.Printf("Error getting Id for new tutor: %s", lastInsertIdErr.Error()) - } - return int(id), err + id64, _ := sqlResult.LastInsertId() + return int(id64), err } func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error { _, err := r.db.Exec("DELETE FROM officeHour WHERE id=?", officeHour.Id) if err != nil { - err = fmt.Errorf("Error deleting officeHour from database: %w", err) - log.Println(err.Error()) - return err + return fmt.Errorf("Error deleting officeHour from database: %s", err.Error()) } return nil } @@ -152,29 +128,12 @@ func (r *OfficeHourRepo) getFromRow(row *sql.Row) (models.OfficeHour, error) { var week, day, hour, minute, tutorId, courseId, roomId int err := row.Scan(&officeHour.Id, &tutorId, &day, &hour, &minute, &roomId, &courseId, &week, &officeHour.Info, &officeHour.Active, &officeHour.Duration) if err != nil { - err = fmt.Errorf("Error getting single officeHour row from database: %w", err) - log.Println(err.Error()) - return models.OfficeHour{}, err + return models.OfficeHour{}, fmt.Errorf("Error getting single officeHours row from database: %s", err.Error()) } officeHour.Date = models.Date{Week: week, Day: day, Hour: hour, Minute: minute} - officeHour.Room, err = r.roomRepo.FindById(roomId) - if err != nil { - err = fmt.Errorf("Error finding room by id %d for office hour: %w", roomId, err) - log.Println(err.Error()) - return officeHour, err - } - officeHour.Tutor, err = r.tutorRepo.FindById(tutorId) - if err != nil { - err = fmt.Errorf("Error finding tutor by id %d for office hour: %w", tutorId, err) - log.Println(err.Error()) - return officeHour, err - } - officeHour.Course, err = r.courseRepo.FindById(courseId) - if err != nil { - err = fmt.Errorf("Error finding course by id %d for office hour: %w", courseId, err) - log.Println(err.Error()) - return officeHour, err - } + officeHour.Room, _ = r.roomRepo.FindById(roomId) + officeHour.Tutor, _ = r.tutorRepo.FindById(tutorId) + officeHour.Course, _ = r.courseRepo.FindById(courseId) return officeHour, nil } @@ -183,29 +142,13 @@ func (r *OfficeHourRepo) getFromRows(rows *sql.Rows) ([]models.OfficeHour, error for rows.Next() { var officeHour models.OfficeHour var week, day, hour, minute, tutorId, roomId, courseId int - var err error if err := rows.Scan(&officeHour.Id, &tutorId, &day, &hour, &minute, &roomId, &courseId, &week, &officeHour.Info, &officeHour.Active, &officeHour.Duration); err != nil { - return officeHours, fmt.Errorf("Error getting multiple officeHour rows from database: %w", err) + return officeHours, fmt.Errorf("Error getting multiple officeHour rows from database: %s", err.Error()) } officeHour.Date = models.Date{Week: week, Day: day, Hour: hour, Minute: minute} - officeHour.Room, err = r.roomRepo.FindById(roomId) - if err != nil { - err = fmt.Errorf("Error finding room by id %d for office hour: %w", roomId, err) - log.Println(err.Error()) - return officeHours, err - } - officeHour.Tutor, err = r.tutorRepo.FindById(tutorId) - if err != nil { - err = fmt.Errorf("Error finding tutor by id %d for office hour: %w", tutorId, err) - log.Println(err.Error()) - return officeHours, err - } - officeHour.Course, err = r.courseRepo.FindById(courseId) - if err != nil { - err = fmt.Errorf("Error finding course by id %d for office hour: %w", courseId, err) - log.Println(err.Error()) - return officeHours, err - } + officeHour.Room, _ = r.roomRepo.FindById(roomId) + officeHour.Tutor, _ = r.tutorRepo.FindById(tutorId) + officeHour.Course, _ = r.courseRepo.FindById(courseId) officeHours = append(officeHours, officeHour) } return officeHours, nil @@ -220,9 +163,7 @@ func (r *OfficeHourRepo) NumberByTimeSpanAndRoom(date models.Date, duration int, rows, err = r.db.Query("SELECT * FROM officeHour WHERE room=?", room.Id) } if err != nil { - err = fmt.Errorf("Error getting officeHours by timespan and room from database: %w", err) - log.Println(err.Error()) - return 0, err + return 0, fmt.Errorf("Error getting officeHours by timespan and room from database: %s", err.Error()) } defer rows.Close() officeHours, err := r.getFromRows(rows) diff --git a/repositories/request.go b/repositories/request.go index e6273e9..2ebdb73 100644 --- a/repositories/request.go +++ b/repositories/request.go @@ -5,14 +5,13 @@ import ( "bytes" "crypto/rand" "database/sql" - "errors" "fmt" "log" "math/big" "net/smtp" "officeHours/config" + "officeHours/controllers" "officeHours/models" - "officeHours/templating" ) type RequestRepo struct { @@ -54,8 +53,6 @@ func (r *RequestRepo) FindByOfficeHour(officeHour models.OfficeHour) ([]models.R var request models.Request var officeHourId int if err := rows.Scan(&request.Id, &officeHourId, &request.Action, &request.Secret); err != nil { - err = fmt.Errorf("Error scanning request row: %w", err) - log.Println(err.Error()) return requests, err } request.OfficeHour, err = r.officeHourRepo.FindById(officeHourId) @@ -69,7 +66,7 @@ func (r *RequestRepo) FindByOfficeHour(officeHour models.OfficeHour) ([]models.R func (r *RequestRepo) Add(officeHour models.OfficeHour, action int) (int, error) { existents, err := r.FindByOfficeHour(officeHour) - if err != nil && !errors.Is(err, sql.ErrNoRows) { + if err != nil && err != sql.ErrNoRows { return 0, err } /* Resend confirmation mail if identical request exists, @@ -103,10 +100,10 @@ func (r *RequestRepo) Execute(request models.Request) error { _, err = r.db.Exec("UPDATE officeHour SET active=true WHERE id=?", request.OfficeHour.Id) r.db.Exec("DELETE FROM request WHERE officeHour=?", request.OfficeHour.Id) case models.RequestDelete: - err = r.officeHourRepo.Delete(request.OfficeHour) + r.officeHourRepo.Delete(request.OfficeHour) r.db.Exec("DELETE FROM request WHERE officeHour=?", request.OfficeHour.Id) default: - _, err = r.db.Exec("DELETE FROM request WHERE id=?", request.Id) + r.db.Exec("DELETE FROM request WHERE id=?", request.Id) } return err } @@ -115,10 +112,10 @@ func (r *RequestRepo) newSecret() (string, error) { var err error var secret string // find unused secret - for !errors.Is(err, sql.ErrNoRows) { + for err != sql.ErrNoRows { secret = randomString(r.config.Request.SecretLength) _, err = r.FindBySecret(secret) - if err != nil && !errors.Is(err, sql.ErrNoRows) { + if err != nil && err != sql.ErrNoRows { return "", err } } @@ -131,13 +128,11 @@ func (r *RequestRepo) sendConfirmationMail(request models.Request) error { Config config.Config Request models.Request }{r.config, request} - err := templating.WriteTemplate(&message, "confirmationMail", data) + err := controllers.RawTemplates.ExecuteTemplate(&message, "confirmationMail", data) if err != nil { - err = fmt.Errorf("Error parsing confirmation Mail: %w", err) - log.Println(err.Error()) + log.Printf("Error parsing confirmation Mail: %s", err.Error()) return err } - switch r.config.Mailer.Type { case "Stdout": fmt.Println(message.String()) @@ -147,12 +142,7 @@ func (r *RequestRepo) sendConfirmationMail(request models.Request) error { if r.config.Mailer.SmtpUseAuth { auth = smtp.PlainAuth(r.config.Mailer.SmtpIdentity, r.config.Mailer.FromAddress, r.config.Mailer.SmtpPassword, r.config.Mailer.SmtpHost) } - err = smtp.SendMail(fmt.Sprintf("%s:%d", r.config.Mailer.SmtpHost, r.config.Mailer.SmtpPort), auth, string(r.config.Mailer.FromName), to, message.Bytes()) - if err != nil { - err = fmt.Errorf("Error sending mail by smtp: %w", err) - log.Println(err.Error()) - } - return err + return smtp.SendMail(fmt.Sprintf("%s:%d", r.config.Mailer.SmtpHost, r.config.Mailer.SmtpPort), auth, string(r.config.Mailer.FromName), to, message.Bytes()) } return nil } @@ -164,10 +154,7 @@ func randomString(n int) string { s := make([]rune, n) for i := range s { - position, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) - if err != nil { - log.Printf("Error getting random position in randomString(n int): %s", err.Error()) - } + position, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) s[i] = letters[position.Int64()] } return string(s) diff --git a/repositories/room.go b/repositories/room.go index 771eb8c..2ad0c69 100644 --- a/repositories/room.go +++ b/repositories/room.go @@ -3,9 +3,6 @@ package repositories import ( "database/sql" - "errors" - "fmt" - "log" "officeHours/models" ) @@ -32,10 +29,6 @@ func (r *RoomRepo) FindById(id int) (models.Room, error) { row := r.db.QueryRow("SELECT * FROM room WHERE id=?", id) var room models.Room if err := row.Scan(&room.Id, &room.Name, &room.MaxOccupy); err != nil { - err = fmt.Errorf("Error scanning row to get room: %w", err) - if !errors.Is(err, sql.ErrNoRows) { - log.Println(err.Error()) - } return models.Room{}, err } return room, nil @@ -44,8 +37,6 @@ func (r *RoomRepo) FindById(id int) (models.Room, error) { func (r *RoomRepo) GetAll() ([]models.Room, error) { rows, err := r.db.Query("SELECT * FROM room") if err != nil { - err = fmt.Errorf("Error getting all rooms: %w", err) - log.Println(err.Error()) return nil, err } defer rows.Close() @@ -54,10 +45,15 @@ func (r *RoomRepo) GetAll() ([]models.Room, error) { for rows.Next() { var room models.Room if err := rows.Scan(&room.Id, &room.Name, &room.MaxOccupy); err != nil { - err = fmt.Errorf("Error scanning row to get room: %w", err) return rooms, err } rooms = append(rooms, room) } return rooms, nil } +func (r *RoomRepo) Save(room models.Room) error { + return nil +} +func (r *RoomRepo) Add(room models.Room) error { + return nil +} diff --git a/repositories/tutor.go b/repositories/tutor.go index 3c84819..c5693c1 100644 --- a/repositories/tutor.go +++ b/repositories/tutor.go @@ -3,9 +3,6 @@ package repositories import ( "database/sql" - "errors" - "fmt" - "log" "officeHours/models" ) @@ -30,8 +27,6 @@ func (r *TutorRepo) FindByEmail(email string) ([]models.Tutor, error) { for rows.Next() { var tutor models.Tutor if err := rows.Scan(&tutor.Id, &tutor.Name, &tutor.Email); err != nil { - err = fmt.Errorf("Error scanning tutor row: %w", err) - log.Println(err.Error()) return tutors, err } tutors = append(tutors, tutor) @@ -68,24 +63,23 @@ func (r *TutorRepo) GetAll() ([]models.Tutor, error) { for rows.Next() { var tutor models.Tutor if err := rows.Scan(&tutor.Id, &tutor.Name, &tutor.Email); err != nil { - err = fmt.Errorf("Error scanning tutor row: %w", err) - log.Println(err.Error()) return tutors, err } tutors = append(tutors, tutor) } return tutors, nil } +func (r *TutorRepo) Save(tutor models.Tutor) error { + return nil +} func (r *TutorRepo) Add(tutor models.Tutor) (int, error) { //Don't add identical tutors existentTutor, err := r.FindByNameAndEmail(tutor.Name, tutor.Email) - if errors.Is(err, sql.ErrNoRows) { + if err == sql.ErrNoRows { sqlResult, err := r.db.Exec("INSERT INTO `tutor` (name, email) VALUES (?,?)", tutor.Name, tutor.Email) - id, lastInsertIdErr := sqlResult.LastInsertId() - if lastInsertIdErr != nil { - log.Printf("Error getting Id for new tutor: %s", lastInsertIdErr.Error()) - } + id, _ := sqlResult.LastInsertId() return int(id), err } return existentTutor.Id, err + } diff --git a/sqldb/sqldb.go b/sqldb/sqldb.go index f4c5e26..783ba88 100644 --- a/sqldb/sqldb.go +++ b/sqldb/sqldb.go @@ -3,13 +3,14 @@ package sqldb import ( "database/sql" "fmt" + "log" "officeHours/config" _ "github.com/go-sql-driver/mysql" _ "github.com/mattn/go-sqlite3" ) -func Connect(config config.Config) (*sql.DB, error) { +func Connect(config config.Config) *sql.DB { switch config.SQL.Type { case "SQLite": return connectSQLite(config.SQL.SQLiteFile) @@ -20,28 +21,30 @@ func Connect(config config.Config) (*sql.DB, error) { config.SQL.MysqlPort, config.SQL.MysqlDatabase) default: - return nil, fmt.Errorf("Type of database not recognised: %s", config.SQL.Type) + log.Fatal("Type of database not recognised.") } + return nil } -func connectSQLite(file string) (*sql.DB, error) { +func connectSQLite(file string) *sql.DB { db, err := sql.Open("sqlite3", file) if err != nil { - return db, fmt.Errorf("Error opening SQLite database: %w", err) + log.Fatal(err) } - return db, nil + + return db } -func connectMysql(user string, password string, address string, port int, database string) (*sql.DB, error) { +func connectMysql(user string, password string, address string, port int, database string) *sql.DB { db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", user, password, address, port, database)) if err != nil { - return db, fmt.Errorf("Error connecting to Mysql database: %w", err) + log.Fatalf("Error connecting to database: %s", err) } err = db.Ping() // handle error if err != nil { - return db, fmt.Errorf("Error pinging Mysql database: %w", err) + log.Fatalf("Error pinging database: %s", err) } - return db, nil + return db } diff --git a/templating/templates/addFailure.html b/templates/addFailure.html similarity index 100% rename from templating/templates/addFailure.html rename to templates/addFailure.html diff --git a/templating/templates/addMask.html b/templates/addMask.html similarity index 100% rename from templating/templates/addMask.html rename to templates/addMask.html diff --git a/templating/templates/addSuccess.html b/templates/addSuccess.html similarity index 100% rename from templating/templates/addSuccess.html rename to templates/addSuccess.html diff --git a/templating/templates/base.html b/templates/base.html similarity index 100% rename from templating/templates/base.html rename to templates/base.html diff --git a/templating/templates/confirmationMail b/templates/confirmationMail similarity index 100% rename from templating/templates/confirmationMail rename to templates/confirmationMail diff --git a/templating/templates/deleteSuccess.html b/templates/deleteSuccess.html similarity index 100% rename from templating/templates/deleteSuccess.html rename to templates/deleteSuccess.html diff --git a/templating/templates/executeFailure.html b/templates/executeFailure.html similarity index 100% rename from templating/templates/executeFailure.html rename to templates/executeFailure.html diff --git a/templating/templates/executeSuccess.html b/templates/executeSuccess.html similarity index 100% rename from templating/templates/executeSuccess.html rename to templates/executeSuccess.html diff --git a/templating/templates/index.html b/templates/index.html similarity index 100% rename from templating/templates/index.html rename to templates/index.html diff --git a/templating/templates/officeHourTable.html b/templates/officeHourTable.html similarity index 100% rename from templating/templates/officeHourTable.html rename to templates/officeHourTable.html diff --git a/templating/templates/requestNotFound.html b/templates/requestNotFound.html similarity index 100% rename from templating/templates/requestNotFound.html rename to templates/requestNotFound.html diff --git a/templating/templates/td.html b/templates/td.html similarity index 100% rename from templating/templates/td.html rename to templates/td.html diff --git a/templating/templates.go b/templating/templates.go deleted file mode 100644 index 982b2c2..0000000 --- a/templating/templates.go +++ /dev/null @@ -1,138 +0,0 @@ -package templating - -import ( - "fmt" - "html/template" - "io" - "log" - "net/http" - "officeHours/models" - "os" - "time" -) - -// parsed templates available for execution -var templates map[string]*template.Template = map[string]*template.Template{} - -// Initialise and parse templates. -// -// Should only be called once. -// -// Since this is something which may error and feels like -// it should not be done automatically on import, -// put it into a function. -func InitTemplates() error { - const templateDir = "templating/templates/" - var funcs = template.FuncMap{ - "DayName": models.DayName, - "divide": func(i int, j int) int { return i / j }, - } - var emptyTemplate = template.New("").Funcs(funcs) - var baseTemplate, err = template.ParseFiles(templateDir + "base.html") - if err != nil { - return fmt.Errorf("parsing base template failed:\n%w", err) - } - baseTemplate.Funcs(funcs) - - type toCache struct { - filename string - standalone bool - } - var toParse = map[string]toCache{ - // full html templates - "addFailure": {"addFailure.html", false}, - "addMask": {"addMask.html", false}, - "addSuccess": {"addSuccess.html", false}, - "deleteSuccess": {"deleteSuccess.html", false}, - "executeFailure": {"executeFailure.html", false}, - "executeSuccess": {"executeSuccess.html", false}, - "index": {"index.html", false}, - "requestNotFound": {"requestNotFound.html", false}, - // standalone templates - "confirmationMail": {"confirmationMail", true}, - "officeHourTable": {"officeHourTable.html", true}, - "td": {"td.html", true}, - } - - // parse templates and add to global mapping - for key, tmpl := range toParse { - if _, exists := templates[key]; exists { - return fmt.Errorf("template '%s' already parsed", key) - } - fullName := templateDir + tmpl.filename - // check that template file - info, err := os.Stat(fullName) - if err != nil { - return fmt.Errorf("adding template %s failed:\n%w", tmpl.filename, err) - } - if info.IsDir() { - return fmt.Errorf("adding template %s failed: is a directory", tmpl.filename) - } - // parse - var parsed *template.Template - if tmpl.standalone { - parsed, err = emptyTemplate.Clone() - parsed = parsed.New(tmpl.filename) - } else { - parsed, err = baseTemplate.Clone() - } - if err != nil { - return fmt.Errorf("cloning base template failed:\n%w", err) - } - parsed, err = parsed.ParseFiles(fullName) - if err != nil { - return fmt.Errorf("parsing template %s failed:\n%w", tmpl.filename, err) - } - templates[key] = parsed - } - return nil -} - -// Execute a template and write it to the given writer. -// -// Parameters: -// - name: name of the template to execute -// - data: passed through to the template -func WriteTemplate(w io.Writer, name string, data any) error { - tmpl, exists := templates[name] - if !exists { - return fmt.Errorf("template %s not available", name) - } - tmpl, err := tmpl.Clone() - if err != nil { - return fmt.Errorf("cloning template failed:\n%w", err) - } - err = tmpl.Execute(w, data) - if err != nil { - return fmt.Errorf("template execution failed:\n%w", err) - } - return nil -} - -// Execute a template and write it to a http writer. -// -// Similar to WriteTemplate, but in error case this adds a corresponding -// status code and writes an error message to the writer. -// -// Typically, this is the final action in handling an http request. -// -// Parameters: -// - name: name of the template to execute -// - data: passed through to the template -func ServeTemplate(w http.ResponseWriter, name string, data any) { - // TODO: make this return an error, handle on top of every request handler - err := WriteTemplate(w, name, data) - if err != nil { - err = fmt.Errorf("writing template failed:\n%w", err) - log.Println(err.Error()) - w.WriteHeader(http.StatusInternalServerError) - io.WriteString(w, `Internal Server Error. - -Du kannst uns helfen, indem du folgende Fehlermeldung per Mail -an sprechstunden@mathebau.de sendest: - -Fehler um\n -`+time.Now().String()+"\n"+err.Error()) - return - } -}