From 06b9cfa0db34a7f79d793a178e44e1efac1a9358 Mon Sep 17 00:00:00 2001 From: Andrea Fazzi Date: Mon, 9 Dec 2019 08:27:46 +0100 Subject: [PATCH] Add categories --- handlers/role.go | 2 +- main.go | 4 + orm/category.go | 124 +++++++++++++++++++++ orm/orm.go | 9 ++ orm/participant.go | 101 +++++++++++------ renderer/funcmap.go | 10 ++ templates/categories.html.tpl | 33 ++++++ templates/categories_add_update.html.tpl | 28 +++++ templates/categories_show.html.tpl | 27 +++++ templates/layout/base.html.tpl | 5 + templates/layout/select.html.tpl | 2 +- templates/participants_add_update.html.tpl | 25 ++++- templates/participants_show.html.tpl | 26 +++-- 13 files changed, 353 insertions(+), 43 deletions(-) create mode 100644 orm/category.go create mode 100644 templates/categories.html.tpl create mode 100644 templates/categories_add_update.html.tpl create mode 100644 templates/categories_show.html.tpl diff --git a/handlers/role.go b/handlers/role.go index 0056f0dd..ab5c4776 100644 --- a/handlers/role.go +++ b/handlers/role.go @@ -21,7 +21,7 @@ var ( }, "school": map[string][]int{ - "Participant": []int{PermissionCreate, PermissionRead, PermissionUpdate, PermissionDelete}, + "Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, "School": []int{PermissionRead, PermissionUpdate}, }, diff --git a/main.go b/main.go index c7fea16b..9cb4eaa8 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,7 @@ var ( &orm.School{}, &orm.Response{}, &orm.User{}, + &orm.Category{}, } ) @@ -70,6 +71,9 @@ func main() { orm.AutoMigrate(models...) } + log.Println("Eventually write categories on DB...") + orm.CreateCategories() + log.Println("Map models <-> handlers") if err := orm.MapHandlers(models); err != nil { panic(err) diff --git a/orm/category.go b/orm/category.go new file mode 100644 index 00000000..3004370a --- /dev/null +++ b/orm/category.go @@ -0,0 +1,124 @@ +package orm + +import ( + "net/http" + + "git.andreafazzi.eu/andrea/oef/renderer" + "github.com/jinzhu/gorm" +) + +type Category struct { + gorm.Model + + Name string +} + +func (model *Category) GetID() uint { return model.ID } + +func (model *Category) String() string { + return model.Name +} + +func (model *Category) Create(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) { + if r.Method == "GET" { + category := new(Category) + // if err := DB().Find(&category.AllContests).Error; err != nil { + // return nil, err + // } + return category, nil + } else { + category := new(Category) + err := renderer.Decode(category, r) + if err != nil { + return nil, err + } + category, err = CreateCategory(category) + if err != nil { + return nil, err + } + return category, nil + } +} + +func (model *Category) Read(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) { + var category Category + + id := args["id"] + + if err := DB(). /*.Preload("Something")*/ First(&category, id).Error; err != nil { + return nil, err + } + + return &category, nil +} + +func (model *Category) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) { + var categories []*Category + if err := DB(). /*.Preload("Something")*/ Order("created_at").Find(&categories).Error; err != nil { + return nil, err + } + return categories, nil +} + +func (model *Category) Update(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) { + if r.Method == "GET" { + result, err := model.Read(args, w, r) + if err != nil { + return nil, err + } + + category := result.(*Category) + + // if err := DB().Find(&category.AllElements).Error; err != nil { + // return nil, err + // } + + // category.SelectedElement = make(map[uint]string) + // category.SelectedElement[category.ElementID] = "selected" + + return category, nil + } else { + category, err := model.Read(args, w, r) + if err != nil { + return nil, err + } + err = renderer.Decode(category, r) + if err != nil { + return nil, err + } + _, err = SaveCategory(category) + if err != nil { + return nil, err + } + category, err = model.Read(args, w, r) + if err != nil { + return nil, err + } + return category.(*Category), nil + } +} + +func (model *Category) Delete(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) { + category, err := model.Read(args, w, r) + if err != nil { + return nil, err + } + if err := DB().Unscoped().Delete(category.(*Category)).Error; err != nil { + return nil, err + } + return category.(*Category), nil +} + +func CreateCategory(category *Category) (*Category, error) { + if err := DB().Create(category).Error; err != nil { + return nil, err + } + return category, nil +} + +func SaveCategory(category interface{}) (interface{}, error) { + if err := DB(). /*.Omit("Something")*/ Save(category).Error; err != nil { + return nil, err + } + return category, nil +} diff --git a/orm/orm.go b/orm/orm.go index f4440a21..6e08b0be 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -46,6 +46,15 @@ func AutoMigrate(models ...interface{}) { } +func CreateCategories() { + for _, name := range []string{"Junior", "Senior"} { + var category Category + if err := currDB.FirstOrCreate(&category, Category{Name: name}).Error; err != nil { + panic(err) + } + } +} + func Use(db *gorm.DB) { currDB = db } diff --git a/orm/participant.go b/orm/participant.go index 4a7682bf..38ea04f7 100644 --- a/orm/participant.go +++ b/orm/participant.go @@ -27,16 +27,21 @@ type Participant struct { FiscalCode string - SchoolID uint `schema:"school_id"` + CategoryID uint `schema:"category_id"` + SchoolID uint `schema:"school_id"` - User *User - School *School + User *User + School *School + Category *Category Responses []*Response ContestIDs []uint `schema:"contest_ids" gorm:"-"` Contests []*Contest `gorm:"many2many:subscriptions"` + SelectedCategory map[uint]string `gorm:"-"` + AllCategories []*Category `gorm:"-"` + SelectedContest map[uint]string `gorm:"-"` AllContests []*Contest `gorm:"-"` @@ -121,19 +126,17 @@ func (model *Participant) AfterDelete(tx *gorm.DB) 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 { - return nil, err - } if isSchool(r) { - schoolID, err := strconv.Atoi(getUserIDFromToken(r)) - if err != nil { + if err := DB().Find(&participant.AllCategories).Error; err != nil { return nil, err } - if err := DB().Find(&participant.AllSchools, schoolID).Error; err != nil { - return nil, err - } - } else { + if err := DB().Find(&participant.AllCategories).Error; err != nil { + return nil, err + } + if err := DB().Find(&participant.AllContests).Error; err != nil { + return nil, err + } if err := DB().Find(&participant.AllSchools).Error; err != nil { return nil, err } @@ -161,6 +164,13 @@ func (model *Participant) Create(args map[string]string, w http.ResponseWriter, participant.UserModifierCreate = NewUserModifierCreate(r) + if isSchool(r) { + schoolID, err := strconv.Atoi(getUserIDFromToken(r)) + if err != nil { + return nil, err + } + participant.SchoolID = uint(schoolID) + } participant, err = CreateParticipant(participant) if err != nil { return nil, err @@ -184,10 +194,15 @@ func (model *Participant) Read(args map[string]string, w http.ResponseWriter, 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 + if err := DB().Preload("User").Preload("School").Preload("Category").First(&participant, id).Error; err != nil { + return nil, err + } + + } else { + if err := DB().Preload("User").Preload("School").Preload("Responses").Preload("Contests").Preload("Category").First(&participant, id).Error; err != nil { + return nil, err + } } return &participant, nil @@ -195,8 +210,20 @@ func (model *Participant) Read(args map[string]string, w http.ResponseWriter, r func (model *Participant) ReadAll(args map[string]string, w http.ResponseWriter, r *http.Request) (interface{}, error) { var participants []*Participant - if err := DB().Preload("School").Preload("Contests").Preload("Responses").Order("created_at").Find(&participants).Error; err != nil { - return nil, err + + // School user can access to its participants only! + if isSchool(r) { + schoolId, err := strconv.Atoi(getUserIDFromToken(r)) + if err != nil { + return nil, err + } + if err := DB().Preload("Category").Preload("School").Preload("Contests").Order("lastname").Find(&participants, &Participant{SchoolID: uint(schoolId)}).Error; err != nil { + return nil, err + } + } else { + if err := DB().Preload("School").Preload("Contests").Preload("Responses").Order("created_at").Find(&participants).Error; err != nil { + return nil, err + } } return participants, nil } @@ -210,22 +237,30 @@ func (model *Participant) Update(args map[string]string, w http.ResponseWriter, participant := result.(*Participant) - if err := DB().Find(&participant.AllContests).Error; err != nil { - return nil, err + if isSchool(r) { + if err := DB().Find(&participant.AllCategories).Error; err != nil { + return nil, err + } + + participant.SelectedCategory = make(map[uint]string) + participant.SelectedCategory[participant.CategoryID] = "selected" + } else { + if err := DB().Find(&participant.AllContests).Error; err != nil { + return nil, err + } + + participant.SelectedContest = make(map[uint]string) + for _, c := range participant.Contests { + participant.SelectedContest[c.ID] = "selected" + } + + if err := DB().Find(&participant.AllSchools).Error; err != nil { + return nil, err + } + + participant.SelectedSchool = make(map[uint]string) + participant.SelectedSchool[participant.SchoolID] = "selected" } - - participant.SelectedContest = make(map[uint]string) - for _, c := range participant.Contests { - participant.SelectedContest[c.ID] = "selected" - } - - if err := DB().Find(&participant.AllSchools).Error; err != nil { - return nil, err - } - - participant.SelectedSchool = make(map[uint]string) - participant.SelectedSchool[participant.SchoolID] = "selected" - return participant, nil } else { participant, err := model.Read(args, w, r) @@ -296,7 +331,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("School").Save(participant).Error; err != nil { + if err := DB().Omit("Category", "School").Save(participant).Error; err != nil { return nil, err } return participant, nil diff --git a/renderer/funcmap.go b/renderer/funcmap.go index 5e144897..8cfc6a8f 100644 --- a/renderer/funcmap.go +++ b/renderer/funcmap.go @@ -6,6 +6,7 @@ import ( "html/template" "net/url" "reflect" + "strconv" "strings" "time" @@ -56,6 +57,7 @@ var ( "isSubscriber": isSubscriber, "isSchool": isSchool, "attr": attr, + "userId": userId, } ) @@ -63,6 +65,14 @@ func username(claims jwt.MapClaims) string { return claims["username"].(string) } +func userId(claims jwt.MapClaims) (uint, error) { + id, err := strconv.Atoi(claims["user_id"].(string)) + if err != nil { + return 0, err + } + return uint(id), nil +} + func isAdmin(claims jwt.MapClaims) bool { return claims["role"].(string) == "administrator" } diff --git a/templates/categories.html.tpl b/templates/categories.html.tpl new file mode 100644 index 00000000..0ed9bb8e --- /dev/null +++ b/templates/categories.html.tpl @@ -0,0 +1,33 @@ +{{ define "content" }} + + +
+{{$options := ` + title: "Categories" + buttonTitle: "Crea nuovo Category" + `}} + + {{template "read_all_header" dict "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "Category")}} + {{template "search_input"}} + + {{if not .}} + {{template "display_no_elements"}} + {{else}} + + +
+ + +{{ end }} diff --git a/templates/categories_add_update.html.tpl b/templates/categories_add_update.html.tpl new file mode 100644 index 00000000..75c91201 --- /dev/null +++ b/templates/categories_add_update.html.tpl @@ -0,0 +1,28 @@ +{{ define "content" }} +
+ +{{$update := .Options.Get "update"}} + +{{if $update}} + +{{template "breadcrumb" toSlice "Categories" (all "Category") (.Data|string) (.Data.ID|show "Category") "Aggiorna" "current"}} +{{else}} +{{template "breadcrumb" toSlice "Categories" (all "Category") "Aggiungi" "current"}} +{{end}} + +{{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo ELEMENTO" "updateTitle" (printf "Aggiorna ELEMENTO %s" (.Data|string))}} +{{$form := "form_add_update"}} +
+ + {{$options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Category" } `}} + {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}} + +
+ +
+{{ end }} diff --git a/templates/categories_show.html.tpl b/templates/categories_show.html.tpl new file mode 100644 index 00000000..544e102f --- /dev/null +++ b/templates/categories_show.html.tpl @@ -0,0 +1,27 @@ +{{ define "content" }} + +
+ + {{template "breadcrumb" toSlice "ELEMENTS" (all "Category") (.Data|string) "current"}} + {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Category") "deletePath" (.Data.ID|delete "Category")}} + +

GENERAL SECTION

+ +
+
+ + {{$options := ` + title: "RELATIONS" + model: "MODEL" + icon: "ICON_CLASS" + `}} + + {{$noElements := "NO ELEMENTS"}} + {{template "relation_list" dict "options" ($options|yaml) "data" .Data.RELATIONS "noElements" $noElements}} + +
+
+ +
+ +{{ end }} diff --git a/templates/layout/base.html.tpl b/templates/layout/base.html.tpl index d1dfe2e8..f9cc50b4 100644 --- a/templates/layout/base.html.tpl +++ b/templates/layout/base.html.tpl @@ -42,6 +42,11 @@ Scuole Partecipanti {{end}} + {{if $isSchool}} + Scuola + Partecipanti + {{end}} +