Merge branch 'fix_errors'
This commit is contained in:
commit
f09fc930c1
19 changed files with 198 additions and 126 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
0.4.2-7-gf33e5bc-master
|
||||
0.4.2-10-g9d99f56-fix_errors
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
url: "http://localhost:3000"
|
||||
log_level: 2
|
||||
language: "it"
|
||||
jwt_expire_time: 1
|
||||
jwt_expire_time: 60
|
||||
|
||||
keys:
|
||||
cookie_store_key: "something-very-secret"
|
||||
|
|
|
@ -10,6 +10,7 @@ type Error struct {
|
|||
TemplateName string
|
||||
Err error
|
||||
Referer string
|
||||
Title string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
|
@ -20,6 +21,7 @@ var (
|
|||
RecordExists = errors.New("Record already exists!")
|
||||
|
||||
NotAuthorized = &Error{
|
||||
Title: "Errore di autenticazione",
|
||||
TemplateName: "error_not_authorized",
|
||||
Err: errors.New(i18n.Authorization["notAuthorized"]["it"]),
|
||||
}
|
||||
|
|
|
@ -47,10 +47,10 @@ type Handlers struct {
|
|||
|
||||
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) handlerFuncWithError
|
||||
Logout func(store *sessions.CookieStore) http.Handler
|
||||
Home func() http.Handler
|
||||
GetToken func(db *orm.Database, signingKey []byte) http.Handler
|
||||
GetToken func(db *orm.Database, signingKey []byte) handlerFuncWithError
|
||||
Static func() http.Handler
|
||||
Recover func(next http.Handler) http.Handler
|
||||
|
||||
|
@ -174,12 +174,12 @@ func NewHandlers(config *config.ConfigT, renderer map[string]renderer.Renderer,
|
|||
|
||||
// Authentication
|
||||
|
||||
r.Handle("/login", handlers.Login(handlers.Database, handlers.CookieStore, []byte(config.Keys.JWTSigningKey)))
|
||||
r.Handle("/login", newRootMiddleware(handlers, handlers.Login(handlers.Database, handlers.CookieStore, []byte(config.Keys.JWTSigningKey))))
|
||||
r.Handle("/logout", handlers.Logout(handlers.CookieStore))
|
||||
|
||||
// School subscription
|
||||
|
||||
r.Handle("/subscribe", handlers.Login(handlers.Database, handlers.CookieStore, []byte(config.Keys.JWTSigningKey)))
|
||||
r.Handle("/subscribe", newRootMiddleware(handlers, handlers.Login(handlers.Database, handlers.CookieStore, []byte(config.Keys.JWTSigningKey))))
|
||||
|
||||
// Captcha
|
||||
|
||||
|
@ -197,7 +197,7 @@ func NewHandlers(config *config.ConfigT, renderer map[string]renderer.Renderer,
|
|||
|
||||
// Token handling
|
||||
|
||||
r.Handle("/get_token", handlers.GetToken(handlers.Database, []byte(config.Keys.JWTSigningKey)))
|
||||
r.Handle("/get_token", newRootMiddleware(handlers, handlers.GetToken(handlers.Database, []byte(config.Keys.JWTSigningKey))))
|
||||
|
||||
// Static file server
|
||||
|
||||
|
@ -270,7 +270,6 @@ func (h *Handlers) cookieExtractor(r *http.Request) (string, error) {
|
|||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if session.Values["token"] == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
@ -344,7 +343,10 @@ func (h *Handlers) get(w http.ResponseWriter, r *http.Request, model string, pat
|
|||
return err
|
||||
}
|
||||
format := r.URL.Query().Get("format")
|
||||
h.Renderer[format].Render(w, r, h.CookieStore, data, r.URL.Query())
|
||||
err = h.Renderer[format].Render(w, r, h.CookieStore, data, r.URL.Query())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -363,7 +365,10 @@ func (h *Handlers) post(w http.ResponseWriter, r *http.Request, model string, pa
|
|||
}
|
||||
} else {
|
||||
format := renderer.GetContentFormat(r)
|
||||
h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
|
||||
err := h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -385,7 +390,10 @@ func (h *Handlers) delete(w http.ResponseWriter, r *http.Request, model string,
|
|||
json.NewEncoder(w).Encode(data)
|
||||
} else {
|
||||
format := renderer.GetContentFormat(r)
|
||||
h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
|
||||
err := h.Renderer[format].Render(w, r, h.CookieStore, data.(orm.IDer).GetID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -399,10 +407,12 @@ func respondWithError(h *Handlers, w http.ResponseWriter, r *http.Request, err e
|
|||
format = renderer.GetContentFormat(r)
|
||||
}
|
||||
if h.Config.LogLevel > config.LOG_LEVEL_OFF {
|
||||
log.Println(err)
|
||||
log.Println("Error:", err)
|
||||
}
|
||||
// FIXME: this call could be superflous when an error occurs
|
||||
// in a template execution
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
h.Renderer[format].Render(w, r, h.CookieStore, err)
|
||||
h.Renderer[format].WriteError(w, r, err)
|
||||
}
|
||||
|
||||
func (h *Handlers) Create(model interface{}) http.Handler {
|
||||
|
@ -550,10 +560,6 @@ func (m *rootMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
// This is where our error handling logic starts.
|
||||
if m.h.Config.LogLevel > config.LOG_LEVEL_OFF {
|
||||
log.Printf("An error accured: %v", err) // Log the error.
|
||||
}
|
||||
|
||||
if err, ok := err.(*errors.Error); ok {
|
||||
err.Referer = r.Header.Get("Referer")
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
oef_errors "git.andreafazzi.eu/andrea/oef/errors"
|
||||
"git.andreafazzi.eu/andrea/oef/orm"
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
"github.com/gorilla/sessions"
|
||||
|
@ -24,25 +25,36 @@ type UserToken struct {
|
|||
UserID string
|
||||
}
|
||||
|
||||
func clearSession(response http.ResponseWriter) {
|
||||
cookie := &http.Cookie{
|
||||
Name: "login-session",
|
||||
Value: "",
|
||||
Path: "/",
|
||||
MaxAge: -1,
|
||||
}
|
||||
http.SetCookie(response, cookie)
|
||||
}
|
||||
|
||||
func DefaultLogoutHandler(store *sessions.CookieStore) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := store.Get(r, "login-session")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
session.Values["token"] = []uint8{}
|
||||
session.Save(r, w)
|
||||
// session, err := store.Get(r, "login-session")
|
||||
// if err != nil {
|
||||
// // http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
// store.Set(w)
|
||||
// return
|
||||
// }
|
||||
|
||||
// session.Values["token"] = []uint8{}
|
||||
// session.Save(r, w)
|
||||
clearSession(w)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func (h *Handlers) DefaultLoginHandler(db *orm.Database, store *sessions.CookieStore, signingKey []byte) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *Handlers) DefaultLoginHandler(db *orm.Database, store *sessions.CookieStore, signingKey []byte) handlerFuncWithError {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == "GET" {
|
||||
h.Renderer["html"].Render(w, r, store, nil, r.URL.Query())
|
||||
}
|
||||
|
@ -54,7 +66,7 @@ func (h *Handlers) DefaultLoginHandler(db *orm.Database, store *sessions.CookieS
|
|||
} else {
|
||||
session, err := store.Get(r, "login-session")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return oef_errors.NotAuthorized
|
||||
}
|
||||
|
||||
session.Values["token"] = token
|
||||
|
@ -63,8 +75,9 @@ func (h *Handlers) DefaultLoginHandler(db *orm.Database, store *sessions.CookieS
|
|||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
return handlerFuncWithError(fn)
|
||||
}
|
||||
|
||||
// FIXME: This is an hack for fast prototyping: users should have
|
||||
|
@ -137,18 +150,19 @@ func getToken(db *orm.Database, username string, password string, signingKey []b
|
|||
}
|
||||
|
||||
// FIXME: Refactor the functions above please!!!
|
||||
func DefaultGetTokenHandler(db *orm.Database, signingKey []byte) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
func DefaultGetTokenHandler(db *orm.Database, signingKey []byte) handlerFuncWithError {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) error {
|
||||
username, password, _ := r.BasicAuth()
|
||||
|
||||
token, err := getToken(db, username, password, signingKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.Write([]byte(fmt.Sprintf("{\"Token\":\"%s\"}", string(token))))
|
||||
|
||||
return nil
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
return handlerFuncWithError(fn)
|
||||
}
|
||||
|
|
|
@ -18,8 +18,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"git.andreafazzi.eu/andrea/oef/errors"
|
||||
|
||||
oef_errors "git.andreafazzi.eu/andrea/oef/errors"
|
||||
"github.com/gocarina/gocsv"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/gorilla/sessions"
|
||||
|
@ -29,6 +28,7 @@ import (
|
|||
|
||||
type Renderer interface {
|
||||
Render(http.ResponseWriter, *http.Request, *sessions.CookieStore, interface{}, ...url.Values) error
|
||||
WriteError(http.ResponseWriter, *http.Request, interface{})
|
||||
}
|
||||
|
||||
type JSONRenderer struct{}
|
||||
|
@ -36,10 +36,9 @@ type CSVRenderer struct{}
|
|||
type PDFRenderer struct{}
|
||||
|
||||
type htmlTemplateData struct {
|
||||
Data interface{}
|
||||
Options url.Values
|
||||
Claims jwt.MapClaims
|
||||
FlashMessages []interface{}
|
||||
Data interface{}
|
||||
Options url.Values
|
||||
Claims jwt.MapClaims
|
||||
}
|
||||
|
||||
type JsonResponse struct {
|
||||
|
@ -70,6 +69,10 @@ func NewJSONRenderer() (*JSONRenderer, error) {
|
|||
return &JSONRenderer{}, nil
|
||||
}
|
||||
|
||||
func (rend *JSONRenderer) WriteError(w http.ResponseWriter, r *http.Request, data interface{}) {
|
||||
|
||||
}
|
||||
|
||||
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")
|
||||
if isErrorType(data) {
|
||||
|
@ -181,9 +184,16 @@ func NewHTMLRenderer(templatePath string) (*HTMLRenderer, error) {
|
|||
}
|
||||
|
||||
func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, data interface{}) {
|
||||
var t *template.Template
|
||||
var (
|
||||
t *template.Template
|
||||
claims jwt.MapClaims
|
||||
)
|
||||
|
||||
err, ok := data.(*htmlTemplateData).Data.(*errors.Error)
|
||||
if r.Context().Value("user") != nil {
|
||||
claims = r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
||||
}
|
||||
|
||||
err, ok := data.(*oef_errors.Error)
|
||||
if ok {
|
||||
t, ok = rend.templates[err.TemplateName]
|
||||
if !ok {
|
||||
|
@ -191,7 +201,6 @@ func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, dat
|
|||
}
|
||||
|
||||
} else {
|
||||
|
||||
t, ok = rend.templates["error"]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("Error template not found! Can't proceed, sorry."))
|
||||
|
@ -199,12 +208,25 @@ func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, dat
|
|||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
e := t.ExecuteTemplate(w, "base", data)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
|
||||
if claims != nil {
|
||||
e := t.ExecuteTemplate(w, "base", &htmlTemplateData{data, nil, claims})
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
} else {
|
||||
e := t.ExecuteTemplate(w, "error", &htmlTemplateData{data, nil, nil})
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (rend *HTMLRenderer) WriteError(w http.ResponseWriter, r *http.Request, data interface{}) {
|
||||
rend.writeError(w, r, data)
|
||||
}
|
||||
|
||||
func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, store *sessions.CookieStore, data interface{}, options ...url.Values) error {
|
||||
var claims jwt.MapClaims
|
||||
|
||||
|
@ -212,48 +234,24 @@ func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, store *
|
|||
claims = r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
|
||||
}
|
||||
|
||||
if data != nil && isErrorType(data) {
|
||||
session, err := store.Get(r, "flash-session")
|
||||
if err != nil {
|
||||
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil})
|
||||
return err
|
||||
}
|
||||
fm := session.Flashes()
|
||||
err = session.Save(r, w)
|
||||
if err != nil {
|
||||
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm})
|
||||
return err
|
||||
}
|
||||
rend.writeError(w, r, &htmlTemplateData{data.(error), nil, claims, fm})
|
||||
if err, ok := data.(*oef_errors.Error); ok {
|
||||
// rend.writeError(w, r, &htmlTemplateData{data, nil, claims})
|
||||
return err
|
||||
} 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, claims, nil})
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
|
||||
session, err := store.Get(r, "flash-session")
|
||||
if err != nil {
|
||||
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, nil})
|
||||
return err
|
||||
}
|
||||
fm := session.Flashes()
|
||||
err = session.Save(r, w)
|
||||
if err != nil {
|
||||
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})
|
||||
if err != nil {
|
||||
rend.writeError(w, r, &htmlTemplateData{err, nil, claims, fm})
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
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, claims})
|
||||
return err
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
if err := t.ExecuteTemplate(w, options[0]["tpl_layout"][0], &htmlTemplateData{data, options[0], claims}); err != nil {
|
||||
// rend.writeError(w, r, &htmlTemplateData{err, nil, claims})
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore durante l'iscrizione della scuola"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{$options := `title: "Errore durante l'iscrizione di un partecipante"`}}
|
||||
{{template "show_error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore nella creazione/aggiornamento di un partecipante"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{template "show_error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore di autorizzazione"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
<div class="container">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">
|
||||
Errore di autorizzazione
|
||||
</h4>
|
||||
{{.Data}}
|
||||
Clicca {{"/logout"|alertLink "qui"}} per effettuare il logout e ritornare alla pagina di autenticazione.
|
||||
</div>
|
||||
<p>
|
||||
</p>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore nella gestione della prova di gara"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{template "show_error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore nella creazione/aggiornamento di un partecipante"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{template "show_error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore nell'apertura della prova di gara"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{template "show_error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore nella creazione/aggiornamento di una scuola"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{template "show_error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{ define "content" }}
|
||||
{{$options := `title: "Errore durante l'iscrizione di una scuola"`}}
|
||||
{{template "error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{template "show_error" dict "options" ($options|yaml) "data" .Data}}
|
||||
{{end}}
|
||||
|
|
|
@ -61,16 +61,6 @@
|
|||
</ul>
|
||||
</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">×</span>
|
||||
</button>
|
||||
</div>
|
||||
{{end}}
|
||||
{{- end -}}
|
||||
<div class="base-template">
|
||||
{{ template "content" . }}
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,55 @@
|
|||
{{define "error"}}
|
||||
<div class="container">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">
|
||||
{{.options.title}}
|
||||
</h4>
|
||||
{{.data}}
|
||||
{{if .data.Referer}}
|
||||
Clicca {{.data.Referer|alertLink "qui"}} per tornare all'azione precedente.
|
||||
{{end}}
|
||||
</div>
|
||||
<p>
|
||||
</p>
|
||||
</div>
|
||||
{{- define "error" -}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
||||
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
|
||||
crossorigin="anonymous">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.css">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.9/dist/css/bootstrap-select.min.css">
|
||||
<link rel="stylesheet" href="/styles.css" />
|
||||
<title>Olimpiadi di Economia e Finanza - Piattaforma di gara</title>
|
||||
</head>
|
||||
<body data-spy="scroll">
|
||||
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-primary">
|
||||
{{- $homeURL := "" -}}
|
||||
<a class="navbar-brand" href="{{$homeURL}}">
|
||||
<span class="fa fa-landmark"></span>
|
||||
OEF 2020
|
||||
</a>
|
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
</nav>
|
||||
<div class="base-template">
|
||||
{{ template "content" . }}
|
||||
</div>
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.4.1.min.js"
|
||||
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
|
||||
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script
|
||||
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
|
||||
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap-select@1.13.9/dist/js/bootstrap-select.min.js"></script>
|
||||
<script src="/main.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
|
|
15
templates/layout/show_error.html.tpl
Normal file
15
templates/layout/show_error.html.tpl
Normal file
|
@ -0,0 +1,15 @@
|
|||
{{define "show_error"}}
|
||||
<div class="container">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">
|
||||
{{.options.title}}
|
||||
</h4>
|
||||
{{.data}}
|
||||
{{if .data.Referer}}
|
||||
Clicca {{.data.Referer|alertLink "qui"}} per tornare all'azione precedente.
|
||||
{{end}}
|
||||
</div>
|
||||
<p>
|
||||
</p>
|
||||
</div>
|
||||
{{end}}
|
|
@ -127,6 +127,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2 class="karmen-relation-header">Suggerimenti</h2>
|
||||
{{if .Data.School}}
|
||||
{{if le (len .Data.School.Participants) 1}}
|
||||
<p>
|
||||
E' possibile iscrivere fino a due partecipanti alla gara (di diversa categoria).
|
||||
|
@ -141,7 +142,7 @@
|
|||
<strong>Iscrizione completa.</strong> Non è possibile aggiungere ulteriori partecipanti.
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{end}}
|
||||
<div class="alert alert-danger text-justify">
|
||||
<span class="fa
|
||||
fa-exclamation-triangle mr-1">
|
||||
|
@ -155,9 +156,9 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
|
||||
<div class="container">
|
||||
{{if $isSubscriber}}
|
||||
{{if .FlashMessages}}
|
||||
<p>Si è verificato un errore. Clicca <a href="/logout">qui</a> per uscire da questa sessione.</p>
|
||||
{{else}}
|
||||
<p>
|
||||
Grazie per aver iscritto la scuola <strong>{{.Data.Name}}</strong>
|
||||
alle Olimpiadi di Economia e Finanza.
|
||||
|
@ -27,7 +24,7 @@
|
|||
utilizzare le credenziali ricevute per iscrivere gli studenti alla
|
||||
competizione.
|
||||
</p>
|
||||
{{end}}
|
||||
|
||||
{{else}}
|
||||
|
||||
{{$deletePath := ""}}
|
||||
|
|
Loading…
Reference in a new issue