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
|
@ -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
|
||||
r.tutorRepo.Add(officeHour.Tutor)
|
||||
var err error
|
||||
officeHour.Tutor, err = r.tutorRepo.FindByNameAndEmail(officeHour.Tutor.Name, officeHour.Tutor.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
//Don't add identical officeHours
|
||||
officeHours, err := r.FindByCourse(officeHour.Course, false)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
for _, oldOfficeHour := range officeHours {
|
||||
if officeHour.Tutor == oldOfficeHour.Tutor &&
|
||||
|
@ -94,11 +93,11 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error {
|
|||
officeHour.Info == oldOfficeHour.Info &&
|
||||
officeHour.Active == oldOfficeHour.Active &&
|
||||
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.Date.Day,
|
||||
officeHour.Date.Hour,
|
||||
|
@ -109,7 +108,8 @@ func (r *OfficeHourRepo) Add(officeHour models.OfficeHour) error {
|
|||
officeHour.Info,
|
||||
officeHour.Active,
|
||||
officeHour.Duration)
|
||||
return err
|
||||
id64, _ := sqlResult.LastInsertId()
|
||||
return int(id64), err
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
func (r *TutorRepo) Add(tutor models.Tutor) error {
|
||||
func (r *TutorRepo) Add(tutor models.Tutor) (int, error) {
|
||||
//Don't add identical tutors
|
||||
_, err := r.FindByNameAndEmail(tutor.Name, tutor.Email)
|
||||
existentTutor, err := r.FindByNameAndEmail(tutor.Name, tutor.Email)
|
||||
if err == sql.ErrNoRows {
|
||||
_, err = r.db.Exec("INSERT INTO `tutor` (name, email) VALUES (?,?);", tutor.Name, tutor.Email)
|
||||
return err
|
||||
sqlResult, err := r.db.Exec("INSERT INTO `tutor` (name, email) VALUES (?,?)", tutor.Name, tutor.Email)
|
||||
id, _ := sqlResult.LastInsertId()
|
||||
return int(id), err
|
||||
}
|
||||
return err
|
||||
return existentTutor.Id, err
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue