Working on participant subscription workflow of school user

This commit is contained in:
Andrea Fazzi 2019-12-07 11:44:19 +01:00
parent 4b752f2e50
commit 8f02b2eb5f
12 changed files with 177 additions and 25 deletions

View file

@ -1,5 +1,12 @@
package errors
import "errors"
import (
"errors"
var RecordExists = errors.New("Record already exists!")
"git.andreafazzi.eu/andrea/oef/i18n"
)
var (
RecordExists = errors.New("Record already exists!")
NotAuthorized = errors.New(i18n.Authorization["notAuthorized"]["it"])
)

View file

@ -21,7 +21,7 @@ var (
},
"school": map[string][]int{
"Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete},
"Participant": []int{PermissionCreate, PermissionRead, PermissionUpdate, PermissionDelete},
"School": []int{PermissionRead, PermissionUpdate},
},

View file

@ -17,4 +17,9 @@ var (
"it": "il %02d/%02d/%d alle ore %02d:%02d",
},
}
Authorization = map[string]map[string]string{
"notAuthorized": map[string]string{
"it": "Non si è autorizzati ad accedere a questa pagina",
},
}
)

View file

@ -2,11 +2,13 @@ package orm
import (
"fmt"
"strconv"
"net/http"
"strings"
"git.andreafazzi.eu/andrea/oef/config"
"git.andreafazzi.eu/andrea/oef/errors"
"git.andreafazzi.eu/andrea/oef/i18n"
"git.andreafazzi.eu/andrea/oef/renderer"
"github.com/jinzhu/gorm"
@ -122,8 +124,19 @@ func (model *Participant) Create(args map[string]string, w http.ResponseWriter,
if err := DB().Find(&participant.AllContests).Error; err != nil {
return nil, err
}
if err := DB().Find(&participant.AllSchools).Error; err != nil {
return nil, err
if isSchool(r) {
schoolID, err := strconv.Atoi(getUserIDFromToken(r))
if err != nil {
return nil, err
}
if err := DB().Find(&participant.AllSchools, schoolID).Error; err != nil {
return nil, err
}
} else {
if err := DB().Find(&participant.AllSchools).Error; err != nil {
return nil, err
}
}
return participant, nil
} else {
@ -161,6 +174,18 @@ func (model *Participant) Read(args map[string]string, w http.ResponseWriter, r
id := args["id"]
// School user can access to its participants only!
if isSchool(r) {
if err := DB().Preload("School").First(&participant, id).Error; err != nil {
return nil, err
}
if strconv.Itoa(int(participant.SchoolID)) != getUserIDFromToken(r) {
setFlashMessage(w, r, "notAuthorized")
return nil, errors.NotAuthorized
}
}
if err := DB().Preload("User").Preload("School").Preload("Responses").Preload("Contests").First(&participant, id).Error; err != nil {
return nil, err
}
@ -228,7 +253,7 @@ func (model *Participant) Update(args map[string]string, w http.ResponseWriter,
return nil, err
}
participant.(*School).UserModifierUpdate = NewUserModifierUpdate(r)
participant.(*Participant).UserModifierUpdate = NewUserModifierUpdate(r)
_, err = SaveParticipant(participant)
if err != nil {
@ -271,7 +296,7 @@ func CreateParticipant(participant *Participant) (*Participant, error) {
func SaveParticipant(participant interface{}) (interface{}, error) {
participant.(*Participant).FiscalCode = strings.ToUpper(participant.(*Participant).FiscalCode)
if err := DB(). /*.Omit("Something")*/ Save(participant).Error; err != nil {
if err := DB().Omit("School").Save(participant).Error; err != nil {
return nil, err
}
return participant, nil

38
orm/role.go Normal file
View file

@ -0,0 +1,38 @@
package orm
import (
"net/http"
"github.com/dgrijalva/jwt-go"
)
func getClaims(r *http.Request) jwt.MapClaims {
return r.Context().Value("user").(*jwt.Token).Claims.(jwt.MapClaims)
}
func isRole(role string, r *http.Request) bool {
if r.Context().Value("user") != nil {
return getClaims(r)["role"].(string) == role
}
return false
}
func isAdministrator(r *http.Request) bool {
return isRole("administrator", r)
}
func isParticipant(r *http.Request) bool {
return isRole("participant", r)
}
func isSchool(r *http.Request) bool {
return isRole("school", r)
}
func isSubscriber(r *http.Request) bool {
return isRole("subscriber", r)
}
func getUserIDFromToken(r *http.Request) string {
return getClaims(r)["user_id"].(string)
}

View file

@ -6,6 +6,7 @@ import (
"strings"
"time"
"git.andreafazzi.eu/andrea/oef/errors"
"git.andreafazzi.eu/andrea/oef/mail"
"git.andreafazzi.eu/andrea/oef/renderer"
"github.com/jinzhu/gorm"
@ -69,6 +70,10 @@ func (model *School) BeforeSave(tx *gorm.DB) error {
return err
}
model.UserID = user.ID
// School code is always uppercase
model.Code = strings.ToUpper(model.Code)
return nil
}
@ -134,6 +139,11 @@ func (model *School) Read(args map[string]string, w http.ResponseWriter, r *http
id := args["id"]
if isSchool(r) && id != getUserIDFromToken(r) {
setFlashMessage(w, r, "notAuthorized")
return nil, errors.NotAuthorized
}
if err := DB().Preload("User").Preload("Participants").First(&school, id).Error; err != nil {
return nil, err
}
@ -222,7 +232,7 @@ func CreateSchool(school *School) (*School, error) {
}
func SaveSchool(school interface{}) (interface{}, error) {
school.(*School).Code = strings.ToUpper(school.(*School).Code)
// school.(*School).Code = strings.ToUpper(school.(*School).Code)
if err := DB(). /*.Omit("Something")*/ Save(school).Error; err != nil {
return nil, err
}

View file

@ -54,6 +54,7 @@ var (
"isAdmin": isAdmin,
"isParticipant": isParticipant,
"isSubscriber": isSubscriber,
"isSchool": isSchool,
"attr": attr,
}
)
@ -70,6 +71,10 @@ func isParticipant(claims jwt.MapClaims) bool {
return claims["role"].(string) == "participant"
}
func isSchool(claims jwt.MapClaims) bool {
return claims["role"].(string) == "school"
}
func isSubscriber(claims jwt.MapClaims) bool {
return claims["role"].(string) == "subscriber"
}

View file

@ -1,4 +1,10 @@
{{define "base"}}
{{$isAdmin := .Claims|isAdmin}}
{{$isSubscriber := .Claims|isSubscriber}}
{{$isSchool := .Claims|isSchool}}
{{$isParticipant := .Claims|isParticipant}}
<!DOCTYPE html>
<html lang="it">
<head>
@ -12,7 +18,14 @@
<body>
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-primary">
<a class="navbar-brand" href="{{all "Contest"}}">
{{$homeURL := ""}}
{{if $isAdmin}}{{$homeURL = all "Contest"}}{{end}}
{{if $isSubscriber}}{{$homeURL = "#"}}{{end}}
{{if $isParticipant}}{{$homeURL = "#"}}{{end}}
{{if $isSchool}}{{$homeURL = "#"}}{{end}}
<a class="navbar-brand" href="{{$homeURL}}">
<span class="fa fa-landmark"></span>
OEF 2020
</a>

View file

@ -7,7 +7,9 @@
<div class="col-md-4">
<div class="btn-group float-right" role="group">
{{template "update_button" dict "modelPath" .updatePath}}
{{if .deletePath}}
{{template "delete_button" dict "modelPath" .deletePath}}
{{end}}
</div>
</div>
</div>

View file

@ -1,8 +1,18 @@
{{ define "content" }}
{{$isAdmin := .Claims|isAdmin}}
{{$isSchool := .Claims|isSchool}}
<div class="container">
{{if $isAdmin}}
{{template "breadcrumb" toSlice "Partecipanti" (all "Participant") (.Data|string) "current"}}
{{end}}
{{if $isSchool}}
{{template "breadcrumb" toSlice (.Data.School|string) (.Data.SchoolID|show "School") (.Data|string) "current"}}
{{end}}
{{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Participant") "deletePath" (.Data.ID|delete "Participant")}}
<h2 class="karmen-relation-header">Informazioni generali</h2>
@ -24,7 +34,6 @@
<dd class="col-sm-9">{{.Data.UpdaterIP}}</dd>
{{end}}
</dl>
<div class="row">

View file

@ -1,14 +1,20 @@
{{ define "content" }}
<div class="container">
{{$isAdmin := .Claims|isAdmin}}
{{$isSubscriber := .Claims|isSubscriber}}
{{$isSchool := .Claims|isSchool}}
{{$update := .Options.Get "update"}}
{{if not $isSubscriber}}
{{if $update}}
{{if $isSchool}}
{{template "breadcrumb" toSlice (.Data|string) (.Data.ID|show "School") "Aggiorna" "current"}}
{{else}}
{{template "breadcrumb" toSlice "Scuole" (all "School") (.Data|string) (.Data.ID|show "School") "Aggiorna" "current"}}
{{end}}
{{else}}
{{template "breadcrumb" toSlice "Scuole" (all "School") "Aggiungi" "current"}}
{{end}}
@ -31,7 +37,9 @@
{{$options := ` { name: "Name",id: "school_name",label: "Denominazione dell'istituto",placeholder: "Inserire la denominazione",type: "text",required: "true"} `}}
{{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
{{$options := `
{{$codeOptions := ""}}
{{if or $isAdmin $isSubscriber}}
{{$codeOptions = `
name: "Code"
id: "school_code"
label: "Codice meccanografico"
@ -41,7 +49,20 @@
otherAttrs: "maxlength=10 minlength=10"
required: "true"
`}}
{{template "input" dict "options" ($options|yaml) "value" (.Data|field "Code") "update" $update}}
{{end}}
{{if $isSchool}}
{{$codeOptions = `
name: "Code"
id: "school_code"
label: "Codice meccanografico"
type: "text"
inputClass: "form-control-plaintext"
otherAttrs: "readonly"
`}}
{{end}}
{{template "input" dict "options" ($codeOptions|yaml) "value" (.Data|field "Code") "update" $update}}
{{$options := ` { name: "Email",id: "school_email",label: "Indirizzo email",placeholder: "Inserire l'indirizzo di posta istituzionale",type: "email",required: "true"} `}}
{{template "input" dict "options" ($options|yaml) "value" (.Data|field "Email") "update" $update}}

View file

@ -1,7 +1,11 @@
{{ define "content" }}
{{$isAdmin := .Claims|isAdmin}}
{{$isSchool := .Claims|isSchool}}
{{$isSubscriber := .Claims|isSubscriber}}
<div class="container">
{{if .Claims|isSubscriber}}
{{if $isSubscriber}}
{{if .FlashMessages}}
<p>Si è verificato un errore. Clicca <a href="/logout">qui</a> per uscire da questa sessione.</p>
{{else}}
@ -20,8 +24,16 @@
</p>
{{end}}
{{else}}
{{$deletePath := ""}}
{{if $isAdmin}}
{{$deletePath = (.Data.ID|delete "School")}}
{{end}}
{{if $isAdmin}}
{{template "breadcrumb" toSlice "Scuole" (all "School") (.Data|string|trim) "current"}}
{{template "show_header" dict "title" (.Data|string|trim) "updatePath" (.Data.ID|update "School") "deletePath" (.Data.ID|delete "School")}}
{{end}}
{{template "show_header" dict "title" (.Data|string|trim) "updatePath" (.Data.ID|update "School") "deletePath" $deletePath}}
<h2 class="karmen-relation-header">Informazioni sulla scuola</h2>
<dl class="row">
@ -41,33 +53,38 @@
<dd class="col-sm-9">{{.Data.User.Password}}</dd>
{{if $creatorUser:=.Data.CreatedBy}}
<dt class="col-sm-3">Creato da</dt>
<dd class="col-sm-9">{{$creatorUser.Username}}[{{$creatorUser.Role}}] {{$.Data.CreatedAt|prettyDateTime}}</dd>
<dt class="col-sm-3">IP di chi ha creato la scuola</dt>
<dd class="col-sm-9">{{.Data.CreatorIP}}</dd>
<dd class="col-sm-9">{{$creatorUser.Username}}[{{$creatorUser.Role}}] {{$.Data.CreatedAt|prettyDateTime}} da {{.Data.CreatorIP}}</dd>
{{end}}
{{if $updaterUser:=.Data.UpdatedBy}}
<dt class="col-sm-3">Modificato da</dt>
<dd class="col-sm-9">{{$updaterUser.Username}}[{{$updaterUser.Role}}] {{$.Data.UpdatedAt|prettyDateTime}}</dd>
<dt class="col-sm-3">IP di chi ha modificato la scuola</dt>
<dd class="col-sm-9">{{.Data.UpdaterIP}}</dd>
<dd class="col-sm-9">{{$updaterUser.Username}}[{{$updaterUser.Role}}] {{$.Data.UpdatedAt|prettyDateTime}} da {{.Data.UpdaterIP}}</dd>
{{end}}
</dl>
<div class="row">
<div class="col-md-12">
{{$options := `
title: "Partecipanti"
model: "Participant"
icon: "fa fa-user"
`}}
{{$noElements := "La scuola non ha iscritto alcun partecipante."}}
{{$noElements := (printf "La scuola non ha iscritto alcun partecipante. Clicca %s per iscrivere il primo partecipante." ((create "Participant")|anchor "qui")|html)}}
{{template "relation_list" dict "options" ($options|yaml) "data" .Data.Participants "noElements" $noElements}}
</div>
</div>
{{if eq (len .Data.Participants) 1}}
<div class="row">
<div class="col-md-12">
<p class="mt-4">
{{(printf "Clicca %s per iscrivere il secondo partecipante." ((create "Participant")|anchor "qui")|html)}}
</p>
</div>
</div>
{{end}}
{{end}}
</div>