Introducing flash messages and i18n support

This commit is contained in:
Andrea Fazzi 2019-12-03 11:14:29 +01:00
parent 2fb6cda55c
commit 65f0aeadd0
12 changed files with 155 additions and 74 deletions

View file

@ -21,6 +21,10 @@ type ConfigT struct {
Url string
Domain string
// Language
Language string
// Logging
LogLevel int `yaml:"log_level"`

View file

@ -180,7 +180,7 @@ func get(w http.ResponseWriter, r *http.Request, model string, pattern PathPatte
log.Println("Error:", err)
respondWithError(w, r, err)
} else {
data, err := getFn(mux.Vars(r), r)
data, err := getFn(mux.Vars(r), w, r)
if err != nil {
renderer.Render[format](w, r, err)
} else {
@ -202,7 +202,7 @@ func post(w http.ResponseWriter, r *http.Request, model string, pattern PathPatt
if err != nil {
respondWithError(w, r, err)
} else {
data, err = postFn(mux.Vars(r), r)
data, err = postFn(mux.Vars(r), w, r)
if err != nil {
respondWithError(w, r, err)
} else if pattern.RedirectPattern != "" {
@ -232,7 +232,7 @@ func delete(w http.ResponseWriter, r *http.Request, model string, pattern PathPa
if err != nil {
renderer.Render[r.URL.Query().Get("format")](w, r, err)
}
data, err = postFn(mux.Vars(r), r)
data, err = postFn(mux.Vars(r), w, r)
if err != nil {
renderer.Render["html"](w, r, err)
} else if pattern.RedirectPattern != "" {

9
i18n/i18n.go Normal file
View file

@ -0,0 +1,9 @@
package i18n
var (
FlashMessages = map[string]map[string]string{
"participantExists": map[string]string{
"it": "Un partecipante con questo codice fiscale è già presente nella base dati!",
},
}
)

View file

@ -26,7 +26,7 @@ func (a *Answer) String() string {
return a.Text
}
func (a *Answer) Create(args map[string]string, r *http.Request) (interface{}, error) {
func (a *Answer) Create(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
answer := new(Answer)
if err := DB().Find(&answer.AllQuestions).Error; err != nil {
@ -48,7 +48,7 @@ func (a *Answer) Create(args map[string]string, r *http.Request) (interface{}, e
}
}
func (a *Answer) Read(args map[string]string, r *http.Request) (interface{}, error) {
func (a *Answer) Read(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var answer Answer
id := args["id"]
@ -60,7 +60,7 @@ func (a *Answer) Read(args map[string]string, r *http.Request) (interface{}, err
return &answer, nil
}
func (a *Answer) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
func (a *Answer) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var answers []*Answer
if err := DB().Preload("Question").Order("created_at").Find(&answers).Error; err != nil {
return nil, err
@ -68,9 +68,9 @@ func (a *Answer) ReadAll(args map[string]string, r *http.Request) (interface{},
return answers, nil
}
func (a *Answer) Update(args map[string]string, r *http.Request) (interface{}, error) {
func (a *Answer) Update(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
result, err := a.Read(args, r)
result, err := a.Read(args, w, r)
if err != nil {
return nil, err
}
@ -86,7 +86,7 @@ func (a *Answer) Update(args map[string]string, r *http.Request) (interface{}, e
return answer, nil
} else {
answer, err := a.Read(args, nil)
answer, err := a.Read(args, w, r)
if err != nil {
return nil, err
}
@ -102,7 +102,7 @@ func (a *Answer) Update(args map[string]string, r *http.Request) (interface{}, e
if err != nil {
return nil, err
}
answer, err = a.Read(args, nil)
answer, err = a.Read(args, w, r)
if err != nil {
return nil, err
}
@ -110,7 +110,7 @@ func (a *Answer) Update(args map[string]string, r *http.Request) (interface{}, e
}
}
func (a *Answer) Delete(args map[string]string, r *http.Request) (interface{}, error) {
func (a *Answer) Delete(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
return nil, nil
}

View file

@ -31,7 +31,7 @@ func (c *Contest) String() string {
return c.Name
}
func (c *Contest) Create(args map[string]string, r *http.Request) (interface{}, error) {
func (c *Contest) Create(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
return nil, nil
} else {
@ -69,7 +69,7 @@ func (c *Contest) Create(args map[string]string, r *http.Request) (interface{},
}
}
func (c *Contest) Read(args map[string]string, r *http.Request) (interface{}, error) {
func (c *Contest) Read(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var contest Contest
id := args["id"]
@ -81,7 +81,7 @@ func (c *Contest) Read(args map[string]string, r *http.Request) (interface{}, er
return &contest, nil
}
func (c *Contest) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
func (c *Contest) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var contests []*Contest
claims := r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
@ -103,9 +103,9 @@ func (c *Contest) ReadAll(args map[string]string, r *http.Request) (interface{},
}
}
func (c *Contest) Update(args map[string]string, r *http.Request) (interface{}, error) {
func (c *Contest) Update(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
result, err := c.Read(args, r)
result, err := c.Read(args, w, r)
if err != nil {
return nil, err
}
@ -113,7 +113,7 @@ func (c *Contest) Update(args map[string]string, r *http.Request) (interface{},
return contest, nil
} else {
contest, err := c.Read(args, nil)
contest, err := c.Read(args, w, r)
if err != nil {
return nil, err
}
@ -146,7 +146,7 @@ func (c *Contest) Update(args map[string]string, r *http.Request) (interface{},
if err != nil {
return nil, err
}
contest, err = c.Read(args, nil)
contest, err = c.Read(args, w, r)
if err != nil {
return nil, err
}
@ -154,7 +154,7 @@ func (c *Contest) Update(args map[string]string, r *http.Request) (interface{},
}
}
func (c *Contest) Delete(args map[string]string, r *http.Request) (interface{}, error) {
func (c *Contest) Delete(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
return nil, nil
}

View file

@ -7,6 +7,8 @@ import (
"reflect"
"strings"
"git.andreafazzi.eu/andrea/oef/config"
"github.com/gorilla/sessions"
"github.com/jinzhu/gorm"
"github.com/jinzhu/inflection"
@ -17,15 +19,16 @@ type IDer interface {
GetID() uint
}
type GetFn func(map[string]string, *http.Request) (interface{}, error)
type GetFn func(map[string]string, http.ResponseWriter, *http.Request) (interface{}, error)
var (
fns map[string]func(map[string]string, *http.Request) (interface{}, error)
fns map[string]func(map[string]string, http.ResponseWriter, *http.Request) (interface{}, error)
currDB *gorm.DB
store = sessions.NewCookieStore([]byte(config.Config.Keys.CookieStoreKey))
)
func init() {
fns = make(map[string]func(map[string]string, *http.Request) (interface{}, error), 0)
fns = make(map[string]func(map[string]string, http.ResponseWriter, *http.Request) (interface{}, error), 0)
}
func New(connection string) (*gorm.DB, error) {
@ -69,7 +72,7 @@ func MapHandlers(models []interface{}) error {
if strings.HasSuffix(p, "/") {
joinedPath += "/"
}
fns[joinedPath] = method.Interface().(func(map[string]string, *http.Request) (interface{}, error))
fns[joinedPath] = method.Interface().(func(map[string]string, http.ResponseWriter, *http.Request) (interface{}, error))
}
}
@ -89,7 +92,7 @@ func GetNothing(args map[string]string) (interface{}, error) {
return nil, nil
}
func PostNothing(args map[string]string, r *http.Request) (IDer, error) {
func PostNothing(args map[string]string, w http.ResponseWriter, r *http.Request) (IDer, error) {
return nil, nil
}

View file

@ -6,7 +6,8 @@ import (
"net/http"
"strings"
"git.andreafazzi.eu/andrea/oef/errors"
"git.andreafazzi.eu/andrea/oef/config"
"git.andreafazzi.eu/andrea/oef/i18n"
"git.andreafazzi.eu/andrea/oef/renderer"
"github.com/jinzhu/gorm"
)
@ -49,16 +50,30 @@ func (model *Participant) String() string {
return fmt.Sprintf("%s %s", strings.ToUpper(model.Lastname), strings.Title(strings.ToLower(model.Firstname)))
}
func (model *Participant) BeforeSave(tx *gorm.DB) error {
users := make([]*User, 0)
if err := tx.Where("username = ?", model.FiscalCode).Find(&users).Error; err != nil {
func setFlashMessage(w http.ResponseWriter, r *http.Request, key string) error {
session, err := store.Get(r, "flash-session")
if err != nil {
return err
}
if len(users) > 0 {
return errors.RecordExists
session.AddFlash(i18n.FlashMessages[key][config.Config.Language])
err = session.Save(r, w)
if err != nil {
return err
}
return nil
}
func (model *Participant) exists() (*User, error) {
var user User
if err := DB().First(&user, &User{Username: model.username()}).Error; err != nil && err != gorm.ErrRecordNotFound {
return nil, err
} else if err == gorm.ErrRecordNotFound {
return nil, nil
}
return &user, nil
}
func (model *Participant) BeforeSave(tx *gorm.DB) error {
var user User
if err := tx.FirstOrCreate(&user, &User{
Username: model.username(),
@ -93,7 +108,7 @@ func (model *Participant) AfterDelete(tx *gorm.DB) error {
return nil
}
func (model *Participant) Create(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Participant) Create(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
participant := new(Participant)
if err := DB().Find(&participant.AllContests).Error; err != nil {
@ -107,6 +122,19 @@ func (model *Participant) Create(args map[string]string, r *http.Request) (inter
return nil, err
}
if user, err := participant.exists(); err == nil && user != nil {
if err := DB().Where("user_id = ?", user.ID).Find(&participant).Error; err != nil {
return nil, err
}
err := setFlashMessage(w, r, "participantExists")
if err != nil {
return nil, err
}
return participant, nil
} else if err != nil {
return nil, err
}
participant, err = CreateParticipant(participant)
if err != nil {
return nil, err
@ -115,7 +143,7 @@ func (model *Participant) Create(args map[string]string, r *http.Request) (inter
}
}
func (model *Participant) Read(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Participant) Read(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var participant Participant
id := args["id"]
@ -127,7 +155,7 @@ func (model *Participant) Read(args map[string]string, r *http.Request) (interfa
return &participant, nil
}
func (model *Participant) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Participant) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var participants []*Participant
if err := DB().Preload("Contests").Preload("Responses").Order("created_at").Find(&participants).Error; err != nil {
return nil, err
@ -135,9 +163,9 @@ func (model *Participant) ReadAll(args map[string]string, r *http.Request) (inte
return participants, nil
}
func (model *Participant) Update(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Participant) Update(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
result, err := model.Read(args, r)
result, err := model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -155,7 +183,7 @@ func (model *Participant) Update(args map[string]string, r *http.Request) (inter
return participant, nil
} else {
participant, err := model.Read(args, nil)
participant, err := model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -164,6 +192,18 @@ func (model *Participant) Update(args map[string]string, r *http.Request) (inter
return nil, err
}
if user, err := participant.(*Participant).exists(); err == nil && user != nil {
if user.ID != participant.(*Participant).UserID {
err := setFlashMessage(w, r, "participantExists")
if err != nil {
return nil, err
}
return participant, nil
}
} else if err != nil {
return nil, err
}
if err := DB().Where(participant.(*Participant).ContestIDs).Find(&participant.(*Participant).Contests).Error; err != nil {
return nil, err
}
@ -177,7 +217,7 @@ func (model *Participant) Update(args map[string]string, r *http.Request) (inter
return nil, err
}
participant, err = model.Read(args, nil)
participant, err = model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -185,8 +225,8 @@ func (model *Participant) Update(args map[string]string, r *http.Request) (inter
}
}
func (model *Participant) Delete(args map[string]string, r *http.Request) (interface{}, error) {
participant, err := model.Read(args, nil)
func (model *Participant) Delete(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
participant, err := model.Read(args, w, r)
if err != nil {
return nil, err
}

View file

@ -26,7 +26,7 @@ func (q *Question) String() string {
return q.Text
}
func (q *Question) Create(args map[string]string, r *http.Request) (interface{}, error) {
func (q *Question) Create(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
question := new(Question)
if err := DB().Find(&question.AllContests).Error; err != nil {
@ -47,7 +47,7 @@ func (q *Question) Create(args map[string]string, r *http.Request) (interface{},
}
}
func (q *Question) Read(args map[string]string, r *http.Request) (interface{}, error) {
func (q *Question) Read(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var question Question
id := args["id"]
@ -59,7 +59,7 @@ func (q *Question) Read(args map[string]string, r *http.Request) (interface{}, e
return &question, nil
}
func (q *Question) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
func (q *Question) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var questions []*Question
if err := DB().Preload("Contest").Order("created_at").Find(&questions).Error; err != nil {
return nil, err
@ -67,9 +67,9 @@ func (q *Question) ReadAll(args map[string]string, r *http.Request) (interface{}
return questions, nil
}
func (q *Question) Update(args map[string]string, r *http.Request) (interface{}, error) {
func (q *Question) Update(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
result, err := q.Read(args, r)
result, err := q.Read(args, w, r)
if err != nil {
return nil, err
}
@ -85,7 +85,7 @@ func (q *Question) Update(args map[string]string, r *http.Request) (interface{},
return question, nil
} else {
question, err := q.Read(args, nil)
question, err := q.Read(args, w, r)
if err != nil {
return nil, err
}
@ -97,7 +97,7 @@ func (q *Question) Update(args map[string]string, r *http.Request) (interface{},
if err != nil {
return nil, err
}
question, err = q.Read(args, nil)
question, err = q.Read(args, w, r)
if err != nil {
return nil, err
}
@ -105,7 +105,7 @@ func (q *Question) Update(args map[string]string, r *http.Request) (interface{},
}
}
func (q *Question) Delete(args map[string]string, r *http.Request) (interface{}, error) {
func (q *Question) Delete(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
return nil, nil
}

View file

@ -30,7 +30,7 @@ func (model *Response) String() string {
return model.Name
}
func (model *Response) Create(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Response) Create(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
response := new(Response)
contestID := r.URL.Query().Get("contest_id")
@ -53,7 +53,7 @@ func (model *Response) Create(args map[string]string, r *http.Request) (interfac
}
}
func (model *Response) Read(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Response) Read(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var response Response
id := args["id"]
@ -65,7 +65,7 @@ func (model *Response) Read(args map[string]string, r *http.Request) (interface{
return &response, nil
}
func (model *Response) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Response) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var responses []*Response
if err := DB().Preload("Contest", "Participant").Order("created_at").Find(&responses).Error; err != nil {
return nil, err
@ -73,9 +73,9 @@ func (model *Response) ReadAll(args map[string]string, r *http.Request) (interfa
return responses, nil
}
func (model *Response) Update(args map[string]string, r *http.Request) (interface{}, error) {
func (model *Response) Update(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
result, err := model.Read(args, r)
result, err := model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -91,7 +91,7 @@ func (model *Response) Update(args map[string]string, r *http.Request) (interfac
return response, nil
} else {
response, err := model.Read(args, nil)
response, err := model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -103,7 +103,7 @@ func (model *Response) Update(args map[string]string, r *http.Request) (interfac
if err != nil {
return nil, err
}
response, err = model.Read(args, nil)
response, err = model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -111,8 +111,8 @@ func (model *Response) Update(args map[string]string, r *http.Request) (interfac
}
}
func (model *Response) Delete(args map[string]string, r *http.Request) (interface{}, error) {
response, err := model.Read(args, nil)
func (model *Response) Delete(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
response, err := model.Read(args, w, r)
if err != nil {
return nil, err
}

View file

@ -42,7 +42,7 @@ func (model *User) BeforeSave(tx *gorm.DB) error {
return nil
}
func (model *User) Create(args map[string]string, r *http.Request) (interface{}, error) {
func (model *User) Create(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
user := new(User)
// if err := DB().Find(&user.AllContests).Error; err != nil {
@ -63,7 +63,7 @@ func (model *User) Create(args map[string]string, r *http.Request) (interface{},
}
}
func (model *User) Read(args map[string]string, r *http.Request) (interface{}, error) {
func (model *User) Read(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var user User
id := args["id"]
@ -75,7 +75,7 @@ func (model *User) Read(args map[string]string, r *http.Request) (interface{}, e
return &user, nil
}
func (model *User) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
func (model *User) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
var users []*User
if err := DB(). /*.Preload("Something")*/ Order("created_at").Find(&users).Error; err != nil {
return nil, err
@ -83,9 +83,9 @@ func (model *User) ReadAll(args map[string]string, r *http.Request) (interface{}
return users, nil
}
func (model *User) Update(args map[string]string, r *http.Request) (interface{}, error) {
func (model *User) Update(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
if r.Method == "GET" {
result, err := model.Read(args, r)
result, err := model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -101,7 +101,7 @@ func (model *User) Update(args map[string]string, r *http.Request) (interface{},
return user, nil
} else {
user, err := model.Read(args, nil)
user, err := model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -113,7 +113,7 @@ func (model *User) Update(args map[string]string, r *http.Request) (interface{},
if err != nil {
return nil, err
}
user, err = model.Read(args, nil)
user, err = model.Read(args, w, r)
if err != nil {
return nil, err
}
@ -121,8 +121,8 @@ func (model *User) Update(args map[string]string, r *http.Request) (interface{},
}
}
func (model *User) Delete(args map[string]string, r *http.Request) (interface{}, error) {
user, err := model.Read(args, nil)
func (model *User) Delete(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) {
user, err := model.Read(args, w, r)
if err != nil {
return nil, err
}

View file

@ -8,6 +8,8 @@ import (
"io"
"log"
"git.andreafazzi.eu/andrea/oef/config"
"github.com/gorilla/sessions"
"mime"
"net/http"
"net/url"
@ -33,10 +35,10 @@ type CSVRenderer struct{}
type PDFRenderer struct{}
type htmlTemplateData struct {
Data interface{}
Options url.Values
Claims jwt.MapClaims
Error error
Data interface{}
Options url.Values
Claims jwt.MapClaims
FlashMessages []interface{}
}
type JsonResponse struct {
@ -45,6 +47,7 @@ type JsonResponse struct {
}
var (
store = sessions.NewCookieStore([]byte(config.Config.Keys.CookieStoreKey))
currRenderer Renderer
Render map[string]func(http.ResponseWriter, *http.Request, interface{}, ...url.Values)
@ -241,12 +244,12 @@ 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) {
if data != nil && isErrorType(data) {
rend.writeError(w, r, &htmlTemplateData{data.(error), nil, nil, data.(error)})
rend.writeError(w, r, &htmlTemplateData{data.(error), nil, nil, nil})
} else {
t, ok := rend.templates[options[0]["tpl_content"][0]]
if !ok {
err := fmt.Errorf("Template %s not found", options[0]["tpl_content"][0])
rend.writeError(w, r, &htmlTemplateData{err, nil, nil, err})
rend.writeError(w, r, &htmlTemplateData{err, nil, nil, nil})
}
var claims jwt.MapClaims
@ -256,9 +259,20 @@ func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, data in
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
err := t.ExecuteTemplate(w, options[0]["tpl_layout"][0], &htmlTemplateData{data, options[0], claims, nil})
session, err := store.Get(r, "flash-session")
if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, nil, err})
rend.writeError(w, r, &htmlTemplateData{err, nil, nil, nil})
}
fm := session.Flashes()
err = session.Save(r, w)
if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, nil, nil})
}
err = t.ExecuteTemplate(w, options[0]["tpl_layout"][0], &htmlTemplateData{data, options[0], claims, fm})
if err != nil {
rend.writeError(w, r, &htmlTemplateData{err, nil, nil, nil})
}
}
}

View file

@ -36,6 +36,17 @@
</div><!--/.nav-collapse -->
</nav>
{{if .FlashMessages}}
{{range $message := .FlashMessages}}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>Attenzione!</strong> {{$message}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{{end}}
{{end}}
<div class="base-template">
{{ template "content" . }}
</div>