| 
					
				 | 
			
			
				@@ -8,6 +8,7 @@ import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"net/http" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"path/filepath" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"runtime/debug" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"strconv" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"gogs.carducci-dante.gov.it/karmen/core/config" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"gogs.carducci-dante.gov.it/karmen/core/orm" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -25,9 +26,9 @@ type User struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type PathPattern struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Path         string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	RedirectPath string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	Methods      []string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	PathPattern     string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	RedirectPattern string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	Methods         []string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 var ( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -49,37 +50,44 @@ var ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		SigningMethod: jwt.SigningMethodHS256, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	patterns []PathPattern = []PathPattern{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/%s", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/%s/{id}", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/%s/add/", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/%s/{id}/update", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/%s/{id}/delete", "/%s?format=html&tpl_layout=base&tpl_content=%s", []string{"DELETE"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (pp PathPattern) RedirectPath(model string, id ...uint) string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if len(id) > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return fmt.Sprintf(pp.RedirectPattern, model, strconv.Itoa(int(id[0])), model) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return fmt.Sprintf(pp.RedirectPattern, model, model) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	jsonPatterns []PathPattern = []PathPattern{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/api/%s", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/api/%s/{id}", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/api/%s/add/", "/%s/%d?format=json&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/api/%s/{id}/update", "/%s/%d?format=json&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		PathPattern{"/api/%s/{id}/delete", "/%s?format=json&tpl_layout=base&tpl_content=%s", []string{"DELETE"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (pp PathPattern) Path(model string) string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return fmt.Sprintf(pp.PathPattern, model) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Generate CRUD handlers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func generateHandler(r *mux.Router, base string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func generateHandler(r *mux.Router, model string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		patterns []PathPattern = []PathPattern{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/%s", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/%s/{id}", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/%s/add/", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/%s/{id}/update", "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/%s/{id}/delete", "/%s?format=html&tpl_layout=base&tpl_content=%s", []string{"DELETE"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		jsonPatterns []PathPattern = []PathPattern{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/api/%s", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/api/%s/{id}", "", []string{"GET"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/api/%s/add/", "/%s/%d?format=json&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/api/%s/{id}/update", "/%s/%d?format=json&tpl_layout=base&tpl_content=%s_show", []string{"GET", "POST"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PathPattern{"/api/%s/{id}/delete", "/%s?format=json&tpl_layout=base&tpl_content=%s", []string{"DELETE"}}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for _, pattern := range patterns { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		r.Handle( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			fmt.Sprintf(pattern.Path, base), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			jwtCookie.Handler(recoverHandler(modelHandler( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				fmt.Sprintf(pattern.Path, base), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				pattern.RedirectPath)))).Methods(pattern.Methods...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		r.Handle(pattern.Path(model), jwtCookie.Handler(recoverHandler(modelHandler(model, pattern)))).Methods(pattern.Methods...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for _, pattern := range jsonPatterns { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		r.Handle(fmt.Sprintf(pattern.Path, base), recoverHandler(modelHandler(base, fmt.Sprintf(pattern.Path, base), pattern.RedirectPath))).Methods(pattern.Methods...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		r.Handle(pattern.Path(model), recoverHandler(modelHandler(model, pattern))).Methods(pattern.Methods...) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -154,7 +162,7 @@ func recoverHandler(next http.Handler) http.Handler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return http.HandlerFunc(fn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func modelHandler(base, path, redirectPath string) http.Handler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func modelHandler(model string, pattern PathPattern) http.Handler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	fn := func(w http.ResponseWriter, r *http.Request) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		var ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			ok     bool 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -165,54 +173,39 @@ func modelHandler(base, path, redirectPath string) http.Handler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		switch r.Method { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		case "GET": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			getFn, ok = orm.Get[path] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			getFn, ok = orm.Get[pattern.Path(model)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if !ok { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				renderer.Render[r.URL.Query()["format"][0]](w, r, fmt.Errorf("Can't find ORM function for path %s!", path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				renderer.Render[r.URL.Query().Get("format")](w, r, fmt.Errorf("Can't find ORM function for path %s!", pattern.Path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			data, err := getFn(mux.Vars(r)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				renderer.Render[r.URL.Query()["format"][0]](w, r, err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				renderer.Render[r.URL.Query().Get("format")](w, r, err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				renderer.Render[r.URL.Query()["format"][0]](w, r, data, r.URL.Query()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				renderer.Render[r.URL.Query().Get("format")](w, r, data, r.URL.Query()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		case "POST": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			postFn, ok = orm.Post[path] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			postFn, ok = orm.Post[pattern.Path(model)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if !ok { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				renderer.Render[r.URL.Query()["format"][0]](w, r, fmt.Errorf("Can't find ORM function for path %s!", path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				renderer.Render[r.URL.Query().Get("format")](w, r, fmt.Errorf("Can't find ORM function for path %s!", pattern.Path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			data, err := postFn(mux.Vars(r), r) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				renderer.Render["html"](w, r, err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if mux.Vars(r)["id"] != "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					http.Redirect(w, r, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						fmt.Sprintf( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							"/%s/%s?format=html&tpl_layout=base&tpl_content=%s_show", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							mux.Vars(r)["id"], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						http.StatusSeeOther, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if id := mux.Vars(r)["id"]; id != "" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					modelId, _ := strconv.Atoi(id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					http.Redirect(w, r, pattern.RedirectPath(model, uint(modelId)), http.StatusSeeOther) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					http.Redirect(w, r, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						fmt.Sprintf( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							"/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							data.GetID(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						http.StatusSeeOther, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					http.Redirect(w, r, pattern.RedirectPath(model, data.GetID()), http.StatusSeeOther) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		case "DELETE": 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			postFn, ok = orm.Post[path] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			postFn, ok = orm.Post[pattern.Path(model)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if !ok { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				renderer.Render[r.URL.Query().Get("format")](w, r, fmt.Errorf("Can't find ORM function for path %s!", path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				renderer.Render[r.URL.Query().Get("format")](w, r, fmt.Errorf("Can't find ORM function for path %s!", pattern.Path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			_, err := postFn(mux.Vars(r), r) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if err != nil { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -221,7 +214,7 @@ func modelHandler(base, path, redirectPath string) http.Handler { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				var data struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					RedirectUrl string `json:"redirect_url"` 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				data.RedirectUrl = fmt.Sprintf(redirectPath, base, base) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				data.RedirectUrl = pattern.RedirectPath(model) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				w.Header().Set("Content-Type", "application/json") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				json.NewEncoder(w).Encode(data) 
			 |