From 8a4afd970ef7342407205991a4a2a9dc11839fec Mon Sep 17 00:00:00 2001 From: Andrea Fazzi Date: Thu, 16 Jan 2020 12:47:35 +0100 Subject: [PATCH] Working on better path patterns --- handlers/handlers.go | 54 ++++++++++++++++++++++----------------- handlers/handlers_test.go | 34 +++++++++++++++++++++--- handlers/paths.go | 27 ++++++++++++++++++++ handlers/role.go | 36 -------------------------- main.go | 36 +++++++++++++++++++++++++- 5 files changed, 122 insertions(+), 65 deletions(-) create mode 100644 handlers/paths.go delete mode 100644 handlers/role.go diff --git a/handlers/handlers.go b/handlers/handlers.go index 977db7e7..51a93244 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -47,6 +47,11 @@ type Handlers struct { Static func() http.Handler Recover func(next http.Handler) http.Handler + PathPatterns []PathPattern + APIPathPatterns []PathPattern + + RolePermissions map[string]map[string][]int + CookieStore *sessions.CookieStore JWTSigningKey []byte @@ -89,27 +94,9 @@ func pluralizedModelName(s interface{}) string { // Generate CRUD handlers for models func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) { - var ( - patterns []PathPattern = []PathPattern{ - PathPattern{"/%s", "", []string{"GET"}, PermissionReadAll}, - PathPattern{"/%s/{id}", "", []string{"GET"}, PermissionRead}, - PathPattern{"/%s/create/", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}, PermissionCreate}, - PathPattern{"/%s/{id}/update", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}, PermissionUpdate}, - PathPattern{"/%s/{id}/delete", "/%s?format=html&tpl_layout=base&tpl_content=%s", []string{"DELETE"}, PermissionDelete}, - } - - apiPatterns []PathPattern - ) - - // Generate API patterns prefixing "api" path - - for _, p := range patterns { - apiPatterns = append(apiPatterns, PathPattern{"/api" + p.PathPattern, "", p.Methods, p.Permission}) - } - // Install standard paths - for _, pattern := range patterns { + for _, pattern := range DefaultPathPatterns { r.Handle( pattern.Path( pluralizedModelName(model), @@ -124,7 +111,7 @@ func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) { // Install API paths - for _, pattern := range apiPatterns { + for _, pattern := range h.APIPathPatterns { r.Handle(pattern.Path( pluralizedModelName(model), ), @@ -138,11 +125,11 @@ func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) { // Set permissions for HTML patterns - for role, modelPermissions := range RolePermissions { + for role, modelPermissions := range h.RolePermissions { for m, perm := range modelPermissions { if m == modelName(model) { for _, p := range perm { - for _, pattern := range patterns { + for _, pattern := range h.PathPatterns { if pattern.Permission == p { if permissions[role] == nil { permissions[role] = make(map[string]bool) @@ -151,7 +138,7 @@ func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) { } } - for _, pattern := range apiPatterns { + for _, pattern := range DefaultAPIPathPatterns { if pattern.Permission == p { if permissions[role] == nil { permissions[role] = make(map[string]bool) @@ -167,7 +154,15 @@ func (h *Handlers) generateModelHandlers(r *mux.Router, model interface{}) { } -func NewHandlers(config *config.ConfigT, renderer map[string]renderer.Renderer, db *orm.Database, models []interface{}) *Handlers { +func NewHandlers( + config *config.ConfigT, + renderer map[string]renderer.Renderer, + db *orm.Database, + models []interface{}, + permissions map[string]map[string][]int, + pathPatterns []PathPattern, + apiPathPatterns []PathPattern, +) *Handlers { handlers := new(Handlers) handlers.Config = config @@ -183,6 +178,11 @@ func NewHandlers(config *config.ConfigT, renderer map[string]renderer.Renderer, handlers.Home = DefaultHomeHandler handlers.GetToken = DefaultGetTokenHandler + handlers.RolePermissions = permissions + + handlers.PathPatterns = pathPatterns + handlers.APIPathPatterns = apiPathPatterns + handlers.JWTCookieMiddleware = jwtmiddleware.New(jwtmiddleware.Options{ ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { return []byte(config.Keys.JWTSigningKey), nil @@ -233,6 +233,12 @@ func NewHandlers(config *config.ConfigT, renderer map[string]renderer.Renderer, return handlers } +func (h *Handlers) NewReadAllRequest(model interface{}) (*http.Request, error) { + name := inflection.Plural(orm.ModelName(model)) + request, err := http.NewRequest("GET", "/contests?format=html&tpl_layout=base&tpl_content=contests", nil) + return request, err +} + func (h *Handlers) onError(w http.ResponseWriter, r *http.Request, err string) { http.Redirect(w, r, "/login?tpl_layout=login&tpl_content=login", http.StatusTemporaryRedirect) } diff --git a/handlers/handlers_test.go b/handlers/handlers_test.go index ca63c264..f966ac77 100644 --- a/handlers/handlers_test.go +++ b/handlers/handlers_test.go @@ -110,7 +110,7 @@ func (t *testSuite) BeforeAll() { // Initialize the renderers - htmlRenderer, err := renderer.NewHTMLRenderer("./testdata/templates/") + htmlRenderer, err := renderer.NewHTMLRenderer("../templates/") if err != nil { panic(err) } @@ -119,12 +119,38 @@ func (t *testSuite) BeforeAll() { "html": htmlRenderer, } - handlers = NewHandlers(conf, renderer, db, orm.Models) + permissions := map[string]map[string][]int{ + "administrator": map[string][]int{ + "Contest": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, + "Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, + "School": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, + "Question": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, + "Answer": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, + "Response": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, + }, + + "school": map[string][]int{ + "Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, + "School": []int{PermissionRead, PermissionUpdate}, + }, + + "participant": map[string][]int{ + "Participant": []int{PermissionRead}, + "Response": []int{PermissionUpdate, PermissionRead}, + }, + + "subscriber": map[string][]int{ + "School": []int{PermissionCreate, PermissionRead}, + }, + } + + handlers = NewHandlers(conf, renderer, db, orm.Models, permissions) token = requestToken(db, handlers) } func (t *testSuite) TestReadAllContests() { - req, err := http.NewRequest("GET", "/contests?format=html&tpl_layout=base&tpl_content=contests", nil) + req, err := RequestReadAll(&Contest{}) + // req, err := http.NewRequest("GET", "/contests?format=html&tpl_layout=base&tpl_content=contests", nil) if err != nil { panic(err) } @@ -146,7 +172,7 @@ func (t *testSuite) TestReadAllContests() { t.Equal(http.StatusOK, rr.Code) if !t.Failed() { - doc, err := goquery.NewDocumentFromResponse(rr) + doc, err := goquery.NewDocumentFromResponse(rr.Result()) if err != nil { log.Fatal(err) } diff --git a/handlers/paths.go b/handlers/paths.go new file mode 100644 index 00000000..fa6e12e6 --- /dev/null +++ b/handlers/paths.go @@ -0,0 +1,27 @@ +package handlers + +const ( + PermissionCreate = iota + PermissionRead + PermissionReadAll + PermissionUpdate + PermissionDelete +) + +var ( + DefaultPathPatterns []PathPattern = []PathPattern{ + PathPattern{"/%s", "", []string{"GET"}, PermissionReadAll}, + PathPattern{"/%s/{id}", "", []string{"GET"}, PermissionRead}, + PathPattern{"/%s/create/", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}, PermissionCreate}, + PathPattern{"/%s/{id}/update", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}, PermissionUpdate}, + PathPattern{"/%s/{id}/delete", "/%s?format=html&tpl_layout=base&tpl_content=%s", []string{"DELETE"}, PermissionDelete}, + } + + DefaultAPIPathPatterns []PathPattern = []PathPattern{ + PathPattern{"/api/%s", "", []string{"GET"}, PermissionReadAll}, + PathPattern{"/api/%s/{id}", "", []string{"GET"}, PermissionRead}, + PathPattern{"/api/%s/create/", "", []string{"GET", "POST"}, PermissionCreate}, + PathPattern{"/api/%s/{id}/update", "", []string{"GET", "POST"}, PermissionUpdate}, + PathPattern{"/api/%s/{id}/delete", "", []string{"DELETE"}, PermissionDelete}, + } +) diff --git a/handlers/role.go b/handlers/role.go deleted file mode 100644 index 21c8b00b..00000000 --- a/handlers/role.go +++ /dev/null @@ -1,36 +0,0 @@ -package handlers - -const ( - PermissionCreate = iota - PermissionRead - PermissionReadAll - PermissionUpdate - PermissionDelete -) - -var ( - RolePermissions map[string]map[string][]int = map[string]map[string][]int{ - "administrator": map[string][]int{ - "Contest": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, - "Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, - "School": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, - "Question": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, - "Answer": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, - "Response": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, - }, - - "school": map[string][]int{ - "Participant": []int{PermissionCreate, PermissionRead, PermissionReadAll, PermissionUpdate, PermissionDelete}, - "School": []int{PermissionRead, PermissionUpdate}, - }, - - "participant": map[string][]int{ - "Participant": []int{PermissionRead}, - "Response": []int{PermissionUpdate, PermissionRead}, - }, - - "subscriber": map[string][]int{ - "School": []int{PermissionCreate, PermissionRead}, - }, - } -) diff --git a/main.go b/main.go index ddd1cc2d..bc6d40da 100644 --- a/main.go +++ b/main.go @@ -81,7 +81,41 @@ func main() { "html": htmlRenderer, "json": jsonRenderer, } - if err := http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, oef_handlers.NewHandlers(conf, renderer, db, orm.Models).Router)); err != nil { + + permissions := map[string]map[string][]int{ + "administrator": map[string][]int{ + "Contest": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead, oef_handlers.PermissionReadAll, oef_handlers.PermissionUpdate, oef_handlers.PermissionDelete}, + "Participant": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead, oef_handlers.PermissionReadAll, oef_handlers.PermissionUpdate, oef_handlers.PermissionDelete}, + "School": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead, oef_handlers.PermissionReadAll, oef_handlers.PermissionUpdate, oef_handlers.PermissionDelete}, + "Question": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead, oef_handlers.PermissionReadAll, oef_handlers.PermissionUpdate, oef_handlers.PermissionDelete}, + "Answer": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead, oef_handlers.PermissionReadAll, oef_handlers.PermissionUpdate, oef_handlers.PermissionDelete}, + "Response": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead, oef_handlers.PermissionReadAll, oef_handlers.PermissionUpdate, oef_handlers.PermissionDelete}, + }, + + "school": map[string][]int{ + "Participant": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead, oef_handlers.PermissionReadAll, oef_handlers.PermissionUpdate, oef_handlers.PermissionDelete}, + "School": []int{oef_handlers.PermissionRead, oef_handlers.PermissionUpdate}, + }, + + "participant": map[string][]int{ + "Participant": []int{oef_handlers.PermissionRead}, + "Response": []int{oef_handlers.PermissionUpdate, oef_handlers.PermissionRead}, + }, + + "subscriber": map[string][]int{ + "School": []int{oef_handlers.PermissionCreate, oef_handlers.PermissionRead}, + }, + } + + if err := http.ListenAndServe(":3000", handlers.LoggingHandler(os.Stdout, oef_handlers.NewHandlers( + conf, + renderer, + db, + orm.Models, + permissions, + handlers.DefaultPathPatterns, + handlers.DefaultAPIPathPatterns, + ).Router)); err != nil { panic(err) }