Forráskód Böngészése

Working on new handlers

Andrea Fazzi 6 éve
szülő
commit
8b4ef4ff28

+ 45 - 27
handlers/handlers.go

@@ -162,45 +162,63 @@ func recoverHandler(next http.Handler) http.Handler {
 	return http.HandlerFunc(fn)
 }
 
+func respondWithResult(w http.ResponseWriter, r *http.Request, model string, pattern PathPattern) {
+	getFn, err := orm.GetResultFunc(pattern.Path(model))
+	if err != nil {
+		respondWithError(w, r, err)
+	} else {
+		data, err := getFn(mux.Vars(r))
+		if err != nil {
+			renderer.Render[r.URL.Query().Get("format")](w, r, err)
+		} else {
+			renderer.Render[r.URL.Query().Get("format")](w, r, data, r.URL.Query())
+		}
+	}
+
+}
+
+func respondWithError(w http.ResponseWriter, r *http.Request, err error) {
+	w.WriteHeader(http.StatusInternalServerError)
+	renderer.Render[r.URL.Query().Get("format")](w, r, err)
+}
+
+func post(w http.ResponseWriter, r *http.Request, model string, pattern PathPattern) {
+	postFn, err := orm.PostFunc(pattern.Path(model))
+	if err != nil {
+		respondWithError(w, r, err)
+	} else {
+		data, err := postFn(mux.Vars(r), r)
+		if err != nil {
+			respondWithError(w, r, err)
+		} else if r.URL.Query().Get("format") == "html" {
+			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, pattern.RedirectPath(model, data.GetID()), http.StatusSeeOther)
+			}
+		}
+
+	}
+
+	log.Println(pattern)
+	respondWithResult(w, r, model, pattern)
+}
+
 func modelHandler(model string, pattern PathPattern) http.Handler {
 	fn := func(w http.ResponseWriter, r *http.Request) {
 		var (
 			ok     bool
-			getFn  orm.GetFn
 			postFn orm.PostFn
 		)
 
 		switch r.Method {
 
 		case "GET":
-			getFn, ok = orm.Get[pattern.Path(model)]
-			if !ok {
-				renderer.Render[r.URL.Query().Get("format")](w, r, fmt.Errorf("Can't find ORM function for path %s!", pattern.PathPattern))
-			}
-			data, err := getFn(mux.Vars(r))
-			if err != nil {
-				renderer.Render[r.URL.Query().Get("format")](w, r, err)
-			} else {
-				renderer.Render[r.URL.Query().Get("format")](w, r, data, r.URL.Query())
-			}
+			respondWithResult(w, r, model, pattern)
 
 		case "POST":
-			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!", pattern.PathPattern))
-			}
-			data, err := postFn(mux.Vars(r), r)
-			if err != nil {
-				renderer.Render["html"](w, r, err)
-			} else {
-				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, pattern.RedirectPath(model, data.GetID()), http.StatusSeeOther)
-				}
-
-			}
+			post(w, r, model, pattern)
 
 		case "DELETE":
 			postFn, ok = orm.Post[pattern.Path(model)]

+ 94 - 6
handlers/handlers_test.go

