Browse Source

Work in progress

Andrea Fazzi 6 năm trước cách đây
mục cha
commit
d2a0435f1f

+ 0 - 146
handlers/api.go

@@ -1,146 +0,0 @@
-package api
-
-import (
-	"fmt"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"path/filepath"
-	"runtime/debug"
-
-	jwtmiddleware "github.com/auth0/go-jwt-middleware"
-	jwt "github.com/dgrijalva/jwt-go"
-	"github.com/gorilla/mux"
-	"github.com/gorilla/sessions"
-)
-
-var (
-	signingKey    = []byte("secret")
-	store         = sessions.NewCookieStore([]byte("something-very-secret"))
-	jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{
-		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
-			return signingKey, nil
-		},
-		SigningMethod: jwt.SigningMethodHS256,
-		Extractor:     fromCookie,
-		ErrorHandler:  onError,
-	})
-)
-
-type User struct {
-	Name  string
-	Admin bool
-}
-
-func Handlers() *mux.Router {
-	r := mux.NewRouter()
-
-	// Authentication
-
-	r.Handle("/login", loginHandler())
-	r.Handle("/logout", logoutHandler())
-
-	// Dashboard
-
-	r.Handle("/", jwtMiddleware.Handler(recoverHandler(dashboardHandler())))
-
-	// School
-
-	r.Handle("/school/{id}", jwtMiddleware.Handler(recoverHandler(schoolShowHandler())))
-	r.Handle("/school/{id}/update", jwtMiddleware.Handler(recoverHandler(schoolUpdateHandler()))).Methods("GET", "POST")
-
-	// Teachers
-
-	r.Handle("/teachers/check_username/{username}", jwtMiddleware.Handler(recoverHandler(teachersCheckUsernameHandler())))
-	r.Handle("/teachers", jwtMiddleware.Handler(recoverHandler(teachersHandler())))
-	r.Handle("/teachers/add", jwtMiddleware.Handler(recoverHandler(teachersAddHandler()))).Methods("GET", "POST")
-	r.Handle("/teachers/{id}/delete", jwtMiddleware.Handler(recoverHandler(teachersDeleteHandler()))).Methods("DELETE")
-	r.Handle("/teachers/{id}", jwtMiddleware.Handler(recoverHandler(teacherShowHandler()))).Methods("GET")
-	r.Handle("/teachers/{id}/update", jwtMiddleware.Handler(recoverHandler(teacherUpdateHandler()))).Methods("GET", "POST")
-	r.Handle("/teachers/import", jwtMiddleware.Handler(recoverHandler(teachersImportHandler()))).Methods("POST")
-
-	// Teachers -> Subjects
-
-	r.Handle("/teachers/{id}/subjects/add", jwtMiddleware.Handler(recoverHandler(teacherSubjectsAdd()))).Methods("GET")
-	r.Handle("/teachers/{id}/subjects/add", jwtMiddleware.Handler(recoverHandler(teacherSubjectsAdd()))).Methods("POST")
-	r.Handle("/teachers/{id}/subjects/{subject_id}/delete", jwtMiddleware.Handler(recoverHandler(teachersSubjectsDelete()))).Methods("DELETE")
-
-	// Teachers -> Classes
-
-	r.Handle("/teachers/{id}/classes/add", jwtMiddleware.Handler(recoverHandler(teacherClassesAdd()))).Methods("GET")
-	r.Handle("/teachers/{id}/classes/add", jwtMiddleware.Handler(recoverHandler(teacherClassesAdd()))).Methods("POST")
-	r.Handle("/teachers/{id}/classes/{class_id}/delete", jwtMiddleware.Handler(recoverHandler(teachersClassesDelete()))).Methods("DELETE")
-
-	// Subjects
-
-	r.Handle("/subjects", jwtMiddleware.Handler(recoverHandler(subjectsHandler())))
-	r.Handle("/subjects/add", jwtMiddleware.Handler(recoverHandler(subjectsAddHandler()))).Methods("GET", "POST")
-	r.Handle("/subjects/{id}", jwtMiddleware.Handler(recoverHandler(subjectsShowHandler()))).Methods("GET")
-	r.Handle("/subjects/{id}/update", jwtMiddleware.Handler(recoverHandler(subjectsUpdateHandler()))).Methods("GET", "POST")
-	r.Handle("/subjects/{id}/delete", jwtMiddleware.Handler(recoverHandler(subjectsDeleteHandler()))).Methods("DELETE")
-	r.Handle("/subjects/import", jwtMiddleware.Handler(recoverHandler(subjectsImportHandler()))).Methods("POST")
-
-	// Activities
-
-	r.Handle("/activities", jwtMiddleware.Handler(recoverHandler(activitiesHandler())))
-	r.Handle("/activities/add", jwtMiddleware.Handler(recoverHandler(activitiesAddHandler()))).Methods("GET", "POST")
-	r.Handle("/activities/{id}/update", jwtMiddleware.Handler(recoverHandler(activitiesUpdateHandler()))).Methods("GET", "POST")
-	r.Handle("/activities/{id}/delete", jwtMiddleware.Handler(recoverHandler(activitiesDeleteHandler()))).Methods("DELETE")
-
-	// Classes
-
-	r.Handle("/classes", jwtMiddleware.Handler(recoverHandler(classesHandler())))
-	r.Handle("/classes/add", jwtMiddleware.Handler(recoverHandler(classesAddHandler()))).Methods("GET", "POST")
-	r.Handle("/classes/{id}", jwtMiddleware.Handler(recoverHandler(classesShowHandler()))).Methods("GET")
-	r.Handle("/classes/{id}/update", jwtMiddleware.Handler(recoverHandler(classesUpdateHandler()))).Methods("GET", "POST")
-	r.Handle("/classes/{id}/delete", jwtMiddleware.Handler(recoverHandler(classesDeleteHandler()))).Methods("DELETE")
-	r.Handle("/classes/import", jwtMiddleware.Handler(recoverHandler(classesImportHandler()))).Methods("POST")
-
-	// Static file server
-
-	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./dist/")))
-
-	return r
-}
-
-func onError(w http.ResponseWriter, r *http.Request, err string) {
-	http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
-}
-
-func respondWithStaticFile(w http.ResponseWriter, filename string) error {
-	f, err := ioutil.ReadFile(filepath.Join("public/html", filename))
-	if err != nil {
-		return err
-	}
-	w.Write(f)
-	return nil
-}
-
-func fromCookie(r *http.Request) (string, error) {
-	session, err := store.Get(r, "login-session")
-	if err != nil {
-		return "", nil
-	}
-
-	if session.Values["token"] == nil {
-		return "", nil
-	}
-
-	token := session.Values["token"].([]uint8)
-
-	return string(token), nil
-}
-
-func recoverHandler(next http.Handler) http.Handler {
-	fn := func(w http.ResponseWriter, r *http.Request) {
-		defer func() {
-			if err := recover(); err != nil {
-				panicMsg := fmt.Sprintf("PANIC: %v\n\n== STACKTRACE ==\n%s", err, debug.Stack())
-				log.Print(panicMsg)
-				http.Error(w, panicMsg, http.StatusInternalServerError)
-			}
-		}()
-		next.ServeHTTP(w, r)
-	}
-	return http.HandlerFunc(fn)
-}

