Speichere Konfiguration in config/config.json
This commit is contained in:
parent
43b3631da2
commit
c38286bcc5
14 changed files with 249 additions and 78 deletions
88
config/config.go
Normal file
88
config/config.go
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Server struct {
|
||||||
|
ListenAddress string
|
||||||
|
ListenPort int
|
||||||
|
Protocol string
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
Date struct {
|
||||||
|
MinuteGranularity int
|
||||||
|
}
|
||||||
|
Request struct {
|
||||||
|
SecretLength int
|
||||||
|
}
|
||||||
|
Mailer struct {
|
||||||
|
Type string
|
||||||
|
FromAddress string
|
||||||
|
FromName template.HTML
|
||||||
|
SmtpHost string
|
||||||
|
SmtpPort int
|
||||||
|
SmtpUseAuth bool
|
||||||
|
SmtpIdentity string
|
||||||
|
SmtpPassword string
|
||||||
|
}
|
||||||
|
SQL struct {
|
||||||
|
Type string
|
||||||
|
SQLiteFile string
|
||||||
|
MysqlUser string
|
||||||
|
MysqlPassword string
|
||||||
|
MysqlHost string
|
||||||
|
MysqlPort int
|
||||||
|
MysqlDatabase string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadConfigFile takes a file path as an argument and attempts to
|
||||||
|
// unmarshal the content of the file into a struct containing a
|
||||||
|
// configuration.
|
||||||
|
func ReadConfigFile(filename string, conf *Config) error {
|
||||||
|
configData, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(configData, conf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return validateConfig(conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateConfig(conf *Config) error {
|
||||||
|
var err error
|
||||||
|
if !(conf.Server.ListenPort >= 1 && conf.Server.ListenPort <= 65535) {
|
||||||
|
err = fmt.Errorf("Validating config: Server port must be between 1 and 65535, but is %d.", conf.Server.ListenPort)
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
if !(conf.Server.Protocol == "http" || conf.Server.Protocol == "https") {
|
||||||
|
err = fmt.Errorf("Validating config: Server protocol must be http or https, but is '%s'.", conf.Server.Protocol)
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
if !(conf.Date.MinuteGranularity >= 1 && conf.Date.MinuteGranularity <= 60) {
|
||||||
|
err = fmt.Errorf("Validating config: Minute granularity must be between 1 and 60, but is %d.", conf.Date.MinuteGranularity)
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
if !(conf.Request.SecretLength >= 5 && conf.Request.SecretLength <= 50) {
|
||||||
|
err = fmt.Errorf("Validating config: Requests' secret length must be between 5 and 50, but is %d.", conf.Request.SecretLength)
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
if !(conf.Mailer.Type == "Stdout" || conf.Mailer.Type == "Smtp") {
|
||||||
|
err = fmt.Errorf("Validating config: Mailer type must be 'stdout' or 'smtp', but is '%s'.", conf.Mailer.Type)
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
if !(conf.SQL.Type == "SQLite" || conf.SQL.Type == "Mysql") {
|
||||||
|
err = fmt.Errorf("Validating config: SQL type must be 'SQLite' or 'Mysql', but is '%s'.", conf.SQL.Type)
|
||||||
|
log.Println(err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
33
config/config.json
Normal file
33
config/config.json
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"listenAddress": "",
|
||||||
|
"listenPort": 8080,
|
||||||
|
"protocol": "https",
|
||||||
|
"domain": "localhost:8080"
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"minuteGranularity": 5
|
||||||
|
},
|
||||||
|
"request": {
|
||||||
|
"secretLength": 15
|
||||||
|
},
|
||||||
|
"mailer": {
|
||||||
|
"type": "Stdout",
|
||||||
|
"fromAddress": "sprechstunden@localhost",
|
||||||
|
"fromName": "Mathebau Sprechstunden <sprechstunden@localhost>",
|
||||||
|
"smtpHost": "localhost",
|
||||||
|
"smtpPort": 25,
|
||||||
|
"smtpUseAuth": false,
|
||||||
|
"smtpIdentity": "",
|
||||||
|
"smtpPassword": ""
|
||||||
|
},
|
||||||
|
"SQL": {
|
||||||
|
"type": "SQLite",
|
||||||
|
"SQLiteFile": "officeHours.db",
|
||||||
|
"mysqlUser": "officeHours",
|
||||||
|
"mysqlPassword": "",
|
||||||
|
"mysqlHost": "localhost",
|
||||||
|
"mysqlPort": 3306,
|
||||||
|
"mysqlDatabase": "officeHours"
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,14 +77,14 @@ func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Requ
|
||||||
errors = append(errors, "Die Stunde muss eine ganze Zahl sein.")
|
errors = append(errors, "Die Stunde muss eine ganze Zahl sein.")
|
||||||
}
|
}
|
||||||
if !(hour >= 8 && hour <= 17) {
|
if !(hour >= 8 && hour <= 17) {
|
||||||
errors = append(errors, fmt.Sprintf("Sprechstunden müssen zwischen 08:00 Uhr und 17:%d starten.", 60-models.MinuteGranularity))
|
errors = append(errors, fmt.Sprintf("Sprechstunden müssen zwischen 08:00 Uhr und 17:%d starten.", 60-b.config.Date.MinuteGranularity))
|
||||||
}
|
}
|
||||||
minute, err = strconv.Atoi(time[1])
|
minute, err = strconv.Atoi(time[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors = append(errors, "Die Minute muss eine ganze Zahl sein.")
|
errors = append(errors, "Die Minute muss eine ganze Zahl sein.")
|
||||||
}
|
}
|
||||||
if !(minute >= 0 && minute <= 60-models.MinuteGranularity && minute%models.MinuteGranularity == 0) {
|
if !(minute >= 0 && minute <= 60-b.config.Date.MinuteGranularity && minute%b.config.Date.MinuteGranularity == 0) {
|
||||||
errors = append(errors, fmt.Sprintf("Sprechstunden dürfen nur alle %d Minuten starten.", models.MinuteGranularity))
|
errors = append(errors, fmt.Sprintf("Sprechstunden dürfen nur alle %d Minuten starten.", b.config.Date.MinuteGranularity))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
date := models.Date{week, day, hour, minute}
|
date := models.Date{week, day, hour, minute}
|
||||||
|
@ -92,8 +92,8 @@ func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Requ
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors = append(errors, "Die Dauer muss eine ganze Zahl sein.")
|
errors = append(errors, "Die Dauer muss eine ganze Zahl sein.")
|
||||||
}
|
}
|
||||||
if !(duration >= models.MinuteGranularity && duration <= 120 && duration%models.MinuteGranularity == 0) {
|
if !(duration >= b.config.Date.MinuteGranularity && duration <= 120 && duration%b.config.Date.MinuteGranularity == 0) {
|
||||||
errors = append(errors, fmt.Sprintf("Sprechstunden müssen zwischen %d und 120 Minuten lang sein.", models.MinuteGranularity))
|
errors = append(errors, fmt.Sprintf("Sprechstunden müssen zwischen %d und 120 Minuten lang sein.", b.config.Date.MinuteGranularity))
|
||||||
}
|
}
|
||||||
|
|
||||||
roomname := req.FormValue("raumname")
|
roomname := req.FormValue("raumname")
|
||||||
|
@ -120,7 +120,7 @@ func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Requ
|
||||||
var data maskData = maskData{
|
var data maskData = maskData{
|
||||||
courses,
|
courses,
|
||||||
rooms,
|
rooms,
|
||||||
models.MinuteGranularity,
|
b.config.Date.MinuteGranularity,
|
||||||
courseid,
|
courseid,
|
||||||
roomid,
|
roomid,
|
||||||
date,
|
date,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import "sprechstundentool/models"
|
import (
|
||||||
|
"sprechstundentool/config"
|
||||||
|
"sprechstundentool/models"
|
||||||
|
)
|
||||||
|
|
||||||
// BaseHandler will hold everything that controller needs
|
// BaseHandler will hold everything that controller needs
|
||||||
type BaseHandler struct {
|
type BaseHandler struct {
|
||||||
|
@ -9,9 +12,15 @@ type BaseHandler struct {
|
||||||
courseRepo models.CourseRepository
|
courseRepo models.CourseRepository
|
||||||
tutorRepo models.TutorRepository
|
tutorRepo models.TutorRepository
|
||||||
requestRepo models.RequestRepository
|
requestRepo models.RequestRepository
|
||||||
|
config config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBaseHandler returns a new BaseHandler
|
// NewBaseHandler returns a new BaseHandler
|
||||||
func NewBaseHandler(roomRepo models.RoomRepository, officeHourRepo models.OfficeHourRepository, courseRepo models.CourseRepository, tutorRepo models.TutorRepository, requestRepo models.RequestRepository) *BaseHandler {
|
func NewBaseHandler(roomRepo models.RoomRepository,
|
||||||
return &BaseHandler{roomRepo, officeHourRepo, courseRepo, tutorRepo, requestRepo}
|
officeHourRepo models.OfficeHourRepository,
|
||||||
|
courseRepo models.CourseRepository,
|
||||||
|
tutorRepo models.TutorRepository,
|
||||||
|
requestRepo models.RequestRepository,
|
||||||
|
config config.Config) *BaseHandler {
|
||||||
|
return &BaseHandler{roomRepo, officeHourRepo, courseRepo, tutorRepo, requestRepo, config}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ func (b *BaseHandler) DeleteOfficeHourHandler(w http.ResponseWriter, req *http.R
|
||||||
Templates.ExecuteTemplate(w, "deleteSuccess.html", struct{}{})
|
Templates.ExecuteTemplate(w, "deleteSuccess.html", struct{}{})
|
||||||
} else {
|
} else {
|
||||||
officeHours, _ := b.officeHourRepo.GetAll(true)
|
officeHours, _ := b.officeHourRepo.GetAll(true)
|
||||||
timetable, slots := GetTimetable(officeHours)
|
timetable, slots := b.GetTimetable(officeHours)
|
||||||
b.writeTimetablePage(w, req, printTimetable(timetable, slots, true))
|
b.writeTimetablePage(w, req, b.printTimetable(timetable, slots, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@ func (b *BaseHandler) GetByRoomHandler(w http.ResponseWriter, req *http.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
officeHours, _ := b.officeHourRepo.FindByRoom(room, true)
|
officeHours, _ := b.officeHourRepo.FindByRoom(room, true)
|
||||||
timetable, slots := GetTimetable(officeHours)
|
timetable, slots := b.GetTimetable(officeHours)
|
||||||
b.writeTimetablePage(w, req, printTimetable(timetable, slots, false))
|
b.writeTimetablePage(w, req, b.printTimetable(timetable, slots, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseHandler) GetByCourseHandler(w http.ResponseWriter, req *http.Request) {
|
func (b *BaseHandler) GetByCourseHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -35,8 +35,8 @@ func (b *BaseHandler) GetByCourseHandler(w http.ResponseWriter, req *http.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
officeHours, _ := b.officeHourRepo.FindByCourse(course, true)
|
officeHours, _ := b.officeHourRepo.FindByCourse(course, true)
|
||||||
timetable, slots := GetTimetable(officeHours)
|
timetable, slots := b.GetTimetable(officeHours)
|
||||||
b.writeTimetablePage(w, req, printTimetable(timetable, slots, false))
|
b.writeTimetablePage(w, req, b.printTimetable(timetable, slots, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseHandler) writeTimetablePage(w http.ResponseWriter, req *http.Request, timetable template.HTML) {
|
func (b *BaseHandler) writeTimetablePage(w http.ResponseWriter, req *http.Request, timetable template.HTML) {
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"sprechstundentool/models"
|
"sprechstundentool/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetTimetable(officeHours []models.OfficeHour) (timetable map[models.Date]map[int]models.OfficeHour, slots []int) {
|
func (b *BaseHandler) GetTimetable(officeHours []models.OfficeHour) (timetable map[models.Date]map[int]models.OfficeHour, slots []int) {
|
||||||
var fullTimetable = make(map[models.Date]map[int]models.OfficeHour)
|
var fullTimetable = make(map[models.Date]map[int]models.OfficeHour)
|
||||||
for _, officeHour := range officeHours {
|
for _, officeHour := range officeHours {
|
||||||
var slot int = 0
|
var slot int = 0
|
||||||
for minute := 0; minute < officeHour.Duration; minute += models.MinuteGranularity { // find slot id
|
for minute := 0; minute < officeHour.Duration; minute += b.config.Date.MinuteGranularity { // find slot id
|
||||||
_, exists := fullTimetable[models.GetEndDate(officeHour.Date, minute, true)]
|
_, exists := fullTimetable[models.GetEndDate(officeHour.Date, minute, true)]
|
||||||
if exists {
|
if exists {
|
||||||
_, exists := fullTimetable[models.GetEndDate(officeHour.Date, minute, true)][slot]
|
_, exists := fullTimetable[models.GetEndDate(officeHour.Date, minute, true)][slot]
|
||||||
|
@ -25,7 +25,7 @@ func GetTimetable(officeHours []models.OfficeHour) (timetable map[models.Date]ma
|
||||||
fullTimetable[models.GetEndDate(officeHour.Date, minute, true)] = make(map[int]models.OfficeHour)
|
fullTimetable[models.GetEndDate(officeHour.Date, minute, true)] = make(map[int]models.OfficeHour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for minute := 0; minute < officeHour.Duration; minute += models.MinuteGranularity { // write officeHour id to timetable
|
for minute := 0; minute < officeHour.Duration; minute += b.config.Date.MinuteGranularity { // write officeHour id to timetable
|
||||||
fullTimetable[models.GetEndDate(officeHour.Date, minute, true)][slot] = officeHour
|
fullTimetable[models.GetEndDate(officeHour.Date, minute, true)][slot] = officeHour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,10 +47,10 @@ func GetTimetable(officeHours []models.OfficeHour) (timetable map[models.Date]ma
|
||||||
return fullTimetable, slots
|
return fullTimetable, slots
|
||||||
}
|
}
|
||||||
|
|
||||||
func printTimetable(timetable map[models.Date]map[int]models.OfficeHour, slots []int, deleteIcons bool) template.HTML {
|
func (b *BaseHandler) printTimetable(timetable map[models.Date]map[int]models.OfficeHour, slots []int, deleteIcons bool) template.HTML {
|
||||||
var tableBody string
|
var tableBody string
|
||||||
for hour := 8; hour < 19; hour += 1 {
|
for hour := 8; hour < 19; hour += 1 {
|
||||||
for minute := 0; minute < 60; minute += models.MinuteGranularity {
|
for minute := 0; minute < 60; minute += b.config.Date.MinuteGranularity {
|
||||||
tableBody += "<tr>"
|
tableBody += "<tr>"
|
||||||
if minute == 0 {
|
if minute == 0 {
|
||||||
tableBody += fmt.Sprintf("<td>%d Uhr</td>\n", hour)
|
tableBody += fmt.Sprintf("<td>%d Uhr</td>\n", hour)
|
||||||
|
@ -65,10 +65,10 @@ func printTimetable(timetable map[models.Date]map[int]models.OfficeHour, slots [
|
||||||
var continued bool = false // is this slot occupied by the same office hour the previous minute?
|
var continued bool = false // is this slot occupied by the same office hour the previous minute?
|
||||||
var predecessorExists bool
|
var predecessorExists bool
|
||||||
var predecessor models.OfficeHour
|
var predecessor models.OfficeHour
|
||||||
if hour > 0 && minute < models.MinuteGranularity {
|
if hour > 0 && minute < b.config.Date.MinuteGranularity {
|
||||||
predecessor, predecessorExists = timetable[models.Date{0, day, hour - 1, 60 - models.MinuteGranularity}][slot]
|
predecessor, predecessorExists = timetable[models.Date{0, day, hour - 1, 60 - b.config.Date.MinuteGranularity}][slot]
|
||||||
} else {
|
} else {
|
||||||
predecessor, predecessorExists = timetable[models.Date{0, day, hour, minute - models.MinuteGranularity}][slot]
|
predecessor, predecessorExists = timetable[models.Date{0, day, hour, minute - b.config.Date.MinuteGranularity}][slot]
|
||||||
}
|
}
|
||||||
if predecessorExists {
|
if predecessorExists {
|
||||||
continued = (predecessor == current)
|
continued = (predecessor == current)
|
||||||
|
@ -83,7 +83,7 @@ func printTimetable(timetable map[models.Date]map[int]models.OfficeHour, slots [
|
||||||
OfficeHour models.OfficeHour
|
OfficeHour models.OfficeHour
|
||||||
MinuteGranularity int
|
MinuteGranularity int
|
||||||
DeleteIcons bool
|
DeleteIcons bool
|
||||||
}{current, models.MinuteGranularity, deleteIcons}
|
}{current, b.config.Date.MinuteGranularity, deleteIcons}
|
||||||
Templates.ExecuteTemplate(&celldata, "td.html", data)
|
Templates.ExecuteTemplate(&celldata, "td.html", data)
|
||||||
tableBody += celldata.String()
|
tableBody += celldata.String()
|
||||||
}
|
}
|
||||||
|
|
40
main.go
40
main.go
|
@ -1,42 +1,47 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"sprechstundentool/config"
|
||||||
"sprechstundentool/controllers"
|
"sprechstundentool/controllers"
|
||||||
"sprechstundentool/repositories"
|
"sprechstundentool/repositories"
|
||||||
"sprechstundentool/sqldb"
|
"sprechstundentool/sqldb"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
logwriter, e := syslog.New(syslog.LOG_ERR, "sprechstunden")
|
logwriter, e := syslog.New(syslog.LOG_ERR, "office hours")
|
||||||
if e == nil {
|
if e == nil {
|
||||||
log.SetOutput(logwriter)
|
log.SetOutput(logwriter)
|
||||||
}
|
}
|
||||||
|
configFile := flag.String(
|
||||||
var db *sql.DB
|
"config",
|
||||||
switch os.Getenv("ohtDbType") {
|
"config/config.json",
|
||||||
case "mysql":
|
"File path to the configuration file")
|
||||||
db = sqldb.ConnectMysql(os.Getenv("ohtDbMysqlConnection"))
|
flag.Parse()
|
||||||
default:
|
if *configFile == "" {
|
||||||
if os.Getenv("ohtDbFile") != "" && !strings.Contains(os.Getenv("ohtDbFile"), "/") {
|
flag.Usage()
|
||||||
db = sqldb.ConnectSQLite(os.Getenv("ohtDbFile"))
|
os.Exit(1)
|
||||||
} else {
|
|
||||||
db = sqldb.ConnectSQLite("sprechstunden.db")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var conf config.Config
|
||||||
|
err := config.ReadConfigFile(*configFile, &conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%s: %s", "Reading JSON config file into config structure", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
db := sqldb.Connect(conf)
|
||||||
// Create repos
|
// Create repos
|
||||||
roomRepo := repositories.NewRoomRepo(db)
|
roomRepo := repositories.NewRoomRepo(db)
|
||||||
courseRepo := repositories.NewCourseRepo(db)
|
courseRepo := repositories.NewCourseRepo(db)
|
||||||
tutorRepo := repositories.NewTutorRepo(db)
|
tutorRepo := repositories.NewTutorRepo(db)
|
||||||
officeHourRepo := repositories.NewOfficeHourRepo(db, roomRepo, tutorRepo, courseRepo)
|
officeHourRepo := repositories.NewOfficeHourRepo(db, roomRepo, tutorRepo, courseRepo)
|
||||||
requestRepo := repositories.NewRequestRepo(db, officeHourRepo)
|
requestRepo := repositories.NewRequestRepo(db, officeHourRepo, conf)
|
||||||
h := controllers.NewBaseHandler(roomRepo, officeHourRepo, courseRepo, tutorRepo, requestRepo)
|
h := controllers.NewBaseHandler(roomRepo, officeHourRepo, courseRepo, tutorRepo, requestRepo, conf)
|
||||||
|
|
||||||
http.HandleFunc("/getByRoom", h.GetByRoomHandler)
|
http.HandleFunc("/getByRoom", h.GetByRoomHandler)
|
||||||
http.HandleFunc("/getByCourse", h.GetByCourseHandler)
|
http.HandleFunc("/getByCourse", h.GetByCourseHandler)
|
||||||
|
@ -45,5 +50,6 @@ func main() {
|
||||||
http.HandleFunc("/deleteOfficeHour", h.DeleteOfficeHourHandler)
|
http.HandleFunc("/deleteOfficeHour", h.DeleteOfficeHourHandler)
|
||||||
http.HandleFunc("/", h.RootHandler)
|
http.HandleFunc("/", h.RootHandler)
|
||||||
|
|
||||||
http.ListenAndServe(":8080", nil)
|
err = http.ListenAndServe(fmt.Sprintf("%s:%d", conf.Server.ListenAddress, conf.Server.ListenPort), nil)
|
||||||
|
fmt.Println(err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ type Date struct {
|
||||||
Minute int
|
Minute int
|
||||||
}
|
}
|
||||||
|
|
||||||
const MinuteGranularity int = 5
|
|
||||||
|
|
||||||
func DayName(day int) string {
|
func DayName(day int) string {
|
||||||
switch day {
|
switch day {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
@ -11,8 +11,6 @@ type Request struct {
|
||||||
const RequestActivate int = 1
|
const RequestActivate int = 1
|
||||||
const RequestDelete int = 2
|
const RequestDelete int = 2
|
||||||
|
|
||||||
const SecretLength int = 15
|
|
||||||
|
|
||||||
type RequestRepository interface {
|
type RequestRepository interface {
|
||||||
Add(officeHour OfficeHour, action int) (int, error)
|
Add(officeHour OfficeHour, action int) (int, error)
|
||||||
FindBySecret(secret string) (Request, error)
|
FindBySecret(secret string) (Request, error)
|
||||||
|
|
|
@ -114,7 +114,10 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (id int, err error) {
|
||||||
|
|
||||||
func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error {
|
func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error {
|
||||||
_, err := r.db.Exec("DELETE FROM officeHour WHERE id=?", officeHour.Id)
|
_, err := r.db.Exec("DELETE FROM officeHour WHERE id=?", officeHour.Id)
|
||||||
|
if err != nil {
|
||||||
return fmt.Errorf("Error deleting officeHour from database: %s", err.Error())
|
return fmt.Errorf("Error deleting officeHour from database: %s", err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) getFromRow(row *sql.Row) (models.OfficeHour, error) {
|
func (r *OfficeHourRepo) getFromRow(row *sql.Row) (models.OfficeHour, error) {
|
||||||
|
|
|
@ -5,8 +5,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
|
"sprechstundentool/config"
|
||||||
"sprechstundentool/controllers"
|
"sprechstundentool/controllers"
|
||||||
"sprechstundentool/models"
|
"sprechstundentool/models"
|
||||||
)
|
)
|
||||||
|
@ -14,12 +17,14 @@ import (
|
||||||
type RequestRepo struct {
|
type RequestRepo struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
officeHourRepo models.OfficeHourRepository
|
officeHourRepo models.OfficeHourRepository
|
||||||
|
config config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRequestRepo(db *sql.DB, officeHourRepo models.OfficeHourRepository) *RequestRepo {
|
func NewRequestRepo(db *sql.DB, officeHourRepo models.OfficeHourRepository, config config.Config) *RequestRepo {
|
||||||
return &RequestRepo{
|
return &RequestRepo{
|
||||||
db: db,
|
db: db,
|
||||||
officeHourRepo: officeHourRepo,
|
officeHourRepo: officeHourRepo,
|
||||||
|
config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +73,8 @@ func (r *RequestRepo) Add(officeHour models.OfficeHour, action int) (int, error)
|
||||||
* but don't insert new request into database.
|
* but don't insert new request into database.
|
||||||
*/
|
*/
|
||||||
for _, request := range existents {
|
for _, request := range existents {
|
||||||
if request.Action == action { // already covered by selection && request.OfficeHour == officeHour {
|
if request.Action == action { // already covered by selection: && request.OfficeHour == officeHour {
|
||||||
return request.Id, sendConfirmationMail(request)
|
return request.Id, r.sendConfirmationMail(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
secret, err := r.newSecret()
|
secret, err := r.newSecret()
|
||||||
|
@ -85,7 +90,7 @@ func (r *RequestRepo) Add(officeHour models.OfficeHour, action int) (int, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return request.Id, err
|
return request.Id, err
|
||||||
}
|
}
|
||||||
return request.Id, sendConfirmationMail(request)
|
return request.Id, r.sendConfirmationMail(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RequestRepo) Execute(request models.Request) error {
|
func (r *RequestRepo) Execute(request models.Request) error {
|
||||||
|
@ -104,29 +109,42 @@ func (r *RequestRepo) Execute(request models.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RequestRepo) newSecret() (string, error) {
|
func (r *RequestRepo) newSecret() (string, error) {
|
||||||
secret := randomString(models.SecretLength)
|
var err error
|
||||||
|
var secret string
|
||||||
_, err := r.FindBySecret(secret)
|
// find unused secret
|
||||||
|
for err != sql.ErrNoRows {
|
||||||
|
secret = randomString(r.config.Request.SecretLength)
|
||||||
|
_, err = r.FindBySecret(secret)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// find unused secret
|
|
||||||
for err != sql.ErrNoRows {
|
|
||||||
secret = randomString(models.SecretLength)
|
|
||||||
_, err = r.FindBySecret(secret)
|
|
||||||
}
|
}
|
||||||
return secret, nil
|
return secret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendConfirmationMail(request models.Request) error {
|
func (r *RequestRepo) sendConfirmationMail(request models.Request) error {
|
||||||
to := []string{request.OfficeHour.Tutor.Email}
|
|
||||||
var message bytes.Buffer
|
var message bytes.Buffer
|
||||||
err := controllers.Templates.ExecuteTemplate(&message, "confirmationMail", request)
|
var data = struct {
|
||||||
|
Config config.Config
|
||||||
|
Request models.Request
|
||||||
|
}{r.config, request}
|
||||||
|
err := controllers.Templates.ExecuteTemplate(&message, "confirmationMail", data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Error parsing confirmation Mail: %s", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = smtp.SendMail("192.168.0.24:25", nil, "Mathebau Sprechstunden <sprechstunden@mathebau.de>", to, message.Bytes())
|
switch r.config.Mailer.Type {
|
||||||
return err
|
case "Stdout":
|
||||||
|
fmt.Println(message.String())
|
||||||
|
case "Smtp":
|
||||||
|
to := []string{request.OfficeHour.Tutor.Email}
|
||||||
|
var auth smtp.Auth
|
||||||
|
if r.config.Mailer.SmtpUseAuth {
|
||||||
|
auth = smtp.PlainAuth(r.config.Mailer.SmtpIdentity, r.config.Mailer.FromAddress, r.config.Mailer.SmtpPassword, r.config.Mailer.SmtpHost)
|
||||||
|
}
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomString(n int) string {
|
func randomString(n int) string {
|
||||||
|
|
|
@ -2,13 +2,31 @@ package sqldb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"sprechstundentool/config"
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConnectSQLite(file string) *sql.DB {
|
func Connect(config config.Config) *sql.DB {
|
||||||
|
switch config.SQL.Type {
|
||||||
|
case "SQLite":
|
||||||
|
return connectSQLite(config.SQL.SQLiteFile)
|
||||||
|
case "Mysql":
|
||||||
|
return connectMysql(config.SQL.MysqlUser,
|
||||||
|
config.SQL.MysqlPassword,
|
||||||
|
config.SQL.MysqlHost,
|
||||||
|
config.SQL.MysqlPort,
|
||||||
|
config.SQL.MysqlDatabase)
|
||||||
|
default:
|
||||||
|
log.Fatal("Type of database not recognised.")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectSQLite(file string) *sql.DB {
|
||||||
db, err := sql.Open("sqlite3", file)
|
db, err := sql.Open("sqlite3", file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
@ -17,16 +35,16 @@ func ConnectSQLite(file string) *sql.DB {
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectMysql(connection string) *sql.DB {
|
func connectMysql(user string, password string, address string, port int, database string) *sql.DB {
|
||||||
db, err := sql.Open("mysql", connection)
|
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", user, password, address, port, database))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatalf("Error connecting to database: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Ping()
|
err = db.Ping()
|
||||||
// handle error
|
// handle error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatalf("Error pinging database: %s", err)
|
||||||
}
|
}
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
From: Mathebau Sprechstunden <sprechstunden@mathebau.de>
|
From: {{.Config.Mailer.FromName}}
|
||||||
To: {{.OfficeHour.Tutor.Email}}
|
To: {{.Request.OfficeHour.Tutor.Email}}
|
||||||
Subject: Sprechstunde {{if eq .Action 1}}anlegen{{end}}{{if eq .Action 2}}löschen{{end}}
|
Subject: Sprechstunde {{if eq .Request.Action 1}}anlegen{{end}}{{if eq .Request.Action 2}}löschen{{end}}
|
||||||
|
|
||||||
Hallo {{.OfficeHour.Tutor.Name}},
|
Hallo {{.Request.OfficeHour.Tutor.Name}},
|
||||||
|
|
||||||
mit deiner Emailadresse soll eine Sprechstunde mit folgenden Daten {{if eq .Action 1}}angelegt werden{{end}}{{if eq .Action 2}}gelöscht werden{{end}}:
|
mit deiner Emailadresse soll eine Sprechstunde mit folgenden Daten {{if eq .Request.Action 1}}angelegt werden{{end}}{{if eq .Request.Action 2}}gelöscht werden{{end}}:
|
||||||
|
|
||||||
{{.OfficeHour.Course.Name}}
|
{{.Request.OfficeHour.Course.Name}}
|
||||||
{{DayName .OfficeHour.Date.Day}}
|
{{DayName .Request.OfficeHour.Date.Day}}
|
||||||
{{printf "%02d" .OfficeHour.Date.Hour}}:{{printf "%02d" .OfficeHour.Date.Minute}} Uhr bis {{printf "%02d" .OfficeHour.EndDate.Hour}}:{{printf "%02d" .OfficeHour.EndDate.Minute}} Uhr
|
{{printf "%02d" .Request.OfficeHour.Date.Hour}}:{{printf "%02d" .Request.OfficeHour.Date.Minute}} Uhr bis {{printf "%02d" .Request.OfficeHour.EndDate.Hour}}:{{printf "%02d" .Request.OfficeHour.EndDate.Minute}} Uhr
|
||||||
{{.OfficeHour.Tutor.Name}}
|
{{.Request.OfficeHour.Tutor.Name}}
|
||||||
{{.OfficeHour.Room.Name}}
|
{{.Request.OfficeHour.Room.Name}}
|
||||||
|
|
||||||
Falls dies richtig ist, so bestätige die Sprechstunde durch Abrufen der folgenden URL:
|
Falls dies richtig ist, so bestätige die Sprechstunde durch Abrufen der folgenden URL:
|
||||||
https://sprechstunden.mathebau.de/confirmRequest?code={{.Secret}}
|
{{.Config.Server.Protocol}}://{{.Config.Server.Domain}}/confirmRequest?code={{.Request.Secret}}
|
||||||
Solltest du diese Email nicht erwartet haben, so kannst du sie einfach ignorieren.
|
Solltest du diese Email nicht erwartet haben, so kannst du sie einfach ignorieren.
|
||||||
|
|
||||||
Deine Fachschaft Mathematik
|
Deine Fachschaft Mathematik
|
Loading…
Reference in a new issue