Sprechstunden hinzufügen und durch einen E-Mail-Link bestätigen lassen
This commit is contained in:
parent
369f4ebcec
commit
78af58a51d
18 changed files with 291 additions and 29 deletions
|
@ -142,17 +142,21 @@ func (b *BaseHandler) AddOfficeHourHandler(w http.ResponseWriter, req *http.Requ
|
||||||
false,
|
false,
|
||||||
duration,
|
duration,
|
||||||
}
|
}
|
||||||
err := b.officeHourRepo.Add(officeHour)
|
id, err := b.officeHourRepo.Add(officeHour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
failureTemplate, parseErr := template.ParseFiles("templates/addFailure.html")
|
failureTemplate, parseErr := template.ParseFiles("templates/addFailure.html")
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
failureTemplate.Execute(w, err)
|
failureTemplate.Execute(w, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, req, "/", http.StatusTemporaryRedirect)
|
officeHour, _ = b.officeHourRepo.FindById(id)
|
||||||
|
b.requestRepo.Add(officeHour, models.RequestActivate)
|
||||||
|
tmpl, _ := template.ParseFiles("template/addSuccess.html")
|
||||||
|
tmpl.Execute(w, struct{}{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,15 +164,18 @@ func (b *BaseHandler) writeAddOfficeHourMask(w http.ResponseWriter, req *http.Re
|
||||||
tmpl, err := template.ParseFiles("templates/addMask.html")
|
tmpl, err := template.ParseFiles("templates/addMask.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(data.Errors) != 0 {
|
if len(data.Errors) != 0 {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
if req.Method == http.MethodGet {
|
||||||
|
data.Errors = []string{}
|
||||||
|
}
|
||||||
err = tmpl.Execute(w, data)
|
err = tmpl.Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,10 @@ type BaseHandler struct {
|
||||||
officeHourRepo models.OfficeHourRepository
|
officeHourRepo models.OfficeHourRepository
|
||||||
courseRepo models.CourseRepository
|
courseRepo models.CourseRepository
|
||||||
tutorRepo models.TutorRepository
|
tutorRepo models.TutorRepository
|
||||||
|
requestRepo models.RequestRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBaseHandler returns a new BaseHandler
|
// NewBaseHandler returns a new BaseHandler
|
||||||
func NewBaseHandler(roomRepo models.RoomRepository, officeHourRepo models.OfficeHourRepository, courseRepo models.CourseRepository, tutorRepo models.TutorRepository) *BaseHandler {
|
func NewBaseHandler(roomRepo models.RoomRepository, officeHourRepo models.OfficeHourRepository, courseRepo models.CourseRepository, tutorRepo models.TutorRepository, requestRepo models.RequestRepository) *BaseHandler {
|
||||||
return &BaseHandler{roomRepo, officeHourRepo, courseRepo, tutorRepo}
|
return &BaseHandler{roomRepo, officeHourRepo, courseRepo, tutorRepo, requestRepo}
|
||||||
}
|
}
|
||||||
|
|
24
controllers/confirmRequestHandler.go
Normal file
24
controllers/confirmRequestHandler.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *BaseHandler) ConfirmRequestHandler(w http.ResponseWriter, req *http.Request) {
|
||||||
|
secret := req.FormValue("code")
|
||||||
|
request, err := b.requestRepo.FindBySecret(secret)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
tmpl, _ := template.ParseFiles("templates/requestNotFound.html")
|
||||||
|
tmpl.Execute(w, struct{}{})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = b.requestRepo.Execute(request)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
tmpl, err := template.ParseFiles("templates/executeFailure.html")
|
||||||
|
tmpl.Execute(w, err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,6 @@ func (b *BaseHandler) GetByRoomHandler(w http.ResponseWriter, req *http.Request)
|
||||||
roomId, _ := strconv.Atoi(req.FormValue("raum"))
|
roomId, _ := strconv.Atoi(req.FormValue("raum"))
|
||||||
room, err := b.roomRepo.FindById(roomId)
|
room, err := b.roomRepo.FindById(roomId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
|
||||||
b.RootHandler(w, req)
|
b.RootHandler(w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -53,12 +52,12 @@ func (b *BaseHandler) writeTimetablePage(w http.ResponseWriter, req *http.Reques
|
||||||
tmpl, err := template.ParseFiles("templates/index.html")
|
tmpl, err := template.ParseFiles("templates/index.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = tmpl.Execute(w, data)
|
err = tmpl.Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", string(err.Error()))))
|
w.Write([]byte(fmt.Sprintf("Template konnte nicht geparst werden : %s", err.Error())))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5
main.go
5
main.go
|
@ -15,12 +15,13 @@ func main() {
|
||||||
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)
|
||||||
h := controllers.NewBaseHandler(roomRepo, officeHourRepo, courseRepo, tutorRepo)
|
h := controllers.NewBaseHandler(roomRepo, officeHourRepo, courseRepo, tutorRepo, requestRepo)
|
||||||
|
|
||||||
http.HandleFunc("/getByRoom", h.GetByRoomHandler)
|
http.HandleFunc("/getByRoom", h.GetByRoomHandler)
|
||||||
http.HandleFunc("/getByCourse", h.GetByCourseHandler)
|
http.HandleFunc("/getByCourse", h.GetByCourseHandler)
|
||||||
http.HandleFunc("/addOfficeHour", h.AddOfficeHourHandler)
|
http.HandleFunc("/addOfficeHour", h.AddOfficeHourHandler)
|
||||||
|
http.HandleFunc("/confirmRequest", h.ConfirmRequestHandler)
|
||||||
http.HandleFunc("/", h.RootHandler)
|
http.HandleFunc("/", h.RootHandler)
|
||||||
|
|
||||||
http.ListenAndServe(":8080", nil)
|
http.ListenAndServe(":8080", nil)
|
||||||
|
|
|
@ -9,3 +9,20 @@ type Date struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const MinuteGranularity int = 5
|
const MinuteGranularity int = 5
|
||||||
|
|
||||||
|
func DayName(day int) string {
|
||||||
|
switch day {
|
||||||
|
case 0:
|
||||||
|
return "Montag"
|
||||||
|
case 1:
|
||||||
|
return "Dienstag"
|
||||||
|
case 2:
|
||||||
|
return "Mittwoch"
|
||||||
|
case 3:
|
||||||
|
return "Donnerstag"
|
||||||
|
case 4:
|
||||||
|
return "Freitag"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,5 +18,5 @@ type OfficeHourRepository interface {
|
||||||
FindByRoom(room Room, activatedOnly bool) ([]OfficeHour, error)
|
FindByRoom(room Room, activatedOnly bool) ([]OfficeHour, error)
|
||||||
GetAll(activatedOnly bool) ([]OfficeHour, error)
|
GetAll(activatedOnly bool) ([]OfficeHour, error)
|
||||||
Delete(officeHour OfficeHour) error
|
Delete(officeHour OfficeHour) error
|
||||||
Add(officeHour OfficeHour) error
|
Add(officeHour OfficeHour) (int, error)
|
||||||
}
|
}
|
||||||
|
|
20
models/request.go
Normal file
20
models/request.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// request
|
||||||
|
package models
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
Id int
|
||||||
|
OfficeHour OfficeHour
|
||||||
|
Action int
|
||||||
|
Secret string
|
||||||
|
}
|
||||||
|
|
||||||
|
const RequestActivate int = 1
|
||||||
|
const RequestDelete int = 2
|
||||||
|
|
||||||
|
const SecretLength int = 15
|
||||||
|
|
||||||
|
type RequestRepository interface {
|
||||||
|
Add(officeHour OfficeHour, action int) (int, error)
|
||||||
|
FindBySecret(secret string) (Request, error)
|
||||||
|
Execute(request Request) error
|
||||||
|
}
|
|
@ -12,5 +12,5 @@ type TutorRepository interface {
|
||||||
FindByNameAndEmail(name string, email string) (Tutor, error)
|
FindByNameAndEmail(name string, email string) (Tutor, error)
|
||||||
FindById(Id int) (Tutor, error)
|
FindById(Id int) (Tutor, error)
|
||||||
GetAll() ([]Tutor, error)
|
GetAll() ([]Tutor, error)
|
||||||
Add(tutor Tutor) error
|
Add(tutor Tutor) (int, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,19 +72,18 @@ func (r *OfficeHourRepo) FindById(id int) (models.OfficeHour, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error {
|
func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) (id int, err error) {
|
||||||
// Find correct tutor or add if not existent
|
// Find correct tutor or add if not existent
|
||||||
r.tutorRepo.Add(officeHour.Tutor)
|
r.tutorRepo.Add(officeHour.Tutor)
|
||||||
var err error
|
|
||||||
officeHour.Tutor, err = r.tutorRepo.FindByNameAndEmail(officeHour.Tutor.Name, officeHour.Tutor.Email)
|
officeHour.Tutor, err = r.tutorRepo.FindByNameAndEmail(officeHour.Tutor.Name, officeHour.Tutor.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
//Don't add identical officeHours
|
//Don't add identical officeHours
|
||||||
officeHours, err := r.FindByCourse(officeHour.Course, false)
|
officeHours, err := r.FindByCourse(officeHour.Course, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
for _, oldOfficeHour := range officeHours {
|
for _, oldOfficeHour := range officeHours {
|
||||||
if officeHour.Tutor == oldOfficeHour.Tutor &&
|
if officeHour.Tutor == oldOfficeHour.Tutor &&
|
||||||
|
@ -94,11 +93,11 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error {
|
||||||
officeHour.Info == oldOfficeHour.Info &&
|
officeHour.Info == oldOfficeHour.Info &&
|
||||||
officeHour.Active == oldOfficeHour.Active &&
|
officeHour.Active == oldOfficeHour.Active &&
|
||||||
officeHour.Duration == oldOfficeHour.Duration {
|
officeHour.Duration == oldOfficeHour.Duration {
|
||||||
return nil
|
return officeHour.Id, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.db.Exec("INSERT INTO `officeHour` (tutor, day, hour, minute, room, course, week, info, active, duration) VALUES (?,?,?,?,?,?,?,?,?,?)",
|
sqlResult, err := r.db.Exec("INSERT INTO `officeHour` (tutor, day, hour, minute, room, course, week, info, active, duration) VALUES (?,?,?,?,?,?,?,?,?,?)",
|
||||||
officeHour.Tutor.Id,
|
officeHour.Tutor.Id,
|
||||||
officeHour.Date.Day,
|
officeHour.Date.Day,
|
||||||
officeHour.Date.Hour,
|
officeHour.Date.Hour,
|
||||||
|
@ -109,7 +108,8 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error {
|
||||||
officeHour.Info,
|
officeHour.Info,
|
||||||
officeHour.Active,
|
officeHour.Active,
|
||||||
officeHour.Duration)
|
officeHour.Duration)
|
||||||
return err
|
id64, _ := sqlResult.LastInsertId()
|
||||||
|
return int(id64), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error {
|
func (r *OfficeHourRepo) Delete(officeHour models.OfficeHour) error {
|
||||||
|
|
141
repositories/request.go
Normal file
141
repositories/request.go
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
// request
|
||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"database/sql"
|
||||||
|
"html/template"
|
||||||
|
"math/big"
|
||||||
|
"net/smtp"
|
||||||
|
"sprechstundentool/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RequestRepo struct {
|
||||||
|
db *sql.DB
|
||||||
|
officeHourRepo models.OfficeHourRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequestRepo(db *sql.DB, officeHourRepo models.OfficeHourRepository) *RequestRepo {
|
||||||
|
return &RequestRepo{
|
||||||
|
db: db,
|
||||||
|
officeHourRepo: officeHourRepo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestRepo) FindBySecret(secret string) (models.Request, error) {
|
||||||
|
// This query is not safe against timing sidechannel attacks – I don't care.
|
||||||
|
row := r.db.QueryRow("SELECT * FROM request WHERE secret=?", secret)
|
||||||
|
var request models.Request
|
||||||
|
var officeHourId int
|
||||||
|
err := row.Scan(&request.Id, &officeHourId, &request.Action, &request.Secret)
|
||||||
|
if err != nil {
|
||||||
|
return models.Request{}, err
|
||||||
|
}
|
||||||
|
request.OfficeHour, err = r.officeHourRepo.FindById(officeHourId)
|
||||||
|
return request, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestRepo) FindByOfficeHour(officeHour models.OfficeHour) ([]models.Request, error) {
|
||||||
|
rows, err := r.db.Query("SELECT * FROM request WHERE officeHour=?", officeHour.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var requests []models.Request
|
||||||
|
for rows.Next() {
|
||||||
|
var request models.Request
|
||||||
|
var officeHourId int
|
||||||
|
if err := rows.Scan(&request.Id, &officeHourId, &request.Action, &request.Secret); err != nil {
|
||||||
|
return requests, err
|
||||||
|
}
|
||||||
|
requests = append(requests, request)
|
||||||
|
}
|
||||||
|
return requests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestRepo) Add(officeHour models.OfficeHour, action int) (int, error) {
|
||||||
|
existents, err := r.FindByOfficeHour(officeHour)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
/* Resend confirmation mail if identical request exists,
|
||||||
|
* but don't insert new request into database.
|
||||||
|
*/
|
||||||
|
for _, request := range existents {
|
||||||
|
if request.Action == action { // already covered by selection && request.OfficeHour == officeHour {
|
||||||
|
return request.Id, sendConfirmationMail(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secret, err := r.newSecret()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
request := models.Request{0, officeHour, action, secret}
|
||||||
|
_, err = r.db.Exec("INSERT INTO `request` (officeHour, action, secret) VALUES (?,?,?)", officeHour.Id, action, secret)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err = r.FindBySecret(secret)
|
||||||
|
if err != nil {
|
||||||
|
return request.Id, err
|
||||||
|
}
|
||||||
|
return request.Id, sendConfirmationMail(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestRepo) Execute(request models.Request) error {
|
||||||
|
var err error
|
||||||
|
switch request.Action {
|
||||||
|
case models.RequestActivate:
|
||||||
|
_, err = r.db.Exec("UPDATE officeHour SET active=true WHERE id=?", request.OfficeHour.Id)
|
||||||
|
r.db.Exec("DELETE FROM request WHERE id=?", request.Id)
|
||||||
|
case models.RequestDelete:
|
||||||
|
_, err = r.db.Exec("DELETE FROM officeHour WHERE id=?", request.OfficeHour.Id)
|
||||||
|
r.db.Exec("DELETE FROM request WHERE id=?", request.Id)
|
||||||
|
default:
|
||||||
|
r.db.Exec("DELETE FROM request WHERE id=?", request.Id)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RequestRepo) newSecret() (string, error) {
|
||||||
|
secret := randomString(models.SecretLength)
|
||||||
|
|
||||||
|
_, err := r.FindBySecret(secret)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// find unused secret
|
||||||
|
for err != sql.ErrNoRows {
|
||||||
|
secret = randomString(models.SecretLength)
|
||||||
|
_, err = r.FindBySecret(secret)
|
||||||
|
}
|
||||||
|
return secret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendConfirmationMail(request models.Request) error {
|
||||||
|
to := []string{request.OfficeHour.Tutor.Email}
|
||||||
|
tmpl, err := template.New("confirmationMail").Funcs(template.FuncMap{"DayName": models.DayName}).ParseFiles("templates/confirmationMail")
|
||||||
|
var message bytes.Buffer
|
||||||
|
err = tmpl.Execute(&message, request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = smtp.SendMail("192.168.0.24:25", nil, "Mathebau Sprechstunden <sprechstunden@mathebau.de>", to, message.Bytes())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomString(n int) string {
|
||||||
|
// []byte would be faster and also work, but []rune keeps working for UTF8 characters
|
||||||
|
// if someone would like them.
|
||||||
|
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||||
|
|
||||||
|
s := make([]rune, n)
|
||||||
|
for i := range s {
|
||||||
|
position, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
|
||||||
|
s[i] = letters[position.Int64()]
|
||||||
|
}
|
||||||
|
return string(s)
|
||||||
|
}
|
|
@ -72,13 +72,14 @@ func (r *TutorRepo) GetAll() ([]models.Tutor, error) {
|
||||||
func (r *TutorRepo) Save(tutor models.Tutor) error {
|
func (r *TutorRepo) Save(tutor models.Tutor) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (r *TutorRepo) Add(tutor models.Tutor) error {
|
func (r *TutorRepo) Add(tutor models.Tutor) (int, error) {
|
||||||
//Don't add identical tutors
|
//Don't add identical tutors
|
||||||
_, err := r.FindByNameAndEmail(tutor.Name, tutor.Email)
|
existentTutor, err := r.FindByNameAndEmail(tutor.Name, tutor.Email)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
_, err = r.db.Exec("INSERT INTO `tutor` (name, email) VALUES (?,?);", tutor.Name, tutor.Email)
|
sqlResult, err := r.db.Exec("INSERT INTO `tutor` (name, email) VALUES (?,?)", tutor.Name, tutor.Email)
|
||||||
return err
|
id, _ := sqlResult.LastInsertId()
|
||||||
|
return int(id), err
|
||||||
}
|
}
|
||||||
return err
|
return existentTutor.Id, err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ DROP TABLE IF EXISTS `request`;
|
||||||
CREATE TABLE `request` (
|
CREATE TABLE `request` (
|
||||||
`id` INTEGER PRIMARY KEY,
|
`id` INTEGER PRIMARY KEY,
|
||||||
`officeHour` int DEFAULT NULL,
|
`officeHour` int DEFAULT NULL,
|
||||||
`type` int DEFAULT NULL,
|
`action` int DEFAULT NULL,
|
||||||
`code` text DEFAULT NULL
|
`secret` text DEFAULT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
10
templates/addSuccess.html
Normal file
10
templates/addSuccess.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Sprechstunde anlegen</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Die Sprechstunde wurde angelegt. Du solltest eine Mail mit einem Aktivierungslink erhalten haben.
|
||||||
|
<br />
|
||||||
|
{{.}}
|
||||||
|
</body>
|
||||||
|
</html>
|
20
templates/confirmationMail
Normal file
20
templates/confirmationMail
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
To: {{.OfficeHour.Tutor.Email}}
|
||||||
|
|
||||||
|
Subject: Sprechstunde anlegen
|
||||||
|
|
||||||
|
|
||||||
|
Hallo {{.OfficeHour.Tutor.Name}},
|
||||||
|
|
||||||
|
mit deiner Emailadresse soll eine Sprechstunde mit folgenden Daten angelegt werden:
|
||||||
|
|
||||||
|
{{.OfficeHour.Course.Name}}
|
||||||
|
{{DayName .OfficeHour.Date.Day}}
|
||||||
|
ab {{.OfficeHour.Date.Hour}}:{{printf "%02d" .OfficeHour.Date.Minute}} Uhr
|
||||||
|
{{.OfficeHour.Duration}} Minuten
|
||||||
|
{{.OfficeHour.Tutor.Name}}
|
||||||
|
|
||||||
|
Wenn diese Daten richtig sind, so bestätige die Sprechstunde durch Abrufen der folgenden URL:
|
||||||
|
https://sprechstunden.mathebau.de/confirmRequest?code={{.Secret}}
|
||||||
|
Solltest du diese Email nicht erwartet haben, so kannst du sie einfach ignorieren.
|
||||||
|
|
||||||
|
Deine Fachschaft Mathematik
|
10
templates/executeFailure.html
Normal file
10
templates/executeFailure.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Anfrage ausführen fehlgeschlagen</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
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.
|
||||||
|
<br />
|
||||||
|
{{.}}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -22,6 +22,9 @@
|
||||||
<input type="submit" value="Auswählen" />
|
<input type="submit" value="Auswählen" />
|
||||||
</form>
|
</form>
|
||||||
{{.Timetable}}
|
{{.Timetable}}
|
||||||
Technische Fragen an <a href="mailto:sprechstundentool@mathebau.de">sprechstundentool@mathebau.de</a>
|
<footer>
|
||||||
|
<a href="/addOfficeHour">Sprechstunde anlegen</a><br />
|
||||||
|
Technische Fragen an <a href="mailto:sprechstundentool@mathebau.de">sprechstundentool@mathebau.de</a>
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
8
templates/requestNotFound.html
Normal file
8
templates/requestNotFound.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Anfrage bestätigen fehlgeschlagen</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Dieser Bestätigungscode ist nicht verfügbar.
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue