Compare commits
1 commit
main
...
configSupp
Author | SHA1 | Date | |
---|---|---|---|
83bc490740 |
35 changed files with 226 additions and 331 deletions
|
@ -7,8 +7,7 @@ e.g. by executing `go version`.
|
|||
Initialize the database. For developing, we recommend using sqlite:
|
||||
|
||||
user@host:path/to/repo$ sqlite3 officeHours.db -init officeHoursSQLite.sql
|
||||
sqlite> .read dummydata/rooms.sql
|
||||
sqlite> .read dummydata/summerCourses.sql
|
||||
sqlite> .read dummydatasqlite.sql
|
||||
|
||||
Now start the development webserver, note that you need to manually
|
||||
restart it to code changes take effect.
|
||||
|
|
|
@ -46,6 +46,7 @@ type Config struct {
|
|||
SmtpUseAuth bool // Set whether to use authentication on the smarthosthost
|
||||
SmtpIdentity string // Smarthost username
|
||||
SmtpPassword string // Smarthost password
|
||||
SupportMail string // separate mail address for support contact
|
||||
}
|
||||
SQL struct {
|
||||
Type string // Can be "SQLite" or "Mysql"
|
||||
|
@ -68,13 +69,13 @@ 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)
|
||||
err = fmt.Errorf("Error reading config file: %w", err)
|
||||
log.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(configData, conf)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing config file as json: %w", err)
|
||||
err = fmt.Errorf("Error parsing config file as json: %w", err)
|
||||
log.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
|
@ -85,66 +86,75 @@ func ReadConfigFile(filename string, conf *Config) error {
|
|||
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)
|
||||
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)
|
||||
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)
|
||||
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.Date.EarliestStartTime.Hour >= 0 && conf.Date.EarliestStartTime.Hour <= 23) {
|
||||
err = fmt.Errorf("validating config: Earliest start time hour must be between 0 and 23, but is %d.", conf.Date.EarliestStartTime.Hour)
|
||||
err = fmt.Errorf("Validating config: Earliest start time hour must be between 0 and 23, but is %d.", conf.Date.EarliestStartTime.Hour)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
if !(conf.Date.EarliestStartTime.Minute >= 0 && conf.Date.EarliestStartTime.Minute <= 60) {
|
||||
err = fmt.Errorf("validating config: Earliest start time minute must be between 0 and 60, but is %d.", conf.Date.EarliestStartTime.Minute)
|
||||
err = fmt.Errorf("Validating config: Earliest start time minute must be between 0 and 60, but is %d.", conf.Date.EarliestStartTime.Minute)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
if !(conf.Date.MaxDuration >= conf.Date.MinuteGranularity && conf.Date.MaxDuration <= 4*60) {
|
||||
err = fmt.Errorf("validating config: Maximum duration must be between %d minute and 4 hours, but is %d.", conf.Date.MinuteGranularity, conf.Date.MaxDuration)
|
||||
err = fmt.Errorf("Validating config: Maximum duration must be between %d minute and 4 hours, but is %d.", conf.Date.MinuteGranularity, conf.Date.MaxDuration)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
if !(conf.Date.LatestStartTime.Hour >= 0 && conf.Date.LatestStartTime.Hour <= 23) {
|
||||
err = fmt.Errorf("validating config: Latest start time hour must be between 0 and 23, but is %d.", conf.Date.LatestStartTime.Hour)
|
||||
err = fmt.Errorf("Validating config: Latest start time hour must be between 0 and 23, but is %d.", conf.Date.LatestStartTime.Hour)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
if !(conf.Date.LatestStartTime.Minute >= 0 && conf.Date.LatestStartTime.Minute <= 60) {
|
||||
err = fmt.Errorf("validating config: Latest start time minute must be between 0 and 60, but is %d.", conf.Date.LatestStartTime.Minute)
|
||||
err = fmt.Errorf("Validating config: Latest start time minute must be between 0 and 60, but is %d.", conf.Date.LatestStartTime.Minute)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
if !(conf.Date.EarliestStartTime.Hour < conf.Date.LatestStartTime.Hour || (conf.Date.EarliestStartTime.Hour == conf.Date.LatestStartTime.Hour && conf.Date.EarliestStartTime.Minute < conf.Date.LatestStartTime.Minute)) {
|
||||
err = fmt.Errorf("validating config: Latest start time minute must be after earliest start time.")
|
||||
err = fmt.Errorf("Validating config: Latest start time minute must be after earliest start time.")
|
||||
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)
|
||||
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)
|
||||
err = fmt.Errorf("Validating config: Mailer type must be 'Stdout' or 'Smtp', but is '%s'.", conf.Mailer.Type)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
mailFromAddress, mailFromAddressErr := mail.ParseAddress(conf.Mailer.FromAddress)
|
||||
if !(mailFromAddressErr == nil) {
|
||||
err = fmt.Errorf("validating config: Mail FromAddress could not be parsed (%w)", mailFromAddressErr)
|
||||
err = fmt.Errorf("Validating config: Mail FromAddress could not be parsed (%w)", mailFromAddressErr)
|
||||
log.Println(err)
|
||||
} else {
|
||||
if !(mailFromAddress.Name == "") {
|
||||
err = fmt.Errorf("validating config: Mail FromAddress must not contain a name value, but has '%s'", mailFromAddress.Name)
|
||||
err = fmt.Errorf("Validating config: Mail FromAddress must not contain a name value, but has '%s'", mailFromAddress.Name)
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
_, mailFromNameErr := mail.ParseAddress(string(conf.Mailer.FromName))
|
||||
if !(mailFromNameErr == nil) {
|
||||
err = fmt.Errorf("validating config: Mail FromName could not be parsed (%w)", mailFromNameErr)
|
||||
err = fmt.Errorf("Validating config: Mail FromName could not be parsed (%w)", mailFromNameErr)
|
||||
log.Println(err)
|
||||
}
|
||||
supportMail, mailSupportMailErr := mail.ParseAddress(string(conf.Mailer.SupportMail))
|
||||
if !(mailSupportMailErr == nil) {
|
||||
err = fmt.Errorf("Validating config: SupportMail could not be parsed (%w)", mailSupportMailErr)
|
||||
log.Println(err)
|
||||
}
|
||||
if !(supportMail.Name == "") {
|
||||
err = fmt.Errorf("Validating config: SupportMail must not contain a name")
|
||||
log.Println(err)
|
||||
}
|
||||
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)
|
||||
err = fmt.Errorf("Validating config: SQL type must be 'SQLite' or 'Mysql', but is '%s'.", conf.SQL.Type)
|
||||
log.Println(err.Error())
|
||||
}
|
||||
return err
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
"smtpPort": 25,
|
||||
"smtpUseAuth": false,
|
||||
"smtpIdentity": "",
|
||||
"smtpPassword": ""
|
||||
"smtpPassword": "",
|
||||
"supportMail": "officeHoursSupport@localhost"
|
||||
},
|
||||
"SQL": {
|
||||
"type": "SQLite",
|
||||
|
|
|
@ -73,8 +73,8 @@ func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Requ
|
|||
if err != nil {
|
||||
errors = append(errors, "Die Vorlesungswoche muss eine ganze Zahl sein.")
|
||||
}
|
||||
if !(week >= 0 && week <= 5) {
|
||||
errors = append(errors, "Bitte wähle eine der vorgegebenen Optionen für Vorlesungswochen.")
|
||||
if !(week >= 0 && week <= 2) {
|
||||
errors = append(errors, "Sprechstunden müssen jede, jede gerade oder jede ungerade Vorlesungswoche stattfinden.")
|
||||
}
|
||||
day, err := strconv.Atoi(req.FormValue("tag"))
|
||||
if err != nil {
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
INSERT INTO `room` (name, max_occupy) VALUES
|
||||
('S2|15-333', 1),
|
||||
('S2|15-336', 2),
|
||||
('S2|15-345', 2),
|
||||
('S2|15-415', 1),
|
||||
('S2|15-444', 0),
|
||||
('Sonstige', 1024);
|
|
@ -1,54 +0,0 @@
|
|||
INSERT INTO `course` (name) VALUES
|
||||
('Algebraic Geometry'),
|
||||
('Algorithmic Discrete Mathematics'),
|
||||
('Analysis II'),
|
||||
('Analysis II (engl.)'),
|
||||
('Aussagen- und Prädikatenlogik'),
|
||||
('Automorphic Forms'),
|
||||
('Basic Applied Proof Theory'),
|
||||
('Computational Complexity'),
|
||||
('Data Assimilation for Fluid Dynamics'),
|
||||
('Deep Learning Lab'),
|
||||
('Discrete Optimization'),
|
||||
('Einführung in die Algebra'),
|
||||
('Einführung in die Finanzmathematik'),
|
||||
('Einführung in die mathematische Modellierung'),
|
||||
('Einführung in die Programmierung'),
|
||||
('Einführung in die Stochastik'),
|
||||
('Elementare PDE'),
|
||||
('Elementare Zahlentheorie'),
|
||||
('Graph Theory'),
|
||||
('Höhere Mathematik II'),
|
||||
('Integrationstheorie'),
|
||||
('LA für Physik und Lehramt'),
|
||||
('Linear Algebra II (engl.)'),
|
||||
('Lineare Algebra II'),
|
||||
('Logics of Knowledge and Information'),
|
||||
('Logik und Grundlagen'),
|
||||
('Machine Learning for Fluid Dynamics'),
|
||||
('Mathe für Chemiker'),
|
||||
('Mathe II für Informatik'),
|
||||
('Mathe II für Bauwesen'),
|
||||
('Mathe II für ET'),
|
||||
('Mathe II für Maschinenbau'),
|
||||
('Mathe IV für Maschinenbau'),
|
||||
('Mathe IV (ET) / Mathe III (Inf) / Praktische Mathe (MEd)'),
|
||||
('Mathe für MINT'),
|
||||
('Mathe & Statistik für Biologen'),
|
||||
('Mathematical Modelling of Fluid Interfaces'),
|
||||
('Mathematical Statistics'),
|
||||
('Mathematik im Kontext'),
|
||||
('Model Theory'),
|
||||
('Nonsmooth Optimization'),
|
||||
('Nichtlineare Optimierung'),
|
||||
('Numerics of Fluid Dynamics (incompressible)'),
|
||||
('Numerics of Hyperbolic Equations'),
|
||||
('Numerische Lineare Algebra'),
|
||||
('PDE II'),
|
||||
('Riemannsche Flächen'),
|
||||
('Seitenkanalangriffe gegen IT-Systeme'),
|
||||
('Sobolev Spaces'),
|
||||
('Spin Systems and Statistical Mechanics'),
|
||||
('Topologie'),
|
||||
('Variations of geometric energies'),
|
||||
('Vertrauenspersonen');
|
|
@ -1,41 +0,0 @@
|
|||
INSERT INTO `course` (name) VALUES
|
||||
('Algebra'),
|
||||
('Analysis I'),
|
||||
('Analysis I (engl.)'),
|
||||
('Applied Proof Theory'),
|
||||
('Automaten, Formale Sprachen und Entscheidbarkeit'),
|
||||
('Complex Analysis'),
|
||||
('Differentialgeometrie'),
|
||||
('Einführung in die Numerische Mathematik'),
|
||||
('Einführung in die Optimierung'),
|
||||
('Einführung in die Programmierung'),
|
||||
('Funktionalanalysis'),
|
||||
('Geometrie für Lehramt'),
|
||||
('Gewöhnliche Differentialgleichungen'),
|
||||
('Höhere Mathematik I'),
|
||||
('Introduction to mathematical logic'),
|
||||
('LA für Physik und Lehramt'),
|
||||
('Linear Algebra I (engl.)'),
|
||||
('Lineare Algebra I'),
|
||||
('Mathe für Chemiker'),
|
||||
('Mathe I für Informatik'),
|
||||
('Mathe I für Maschinenbau'),
|
||||
('Mathe I für Bau'),
|
||||
('Mathe I für ET'),
|
||||
('Mathe III für Maschinenbau'),
|
||||
('Mathe III für Bau'),
|
||||
('Mathe III ET'),
|
||||
('Mathe IV für Maschinenbau'),
|
||||
('Mathe IV (ET) / Mathe III (Inf) / Praktische Mathe (MEd)'),
|
||||
('Mathe für MINT'),
|
||||
('Mathe & Statistik für Biologen'),
|
||||
('Mathematik als gemeinsame Sprache der Naturwissenschaften'),
|
||||
('Numerik gewöhnlicher Differentialgleichungen'),
|
||||
('Numerische Mathe für MB (IV)'),
|
||||
('Parabolische PDEs'),
|
||||
('Partial Differential Equations'),
|
||||
('Probability Theory'),
|
||||
('Statistik I für Humanwissenschaftler'),
|
||||
('Statistik I für WI'),
|
||||
('Vertrauenspersonen'),
|
||||
('Wahrscheinlichkeitstheorie');
|
91
dummydatasqlite.sql
Normal file
91
dummydatasqlite.sql
Normal file
|
@ -0,0 +1,91 @@
|
|||
INSERT INTO `room` (name, max_occupy) VALUES
|
||||
('S2|15-333', 1),
|
||||
('S2|15-336', 2),
|
||||
('S2|15-345', 2),
|
||||
('S2|15-415', 1),
|
||||
('S2|15-444', 1),
|
||||
('Sonstige', 1024);
|
||||
INSERT INTO `course` (name) VALUES
|
||||
('Algebra'),
|
||||
('Algebraische Geometrie'),
|
||||
('Algebraische Kurven'),
|
||||
('Algebraische Topologie'),
|
||||
('Algorithmic Discrete Mathematics'),
|
||||
('Analysis I (engl.)'),
|
||||
('Analysis I'),
|
||||
('Analysis II (engl.)'),
|
||||
('Analysis II'),
|
||||
('Applied Proof Theory'),
|
||||
('Aussagen- und Prädikatenlogik'),
|
||||
('Automaten, Formale Sprachen und Entscheidbarkeit'),
|
||||
('Banach- und C*-Algebren'),
|
||||
('Classical and Non-Classical Model Theory'),
|
||||
('Complex Analysis'),
|
||||
('Darstellende Geometrie'),
|
||||
('Darstellungstheorie'),
|
||||
('Differentialgeometrie'),
|
||||
('Differentialgeometrie für VI'),
|
||||
('Diskrete Mathematik'),
|
||||
('Diskrete Optimierung'),
|
||||
('Einführung in die Algebra'),
|
||||
('Einführung in die Finanzmathematik'),
|
||||
('Einführung in die Numerische Mathematik'),
|
||||
('Einführung in die Optimierung'),
|
||||
('Einführung in die Programmierung'),
|
||||
('Einführung in die Stochastik'),
|
||||
('Einführung in die mathematische Modellierung'),
|
||||
('Elementare PDE'),
|
||||
('Elementare Zahlentheorie'),
|
||||
('Funktionalanalysis'),
|
||||
('Funktionalanalysis II'),
|
||||
('Geometrie für Lehramt'),
|
||||
('Gewöhnliche Differentialgleichungen'),
|
||||
('Höhere Mathematik I'),
|
||||
('Höhere Mathematik II'),
|
||||
('Integrationstheorie'),
|
||||
('Introduction to mathematical logic'),
|
||||
('Kurvenschätzung'),
|
||||
('LA für Physik und Lehramt'),
|
||||
('Lebensversicherungsmathematik'),
|
||||
('Linear Algebra I (engl.)'),
|
||||
('Lineare Algebra I'),
|
||||
('Linear Algebra II (engl.)'),
|
||||
('Lineare Algebra II'),
|
||||
('Logics of Knowledge and Information'),
|
||||
('Manifolds'),
|
||||
('Mathe für Chemiker'),
|
||||
('Mathe I für Informatik'),
|
||||
('Mathe I für Maschinenbau'),
|
||||
('Mathe I für Bau'),
|
||||
('Mathe I für ET'),
|
||||
('Mathe II für Informatik'),
|
||||
('Mathe II für Bauwesen'),
|
||||
('Mathe II für ET'),
|
||||
('Mathe II für Maschinenbau'),
|
||||
('Mathe III für Maschinenbau'),
|
||||
('Mathe III für Bau'),
|
||||
('Mathe III ET'),
|
||||
('Mathe IV für Maschinenbau'),
|
||||
('Mathe IV (ET) / Mathe III (Inf) / Praktische Mathe (MEd)'),
|
||||
('Mathe für MINT'),
|
||||
('Mathe & Statistik für Biologen'),
|
||||
('Mathematik als gemeinsame Sprache der Naturwissenschaften'),
|
||||
('Mathematik im Kontext'),
|
||||
('Mathematische Grundlagen der Quantenmechanik'),
|
||||
('Mathematische Statistik'),
|
||||
('Nichtlineare Optimierung'),
|
||||
('Numerik gewöhnlicher Differentialgleichungen'),
|
||||
('Numerische Lineare Algebra'),
|
||||
('Numerische Mathe für MB (IV)'),
|
||||
('Parabolische PDEs'),
|
||||
('Partial Differential Equations I'),
|
||||
('Probability Theory'),
|
||||
('Riemannsche Flächen'),
|
||||
('Schadenversicherungsmathematik'),
|
||||
('Sobolev Spaces'),
|
||||
('Spieltheorie'),
|
||||
('Statistik I für Humanwissenschaftler'),
|
||||
('Statistik I für WI'),
|
||||
('Stochastische Prozesse I'),
|
||||
('Topologie'),
|
||||
('Wahrscheinlichkeitstheorie');
|
11
go.mod
11
go.mod
|
@ -2,13 +2,6 @@ module officeHours
|
|||
|
||||
go 1.18
|
||||
|
||||
require github.com/mattn/go-sqlite3 v1.14.24
|
||||
require github.com/mattn/go-sqlite3 v1.14.19
|
||||
|
||||
require github.com/go-sql-driver/mysql v1.8.1
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/wneessen/go-mail v0.6.2 // indirect
|
||||
golang.org/x/crypto v0.33.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
)
|
||||
require github.com/go-sql-driver/mysql v1.7.1
|
||||
|
|
80
go.sum
80
go.sum
|
@ -1,76 +1,4 @@
|
|||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/wneessen/go-mail v0.6.2 h1:c6V7c8D2mz868z9WJ+8zDKtUyLfZ1++uAZmo2GRFji8=
|
||||
github.com/wneessen/go-mail v0.6.2/go.mod h1:L/PYjPK3/2ZlNb2/FjEBIn9n1rUWjW+Toy531oVmeb4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
|
||||
github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
type Date struct {
|
||||
Week int // Set whether the date is all weeks (0), weeks with exercise session (1) or weeks without exercise session (2), even weeks (3), odd weeks (4) or other (5).
|
||||
Week int // Set whether the date is all weeks (0), odd weeks (1) or even weeks (2).
|
||||
Day int
|
||||
Hour int
|
||||
Minute int
|
||||
|
|
|
@ -30,7 +30,7 @@ func (r *CourseRepo) FindById(id int) (models.Course, error) {
|
|||
func (r *CourseRepo) GetAll() ([]models.Course, error) {
|
||||
rows, err := r.db.Query("SELECT * FROM course ORDER BY name ASC")
|
||||
if err != nil {
|
||||
log.Printf("error getting all courses: %s", err.Error())
|
||||
log.Printf("Error getting all courses: %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
@ -56,9 +56,9 @@ func (r *CourseRepo) getFromRows(rows *sql.Rows) ([]models.Course, error) {
|
|||
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)
|
||||
err = fmt.Errorf("Error getting course row: %w", err)
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
log.Print(err.Error())
|
||||
log.Printf(err.Error())
|
||||
}
|
||||
return models.Course{}, err
|
||||
}
|
||||
|
|
|
@ -37,7 +37,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)
|
||||
err = fmt.Errorf("Error getting all officeHours from database: %w", err)
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func (r *OfficeHourRepo) FindByCourse(course models.Course, activeOnly bool) ([]
|
|||
}
|
||||
defer rows.Close()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error getting officeHours by course from database: %w", err)
|
||||
err = fmt.Errorf("Error getting officeHours by course from database: %w", err)
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
|
@ -75,7 +75,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)
|
||||
err = fmt.Errorf("Error getting officeHours by room from database: %w", err)
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (int, error) {
|
|||
}
|
||||
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)
|
||||
err = fmt.Errorf("Newly added tutor not found: %w", err)
|
||||
log.Println(err.Error())
|
||||
return 0, err
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (int, error) {
|
|||
}
|
||||
id, lastInsertIdErr := sqlResult.LastInsertId()
|
||||
if lastInsertIdErr != nil {
|
||||
log.Printf("error getting Id for new tutor: %s", lastInsertIdErr.Error())
|
||||
log.Printf("Error getting Id for new tutor: %s", lastInsertIdErr.Error())
|
||||
}
|
||||
return int(id), err
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (int, error) {
|
|||
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)
|
||||
err = fmt.Errorf("Error deleting officeHour from database: %w", err)
|
||||
log.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
|
@ -160,26 +160,26 @@ 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, &officeHour.RoomName, &courseId, &week, &officeHour.Info, &officeHour.Active, &officeHour.Duration)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error getting single officeHour row from database: %w", err)
|
||||
err = fmt.Errorf("Error getting single officeHour row from database: %w", err)
|
||||
log.Println(err.Error())
|
||||
return models.OfficeHour{}, err
|
||||
}
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
err = fmt.Errorf("Error finding course by id %d for office hour: %w", courseId, err)
|
||||
log.Println(err.Error())
|
||||
return officeHour, err
|
||||
}
|
||||
|
@ -193,24 +193,24 @@ func (r *OfficeHourRepo) getFromRows(rows *sql.Rows) ([]models.OfficeHour, error
|
|||
var week, day, hour, minute, tutorId, roomId, courseId int
|
||||
var err error
|
||||
if err := rows.Scan(&officeHour.Id, &tutorId, &day, &hour, &minute, &roomId, &officeHour.RoomName, &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: %w", err)
|
||||
}
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
err = fmt.Errorf("Error finding course by id %d for office hour: %w", courseId, err)
|
||||
log.Println(err.Error())
|
||||
return officeHours, err
|
||||
}
|
||||
|
@ -229,7 +229,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)
|
||||
err = fmt.Errorf("Error getting officeHours by timespan and room from database: %w", err)
|
||||
log.Println(err.Error())
|
||||
return 0, err
|
||||
}
|
||||
|
@ -245,7 +245,9 @@ func (r *OfficeHourRepo) NumberByTimeSpanAndRoom(date models.Date, duration int,
|
|||
for _, officeHour := range officeHours {
|
||||
// increase count if officehour starts before this point in time and ends later
|
||||
if models.DateLess(officeHour.Date, models.GetEndDate(date, minute, false)) && models.DateLess(models.GetEndDate(date, minute, false), models.GetEndDate(officeHour.Date, officeHour.Duration, false)) {
|
||||
minuteCount += 1
|
||||
if date.Week == 0 || officeHour.Week == 0 || date.Week == officeHour.Week { // office hours in alternating weeks should not collide
|
||||
minuteCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if minuteCount > count {
|
||||
|
|
|
@ -7,9 +7,10 @@ import (
|
|||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/wneessen/go-mail"
|
||||
"html/template"
|
||||
"log"
|
||||
"math/big"
|
||||
"net/smtp"
|
||||
"officeHours/config"
|
||||
"officeHours/models"
|
||||
"officeHours/templating"
|
||||
|
@ -54,7 +55,7 @@ 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)
|
||||
err = fmt.Errorf("Error scanning request row: %w", err)
|
||||
log.Println(err.Error())
|
||||
return requests, err
|
||||
}
|
||||
|
@ -109,7 +110,7 @@ func (r *RequestRepo) Execute(request models.Request) error {
|
|||
r.db.Exec("DELETE FROM request WHERE officeHour=?", request.OfficeHour.Id)
|
||||
err = r.officeHourRepo.Delete(request.OfficeHour)
|
||||
default:
|
||||
log.Printf("executing request: Action type %d unknown.", request.Action)
|
||||
log.Printf("Executing request: Action type %d unknown.", request.Action)
|
||||
_, err = r.db.Exec("DELETE FROM request WHERE id=?", request.Id)
|
||||
}
|
||||
return err
|
||||
|
@ -131,55 +132,34 @@ func (r *RequestRepo) newSecret() (string, error) {
|
|||
}
|
||||
|
||||
func (r *RequestRepo) sendConfirmationMail(request models.Request) error {
|
||||
var messageText bytes.Buffer
|
||||
var message bytes.Buffer
|
||||
var data = struct {
|
||||
Config config.Config
|
||||
Request models.Request
|
||||
}{r.config, request}
|
||||
err := templating.WriteTemplate(&messageText, "confirmationMail", data)
|
||||
Config config.Config
|
||||
Request models.Request
|
||||
MessageId template.HTML
|
||||
}{r.config, request, template.HTML("<" + randomString(15) + "@" + r.config.Server.Domain + ">")}
|
||||
err := templating.WriteTemplate(&message, "confirmationMail", data)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing confirmation Mail: %w", err)
|
||||
err = fmt.Errorf("Error parsing confirmation Mail: %w", err)
|
||||
log.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
switch r.config.Mailer.Type {
|
||||
case "Stdout":
|
||||
fmt.Println(messageText.String())
|
||||
fmt.Println(message.String())
|
||||
case "Smtp":
|
||||
message := mail.NewMsg()
|
||||
if err := message.From(r.config.Mailer.FromAddress); err != nil {
|
||||
log.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
if err := message.To(request.OfficeHour.Tutor.Email); err != nil {
|
||||
log.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
switch request.Action {
|
||||
case models.RequestActivate:
|
||||
message.Subject("Sprechstunde anlegen")
|
||||
case models.RequestDelete:
|
||||
message.Subject("Sprechstunde löschen")
|
||||
}
|
||||
message.SetBodyString(mail.TypeTextPlain, messageText.String())
|
||||
|
||||
var options []mail.Option
|
||||
options = append(options, mail.WithPort(r.config.Mailer.SmtpPort))
|
||||
to := []string{request.OfficeHour.Tutor.Email}
|
||||
var auth smtp.Auth
|
||||
if r.config.Mailer.SmtpUseAuth {
|
||||
options = append(options, mail.WithSMTPAuth(mail.SMTPAuthPlain))
|
||||
options = append(options, mail.WithUsername(r.config.Mailer.SmtpIdentity))
|
||||
options = append(options, mail.WithPassword(r.config.Mailer.SmtpPassword))
|
||||
auth = smtp.PlainAuth(r.config.Mailer.SmtpIdentity, r.config.Mailer.FromAddress, r.config.Mailer.SmtpPassword, r.config.Mailer.SmtpHost)
|
||||
}
|
||||
client, err := mail.NewClient(r.config.Mailer.SmtpHost, options...)
|
||||
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
|
||||
}
|
||||
if err := client.DialAndSend(message); err != nil {
|
||||
log.Println(err.Error())
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ 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)
|
||||
err = fmt.Errorf("Error scanning row to get room: %w", err)
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
log.Println(err.Error())
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ func (r *RoomRepo) FindById(id int) (models.Room, error) {
|
|||
func (r *RoomRepo) GetAll() ([]models.Room, error) {
|
||||
rows, err := r.db.Query("SELECT * FROM room ORDER BY name ASC")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error getting all rooms: %w", err)
|
||||
err = fmt.Errorf("Error getting all rooms: %w", err)
|
||||
log.Println(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ 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)
|
||||
err = fmt.Errorf("Error scanning row to get room: %w", err)
|
||||
return rooms, err
|
||||
}
|
||||
rooms = append(rooms, room)
|
||||
|
|
|
@ -58,7 +58,7 @@ func (r *TutorRepo) Add(tutor models.Tutor) (int, error) {
|
|||
}
|
||||
id, lastInsertIdErr := sqlResult.LastInsertId()
|
||||
if lastInsertIdErr != nil {
|
||||
log.Printf("error getting Id for new tutor: %s", lastInsertIdErr.Error())
|
||||
log.Printf("Error getting Id for new tutor: %s", lastInsertIdErr.Error())
|
||||
}
|
||||
return int(id), err
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ func (r *TutorRepo) getFromRows(rows *sql.Rows) ([]models.Tutor, error) {
|
|||
for rows.Next() {
|
||||
var tutor models.Tutor
|
||||
if err := rows.Scan(&tutor.Id, &tutor.Name, &tutor.Email, &tutor.SubscribeToMailinglist); err != nil {
|
||||
err = fmt.Errorf("error scanning tutor row: %w", err)
|
||||
err = fmt.Errorf("Error scanning tutor row: %w", err)
|
||||
log.Println(err.Error())
|
||||
return tutors, err
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ 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)
|
||||
return nil, fmt.Errorf("Type of database not recognised: %s", config.SQL.Type)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ func Connect(config config.Config) (*sql.DB, error) {
|
|||
func connectSQLite(file string) (*sql.DB, error) {
|
||||
db, err := sql.Open("sqlite3", file)
|
||||
if err != nil {
|
||||
return db, fmt.Errorf("error opening SQLite database: %w", err)
|
||||
return db, fmt.Errorf("Error opening SQLite database: %w", err)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
@ -38,12 +38,12 @@ func connectSQLite(file string) (*sql.DB, error) {
|
|||
func connectMysql(user string, password string, address string, port int, database string) (*sql.DB, error) {
|
||||
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)
|
||||
return db, fmt.Errorf("Error connecting to Mysql database: %w", err)
|
||||
}
|
||||
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
return db, fmt.Errorf("error pinging Mysql database: %w", err)
|
||||
return db, fmt.Errorf("Error pinging Mysql database: %w", err)
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
bootstrap-5.3.3-dist
|
||||
bootstrap-5.2.3-dist
|
7
static/bootstrap-5.2.3-dist/css/bootstrap.min.css
vendored
Normal file
7
static/bootstrap-5.2.3-dist/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap-5.2.3-dist/css/bootstrap.min.css.map
Normal file
1
static/bootstrap-5.2.3-dist/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
7
static/bootstrap-5.2.3-dist/js/bootstrap.bundle.min.js
vendored
Normal file
7
static/bootstrap-5.2.3-dist/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,8 +1,8 @@
|
|||
{{define "title"}}Sprechstunde anlegen – Fehler{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="col-md-8 offset-md-2 alert alert-danger">
|
||||
Irgendetwas ist schief gegangen. Bitte sende folgende Daten an <a href="mailto:sprechstundentool@mathebau.de">sprechstundentool@mathebau.de</a> mit einer Beschreibung, was du tun wolltest.
|
||||
<div class="col-md-8 offset-md-2">
|
||||
Irgendetwas ist schief gegangen. Bitte sende folgende Daten an <a href="mailto:{{.Config.Mailer.SupportMail}}">{{.Config.Mailer.SupportMail}}</a> mit einer Beschreibung, was du tun wolltest.
|
||||
<br>
|
||||
{{.}}
|
||||
</div>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<div class="form-floating mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" name="subscribeToMailinglist" id="subscribeToMailinglist" type="checkbox" value="subscribe" {{if eq .SubscribeToMailinglist true}}checked{{end}}>
|
||||
<label class="form-check-label" for="subscribeToMailinglist"><a href="https://lists.mathebau.de/postorius/lists/shk.lists.mathebau.de/">Mailingliste für SHK</a> abonnieren</label>
|
||||
<label class="form-check-label" for="subscribeToMailinglist"><a href="https://lists.mathebau.de/postorius/lists/shk.mathebau.de/">Mailingliste für SHK</a> abbonieren</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -50,7 +50,7 @@
|
|||
<label for="veranstaltung">Veranstaltung</label>
|
||||
<div class="form-text">
|
||||
Wenn du eine Veranstaltung hier vermisst, schreibe an
|
||||
<a href="mailto:sprechstundentool@mathebau.de?subject=Sprechstundentool: Neue Veranstaltung&body=Hey liebe Sprechstundentool-Admins,%0D%0A%0D%0Ameine Veranstaltung fehlt im Auswahlmenü.%0D%0AEs ist die Veranstaltung%0D%0A%0D%0AViele Grüße%0D%0A" tabindex="-1">sprechstundentool@mathebau.de</a>.
|
||||
<a href="mailto:{{.Config.Mailer.SupportMail}}?subject=Sprechstundentool: Neue Veranstaltung&body=Hey liebe Sprechstundentool-Admins,%0D%0A%0D%0Ameine Veranstaltung fehlt im Auswahlmenü.%0D%0AEs ist die Veranstaltung%0D%0A%0D%0AViele Grüße%0D%0A" tabindex="-1">{{.Config.Mailer.SupportMail}}</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -59,12 +59,9 @@
|
|||
|
||||
<div class="form-floating mb-3">
|
||||
<select class="form-control form-select required" required name="woche" id="woche">
|
||||
<option value="0"{{if eq 0 $.Date.Week}} selected{{end}}>Jede Woche</option>
|
||||
<option value="1"{{if eq 1 $.Date.Week}} selected{{end}}>In Wochen mit Übung</option>
|
||||
<option value="2"{{if eq 2 $.Date.Week}} selected{{end}}>In Wochen ohne Übung</option>
|
||||
<option value="3"{{if eq 3 $.Date.Week}} selected{{end}}>In geraden Vorlesungswochen</option>
|
||||
<option value="4"{{if eq 4 $.Date.Week}} selected{{end}}>In ungeraden Vorlesungswochen</option>
|
||||
<option value="5"{{if eq 5 $.Date.Week}} selected{{end}}>Etwas anderes (nutze Infofeld)</option>
|
||||
<option value="0"{{if eq 0 $.Date.Week}} selected{{end}}>Jede</option>
|
||||
<option value="1"{{if eq 1 $.Date.Week}} selected{{end}}>Ungerade</option>
|
||||
<option value="2"{{if eq 2 $.Date.Week}} selected{{end}}>Gerade</option>
|
||||
</select>
|
||||
<label for="woche">Vorlesungswoche</label>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
{{define "title"}}Sprechstunde anlegen{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="col-md-8 offset-md-2 alert alert-success">
|
||||
<div class="col-md-8 offset-md-2">
|
||||
<div class="alert alert-danger">
|
||||
Die Mailzustellung an Web und GMX ist gerade gestört.
|
||||
Falls deine Mailadresse dorthin weiterleitet und du die Bestätigung nicht erhältst,
|
||||
melde dich bei <a href="mailto:{{.Config.Mailer.SupportMail}}">{{.Config.Mailer.SupportMail}}</a>.
|
||||
</div>
|
||||
Die Sprechstunde wurde angelegt.
|
||||
Du solltest eine Mail mit einem Aktivierungslink erhalten haben.
|
||||
Klicke auf diesen, um die Sprechstunde öffentlich anzuzeigen.
|
||||
</div>
|
||||
|
||||
{{end}}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de" data-bs-theme="auto">
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="keywords" content="Mathebau, Sprechstunde, Sprechstunden, Mathe, Mathematik, technische, Universität, Darmstadt, TU, Fachschaft">
|
||||
|
@ -13,7 +13,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<nav class="col-md-8 offset-md-2 bg-secondary bg-gradient mt-3 mb-2 p-3 rounded" style="--bs-bg-opacity: .3;">
|
||||
<div class="col-md-8 offset-md-2 bg-secondary bg-gradient mt-3 mb-2 p-3 rounded" style="--bs-bg-opacity: .3;">
|
||||
<h5 class="text-center m-1">Sprechstunden für Matheveranstaltungen an der TU Darmstadt</h5>
|
||||
<p class="text-center mb-0">
|
||||
<a href="/">Startseite</a>
|
||||
|
@ -22,39 +22,24 @@
|
|||
•
|
||||
<a href="/deleteOfficeHour">Sprechstunde löschen</a>
|
||||
</p>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<main id="content">
|
||||
<div id="content">
|
||||
<h1 class="h3 m-1 mb-3 text-center">{{template "title" .}}</h1>
|
||||
{{block "content" .}}Du solltest dies nicht sehen.{{end}}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="container">
|
||||
<div class="col-md-8 offset-md-2 bg-secondary bg-gradient my-3 p-3 rounded" style="--bs-bg-opacity: .3;">
|
||||
© <a class="text-body" href="https://mathebau.de/">Fachschaft Mathematik, TU Darmstadt</a>
|
||||
<br>
|
||||
<!-- NOTE: when updating this hard coded email adress, also update it in addMask.html -->
|
||||
Technische Fragen an <a href="mailto:sprechstundentool@mathebau.de">sprechstundentool@mathebau.de</a>
|
||||
Technische Fragen an <a href="mailto:{{.Config.Mailer.SupportMail}}">{{.Config.Mailer.SupportMail}}</a>
|
||||
<br>
|
||||
Quellcode und Featurewünsche: <a href="https://gitea.mathebau.de/Fachschaft/sprechstunden-go">Gitea-Repository</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="/static/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- switch to dark mode if browser likes it -->
|
||||
<script>
|
||||
;(function () {
|
||||
const htmlElement = document.querySelector("html")
|
||||
if(htmlElement.getAttribute("data-bs-theme") === 'auto') {
|
||||
function updateTheme() {
|
||||
document.querySelector("html").setAttribute("data-bs-theme",
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light")
|
||||
}
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme)
|
||||
updateTheme()
|
||||
}
|
||||
})()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
From: {{.Config.Mailer.FromName}}
|
||||
To: {{.Request.OfficeHour.Tutor.Email}}
|
||||
Subject: Sprechstunde {{if eq .Request.Action 0}}anlegen{{end}}{{if eq .Request.Action 1}}löschen{{end}}
|
||||
Message-ID: {{.MessageId}}
|
||||
|
||||
Hallo {{.Request.OfficeHour.Tutor.Name}},
|
||||
|
||||
mit deiner Emailadresse soll eine Sprechstunde mit folgenden Daten {{if eq .Request.Action 0}}angelegt werden{{end}}{{if eq .Request.Action 1}}gelöscht werden{{end}}:
|
||||
|
@ -5,7 +10,6 @@ mit deiner Emailadresse soll eine Sprechstunde mit folgenden Daten {{if eq .Requ
|
|||
{{.Request.OfficeHour.Course.Name}}
|
||||
{{DayName .Request.OfficeHour.Date.Day}}
|
||||
{{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
|
||||
{{if eq 0 .Request.OfficeHour.Date.Week}}Jede Woche{{end}}{{if eq 1 .Request.OfficeHour.Date.Week}}In Wochen mit Übung{{end}}{{if eq 2 .Request.OfficeHour.Date.Week}}In Wochen ohne Übung{{end}}{{if eq 3 .Request.OfficeHour.Date.Week}}In geraden Vorlesungswochen{{end}}{{if eq 4 .Request.OfficeHour.Date.Week}}In ungeraden Vorlesungswochen{{end}}
|
||||
{{.Request.OfficeHour.Tutor.Name}}
|
||||
{{.Request.OfficeHour.Room.Name}}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{define "title"}}Sprechstunde löschen – Fehler{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="col-md-8 offset-md-2 alert alert-danger">
|
||||
<div class="col-md-8 offset-md-2">
|
||||
Das Löschen der Sprechstunde ist fehlgeschlagen: {{.Error}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<p>
|
||||
Willst du die Sprechstunde<br>
|
||||
{{printf "%02d" .OfficeHour.Date.Hour}}:{{printf "%02d" .OfficeHour.Date.Minute}} - {{printf "%02d" .OfficeHour.EndDate.Hour}}:{{printf "%02d" .OfficeHour.EndDate.Minute}}<br>
|
||||
{{if eq 0 $.Date.Week}}>Jede Woche<br>{{end}}{{if eq 1 $.Date.Week}}In Wochen mit Übung<br>{{end}}{{if eq 2 $.Date.Week}}In Wochen ohne Übung<br>{{end}}{{if eq 3 $.Date.Week}}In geraden Vorlesungswochen<br>{{end}}{{if eq 4 $.Date.Week}}In ungeraden Vorlesungswochen<br>{{end}}
|
||||
{{if eq .OfficeHour.Date.Week 1}}in ungeraden Vorlesungswochen<br>{{end}}{{if eq .OfficeHour.Date.Week 2}}in geraden Vorlesungswochen<br>{{end}}
|
||||
{{.OfficeHour.Course.Name}}<br>
|
||||
{{.OfficeHour.Tutor.Name}}<br>
|
||||
{{.OfficeHour.Room.Name}}<br>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{define "title"}}Sprechstunde löschen{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="col-md-8 offset-md-2 alert alert-info">
|
||||
<div class="col-md-8 offset-md-2">
|
||||
Du solltest eine Mail mit einem Bestätigungslink erhalten haben.
|
||||
Klicke auf diesen, um die Sprechstunde endgültig zu löschen.
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{define "title"}}Anfrage ausführen fehlgeschlagen{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="col-md-8 offset-md-2 alert alert-danger">
|
||||
Irgendetwas ist schief gegangen. Bitte sende folgende Daten an <a href="mailto:sprechstundentool@mathebau.de">sprechstundentool@mathebau.de</a> mit einer Beschreibung, was du tun wolltest.
|
||||
<div class="col-md-8 offset-md-2">
|
||||
Irgendetwas ist schief gegangen. Bitte sende folgende Daten an <a href="mailto:{{.Config.Mailer.SupportMail}}">{{.Config.Mailer.SupportMail}}</a> mit einer Beschreibung, was du tun wolltest.
|
||||
<br>
|
||||
{{.}}
|
||||
</div>"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{define "title"}}Anfrage ausgeführt{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="col-md-8 offset-md-2 alert alert-success">
|
||||
<div class="col-md-8 offset-md-2">
|
||||
Deine Anfrage wurde ausgeführt.
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<td class="officeHour" rowspan="{{divide .OfficeHour.Duration .MinuteGranularity}}">
|
||||
{{if .DeleteIcons}}<div style="text-align: right;"><a href="/deleteOfficeHour?id={{.OfficeHour.Id}}">❌</a></div>{{end}}
|
||||
{{printf "%02d" .OfficeHour.Date.Hour}}:{{printf "%02d" .OfficeHour.Date.Minute}} - {{printf "%02d" .OfficeHour.EndDate.Hour}}:{{printf "%02d" .OfficeHour.EndDate.Minute}}<br>
|
||||
{{if eq 1 .OfficeHour.Date.Week}}In Wochen mit Übung<br>{{end}}{{if eq 2 .OfficeHour.Date.Week}}In Wochen ohne Übung<br>{{end}}{{if eq 3 .OfficeHour.Date.Week}}In geraden Vorlesungswochen<br>{{end}}{{if eq 4 .OfficeHour.Date.Week}}In ungeraden Vorlesungswochen<br>{{end}}
|
||||
{{if eq .OfficeHour.Date.Week 1}}in ungeraden Vorlesungswochen<br>{{end}}{{if eq .OfficeHour.Date.Week 2}}in geraden Vorlesungswochen<br>{{end}}
|
||||
{{.OfficeHour.Course.Name}}<br>
|
||||
{{.OfficeHour.Tutor.Name}}<br>
|
||||
{{.OfficeHour.Room.Name}}
|
||||
|
|
Loading…
Add table
Reference in a new issue