+ 141 - 0
handlers/handlers.go

@@ -0,0 +1,141 @@
+package api
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"path/filepath"
+	"runtime/debug"
+
+	jwtmiddleware "github.com/auth0/go-jwt-middleware"
+	jwt "github.com/dgrijalva/jwt-go"
+	"github.com/gorilla/mux"
+	"github.com/gorilla/sessions"
+)
+
+var (
+	signingKey    = []byte("secret")
+	store         = sessions.NewCookieStore([]byte("something-very-secret"))
+	jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{
+		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
+			return signingKey, nil
+		},
+		SigningMethod: jwt.SigningMethodHS256,
+		Extractor:     fromCookie,
+		ErrorHandler:  onError,
+	})
+
+	crud []string = []string{"add", "show", "update", "delete"}
+)
+
+type User struct {
+	Name  string
+	Admin bool
+}
+
+// Generate CRUD handlers
+func generateHandler(r *mux.Router, base string) {
+	r.Handle(fmt.Sprintf("/%s", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s", base))))).Methods("GET")
+	r.Handle(fmt.Sprintf("/%s/{id}", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}", base))))).Methods("GET")
+	r.Handle(fmt.Sprintf("/%s/add/", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/add/", base))))).Methods("GET", "POST")
+	r.Handle(fmt.Sprintf("/%s/{id}/update", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}/update", base))))).Methods("GET", "POST")
+	r.Handle(fmt.Sprintf("/%s/{id}/delete", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}/delete", base))))).Methods("POST")
+}
+
+func Handlers() *mux.Router {
+	r := mux.NewRouter()
+
+	// Authentication
+
+	r.Handle("/login", loginHandler())
+	r.Handle("/logout", logoutHandler())
+
+	// Dashboard
+
+	r.Handle("/", jwtMiddleware.Handler(recoverHandler(dashboardHandler())))
+
+	// School
+
+	r.Handle("/school/{id}", jwtMiddleware.Handler(recoverHandler(schoolShowHandler())))
+	r.Handle("/school/{id}/update", jwtMiddleware.Handler(recoverHandler(schoolUpdateHandler()))).Methods("GET", "POST")
+
+	// Generate handlers
+
+	for _, model := range []string{"teachers", "activities"} {
+		generateHandler(r, model)
+	}
+
+	// // Subjects
+
+	// r.Handle("/subjects", jwtMiddleware.Handler(recoverHandler(subjectsHandler())))
+	// r.Handle("/subjects/add", jwtMiddleware.Handler(recoverHandler(subjectsAddHandler()))).Methods("GET", "POST")
+	// r.Handle("/subjects/{id}", jwtMiddleware.Handler(recoverHandler(subjectsShowHandler()))).Methods("GET")
+	// r.Handle("/subjects/{id}/update", jwtMiddleware.Handler(recoverHandler(subjectsUpdateHandler()))).Methods("GET", "POST")
+	// r.Handle("/subjects/{id}/delete", jwtMiddleware.Handler(recoverHandler(subjectsDeleteHandler()))).Methods("DELETE")
+	// r.Handle("/subjects/import", jwtMiddleware.Handler(recoverHandler(subjectsImportHandler()))).Methods("POST")
+
+	// // Activities
+
+	// r.Handle("/activities", jwtMiddleware.Handler(recoverHandler(activitiesHandler())))
+	// r.Handle("/activities/add", jwtMiddleware.Handler(recoverHandler(activitiesAddHandler()))).Methods("GET", "POST")
+	// r.Handle("/activities/{id}/update", jwtMiddleware.Handler(recoverHandler(activitiesUpdateHandler()))).Methods("GET", "POST")
+	// r.Handle("/activities/{id}/delete", jwtMiddleware.Handler(recoverHandler(activitiesDeleteHandler()))).Methods("DELETE")
+
+	// // Classes
+
+	// r.Handle("/classes", jwtMiddleware.Handler(recoverHandler(classesHandler())))
+	// r.Handle("/classes/add", jwtMiddleware.Handler(recoverHandler(classesAddHandler()))).Methods("GET", "POST")
+	// r.Handle("/classes/{id}", jwtMiddleware.Handler(recoverHandler(classesShowHandler()))).Methods("GET")
+	// r.Handle("/classes/{id}/update", jwtMiddleware.Handler(recoverHandler(classesUpdateHandler()))).Methods("GET", "POST")
+	// r.Handle("/classes/{id}/delete", jwtMiddleware.Handler(recoverHandler(classesDeleteHandler()))).Methods("DELETE")
+	// r.Handle("/classes/import", jwtMiddleware.Handler(recoverHandler(classesImportHandler()))).Methods("POST")
+
+	// Static file server
+
+	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./dist/")))
+
+	return r
+}
+
+func onError(w http.ResponseWriter, r *http.Request, err string) {
+	http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
+}
+
+func respondWithStaticFile(w http.ResponseWriter, filename string) error {
+	f, err := ioutil.ReadFile(filepath.Join("public/html", filename))
+	if err != nil {
+		return err
+	}
+	w.Write(f)
+	return nil
+}
+
+func fromCookie(r *http.Request) (string, error) {
+	session, err := store.Get(r, "login-session")
+	if err != nil {
+		return "", nil
+	}
+
+	if session.Values["token"] == nil {
+		return "", nil
+	}
+
+	token := session.Values["token"].([]uint8)
+
+	return string(token), nil
+}
+
+func recoverHandler(next http.Handler) http.Handler {
+	fn := func(w http.ResponseWriter, r *http.Request) {
+		defer func() {
+			if err := recover(); err != nil {
+				panicMsg := fmt.Sprintf("PANIC: %v\n\n== STACKTRACE ==\n%s", err, debug.Stack())
+				log.Print(panicMsg)
+				http.Error(w, panicMsg, http.StatusInternalServerError)
+			}
+		}()
+		next.ServeHTTP(w, r)
+	}
+	return http.HandlerFunc(fn)
+}

+ 0 - 0
handlers/api_test.go → handlers/handlers_test.go


+ 45 - 142
handlers/teachers.go

@@ -1,164 +1,67 @@
 package api
 
 import (
-	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 
 	"github.com/gorilla/mux"
 	"gogs.carducci-dante.gov.it/karmen/core/orm"
 	"gogs.carducci-dante.gov.it/karmen/core/renderer"
-	"gogs.carducci-dante.gov.it/karmen/datasource/edt"
 )
 
-func teachersHandler() http.Handler {
+func generalHandler(base, path string) http.Handler {
 	fn := func(w http.ResponseWriter, r *http.Request) {
-		teachers, err := orm.GetTeachersAll()
-		if err != nil {
-			renderer.Render[r.URL.Query()["format"][0]](w, r, err)
+		var (
+			ok     bool
+			getFn  orm.GetFn
+			postFn orm.PostFn
+		)
+		if r.Method == "GET" {
+			getFn, ok = orm.Get[path]
 		} else {
-			renderer.Render[r.URL.Query()["format"][0]](w, r, teachers, r.URL.Query())
+			postFn, ok = orm.Post[path]
 		}
-	}
-	return http.HandlerFunc(fn)
-}
-
-func teacherShowHandler() http.Handler {
-	fn := func(w http.ResponseWriter, r *http.Request) {
-		teacher, err := orm.GetTeacherAll(mux.Vars(r)["id"])
-		if err != nil {
-			renderer.Render[r.URL.Query()["format"][0]](w, r, err)
+		if !ok {
+			renderer.Render[r.URL.Query()["format"][0]](w, r, fmt.Errorf("Can't find ORM function for path %s!", path))
 		} else {
-			renderer.Render[r.URL.Query()["format"][0]](w, r, teacher, r.URL.Query())
-		}
-	}
-	return http.HandlerFunc(fn)
-}
-
-func teachersAddHandler() http.Handler {
-	fn := func(w http.ResponseWriter, r *http.Request) {
-		if r.Method == "GET" {
-			teacher, err := orm.GetTeacher(mux.Vars(r)["id"])
-			if err != nil {
-				renderer.Render[r.URL.Query()["format"][0]](w, r, err)
-			} else {
-				renderer.Render[r.URL.Query()["format"][0]](w, r, teacher, r.URL.Query())
-			}
-		} else if r.Method == "POST" {
-			teacher := new(orm.Teacher)
-			err := renderer.Decode(teacher, r)
-			if err != nil {
-				panic(err)
-			}
-			_, err = orm.CreateTeacher(teacher)
-			if err != nil {
-				panic(err)
-			}
-			http.Redirect(w, r, fmt.Sprintf("/teachers/%d?format=html&tpl_layout=base&tpl_content=teachers_show", teacher.ID), http.StatusSeeOther)
-		}
-
-	}
-	return http.HandlerFunc(fn)
-}
-
-func teachersDeleteHandler() http.Handler {
-	fn := func(w http.ResponseWriter, r *http.Request) {
-		teacher, err := orm.GetTeacher(mux.Vars(r)["id"])
-		if err != nil {
-			panic(err)
-		}
-		if err := orm.DeleteTeacher(teacher); err != nil {
-			panic(err)
-		}
-
-		var data struct {
-			RedirectUrl string `json:"redirect_url"`
-		}
-
-		data.RedirectUrl = "/teachers?format=html&tpl_layout=base&tpl_content=teachers"
-
-		w.Header().Set("Content-Type", "application/json")
-		json.NewEncoder(w).Encode(data)
-	}
-	return http.HandlerFunc(fn)
-}
-
-func teacherUpdateHandler() http.Handler {
-	fn := func(w http.ResponseWriter, r *http.Request) {
-		if r.Method == "GET" {
-			teacher, err := orm.GetTeacher(mux.Vars(r)["id"])
-			if err != nil {
-				renderer.Render[r.URL.Query()["format"][0]](w, r, err)
+			if r.Method == "GET" {
+				data, err := getFn(mux.Vars(r))
+				if err != nil {
+					renderer.Render[r.URL.Query()["format"][0]](w, r, err)
+				} else {
+					renderer.Render[r.URL.Query()["format"][0]](w, r, data, r.URL.Query())
+				}
 			} else {
-				renderer.Render[r.URL.Query()["format"][0]](w, r, teacher, r.URL.Query())
-			}
-		} else if r.Method == "POST" {
-			teacher, err := orm.GetTeacher(mux.Vars(r)["id"])
-			if err != nil {
-				panic(err)
-			}
-			err = renderer.Decode(teacher, r)
-			if err != nil {
-				panic(err)
+				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,
+						)
+					} else {
+						http.Redirect(w, r,
+							fmt.Sprintf(
+								"/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show",
+								base,
+								data.GetID(),
+								base,
+							),
+							http.StatusSeeOther,
+						)
+					}
+
+				}
 			}
-			_, err = orm.SaveTeacher(teacher)
-			if err != nil {
-				panic(err)
-			}
-			http.Redirect(w, r, fmt.Sprintf("/teachers/%d?format=html&tpl_layout=base&tpl_content=teachers_show", teacher.ID), http.StatusSeeOther)
-		}
-
-	}
-	return http.HandlerFunc(fn)
-}
-
-func teachersCheckUsernameHandler() http.Handler {
-	fn := func(w http.ResponseWriter, r *http.Request) {
-		var teacher orm.Teacher
-		var data struct {
-			Exists bool `json:"exists"`
-		}
-
-		if orm.DB().Where("username = ?", mux.Vars(r)["username"]).Find(&teacher).RecordNotFound() {
-			data.Exists = false
-		} else {
-			data.Exists = true
 		}
-
-		w.Header().Set("Content-Type", "application/json")
-		json.NewEncoder(w).Encode(data)
-
 	}
-	return http.HandlerFunc(fn)
-}
 
-func teachersImportHandler() http.Handler {
-	fn := func(w http.ResponseWriter, r *http.Request) {
-		r.ParseMultipartForm(32 << 20)
-		file, _, err := r.FormFile("teachers_import")
-		if err != nil {
-			panic(err)
-		}
-		defer file.Close()
-		data, err := ioutil.ReadAll(file)
-		if err != nil {
-			panic(err)
-		}
-		if importer, err := edt.NewImporter(
-			string(data),
-			map[string]string{
-				"COGNOME": "surname",
-				"NOME":    "name",
-			},
-		); err != nil {
-			panic(err)
-		} else {
-			if err := orm.Import(&orm.Teacher{}, importer); err != nil {
-				panic(err)
-			}
-			http.Redirect(w, r, "/teachers", http.StatusSeeOther)
-		}
-	}
 	return http.HandlerFunc(fn)
 }

+ 97 - 1
orm/activity.go

@@ -1,6 +1,11 @@
 package orm
 
-import "github.com/jinzhu/gorm"
+import (
+	"net/http"
+
+	"github.com/jinzhu/gorm"
+	"gogs.carducci-dante.gov.it/karmen/core/renderer"
+)
 
 type Activity struct {
 	gorm.Model
@@ -15,3 +20,94 @@ type Activity struct {
 
 	prevTeacherID uint
 }
+
+func (a *Activity) GetID() uint { return a.ID }
+
+func GetActivity(args map[string]string) (interface{}, error) {
+	var activity Activity
+	if err := DB().First(&activity, args["id"]).Error; err != nil {
+		return nil, err
+	}
+	return &activity, nil
+}
+
+func GetActivityAll(args map[string]string) (interface{}, error) {
+	var activity Activity
+
+	id := args["id"]
+
+	if err := DB().Preload("Teacher").Preload("Subject").Preload("Class").First(&activity, id).Error; err != nil {
+		return nil, err
+	}
+	return &activity, nil
+}
+
+func GetActivitiesAll(args map[string]string) (interface{}, error) {
+	var activities []*Activity
+	if err := DB().Preload("Teacher").Preload("Subject").Preload("Class").Order("name").Find(&activities).Error; err != nil {
+		return nil, err
+	}
+	return activities, nil
+}
+
+func GetActivities(args map[string]string) (interface{}, error) {
+	var activities []*Activity
+	if err := DB().Order("surname,name").Find(&activities).Error; err != nil {
+		return nil, err
+	}
+	return activities, nil
+}
+
+func SaveActivity(activity interface{}) (interface{}, error) {
+	if err := DB().Save(activity).Error; err != nil {
+		return nil, err
+	}
+	return activity, nil
+}
+
+func UpdateActivity(args map[string]string, r *http.Request) (IDer, error) {
+	activity, err := GetActivity(args)
+	if err != nil {
+		return nil, err
+	}
+	err = renderer.Decode(activity, r)
+	if err != nil {
+		return nil, err
+	}
+	_, err = SaveActivity(activity)
+	if err != nil {
+		return nil, err
+	}
+	activity, err = GetActivity(args)
+	if err != nil {
+		return nil, err
+	}
+	return activity.(*Activity), nil
+}
+
+func AddActivity(args map[string]string, r *http.Request) (IDer, error) {
+	activity := new(Activity)
+	err := renderer.Decode(activity, r)
+	if err != nil {
+		return nil, err
+	}
+	activity, err = CreateActivity(activity)
+	if err != nil {
+		return nil, err
+	}
+	return activity, nil
+}
+
+func CreateActivity(activity *Activity) (*Activity, error) {
+	if err := DB().Create(activity).Error; err != nil {
+		return nil, err
+	}
+	return activity, nil
+}
+
+func DeleteActivity(activity *Activity) error {
+	if err := DB().Delete(activity).Error; err != nil {
+		return err
+	}
+	return nil
+}

+ 28 - 2
orm/orm.go

@@ -3,6 +3,7 @@ package orm
 import (
 	"errors"
 	"fmt"
+	"net/http"
 	"strings"
 
 	"github.com/jinzhu/gorm"
@@ -22,8 +23,6 @@ const (
 	IssueTeacherHours = iota
 )
 
-var currDB *gorm.DB
-
 type Timetable [][]Activity
 
 type Person interface {
@@ -93,6 +92,33 @@ type Department struct {
 	Teachers []Teacher `gorm:"many2many:department_teachers;"`
 }
 
+type GetFn func(map[string]string) (interface{}, error)
+type PostFn func(map[string]string, *http.Request) (IDer, error)
+
+var (
+	currDB *gorm.DB
+
+	Get map[string]GetFn = map[string]GetFn{
+		"/teachers":             GetTeachersAll,
+		"/teachers/{id}":        GetTeacherAll,
+		"/teachers/{id}/update": GetTeacher,
+		"/teachers/add/":        GetNothing,
+
+		"/activities":             GetActivitiesAll,
+		"/activities/{id}":        GetActivityAll,
+		"/activities/{id}/update": GetActivity,
+		"/activities/add/":        GetNothing,
+	}
+
+	Post map[string]PostFn = map[string]PostFn{
+		"/teachers/{id}/update": UpdateTeacher,
+		"/teachers/add/":        AddTeacher,
+
+		"/activities/{id}/update": UpdateActivity,
+		"/activities/add/":        AddActivity,
+	}
+)
+
 func (b *TheBoss) Create(db *gorm.DB, record map[string]interface{}) error {
 	if record["role"] == "boss" {
 		result := new(TheBoss)

+ 55 - 7
orm/teacher.go

@@ -2,8 +2,10 @@ package orm
 
 import (
 	"errors"
+	"net/http"
 
 	"github.com/jinzhu/gorm"
+	"gogs.carducci-dante.gov.it/karmen/core/renderer"
 )
 
 type Teacher struct {
@@ -19,6 +21,10 @@ type Teacher struct {
 	TheBossId   uint
 }
 
+type IDer interface {
+	GetID() uint
+}
+
 var (
 	selectDistinctTeachers = `
 SELECT teachers.* FROM activities
@@ -35,16 +41,25 @@ INNER JOIN subjects on subjects.id=activities.subject_id
 WHERE activities.teacher_id=?`
 )
 
-func GetTeacher(id string) (*Teacher, error) {
+func (t *Teacher) GetID() uint { return t.ID }
+
+func GetNothing(args map[string]string) (interface{}, error) {
+	return nil, nil
+}
+
+func GetTeacher(args map[string]string) (interface{}, error) {
 	var teacher Teacher
-	if err := DB().First(&teacher, id).Error; err != nil {
+	if err := DB().First(&teacher, args["id"]).Error; err != nil {
 		return nil, err
 	}
 	return &teacher, nil
 }
 
-func GetTeacherAll(id string) (*Teacher, error) {
+func GetTeacherAll(args map[string]string) (interface{}, error) {
 	var teacher Teacher
+
+	id := args["id"]
+
 	if err := DB().First(&teacher, id).Error; err != nil {
 		return nil, err
 	}
@@ -64,7 +79,7 @@ func GetTeacherAll(id string) (*Teacher, error) {
 	return &teacher, nil
 }
 
-func GetTeachers() ([]*Teacher, error) {
+func GetTeachers(args map[string]string) (interface{}, error) {
 	var teachers []*Teacher
 	if err := DB().Order("surname,name").Find(&teachers).Error; err != nil {
 		return nil, err
@@ -72,7 +87,7 @@ func GetTeachers() ([]*Teacher, error) {
 	return teachers, nil
 }
 
-func GetTeachersAll() ([]*Teacher, error) {
+func GetTeachersAll(args map[string]string) (interface{}, error) {
 	var teachers []*Teacher
 	if err := DB().Order("surname,name").Find(&teachers).Error; err != nil {
 		return nil, err
@@ -87,8 +102,41 @@ func GetTeachersAll() ([]*Teacher, error) {
 	return teachers, nil
 }
 
-func SaveTeacher(teacher *Teacher) (*Teacher, error) {
-	if err := DB().Save(&teacher).Error; err != nil {
+func SaveTeacher(teacher interface{}) (interface{}, error) {
+	if err := DB().Save(teacher).Error; err != nil {
+		return nil, err
+	}
+	return teacher, nil
+}
+
+func UpdateTeacher(args map[string]string, r *http.Request) (IDer, error) {
+	teacher, err := GetTeacher(args)
+	if err != nil {
+		return nil, err
+	}
+	err = renderer.Decode(teacher, r)
+	if err != nil {
+		return nil, err
+	}
+	_, err = SaveTeacher(teacher)
+	if err != nil {
+		return nil, err
+	}
+	teacher, err = GetTeacher(args)
+	if err != nil {
+		return nil, err
+	}
+	return teacher.(*Teacher), nil
+}
+
+func AddTeacher(args map[string]string, r *http.Request) (IDer, error) {
+	teacher := new(Teacher)
+	err := renderer.Decode(teacher, r)
+	if err != nil {
+		return nil, err
+	}
+	teacher, err = CreateTeacher(teacher)
+	if err != nil {
 		return nil, err
 	}
 	return teacher, nil

+ 3 - 3
templates/activities.html.tpl

@@ -21,12 +21,12 @@
     <input type="text" id="myInput" class="form-control" aria-describedby="search-query">
   </div>
   
-  {{if not .Activities}}
+  {{if not .Data}}
   <p>Non c'è alcun elemento da visualizzare</p>
   {{else}}
   <div class="list-group" id="myUL">
-    {{range $activity := .Activities}}
-    <a class="list-group-item clearfix" href="/activities/{{$activity.ID}}/update">
+    {{range $activity := .Data}}
+    <a class="list-group-item clearfix" href="/activities/{{$activity.ID}}/update{{queryString "base" "activities_show"}}">
       <span class="glyphicon glyphicon-briefcase"></span>
       {{$activity.Subject.Name}}
       <div class="text-right">

+ 101 - 0
templates/activities_show.html.tpl

@@ -0,0 +1,101 @@
+{{ define "content" }}
+
+<div class="container">
+
+  <ol class="breadcrumb">
+    <li><a href="/activities{{queryString "base" "activities"}}">Attività</a></li>
+    <li class="active"><a href="#">{{.Data.Name}}</a></li>
+  </ol>
+
+  <div class="karmen-info-header">
+    <div class="row">
+      <div class="col-md-8">
+	<h1>{{.Data.Name}}</h1>
+      </div>
+      <div class="col-md-4">
+	<div class="btn-group pull-right" role="group">
+	  <a href="/activities/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "activities_add_update" "update" "true"}}" class="btn btn-primary">
+	    <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
+	    Modifica
+	  </a>
+	  <button href="/activities/{{.Data.ID}}/delete"
+		  data-url="/activities/{{.Data.ID}}/delete"
+		  class="btn btn-danger karmen-ajax-delete">
+	    <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
+	    Elimina
+	  </button>
+	</div>
+      </div>
+    </div>
+  </div>
+
+  <div class="row">
+    <div class="col-md-12">
+      
+      <h2 class="karmen-relation-header">Materia</h2>
+      {{if .Data.Subject}}
+      <div class="list-group" id="materie_list_group">
+    	<a href="/subjects/{{.Data.Subject.ID}}{{queryString "base" "subjects_show"}}" class="list-group-item clearfix">
+    	  <span class="glyphicon glyphicon-book"></span>
+    	  {{.Data.Subject.Name}}
+    	</a>
+      </div>
+      {{else}}
+      <p>All'attività non è associata alcuna materia
+    	didattica. Clicca <a href="/activities/update{{queryString "base" "activities_add_update"}}">qui</a> per
+    	modificare questa attività didattica.</p>
+      {{end}}
+    </div>
+    
+  </div>
+
+  <div class="row">
+    <div class="col-md-12">
+      
+      <h2 class="karmen-relation-header">Classe</h2>
+      {{if .Data.Class}}
+      <div class="list-group" id="classes_list_group">
+
+	<a href="/classes/{{.Data.Class.ID}}{{queryString "base" "classes_show"}}" class="list-group-item clearfix">
+	  <span class="glyphicon glyphicon-blackboard"></span>
+	  {{.Data.Class.Name}}
+	</a>
+	
+      </div>
+      {{else}}
+      
+      <p>All'attività non è associata alcuna classe
+    	didattica. Clicca <a href="/activities/update{{queryString "base" "activities_add_update"}}">qui</a> per
+    	modificare questa attività didattica.</p>
+      
+      {{end}}
+    </div>
+    
+  </div>
+
+  <div class="row">
+    <div class="col-md-12">
+      
+      <h2 class="karmen-relation-header">Docente</h2>
+      {{if .Data.Teacher}}
+      <div class="list-group" id="classes_list_group">
+	<a href="/activities/{{.Data.Teacher.ID}}/update{{queryString "base" "teachers_add_update"}}" class="list-group-item clearfix">
+	  <span class="glyphicon glyphicon-briefcase"></span>
+	  {{.Teacher.Surname}} {{.Teacher.Name}}
+	</a>
+      </div>
+            
+      {{else}}
+
+      <p>All'attività non è associato alcun docente
+    	didattica. Clicca <a href="/activities/update{{queryString "base" "activities_add_update"}}">qui</a> per
+    	modificare questa attività didattica.</p>
+	    
+      {{end}}
+    </div>
+  </div>
+
+
+</div>    
+
+{{ end }}

+ 1 - 1
templates/teachers.html.tpl

@@ -11,7 +11,7 @@
 	
 	<div class="btn-group pull-right">
 	  
-	  <a href="/teachers/add{{queryString "base" "teachers_add_update"}}" class="btn btn-primary">
+	  <a href="/teachers/add/{{queryString "base" "teachers_add_update"}}" class="btn btn-primary">
 	    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
 	    Crea nuovo docente
 	  </a>

+ 5 - 2
templates/teachers_add_update.html.tpl

@@ -20,9 +20,12 @@
   {{else}}
   <h1 class="karmen-info-header">Crea un nuovo docente</h1>
   {{end}}
-  
+
+  {{if .Options.Get "update"}}
   <form action="/teachers/{{.Data.ID}}/update" method="POST" role="form" data-toggle="validator">
-    
+  {{else}}
+  <form action="/teachers/add/" method="POST" role="form" data-toggle="validator">
+  {{end}}  
     <div class="form-group has-feedback">
       <label class="control-label" for="teacher_name">Nome</label>
       <input type="text" name="Name" class="form-control" id="teacher_name" placeholder="Nome" {{if .Options.Get "update"}} value="{{.Data.Name}}" {{end}} required>