@@ -5,6 +5,8 @@ import (
 	"encoding/json"
 	"net/http"
 	"net/http/httptest"
+	"net/url"
+	"strings"
 	"testing"
 	"time"
 
@@ -12,6 +14,7 @@ import (
 	"github.com/remogatto/prettytest"
 	"gogs.carducci-dante.gov.it/karmen/core/config"
 	"gogs.carducci-dante.gov.it/karmen/core/orm"
+	"gogs.carducci-dante.gov.it/karmen/core/renderer"
 )
 
 var (
@@ -38,6 +41,8 @@ func (t *testSuite) BeforeAll() {
 		err error
 	)
 
+	// Initialize the ORM
+
 	connected := false
 	for !connected {
 		time.Sleep(10 * time.Second)
@@ -52,6 +57,30 @@ func (t *testSuite) BeforeAll() {
 	orm.Use(db)
 	orm.AutoMigrate()
 
+	// Load the templates
+
+	htmlRenderer, err := renderer.NewHTMLRenderer("./testdata/templates/")
+	if err != nil {
+		panic(err)
+	}
+
+	jsonRenderer, err := renderer.NewJSONRenderer()
+	if err != nil {
+		panic(err)
+	}
+
+	renderer.Render = make(map[string]func(http.ResponseWriter, *http.Request, interface{}, ...url.Values))
+
+	renderer.Render["html"] = func(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) {
+		htmlRenderer.Render(w, r, data, options...)
+	}
+
+	renderer.Render["json"] = func(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) {
+		jsonRenderer.Render(w, r, data, options...)
+	}
+
+	// Load the configuration
+
 	err = config.ReadFile("testdata/config.yaml", config.Config)
 	if err != nil {
 		panic(err)
@@ -81,8 +110,35 @@ func (t *testSuite) BeforeAll() {
 
 }
 
+func (t *testSuite) TestGetTeachersHTML() {
+
+	req, err := http.NewRequest("GET", "/teachers?format=html&tpl_layout=base&tpl_content=teachers", nil)
+	if err != nil {
+		panic(err)
+	}
+
+	pattern := PathPattern{
+		"/%s",
+		"/%s?format=html&tpl_layout=base&tpl_content=%s",
+		[]string{"GET"},
+	}
+
+	rr := httptest.NewRecorder()
+	modelHandler("teachers", pattern).ServeHTTP(rr, req)
+
+	t.Equal(http.StatusOK, rr.Code)
+
+	if !t.Failed() {
+		t.True(strings.Contains(rr.Body.String(), "DELLE ROSE"))
+	}
+
+}
+
 func (t *testSuite) TestGetTeachersJSON() {
-	var teachers []*orm.Teacher
+	var (
+		teachers []*orm.Teacher
+		response renderer.JsonResponse
+	)
 
 	req, err := http.NewRequest("GET", "/teachers?format=json", nil)
 	if err != nil {
@@ -90,8 +146,8 @@ func (t *testSuite) TestGetTeachersJSON() {
 	}
 
 	pattern := PathPattern{
-		"/api/%s",
-		"/%s?format=json&tpl_layout=base&tpl_content=%s",
+		"/%s",
+		"/%s/%d?format=json",
 		[]string{"GET"},
 	}
 
@@ -101,15 +157,45 @@ func (t *testSuite) TestGetTeachersJSON() {
 	t.Equal(http.StatusOK, rr.Code)
 
 	if !t.Failed() {
-		err := json.Unmarshal(rr.Body.Bytes(), &teachers)
+		err := json.Unmarshal(rr.Body.Bytes(), &response)
 		t.Nil(err)
 		if !t.Failed() {
+			err := json.Unmarshal(response.Result, &teachers)
+			t.Nil(err)
 			t.Equal("AGOSTINO", teachers[0].Surname)
 		}
 	}
 
 }
 
+func (t *testSuite) TestGetErrorJSON() {
+	var (
+		response renderer.JsonResponse
+	)
+
+	req, err := http.NewRequest("GET", "/teacher/100?format=json", nil)
+	if err != nil {
+		panic(err)
+	}
+
+	pattern := PathPattern{"/api/%s/{id}", "/%s?format=json", []string{"GET"}}
+
+	rr := httptest.NewRecorder()
+	modelHandler("teachers", pattern).ServeHTTP(rr, req)
+
+	t.Equal(http.StatusInternalServerError, rr.Code)
+
+	if !t.Failed() {
+		err := json.Unmarshal(rr.Body.Bytes(), &response)
+		t.Nil(err)
+		if !t.Failed() {
+			t.Equal("Can't map /api/teachers/{id}!", string(response.Error))
+
+		}
+	}
+
+}
+
 func (t *testSuite) TestPostTeacherJSON() {
 	teacher := new(orm.Teacher)
 	teacher.Name = "Mario"
@@ -119,13 +205,15 @@ func (t *testSuite) TestPostTeacherJSON() {
 	t.Nil(err)
 
 	req, err := http.NewRequest("POST", "/teachers/add?format=json", bytes.NewBuffer(data))
+	req.Header.Set("Content-Type", "application/json; charset=utf-8")
+
 	if err != nil {
 		panic(err)
 	}
 
 	pattern := PathPattern{
-		"/api/%s/add",
-		"/%s?format=json&tpl_layout=base&tpl_content=%s",
+		"/%s/add",
+		"/%s?format=json",
 		[]string{"POST"},
 	}
 

+ 0 - 1
handlers/testdata/documents/document_1/config.yaml

@@ -1 +0,0 @@
-name: "Document 1"

+ 0 - 0
handlers/testdata/documents/document_1/template.tpl


+ 0 - 1
handlers/testdata/documents/document_2/config.yaml

@@ -1 +0,0 @@
-name: Document 2

+ 11 - 0
handlers/testdata/templates/error.html.tpl

@@ -0,0 +1,11 @@
+{{ define "content" }}
+
+<div class="container">
+
+  <h1>Errore</h1>
+  <p>
+    {{.}}
+  </p>
+    
+</div>
+{{ end }}

+ 11 - 0
handlers/testdata/templates/layout/base.html.tpl

@@ -0,0 +1,11 @@
+{{define "base"}}
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>karmen</title>
+  </head>
+  <body>
+      {{ template "content" . }}
+  </body>
+</html>
+{{end}}

+ 16 - 0
handlers/testdata/templates/teachers.html.tpl

@@ -0,0 +1,16 @@
+{{ define "content" }}
+
+<div class="container">
+  
+  {{if not .Data}}
+  <p>Nothing to show.</p>
+  {{else}}
+  <div class="list-group" id="myUL">
+    {{range $teacher := .Data}}
+      {{$teacher.Surname}} {{$teacher.Name}}
+    {{end}}
+  </div>
+  {{end}}
+  
+</div>
+{{ end }}

+ 0 - 5
main.go

@@ -52,11 +52,6 @@ func main() {
 
 	orm.Use(db)
 
-	if config.Config.Orm.Reset {
-		log.Print("Resetting the DB...")
-		orm.Reset()
-	}
-
 	if config.Config.Orm.AutoMigrate {
 		log.Print("Automigrating...")
 		orm.AutoMigrate()

+ 0 - 73
orm/class.go

@@ -202,76 +202,3 @@ func GetClassForAdd(args map[string]string) (interface{}, error) {
 
 	return data, nil
 }
-
-// func GetClasses() ([]*Class, error) {
-// 	var classes []*Class
-// 	if err := DB().Order("name").Find(&classes).Error; err != nil {
-// 		return nil, err
-// 	}
-// 	return classes, nil
-// }
-
-// func (c *Class) GetTeachers() ([]*Teacher, error) {
-// 	if err := DB().Raw(selectUniqueClassTeachers, c.ID).Scan(&c.Teachers).Error; err != nil {
-// 		return nil, err
-// 	}
-// 	return c.Teachers, nil
-// }
-
-// func GetClassesAll() ([]*Class, error) {
-// 	var classes []*Class
-// 	if err := DB().Order("name").Find(&classes).Error; err != nil {
-// 		return nil, err
-// 	}
-// 	for _, class := range classes {
-// 		class.GetTeachers()
-// 	}
-// 	return classes, nil
-// }
-
-// func GetClass(id string) (*Class, error) {
-// 	var class Class
-
-// 	if err := DB().First(&class, id).Error; err != nil {
-// 		return nil, err
-// 	}
-
-// 	if err := DB().Raw(selectUniqueClassTeachers, id).Scan(&class.Teachers).Error; err != nil {
-// 		return nil, err
-// 	}
-// 	if err := DB().Preload("Teacher").Preload("Class").Preload("Subject").Where("class_id=?", id).Find(&class.Activities).Error; err != nil {
-// 		return nil, err
-// 	}
-
-// 	if class.CoordinatorID != 0 {
-// 		if !DB().First(&class.Coordinator, class.CoordinatorID).RecordNotFound() {
-// 			if err := DB().First(&class.Coordinator, class.CoordinatorID).Error; err != nil {
-// 				return nil, err
-// 			}
-// 		}
-// 	}
-
-// 	if class.MinuterID != 0 {
-// 		if !DB().First(&class.Minuter, class.MinuterID).RecordNotFound() {
-// 			if err := DB().First(&class.Minuter, class.MinuterID).Error; err != nil {
-// 				return nil, err
-// 			}
-// 		}
-// 	}
-
-// 	return &class, nil
-// }
-
-// func (t *Class) Create(db *gorm.DB, record map[string]interface{}) error {
-// 	result := new(Class)
-
-// 	if name := record["name"]; name == nil {
-// 		return errors.New("Error in creating class: field name is empty")
-// 	} else {
-// 		result.Name = name.(string)
-// 	}
-
-// 	db.Create(result)
-
-// 	return nil
-// }

+ 17 - 156
orm/orm.go

@@ -1,10 +1,8 @@
 package orm
 
 import (
-	"errors"
 	"fmt"
 	"net/http"
-	"strings"
 
 	"github.com/jinzhu/gorm"
 	_ "github.com/jinzhu/gorm/dialects/mysql"
@@ -147,7 +145,7 @@ var (
 
 		/// JSON
 
-		"/api/teachers/add": AddTeacher,
+		"/teachers/add": AddTeacher,
 
 		// Classes
 		"/classes/{id}/update": UpdateClass,
@@ -166,139 +164,6 @@ var (
 	}
 )
 
-func (b *TheBoss) Create(db *gorm.DB, record map[string]interface{}) error {
-	if record["role"] == "boss" {
-		result := new(TheBoss)
-		result.Name = record["name"].(string)
-		result.Surname = record["surname"].(string)
-		result.Username = result.GenerateUsername()
-		result.Password = result.GenerateSaltedPassword(result.Username)
-		db.Create(result)
-	} else {
-		boss := TheBoss{}
-		teacher := Teacher{}
-		db.Model(TheBoss{}).First(&boss)
-		db.Where("username=?", record["username"]).First(&teacher)
-		db.Model(&boss).Association("Teachers").Append(&teacher)
-	}
-
-	return nil
-}
-
-func (a *Administrative) Create(db *gorm.DB, record map[string]interface{}) error {
-	result := Administrative{}
-	result.Name = record["name"].(string)
-	result.Surname = record["surname"].(string)
-	result.Username = result.GenerateUsername()
-	result.Password = result.GenerateSaltedPassword(result.Username)
-
-	switch record["role"] {
-	case "personal_administrator":
-		result.Role = ADMINISTRATIVE_ROLE_PERSONAL
-	case "teaching_administrator":
-		result.Role = ADMINISTRATIVE_ROLE_TEACHING
-	case "school_caretaker":
-		result.Role = ADMINISTRATIVE_ROLE_SCHOOL_CARETAKER
-	case "technical_assistant":
-		result.Role = ADMINISTRATIVE_ROLE_TECHNICAL_ASSISTANT
-	case "librarian":
-		result.Role = ADMINISTRATIVE_ROLE_LIBRARIAN
-	case "dsga":
-		result.Role = ADMINISTRATIVE_ROLE_DSGA
-	default:
-		result.Role = ADMINISTRATIVE_ROLE_UNDEFINED
-	}
-
-	db.Create(&result)
-	return nil
-}
-
-func (d *Director) Create(db *gorm.DB, record map[string]interface{}) error {
-	result := new(Director)
-
-	if name := record["name"]; name == nil {
-		return errors.New("Error in creating director: field name is empty")
-	} else {
-		result.Name = name.(string)
-	}
-	if surname := record["surname"]; surname == nil {
-		return errors.New("Error in creating director: field surname is empty")
-	} else {
-		result.Surname = surname.(string)
-	}
-
-	// Generate username and initial password
-
-	result.Username = result.GenerateUsername()
-	result.Password = result.GenerateSaltedPassword(result.Username)
-
-	db.Set("gorm:save_associations", false).Create(result)
-
-	return nil
-}
-
-func (t *Student) Create(db *gorm.DB, record map[string]interface{}) error {
-	result := new(Student)
-
-	if name := record["name"]; name == nil {
-		return errors.New("Error in creating student: field name is empty")
-	} else {
-		result.Name = name.(string)
-	}
-	if surname := record["surname"]; surname == nil {
-		return errors.New("Error in creating student: field surname is empty")
-	} else {
-		result.Surname = surname.(string)
-	}
-
-	// Generate username and initial password
-
-	result.Username = result.GenerateUsername()
-	result.Password = result.GenerateSaltedPassword(result.Username)
-
-	db.Set("gorm:save_associations", false).Create(result)
-
-	return nil
-}
-
-func (d *Department) Create(db *gorm.DB, record map[string]interface{}) error {
-	result := new(Department)
-
-	if name := record["name"]; name == nil {
-		return errors.New("Error in updating subject: field name is empty")
-	} else {
-		result.Name = name.(string)
-	}
-
-	db.Set("gorm:save_associations", false).Create(result)
-
-	// Handle department-subjects relationship
-
-	for _, s := range record["subjects"].([]interface{}) {
-		subject := Subject{}
-		db.Where("name=?", strings.TrimSpace(s.(string))).Find(&subject)
-		db.Model(result).Association("Subjects").Append(subject)
-	}
-
-	// Handle department-teachers relationship
-
-	allTeachers := make([]Teacher, 0)
-	db.Find(&allTeachers)
-
-	for _, t := range allTeachers {
-		db.Model(&t).Related(&t.Subjects, "Subjects")
-		for _, s := range t.Subjects {
-			for _, depS := range result.Subjects {
-				if s.Name == depS.Name {
-					db.Model(result).Association("Teachers").Append(t)
-				}
-			}
-		}
-	}
-
-	return nil
-}
-
 func New(connection string) (*gorm.DB, error) {
 	db, err := gorm.Open("mysql", connection)
 	if err != nil {
@@ -315,22 +180,6 @@ func DB() *gorm.DB {
 	return currDB
 }
 
-func Reset() {
-	currDB.DropTableIfExists(
-		&School{},
-		&Subject{},
-		&Teacher{},
-		&Class{},
-		&Activity{},
-		&Student{},
-		&Department{},
-		&TheBoss{},
-		&Administrative{},
-		&Director{},
-		&Issue{},
-	)
-}
-
 func AutoMigrate() {
 	if err := currDB.AutoMigrate(
 		&School{},
@@ -350,8 +199,20 @@ func AutoMigrate() {
 
 }
 
-func GetTeacherByUsername(username string) (*Teacher, error) {
-	teacher := Teacher{}
-	currDB.Where(fmt.Sprintf("username='%s'", username)).Find(&teacher)
-	return &teacher, nil
+func GetResultFunc(path string) (GetFn, error) {
+	fn, ok := Get[path]
+	if !ok {
+		return nil, fmt.Errorf("Can't map %s!", path)
+	}
+
+	return fn, nil
+}
+
+func PostFunc(path string) (PostFn, error) {
+	fn, ok := Post[path]
+	if !ok {
+		return nil, fmt.Errorf("Can't map %s!", path)
+	}
+
+	return fn, nil
 }

+ 33 - 4
renderer/renderer.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"html/template"
+	"log"
 	"net/http"
 	"net/url"
 	"path"
@@ -25,6 +26,11 @@ type htmlTemplateData struct {
 	Options url.Values
 }
 
+type JsonResponse struct {
+	Result []byte
+	Error  []byte
+}
+
 var (
 	currRenderer Renderer
 	Render       map[string]func(http.ResponseWriter, *http.Request, interface{}, ...url.Values)
@@ -80,11 +86,25 @@ func NewJSONRenderer() (*JSONRenderer, error) {
 
 func (rend *JSONRenderer) Render(w http.ResponseWriter, r *http.Request, data interface{}, options ...url.Values) error {
 	w.Header().Set("Content-Type", "application/json; charset=utf-8")
-	j, err := json.Marshal(data)
-	if err != nil {
-		return err
+	if isErrorType(data) {
+		j, err := json.Marshal(JsonResponse{nil, []byte(data.(error).Error())})
+		if err != nil {
+			return err
+		}
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write(j)
+	} else {
+		result, err := json.Marshal(data)
+		if err != nil {
+			return err
+		}
+
+		response, err := json.Marshal(JsonResponse{result, nil})
+		if err != nil {
+			return err
+		}
+		w.Write(response)
 	}
-	w.Write(j)
 	return nil
 }
 
@@ -128,6 +148,7 @@ func Use(r Renderer) {
 }
 
 func (rend *HTMLRenderer) writeError(w http.ResponseWriter, r *http.Request, err error) {
+	log.Println(rend.templates)
 	t, ok := rend.templates["error"]
 	if !ok {
 		panic(fmt.Errorf("Error template not found! Can't proceed, sorry."))
@@ -157,6 +178,7 @@ func (rend *HTMLRenderer) Render(w http.ResponseWriter, r *http.Request, data in
 }
 
 func Decode(dst interface{}, r *http.Request) error {
+
 	switch r.Header.Get("Content-type") {
 
 	case "application/x-www-form-urlencoded":
@@ -168,6 +190,13 @@ func Decode(dst interface{}, r *http.Request) error {
 		if err := decoder.Decode(dst, r.PostForm); err != nil {
 			return err
 		}
+	case "application/json; charset=utf-8":
+		decoder := json.NewDecoder(r.Body)
+		err := decoder.Decode(&dst)
+		if err != nil {
+			return err
+		}
+
 	}
 
 	return nil

+ 1 - 1
templates/activities.html.tpl

@@ -31,7 +31,7 @@
       {{if not $activity.Subject}}
       <small>no materia</small>
       {{else}}
-      <small>{{$activity.Subject.Name}}</small>
+      {{$activity.Subject.Name}}
       {{end}}
       <div class="text-right">
 	{{if not $activity.Teacher}}