Completed renderer, orm and mail sender refactoring

This commit is contained in:
Andrea Fazzi 2020-01-15 13:40:35 +01:00
parent 3bb8dde670
commit 82de4b68fb
13 changed files with 203 additions and 175 deletions

View file

@ -90,6 +90,7 @@ type ConfigT struct {
From string From string
Cc string Cc string
Bcc string Bcc string
Subject string
} }
Sync struct { Sync struct {
@ -115,13 +116,13 @@ type ConfigT struct {
} }
} }
var ( // var (
Config *ConfigT // Config *ConfigT
) // )
func init() { // func init() {
Config = new(ConfigT) // Config = new(ConfigT)
} // }
// ReadFile reads the config file placed at the given path. // ReadFile reads the config file placed at the given path.
func ReadFile(path string, config *ConfigT) error { func ReadFile(path string, config *ConfigT) error {

View file

@ -38,6 +38,8 @@ type Handlers struct {
Database *orm.Database Database *orm.Database
Models []interface{} Models []interface{}
Renderer map[string]renderer.Renderer
Login func(db *orm.Database, store *sessions.CookieStore, signingKey []byte) http.Handler Login func(db *orm.Database, store *sessions.CookieStore, signingKey []byte) http.Handler
Logout func(store *sessions.CookieStore) http.Handler Logout func(store *sessions.CookieStore) http.Handler
Home func() http.Handler Home func() http.Handler
@ -165,15 +167,17 @@ func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) {
} }
func NewHandlers(config *config.ConfigT, db *orm.Database, models []interface{}) *Handlers { func NewHandlers(config *config.ConfigT, renderer map[string]renderer.Renderer, db *orm.Database, models []interface{}) *Handlers {
handlers := new(Handlers) handlers := new(Handlers)
handlers.Config = config handlers.Config = config
handlers.Renderer = renderer
handlers.Database = db handlers.Database = db
handlers.CookieStore = sessions.NewCookieStore([]byte(config.Keys.CookieStoreKey)) handlers.CookieStore = sessions.NewCookieStore([]byte(config.Keys.CookieStoreKey))
handlers.Login = DefaultLoginHandler handlers.Login = handlers.DefaultLoginHandler
handlers.Logout = DefaultLogoutHandler handlers.Logout = DefaultLogoutHandler
handlers.Recover = DefaultRecoverHandler handlers.Recover = DefaultRecoverHandler
handlers.Home = DefaultHomeHandler handlers.Home = DefaultHomeHandler
@ -230,7 +234,6 @@ func NewHandlers(config *config.ConfigT, db *orm.Database, models []interface{})
} }
func (h *Handlers) onError(w http.ResponseWriter, r *http.Request, err string) { func (h *Handlers) onError(w http.ResponseWriter, r *http.Request, err string) {
log.Print(err)
http.Redirect(w, r, "/login?tpl_layout=login&tpl_content=login", http.StatusTemporaryRedirect) http.Redirect(w, r, "/login?tpl_layout=login&tpl_content=login", http.StatusTemporaryRedirect)
} }
@ -298,21 +301,20 @@ func (h *Handlers) get(w http.ResponseWriter, r *http.Request, model string, pat
getFn, err := h.Database.GetFunc(pattern.Path(model)) getFn, err := h.Database.GetFunc(pattern.Path(model))
if err != nil { if err != nil {
log.Println("Error:", err) log.Println("Error:", err)
respondWithError(w, r, err) respondWithError(h, w, r, err)
} else { } else {
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims) claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
role := claims["role"].(string) role := claims["role"].(string)
if !hasPermission(role, pattern.Path(model)) { if !hasPermission(role, pattern.Path(model)) {
log.Println("ERRORE")
h.setFlashMessage(w, r, "notAuthorized") h.setFlashMessage(w, r, "notAuthorized")
renderer.Render[format](w, r, fmt.Errorf("%s", "Errore di autorizzazione")) h.Renderer[format].Render(w, r, h.CookieStore, fmt.Errorf("%s", "Errore di autorizzazione"))
} else { } else {
data, err := getFn(h.Database, mux.Vars(r), w, r) data, err := getFn(h.Database, mux.Vars(r), w, r)
if err != nil { if err != nil {
renderer.Render[format](w, r, err) h.Renderer[format].Render(w, r, h.CookieStore, err)
} else { } else {
renderer.Render[format](w, r, data, r.URL.Query()) h.Renderer[format].Render(w, r, h.CookieStore, data, r.URL.Query())
} }
} }
} }
@ -329,17 +331,17 @@ func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pa
postFn, err := h.Database.GetFunc(pattern.Path(model)) postFn, err := h.Database.GetFunc(pattern.Path(model))
if err != nil { if err != nil {
respondWithError(w, r, err) respondWithError(h, w, r, err)
} else { } else {
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims) claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
role := claims["role"].(string) role := claims["role"].(string)
if !hasPermission(role, pattern.Path(model)) { if !hasPermission(role, pattern.Path(model)) {
renderer.Render[respFormat](w, r, fmt.Errorf("%s", "Errore di autorizzazione")) h.Renderer[respFormat].Render(w, r, h.CookieStore, fmt.Errorf("%s", "Errore di autorizzazione"))
} else { } else {
data, err = postFn(h.Database, mux.Vars(r), w, r) data, err = postFn(h.Database, mux.Vars(r), w, r)
if err != nil { if err != nil {
respondWithError(w, r, err) respondWithError(h, w, r, err)
} else if pattern.RedirectPattern != "" { } else if pattern.RedirectPattern != "" {
if id := mux.Vars(r)["id"]; id != "" { if id := mux.Vars(r)["id"]; id != "" {
modelId, _ := strconv.Atoi(id) modelId, _ := strconv.Atoi(id)
@ -348,7 +350,7 @@ func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pa
http.Redirect(w, r, pattern.RedirectPath(model, data.(orm.IDer).GetID()), http.StatusSeeOther) http.Redirect(w, r, pattern.RedirectPath(model, data.(orm.IDer).GetID()), http.StatusSeeOther)
} }
} else { } else {
renderer.Render[respFormat](w, r, data.(orm.IDer).GetID()) h.Renderer[respFormat].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
} }
} }
} }
@ -364,15 +366,15 @@ func (h *Handlers) delete(w http.ResponseWriter, r *http.Request, model string,
role := claims["role"].(string) role := claims["role"].(string)
if !hasPermission(role, pattern.Path(model)) { if !hasPermission(role, pattern.Path(model)) {
renderer.Render[respFormat](w, r, fmt.Errorf("%s", "Errore di autorizzazione")) h.Renderer[respFormat].Render(w, r, h.CookieStore, fmt.Errorf("%s", "Errore di autorizzazione"))
} else { } else {
postFn, err := h.Database.GetFunc(pattern.Path(model)) postFn, err := h.Database.GetFunc(pattern.Path(model))
if err != nil { if err != nil {
renderer.Render[r.URL.Query().Get("format")](w, r, err) h.Renderer[r.URL.Query().Get("format")].Render(w, r, h.CookieStore, err)
} }
data, err = postFn(h.Database, mux.Vars(r), w, r) data, err = postFn(h.Database, mux.Vars(r), w, r)
if err != nil { if err != nil {
renderer.Render["html"](w, r, err) h.Renderer["html"].Render(w, r, h.CookieStore, err)
} else if pattern.RedirectPattern != "" { } else if pattern.RedirectPattern != "" {
var data struct { var data struct {
RedirectUrl string `json:"redirect_url"` RedirectUrl string `json:"redirect_url"`
@ -382,15 +384,15 @@ func (h *Handlers) delete(w http.ResponseWriter, r *http.Request, model string,
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data) json.NewEncoder(w).Encode(data)
} else { } else {
renderer.Render[respFormat](w, r, data.(orm.IDer).GetID()) h.Renderer[respFormat].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
} }
} }
} }
func respondWithError(w http.ResponseWriter, r *http.Request, err error) { func respondWithError(h *Handlers, w http.ResponseWriter, r *http.Request, err error) {
respFormat := renderer.GetContentFormat(r) respFormat := renderer.GetContentFormat(r)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
renderer.Render[respFormat](w, r, err) h.Renderer[respFormat].Render(w, r, h.CookieStore, err)
} }
func (h *Handlers) modelHandler(model string, pattern PathPattern) http.Handler { func (h *Handlers) modelHandler(model string, pattern PathPattern) http.Handler {

View file

@ -3,9 +3,9 @@ package handlers
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"log"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -14,13 +14,13 @@ import (
"git.andreafazzi.eu/andrea/oef/orm" "git.andreafazzi.eu/andrea/oef/orm"
"git.andreafazzi.eu/andrea/oef/renderer" "git.andreafazzi.eu/andrea/oef/renderer"
jwt "github.com/dgrijalva/jwt-go" jwt "github.com/dgrijalva/jwt-go"
"github.com/jinzhu/gorm"
"github.com/remogatto/prettytest" "github.com/remogatto/prettytest"
) )
var ( var (
token string token string
handlers *Handlers handlers *Handlers
conf *config.ConfigT
) )
// Start of setup // Start of setup
@ -42,7 +42,7 @@ func authenticate(request *http.Request, tokenString string, signingKey string)
} }
func requestToken(handlers *Handlers) string { func requestToken(db *orm.Database, handlers *Handlers) string {
req, err := http.NewRequest("GET", "/get_token", nil) req, err := http.NewRequest("GET", "/get_token", nil)
if err != nil { if err != nil {
panic(err) panic(err)
@ -52,7 +52,7 @@ func requestToken(handlers *Handlers) string {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
handlers.GetToken([]byte(config.Config.Keys.JWTSigningKey)).ServeHTTP(rr, req) handlers.GetToken(db, []byte(db.Config.Keys.JWTSigningKey)).ServeHTTP(rr, req)
var data struct { var data struct {
Token string Token string
@ -75,10 +75,9 @@ func TestRunner(t *testing.T) {
func (t *testSuite) BeforeAll() { func (t *testSuite) BeforeAll() {
var ( var db *orm.Database
db *gorm.DB
err error conf = new(config.ConfigT)
)
models := []interface{}{ models := []interface{}{
&orm.Question{}, &orm.Question{},
@ -92,25 +91,32 @@ func (t *testSuite) BeforeAll() {
&orm.Region{}, &orm.Region{},
} }
// Load the configuration
err := config.ReadFile("testdata/config.yaml", conf)
if err != nil {
panic(err)
}
// conf.LogLevel = config.LOG_LEVEL_OFF
// Initialize the ORM // Initialize the ORM
connected := false connected := false
for !connected { for !connected {
var err error
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
db, err = orm.New("oef:oef@/oef_test?charset=utf8&parseTime=True&loc=Local")
db, err = orm.NewDatabase(conf, models)
if err != nil { if err != nil {
log.Print(err)
continue continue
} }
connected = true connected = true
} }
orm.Use(db) db.AutoMigrate()
orm.AutoMigrate()
// Map the handlers
if err := orm.MapHandlers(models); err != nil {
panic(err)
}
// Initialize the renderers // Initialize the renderers
@ -119,26 +125,12 @@ func (t *testSuite) BeforeAll() {
panic(err) panic(err)
} }
renderer.Render = make(map[string]func(http.ResponseWriter, *http.Request, interface{}, ...url.Values)) renderer := map[string]renderer.Renderer{
"html": htmlRenderer,
renderer.Render["html"] = func(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) {
htmlRenderer.Render(w, r, data, options...)
}
// Load the configuration
err = config.ReadFile("testdata/config.yaml", config.Config)
if err != nil {
panic(err)
}
config.Config.LogLevel = config.LOG_LEVEL_OFF
handlers = NewHandlers(config.Config, models)
token = requestToken(handlers)
if err := orm.MapHandlers(models); err != nil {
panic(err)
} }
handlers = NewHandlers(conf, renderer, db, models)
token = requestToken(db, handlers)
} }
func (t *testSuite) TestReadAllContests() { func (t *testSuite) TestReadAllContests() {
@ -155,16 +147,7 @@ func (t *testSuite) TestReadAllContests() {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
req, err = authenticate(req, token, config.Config.Keys.JWTSigningKey) req, err = authenticate(req, token, conf.Keys.JWTSigningKey)
// tkn, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
// return []byte("secret"), nil
// })
// if err != nil {
// panic(err)
// }
// ctx := req.Context()
// ctx = context.WithValue(ctx, "user", tkn)
// req = req.WithContext(ctx)
t.Nil(err) t.Nil(err)
if err != nil { if err != nil {

View file

@ -7,9 +7,7 @@ import (
"strconv" "strconv"
"time" "time"
"git.andreafazzi.eu/andrea/oef/config"
"git.andreafazzi.eu/andrea/oef/orm" "git.andreafazzi.eu/andrea/oef/orm"
"git.andreafazzi.eu/andrea/oef/renderer"
jwt "github.com/dgrijalva/jwt-go" jwt "github.com/dgrijalva/jwt-go"
"github.com/gorilla/sessions" "github.com/gorilla/sessions"
) )
@ -22,6 +20,7 @@ type UserToken struct {
} }
var ( var (
// REMOVE
// signingKey = []byte(config.Config.Keys.JWTSigningKey) // signingKey = []byte(config.Config.Keys.JWTSigningKey)
// store = sessions.NewCookieStore([]byte(config.Config.Keys.CookieStoreKey)) // store = sessions.NewCookieStore([]byte(config.Config.Keys.CookieStoreKey))
@ -59,10 +58,10 @@ func DefaultLogoutHandler(store *sessions.CookieStore) http.Handler {
return http.HandlerFunc(fn) return http.HandlerFunc(fn)
} }
func DefaultLoginHandler(db *orm.Database, store *sessions.CookieStore, signingKey []byte) http.Handler { func (h *Handlers) DefaultLoginHandler(db *orm.Database, store *sessions.CookieStore, signingKey []byte) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) { fn := func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" { if r.Method == "GET" {
renderer.Render["html"](w, r, nil, r.URL.Query()) h.Renderer["html"].Render(w, r, store, nil, r.URL.Query())
} }
if r.Method == "POST" { if r.Method == "POST" {
r.ParseForm() r.ParseForm()
@ -90,13 +89,13 @@ func DefaultLoginHandler(db *orm.Database, store *sessions.CookieStore, signingK
func checkCredential(db *orm.Database, username string, password string) (*UserToken, error) { func checkCredential(db *orm.Database, username string, password string) (*UserToken, error) {
// Check if user is the administrator // Check if user is the administrator
if username == config.Config.Admin.Username && password == config.Config.Admin.Password { if username == db.Config.Admin.Username && password == db.Config.Admin.Password {
return &UserToken{username, true, "administrator", "0"}, nil return &UserToken{username, true, "administrator", "0"}, nil
} }
// Check if user is a subscriber // Check if user is a subscriber
if password == config.Config.Subscriber.Password { if password == db.Config.Subscriber.Password {
return &UserToken{"subscriber", false, "subscriber", "0"}, nil return &UserToken{"subscriber", false, "subscriber", "0"}, nil
} }

View file

@ -6,7 +6,7 @@ keys:
jwt_signing_key: "secret" jwt_signing_key: "secret"
orm: orm:
connection: "oef:oef@tcp(db:3306)/oef_test" connection: "oef:oef@tcp(localhost:3306)/oef_test"
options: "charset=utf8&parseTime=True&loc=Local" options: "charset=utf8&parseTime=True&loc=Local"
automigrate: true automigrate: true
reset: false reset: false

View file

@ -6,7 +6,6 @@ import (
"text/template" "text/template"
"git.andreafazzi.eu/andrea/oef/config" "git.andreafazzi.eu/andrea/oef/config"
"gopkg.in/gomail.v2" "gopkg.in/gomail.v2"
) )
@ -17,45 +16,32 @@ type Subscriber interface {
To() string To() string
} }
var ( type MailSender struct {
mail = ` BodyTemplate string
Spettabile {{.NameForMail}},
grazie per l'interesse manifestato per le Olimpiadi di Economia e Finanza.
Di seguito riportiamo le credenziali di accesso tramite le quali potrà gestire le iscrizioni dei suoi studenti alla competizione (Fase Regionale).
username: {{.Username}}
password: {{.Password}}
Per accedere alla pagina di login occorrerà seguire questo link
https://iscrizioni.olimpiadi-economiaefinanza.it/
ed inserire le credenziali riportate sopra (si consiglia di effettuare un copia/incolla).
Cordialmente,
Lo Staff delle OEF 2020.
`
subject = "[OEF2020] - Credenziali di accesso della scuola"
mailTpl *template.Template mailTpl *template.Template
) config *config.ConfigT
func init() {
mailTpl = template.Must(template.New("subscription_mail").Parse(mail))
} }
func SendSubscriptionMail(rcv Subscriber) error { func NewMailSender(config *config.ConfigT, mailBody string) *MailSender {
ms := new(MailSender)
ms.config = config
ms.mailTpl = template.Must(template.New("subscription_mail").Parse(mailBody))
return ms
}
func (ms *MailSender) SendSubscriptionMail(rcv Subscriber) error {
var body bytes.Buffer var body bytes.Buffer
m := gomail.NewMessage() m := gomail.NewMessage()
m.SetHeader("Subject", subject) m.SetHeader("Subject", ms.config.Smtp.Subject)
m.SetHeader("From", config.Config.Smtp.From) m.SetHeader("From", ms.config.Smtp.From)
m.SetHeader("To", rcv.To()) m.SetHeader("To", rcv.To())
m.SetHeader("Bcc", config.Config.Smtp.Bcc) m.SetHeader("Bcc", ms.config.Smtp.Bcc)
err := mailTpl.Execute(&body, rcv) err := ms.mailTpl.Execute(&body, rcv)
if err != nil { if err != nil {
return err return err
} }
@ -63,10 +49,10 @@ func SendSubscriptionMail(rcv Subscriber) error {
m.SetBody("text/plain", body.String()) m.SetBody("text/plain", body.String())
dialer := gomail.NewDialer( dialer := gomail.NewDialer(
config.Config.Smtp.Host, ms.config.Smtp.Host,
config.Config.Smtp.Port, ms.config.Smtp.Port,
config.Config.Smtp.Username, ms.config.Smtp.Username,
config.Config.Smtp.Password, ms.config.Smtp.Password,
) )
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true} dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}

26
main.go
View file

@ -12,6 +12,7 @@ import (
"git.andreafazzi.eu/andrea/oef/config" "git.andreafazzi.eu/andrea/oef/config"
oef_handlers "git.andreafazzi.eu/andrea/oef/handlers" oef_handlers "git.andreafazzi.eu/andrea/oef/handlers"
"git.andreafazzi.eu/andrea/oef/orm" "git.andreafazzi.eu/andrea/oef/orm"
"git.andreafazzi.eu/andrea/oef/renderer"
) )
const ( const (
@ -41,7 +42,9 @@ func main() {
flag.Parse() flag.Parse()
log.Println("Loading config file...") log.Println("Loading config file...")
err = config.ReadFile(*configFile, config.Config)
conf := new(config.ConfigT)
err = config.ReadFile(*configFile, conf)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -52,7 +55,7 @@ func main() {
wait := true wait := true
for wait && count > 0 { for wait && count > 0 {
db, err = orm.NewDatabase(config.Config, models) db, err = orm.NewDatabase(conf, models)
if err != nil { if err != nil {
count-- count--
log.Println(err) log.Println(err)
@ -66,7 +69,7 @@ func main() {
// REMOVE // REMOVE
// orm.Use(db) // orm.Use(db)
if config.Config.Orm.AutoMigrate { if conf.Orm.AutoMigrate {
log.Print("Automigrating...") log.Print("Automigrating...")
db.AutoMigrate() db.AutoMigrate()
} }
@ -78,7 +81,22 @@ func main() {
orm.CreateRegions(db) orm.CreateRegions(db)
log.Println("OEF is listening to port 3000...") log.Println("OEF is listening to port 3000...")
if err := http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, oef_handlers.NewHandlers(config.Config, db, models).Router)); err != nil {
htmlRenderer, err := renderer.NewHTMLRenderer("templates")
if err != nil {
panic(err)
}
jsonRenderer, err := renderer.NewJSONRenderer()
if err != nil {
panic(err)
}
renderer := map[string]renderer.Renderer{
"html": htmlRenderer,
"json": jsonRenderer,
}
if err := http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, oef_handlers.NewHandlers(conf, renderer, db, models).Router)); err != nil {
panic(err) panic(err)
} }

View file

@ -34,6 +34,8 @@ func NewDatabase(config *config.ConfigT, models []interface{}) (*Database, error
db := new(Database) db := new(Database)
db.Config = config
db.fns = make(map[string]func(*Database, map[string]string, http.ResponseWriter, *http.Request) (interface{}, error), 0) db.fns = make(map[string]func(*Database, map[string]string, http.ResponseWriter, *http.Request) (interface{}, error), 0)
db.mapHandlers(models) db.mapHandlers(models)
@ -52,11 +54,11 @@ func (db *Database) AutoMigrate() {
} }
func (db *Database) GetUser(username, password string) (*User, error) { func (db *Database) GetUser(username, password string) (*User, error) {
var user *User var user User
if err := db._db.Where("username = ? AND password = ?", username, password).First(&user).Error; err != nil { if err := db._db.Where("username = ? AND password = ?", username, password).First(&user).Error; err != nil {
return nil, errors.New("Authentication failed!") return nil, errors.New("Authentication failed!")
} }
return user, nil return &user, nil
} }
func (db *Database) DB() *gorm.DB { func (db *Database) DB() *gorm.DB {

View file

@ -210,7 +210,7 @@ func (model *Participant) Create(db *Database, args map[string]string, w http.Re
return nil, errors.CategoryExists return nil, errors.CategoryExists
} }
participant.UserModifierCreate = NewUserModifierCreate(r) participant.UserModifierCreate = NewUserModifierCreate(db, r)
participant, err = CreateParticipant(db, participant) participant, err = CreateParticipant(db, participant)
if err != nil { if err != nil {
@ -223,7 +223,7 @@ func (model *Participant) Create(db *Database, args map[string]string, w http.Re
return nil, err return nil, err
} }
response.UserModifierCreate = NewUserModifierCreate(r) response.UserModifierCreate = NewUserModifierCreate(db, r)
if err := db._db.Save(&response).Error; err != nil { if err := db._db.Save(&response).Error; err != nil {
return nil, err return nil, err
@ -362,7 +362,7 @@ func (model *Participant) Update(db *Database, args map[string]string, w http.Re
return nil, err return nil, err
} }
participant.(*Participant).UserModifierUpdate = NewUserModifierUpdate(r) participant.(*Participant).UserModifierUpdate = NewUserModifierUpdate(db, r)
_, err = SaveParticipant(db, participant) _, err = SaveParticipant(db, participant)
if err != nil { if err != nil {
@ -384,7 +384,7 @@ func (model *Participant) Update(db *Database, args map[string]string, w http.Re
return nil, err return nil, err
} }
response.UserModifierUpdate = NewUserModifierUpdate(r) response.UserModifierUpdate = NewUserModifierUpdate(db, r)
if err := db._db.Save(&response).Error; err != nil { if err := db._db.Save(&response).Error; err != nil {
return nil, err return nil, err

View file

@ -94,7 +94,7 @@ func (model *Response) Create(db *Database, args map[string]string, w http.Respo
return nil, err return nil, err
} }
response.UserModifierCreate = NewUserModifierCreate(r) response.UserModifierCreate = NewUserModifierCreate(db, r)
response, err = CreateResponse(db, response) response, err = CreateResponse(db, response)
if err != nil { if err != nil {
@ -139,7 +139,6 @@ func (model *Response) Read(db *Database, args map[string]string, w http.Respons
qOrder := make([]uint, 0) qOrder := make([]uint, 0)
qIDs := strings.Split(response.QuestionsOrder, " ") qIDs := strings.Split(response.QuestionsOrder, " ")
log.Print("QO", response.QuestionsOrder)
for _, id := range qIDs { for _, id := range qIDs {
id, err := strconv.Atoi(id) id, err := strconv.Atoi(id)
if err != nil { if err != nil {
@ -212,7 +211,7 @@ func (model *Response) Update(db *Database, args map[string]string, w http.Respo
return nil, err return nil, err
} }
response.(*Response).UserModifierUpdate = NewUserModifierUpdate(r) response.(*Response).UserModifierUpdate = NewUserModifierUpdate(db, r)
_, err = SaveResponse(db, response) _, err = SaveResponse(db, response)
if err != nil { if err != nil {

View file

@ -14,6 +14,26 @@ import (
type RegionID uint type RegionID uint
var mailBody = `
Spettabile {{.NameForMail}},
grazie per l'interesse manifestato per le Olimpiadi di Economia e Finanza.
Di seguito riportiamo le credenziali di accesso tramite le quali potrà gestire le iscrizioni dei suoi studenti alla competizione (Fase Regionale).
username: {{.Username}}
password: {{.Password}}
Per accedere alla pagina di login occorrerà seguire questo link
https://iscrizioni.olimpiadi-economiaefinanza.it/
ed inserire le credenziali riportate sopra (si consiglia di effettuare un copia/incolla).
Cordialmente,
Lo Staff delle OEF 2020.
`
type School struct { type School struct {
gorm.Model gorm.Model
@ -41,6 +61,8 @@ type School struct {
SelectedRegion map[uint]string `gorm:"-"` SelectedRegion map[uint]string `gorm:"-"`
AllRegions []*Region `gorm:"-"` AllRegions []*Region `gorm:"-"`
mailSender *mail.MailSender
} }
func (id *RegionID) UnmarshalCSV(csv string) error { func (id *RegionID) UnmarshalCSV(csv string) error {
@ -107,7 +129,7 @@ func (model *School) AfterCreate(tx *gorm.DB) error {
if err := tx.Preload("User").First(model).Error; err != nil { if err := tx.Preload("User").First(model).Error; err != nil {
return err return err
} }
if err := mail.SendSubscriptionMail(model); err != nil { if err := model.mailSender.SendSubscriptionMail(model); err != nil {
return err return err
} }
@ -148,8 +170,9 @@ func (model *School) Create(db *Database, args map[string]string, w http.Respons
return nil, err return nil, err
} }
school.UserModifierCreate = NewUserModifierCreate(r) school.UserModifierCreate = NewUserModifierCreate(db, r)
school.mailSender = mail.NewMailSender(db.Config, mailBody)
school, err = CreateSchool(db, school) school, err = CreateSchool(db, school)
if err != nil { if err != nil {
return nil, err return nil, err
@ -223,7 +246,7 @@ func (model *School) Update(db *Database, args map[string]string, w http.Respons
return nil, err return nil, err
} }
school.(*School).UserModifierUpdate = NewUserModifierUpdate(r) school.(*School).UserModifierUpdate = NewUserModifierUpdate(db, r)
_, err = SaveSchool(db, school) _, err = SaveSchool(db, school)
if err != nil { if err != nil {

View file

@ -17,15 +17,19 @@ type UserModifierCreate struct {
CreatorID string CreatorID string
CreatorRole string CreatorRole string
CreatorIP string CreatorIP string
db *Database
} }
type UserModifierUpdate struct { type UserModifierUpdate struct {
UpdaterID string UpdaterID string
UpdaterRole string UpdaterRole string
UpdaterIP string UpdaterIP string
db *Database
} }
func NewUserModifierCreate(r *http.Request) *UserModifierCreate { func NewUserModifierCreate(db *Database, r *http.Request) *UserModifierCreate {
var claims jwt.MapClaims var claims jwt.MapClaims
if r.Context().Value("user") != nil { if r.Context().Value("user") != nil {
@ -39,20 +43,20 @@ func NewUserModifierCreate(r *http.Request) *UserModifierCreate {
} }
} }
func (um *UserModifierCreate) CreatedBy(db *Database) (*UserAction, error) { func (um *UserModifierCreate) CreatedBy() (*UserAction, error) {
action := new(UserAction) action := new(UserAction)
switch um.CreatorRole { switch um.CreatorRole {
case "participant": case "participant":
var participant Participant var participant Participant
if err := db._db.Preload("User").First(&participant, um.CreatorID).Error; err != nil { if err := um.db._db.Preload("User").First(&participant, um.CreatorID).Error; err != nil {
return nil, err return nil, err
} }
action.User = *participant.User action.User = *participant.User
case "school": case "school":
var school School var school School
if err := db._db.Preload("User").First(&school, um.CreatorID).Error; err != nil { if err := um.db._db.Preload("User").First(&school, um.CreatorID).Error; err != nil {
return nil, err return nil, err
} }
action.User = *school.User action.User = *school.User
@ -67,7 +71,7 @@ func (um *UserModifierCreate) CreatedBy(db *Database) (*UserAction, error) {
return action, nil return action, nil
} }
func NewUserModifierUpdate(r *http.Request) *UserModifierUpdate { func NewUserModifierUpdate(db *Database, r *http.Request) *UserModifierUpdate {
var claims jwt.MapClaims var claims jwt.MapClaims
if r.Context().Value("user") != nil { if r.Context().Value("user") != nil {
@ -80,19 +84,19 @@ func NewUserModifierUpdate(r *http.Request) *UserModifierUpdate {
} }
} }
func (um *UserModifierUpdate) UpdatedBy(db *Database) (*UserAction, error) { func (um *UserModifierUpdate) UpdatedBy() (*UserAction, error) {
action := new(UserAction) action := new(UserAction)
switch um.UpdaterRole { switch um.UpdaterRole {
case "participant": case "participant":
var participant Participant var participant Participant
if err := db._db.Preload("User").First(&participant, um.UpdaterID).Error; err != nil { if err := um.db._db.Preload("User").First(&participant, um.UpdaterID).Error; err != nil {
return nil, err return nil, err
} }
action.User = *participant.User action.User = *participant.User
case "school": case "school":
var school School var school School
if err := db._db.Preload("User").First(&school, um.UpdaterID).Error; err != nil { if err := um.db._db.Preload("User").First(&school, um.UpdaterID).Error; err != nil {
return nil, err return nil, err
} }
action.User = *school.User action.User = *school.User

View file

@ -8,9 +8,6 @@ import (
"io" "io"
"log" "log"
"git.andreafazzi.eu/andrea/oef/config"
"git.andreafazzi.eu/andrea/oef/errors"
"github.com/gorilla/sessions"
"mime" "mime"
"net/http" "net/http"
"net/url" "net/url"
@ -21,14 +18,17 @@ import (
"strings" "strings"
"time" "time"
"git.andreafazzi.eu/andrea/oef/errors"
"github.com/gocarina/gocsv" "github.com/gocarina/gocsv"
"github.com/gorilla/schema" "github.com/gorilla/schema"
"github.com/gorilla/sessions"
jwt "github.com/dgrijalva/jwt-go" jwt "github.com/dgrijalva/jwt-go"
) )
type Renderer interface { type Renderer interface {
Render(http.ResponseWriter, *http.Request, interface{}, ...url.Values) error Render(http.ResponseWriter, *http.Request, *sessions.CookieStore, interface{}, ...url.Values) error
} }
type JSONRenderer struct{} type JSONRenderer struct{}
@ -48,9 +48,10 @@ type JsonResponse struct {
} }
var ( var (
store = sessions.NewCookieStore([]byte(config.Config.Keys.CookieStoreKey)) // REMOVE
currRenderer Renderer // store = sessions.NewCookieStore([]byte(config.Config.Keys.CookieStoreKey))
Render map[string]func(http.ResponseWriter, *http.Request, interface{}, ...url.Values) // currRenderer Renderer
// Render map[string]func(http.ResponseWriter, *http.Request, *sessions.CookieStore, interface{}, ...url.Values)
contentTypeToFormat = map[string]string{ contentTypeToFormat = map[string]string{
"application/x-www-form-urlencoded": "html", "application/x-www-form-urlencoded": "html",
@ -62,43 +63,44 @@ var (
) )
func init() { func init() {
htmlRenderer, err := NewHTMLRenderer("templates/") //REMOVE
if err != nil { // htmlRenderer, err := NewHTMLRenderer("templates/")
panic(err) // if err != nil {
} // panic(err)
// }
jsonRenderer, err := NewJSONRenderer() // jsonRenderer, err := NewJSONRenderer()
if err != nil { // if err != nil {
panic(err) // panic(err)
} // }
csvRenderer, err := NewCSVRenderer() // csvRenderer, err := NewCSVRenderer()
if err != nil { // if err != nil {
panic(err) // panic(err)
} // }
pdfRenderer, err := NewPDFRenderer() // pdfRenderer, err := NewPDFRenderer()
if err != nil { // if err != nil {
panic(err) // panic(err)
} // }
Render = make(map[string]func(http.ResponseWriter, *http.Request, interface{}, ...url.Values)) // Render = make(map[string]func(http.ResponseWriter, *http.Request, *sessions.CookieStore, interface{}, ...url.Values))
Render["html"] = func(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) { // Render["html"] = func(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) {
htmlRenderer.Render(w, r, data, options...) // htmlRenderer.Render(w, r, store, data, options...)
} // }
Render["json"] = func(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) { // Render["json"] = func(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) {
jsonRenderer.Render(w, r, data, options...) // jsonRenderer.Render(w, r, store, data, options...)
} // }
Render["csv"] = func(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) { // Render["csv"] = func(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) {
csvRenderer.Render(w, r, data, options...) // csvRenderer.Render(w, r, data, options...)
} // }
Render["pdf"] = func(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) { // Render["pdf"] = func(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) {
pdfRenderer.Render(w, r, data, options...) // pdfRenderer.Render(w, r, data, options...)
} // }
} }
@ -115,7 +117,7 @@ func NewJSONRenderer() (*JSONRenderer, error) {
return &JSONRenderer{}, nil return &JSONRenderer{}, nil
} }
func (rend *JSONRenderer) Render(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) error { func (rend *JSONRenderer) Render(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
if isErrorType(data) { if isErrorType(data) {
j, err := json.Marshal(JsonResponse{nil, []byte(data.(error).Error())}) j, err := json.Marshal(JsonResponse{nil, []byte(data.(error).Error())})
@ -225,9 +227,10 @@ func NewHTMLRenderer(templatePath string) (*HTMLRenderer, error) {
return r, nil return r, nil
} }
func Use(r Renderer) { // REMOVE
currRenderer = r // func Use(r Renderer) {
} // currRenderer = r
// }
func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, data interface{}) { func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, data interface{}) {
var t *template.Template var t *template.Template
@ -255,7 +258,7 @@ func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, dat
} }
} }
func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) { func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) error {
var claims jwt.MapClaims var claims jwt.MapClaims
if r.Context().Value("user") != nil { if r.Context().Value("user") != nil {
@ -266,18 +269,22 @@ func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, data in
session, err := store.Get(r, "flash-session") session, err := store.Get(r, "flash-session")
if err != nil { if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil}) rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil})
return err
} }
fm := session.Flashes() fm := session.Flashes()
err = session.Save(r, w) err = session.Save(r, w)
if err != nil { if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm}) rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm})
return err
} }
rend.writeError(w, r, &htmlTemplateData{data.(error), nil, claims, fm}) rend.writeError(w, r, &htmlTemplateData{data.(error), nil, claims, fm})
return err
} else { } else {
t, ok := rend.templates[options[0]["tpl_content"][0]] t, ok := rend.templates[options[0]["tpl_content"][0]]
if !ok { if !ok {
err := fmt.Errorf("Template %s not found", options[0]["tpl_content"][0]) err := fmt.Errorf("Template %s not found", options[0]["tpl_content"][0])
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil}) rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil})
return err
} }
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
@ -285,18 +292,22 @@ func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, data in
session, err := store.Get(r, "flash-session") session, err := store.Get(r, "flash-session")
if err != nil { if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil}) rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil})
return err
} }
fm := session.Flashes() fm := session.Flashes()
err = session.Save(r, w) err = session.Save(r, w)
if err != nil { if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm}) rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm})
return err
} }
err = t.ExecuteTemplate(w, options[0]["tpl_layout"][0], &htmlTemplateData{data, options[0], claims, fm}) err = t.ExecuteTemplate(w, options[0]["tpl_layout"][0], &htmlTemplateData{data, options[0], claims, fm})
if err != nil { if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm}) rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm})
return err
} }
} }
return nil
} }
func GetContentFormat(r *http.Request) string { func GetContentFormat(r *http.Request) string {