Browse Source

Merge branch 'master' of https://gogs.carduccidante.edu.it/karmen/core

Andrea Fazzi 2 years ago
parent
commit
af6818b3f2

+ 3 - 3
Dockerfile

@@ -16,8 +16,8 @@ WORKDIR LibreOffice_7.4.0.3_Linux_x86-64_deb/DEBS
 
 ## Install LibreOffice
 
-RUN dpkg -i *.deb
-RUN ln -s /usr/local/bin/libreoffice7.0 /usr/local/bin/libreoffice
+# RUN dpkg -i *.deb
+# RUN ln -s /usr/local/bin/libreoffice7.0 /usr/local/bin/libreoffice
 
 ## Install pandoc
 
@@ -28,7 +28,7 @@ ENV PATH=$PATH:/src/karmen/core
 RUN mkdir -p /src/karmen/core/
 ADD . /src/karmen/core
 
-COPY config/config.yaml /src/karmen/core/config/
+# COPY config/config.yaml /src/karmen/core/config/
 
 WORKDIR /src/karmen/core/
 

+ 83 - 2
client/client.go

@@ -216,6 +216,37 @@ func (c *Client) GetStudents() ([]*orm.Student, error) {
 	return students, nil
 }
 
+func (c *Client) GetStudentsH() ([]*orm.Student, error) {
+	var (
+		response renderer.JsonResponse
+		students []*orm.Student
+	)
+
+	data, err := c.SendRequest("GET", "/api/students?format=json", nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := json.Unmarshal(data, &response); err != nil {
+		return nil, err
+	}
+
+	if string(response.Error) != "" {
+		return nil, errors.New(string(response.Error))
+	}
+
+	if err := json.Unmarshal(response.Result, &students); err != nil {
+		return nil, err
+	}
+	result := make([]*orm.Student, 0)
+	for _, s := range students {
+		if s.Handicap {
+			result = append(result, s)
+		}
+	}
+	return result, nil
+}
+
 func (c *Client) GetSubjects() ([]*orm.Subject, error) {
 	var (
 		response renderer.JsonResponse
@@ -336,6 +367,31 @@ func (c *Client) GetClasses() ([]*orm.Class, error) {
 	return classes, nil
 }
 
+func (c *Client) GetOperators() ([]*orm.Operator, error) {
+	var (
+		response  renderer.JsonResponse
+		operators []*orm.Operator
+	)
+
+	data, err := c.SendRequest("GET", "/api/operators?format=json", nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := json.Unmarshal(data, &response); err != nil {
+		return nil, err
+	}
+
+	if string(response.Error) != "" {
+		return nil, errors.New(string(response.Error))
+	}
+
+	if err := json.Unmarshal(response.Result, &operators); err != nil {
+		return nil, err
+	}
+	return operators, nil
+}
+
 func (c *Client) GetClass(id uint) (*orm.Class, error) {
 	var (
 		response renderer.JsonResponse
@@ -413,7 +469,7 @@ func (c *Client) AddStudent(student *orm.Student) (uint, error) {
 	if err != nil {
 		return 0, err
 	}
-	resp, err := c.SendRequest("POST", "/api/students/add/?format=json", data)
+	resp, err := c.SendRequest("POST", "/api/students/create/?format=json", data)
 	if err != nil {
 		return 0, err
 	}
@@ -437,7 +493,7 @@ func (c *Client) AddActivity(activity *orm.Activity) (uint, error) {
 	if err != nil {
 		return 0, err
 	}
-	resp, err := c.SendRequest("POST", "/api/activities/add/?format=json", data)
+	resp, err := c.SendRequest("POST", "/api/activities/create/?format=json", data)
 	if err != nil {
 		return 0, err
 	}
@@ -611,3 +667,28 @@ func (c *Client) GetGroups() ([]*orm.Group, error) {
 	}
 	return groups, nil
 }
+
+func (c *Client) AddOperator(operator *orm.Operator) (uint, error) {
+	var response renderer.JsonResponse
+
+	data, err := json.Marshal(operator)
+	if err != nil {
+		return 0, err
+	}
+	resp, err := c.SendRequest("POST", "/api/operators/create/?format=json", data)
+	if err != nil {
+		return 0, err
+	}
+	if err := json.Unmarshal(resp, &response); err != nil {
+		return 0, err
+	}
+	if string(response.Error) != "" {
+		return 0, errors.New(string(response.Error))
+	}
+
+	id, err := strconv.Atoi(string(response.Result))
+	if err != nil {
+		return 0, err
+	}
+	return uint(id), nil
+}

+ 1 - 0
go.mod

@@ -14,6 +14,7 @@ require (
 	github.com/jinzhu/gorm v1.9.16
 	github.com/jinzhu/inflection v1.0.0
 	github.com/remogatto/cloud v0.0.0-20200423094407-c201f07eb401
+	github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8
 	github.com/remogatto/slicediff v0.0.0-20190903082355-d19e1ebfb964
 	github.com/robfig/cron v1.2.0
 	github.com/sethvargo/go-password v0.2.0

+ 4 - 0
go.sum

@@ -37,9 +37,12 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
 github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
 github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
 github.com/remogatto/cloud v0.0.0-20200423094407-c201f07eb401 h1:OrdrWowKbZqDQNdilFyiCtn7sUix9ocn/pO9VuimA4o=
 github.com/remogatto/cloud v0.0.0-20200423094407-c201f07eb401/go.mod h1:84Ak6wMU0H33hglQdkwyFJob+r0lRiQhtBiekhNrgL8=
+github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8 h1:nRDwTcxV9B3elxMt+1xINX0bwaPdpouqp5fbynexY8U=
+github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8/go.mod h1:jOEnp79oIHy5cvQSHeLcgVJk1GHOOHJHQWps/d1N5Yo=
 github.com/remogatto/slicediff v0.0.0-20190903082355-d19e1ebfb964 h1:nr+J2/lD7hrKuUU37aaW5GMjnTN9SWcPOZm8bOhw7lk=
 github.com/remogatto/slicediff v0.0.0-20190903082355-d19e1ebfb964/go.mod h1:hYhX1i+/93J3gTMZFUL96Mf/45LmfRZTunoLYPwaHTA=
 github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
@@ -67,6 +70,7 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gG
 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=

+ 1 - 0
main.go

@@ -44,6 +44,7 @@ var (
 		&orm.Document{},
 		&orm.Job{},
 		&orm.File{},
+		&orm.Operator{},
 	}
 )
 

+ 2 - 2
orm/class.go

@@ -73,7 +73,7 @@ func (c *Class) Read(args map[string]string, r *http.Request) (interface{}, erro
 
 	id := args["id"]
 
-	if err := DB().Preload("Coordinator").Preload("Minuter").Where("id = ?", id).Find(&class).Error; err != nil {
+	if err := DB().Preload("Students").Preload("Coordinator").Preload("Minuter").Where("id = ?", id).Find(&class).Error; err != nil {
 		return nil, err
 	}
 
@@ -90,7 +90,7 @@ func (c *Class) Read(args map[string]string, r *http.Request) (interface{}, erro
 
 func (c *Class) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
 	var classes []*Class
-	if err := DB().Preload("Coordinator").Preload("Minuter").Order("name").Find(&classes).Error; err != nil {
+	if err := DB().Preload("Students").Preload("Coordinator").Preload("Minuter").Order("name").Find(&classes).Error; err != nil {
 		return nil, err
 	}
 	for _, class := range classes {

+ 122 - 0
orm/operator.go

@@ -0,0 +1,122 @@
+package orm
+
+import (
+	"fmt"
+	"net/http"
+	"strings"
+
+	"github.com/jinzhu/gorm"
+	"gogs.carduccidante.edu.it/karmen/core/renderer"
+)
+
+type Operator struct {
+	gorm.Model
+
+	Lastname  string
+	Firstname string
+	Email     string
+
+	Description string
+}
+
+func (o *Operator) GetID() uint { return o.ID }
+func (o *Operator) String() string {
+	return fmt.Sprintf("%s %s (%s)", strings.ToUpper(o.Lastname), strings.Title(o.Firstname), o.Description)
+}
+
+func (o *Operator) Create(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		operator := new(Operator)
+		return operator, nil
+	} else {
+		operator := new(Operator)
+		err := renderer.Decode(operator, r)
+		if err != nil {
+			return nil, err
+		}
+		operator, err = CreateOperator(operator)
+		if err != nil {
+			return nil, err
+		}
+		return operator, nil
+	}
+}
+
+func (o *Operator) Read(args map[string]string, r *http.Request) (interface{}, error) {
+	var operator Operator
+
+	id := args["id"]
+
+	if err := DB().Where("id = ?", id).Find(&operator).Error; err != nil {
+		return nil, err
+	}
+
+	return &operator, nil
+}
+
+func (o *Operator) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
+	var operators []*Operator
+
+	if err := DB().Find(&operators).Error; err != nil {
+		return nil, err
+	}
+	return operators, nil
+}
+
+func (o *Operator) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := o.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		operator := result.(*Operator)
+
+		return operator, nil
+	} else {
+		operator, err := o.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		err = renderer.Decode(operator, r)
+		if err != nil {
+			return nil, err
+		}
+		_, err = SaveOperator(operator)
+		if err != nil {
+			return nil, err
+		}
+		operator, err = o.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		return operator.(*Operator), nil
+	}
+}
+
+func (o *Operator) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	operator, err := o.Read(args, r)
+	if err != nil {
+		return nil, err
+	}
+	if err := DB().Unscoped().Delete(operator.(*Operator)).Error; err != nil {
+		return nil, err
+	}
+	return operator.(*Operator), nil
+}
+
+func SaveOperator(operator interface{}) (interface{}, error) {
+	if err := DB().Save(operator).Error; err != nil {
+		return nil, err
+	}
+	return operator, nil
+}
+
+func CreateOperator(operator *Operator) (*Operator, error) {
+	if err := DB().Create(operator).Error; err != nil {
+		return nil, err
+	}
+	return operator, nil
+}

+ 1 - 0
orm/orm.go

@@ -81,6 +81,7 @@ func AutoMigrate() {
 		&GeneratorType{},
 		&Log{},
 		&Group{},
+		&Operator{},
 	).Error; err != nil {
 		panic(err)
 	}

+ 54 - 13
orm/student.go

@@ -10,27 +10,40 @@ import (
 type Student struct {
 	Credential
 
-	// Handicap bool `schema:"Handicap" sql:"default: false"`
-	// DSA      bool `schema:"DSA" sql:"default: false"`
-	// BES      bool `schema:"BES" sql:"default: false"`
-
 	Handicap bool
 	DSA      bool
 	BES      bool
 
+	FatherLastname  string
+	FatherFirstname string
+	FatherEmail     string
+
+	MotherLastname  string
+	MotherFirstname string
+	MotherEmail     string
+
+	LegalGuardianLastname  string
+	LegalGuardianFirstname string
+	LegalGuardianEmail     string
+
 	TutorID uint `schema:"tutor_id"`
 	ClassID uint `schema:"class_id"`
 
+	OperatorIDs []uint      `schema:"operator_ids" gorm:"-"`
+	Operators   []*Operator `gorm:"many2many:student_operators"`
+
 	Class      *Class
 	Tutor      *Teacher
 	Teachers   []*Teacher
 	Activities []*Activity
 
-	AllClasses  []*Class   `gorm:"-"`
-	AllTeachers []*Teacher `gorm:"-"`
+	AllClasses   []*Class    `gorm:"-"`
+	AllTeachers  []*Teacher  `gorm:"-"`
+	AllOperators []*Operator `gorm:"-"`
 
-	SelectedClass   map[uint]string `gorm:"-"`
-	SelectedTeacher map[uint]string `gorm:"-"`
+	SelectedClass    map[uint]string `gorm:"-"`
+	SelectedTeacher  map[uint]string `gorm:"-"`
+	SelectedOperator map[uint]string `gorm:"-"`
 }
 
 var (
@@ -53,7 +66,9 @@ func (s *Student) Create(args map[string]string, r *http.Request) (interface{},
 		if err := DB().Find(&student.AllClasses).Error; err != nil {
 			return nil, err
 		}
-
+		if err := DB().Find(&student.AllOperators).Error; err != nil {
+			return nil, err
+		}
 		return student, nil
 	} else {
 		student := new(Student)
@@ -75,7 +90,7 @@ func (s *Student) Read(args map[string]string, r *http.Request) (interface{}, er
 
 	id := args["id"]
 
-	if err := DB().Preload("Class").Preload("Class.Coordinator").Where("id = ?", id).Find(&student).Error; err != nil {
+	if err := DB().Preload("Class").Preload("Class.Coordinator").Preload("Operators").Where("id = ?", id).Find(&student).Error; err != nil {
 		return nil, err
 	}
 
@@ -89,7 +104,7 @@ func (s *Student) Read(args map[string]string, r *http.Request) (interface{}, er
 func (s *Student) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
 	var students []*Student
 
-	if err := DB().Preload("Class").Preload("Class.Coordinator").Preload("Tutor").Order("surname,name").Find(&students).Error; err != nil {
+	if err := DB().Preload("Operators").Preload("Class").Preload("Class.Coordinator").Preload("Tutor").Order("surname,name").Find(&students).Error; err != nil {
 		return nil, err
 	}
 	for _, student := range students {
@@ -119,12 +134,21 @@ func (s *Student) Update(args map[string]string, r *http.Request) (interface{},
 			return nil, err
 		}
 
+		if err := DB().Find(&student.AllOperators).Error; err != nil {
+			return nil, err
+		}
+
 		student.SelectedTeacher = make(map[uint]string)
 		student.SelectedTeacher[student.TutorID] = "selected"
 
 		student.SelectedClass = make(map[uint]string)
 		student.SelectedClass[student.ClassID] = "selected"
 
+		student.SelectedOperator = make(map[uint]string)
+		for _, o := range student.Operators {
+			student.SelectedOperator[o.ID] = "selected"
+		}
+
 		return student, nil
 	} else {
 		student, err := s.Read(args, r)
@@ -141,10 +165,24 @@ func (s *Student) Update(args map[string]string, r *http.Request) (interface{},
 		if err != nil {
 			return nil, err
 		}
-		_, err = SaveStudent(student)
+		if err := DB().
+			Where([]uint(student.(*Student).OperatorIDs)).
+			Find(&student.(*Student).Operators).Error; err != nil {
+			return nil, err
+		}
+
+		_, err = SaveStudent(student.(*Student))
 		if err != nil {
 			return nil, err
 		}
+
+		if err := DB().
+			Model(student).
+			Association("Operators").
+			Replace(student.(*Student).Operators).Error; err != nil {
+			return nil, err
+		}
+
 		student, err = s.Read(args, r)
 		if err != nil {
 			return nil, err
@@ -165,7 +203,7 @@ func (s *Student) Delete(args map[string]string, r *http.Request) (interface{},
 	return student.(*Student), nil
 }
 
-func SaveStudent(student interface{}) (interface{}, error) {
+func SaveStudent(student *Student) (interface{}, error) {
 	if err := DB().Omit("Class", "Tutor", "Teachers", "Activities").Save(student).Error; err != nil {
 		return nil, err
 	}
@@ -173,6 +211,9 @@ func SaveStudent(student interface{}) (interface{}, error) {
 }
 
 func CreateStudent(student *Student) (*Student, error) {
+	if err := DB().Where([]uint(student.OperatorIDs)).Find(&student.Operators).Error; err != nil {
+		return nil, err
+	}
 	if err := DB().Create(student).Error; err != nil {
 		return nil, err
 	}

+ 7 - 1
templates/administratives_add_update.html.tpl

@@ -12,9 +12,12 @@
   
   {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo ATA" "updateTitle" (printf "Aggiorna ATA %s" (.Data|string))}}
 
+  {{$form := "form_administratives_add_update"}}
   <form
     class="needs-validation"
-    action="{{if $update}}{{.Data.ID|update "Administrative"}}{{else}}{{create "Administrative"}}{{end}}" method="POST" role="form">
+    action="{{if $update}}{{.Data.ID|update "Administrative"}}{{else}}{{create "Administrative"}}{{end}}" method="POST" role="form"
+    id={{$form}}
+    >
 
     {{$options := ` { name: "Name",id: "administrative_name",label: "Nome",placeholder: "Nome",type: "text" } `}}
     {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
@@ -28,6 +31,9 @@
     {{$options := ` { name: "AltEmail",id: "administrative_altemail",label: "Email alternativa",placeholder: "Inserire indirizzo email",type: "email" } `}}
     {{template "input" dict "options" ($options|yaml) "value" (.Data|field "AltEmail") "update" $update}}
 
+    {{$options := ` { name: "office_id", id: "office_id", label: "Ufficio", title: "Seleziona l'ufficio a cui appartiene l'impiegato"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllOffices") "selected" (.Data|field "SelectedOffice") "update" $update "form" $form}}
+
     <div class="form-row">
       <div class="col">
         {{$options := ` { name: "Regenerate",id: "administrative_regenerate",label: "Rigenerare/inviare le credenziali",formClass: "form-check form-check-inline" } `}}

+ 16 - 1
templates/classes_show.html.tpl

@@ -35,7 +35,22 @@
     
     </div>
   </div>
-  
+
+  <div class="row">
+    <div class="col-md-12">
+      
+      {{$options := `
+      title: "Studenti associati alla classe"
+      model: "Student"
+      icon: "fa fa-user"
+      `}}
+      
+      {{$noElements := "Nessuno studente associato alla classe.."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Students "noElements" $noElements}}
+    
+    </div>
+  </div>
+
 </div>    
 
 {{ end }}

+ 3 - 0
templates/layout/base.html.tpl

@@ -21,6 +21,9 @@
 	   <li class="nav-item">
              <a class="nav-link" href="/teachers?{{query "tpl_layout" "base" "tpl_content" "teachers"}}">Docenti</a>
 	   </li>
+	   <li class="nav-item">
+	     <a class="nav-item nav-link" href="/operators?{{query "tpl_layout" "base" "tpl_content" "operators"}}">Operatori</a>
+	   </li>
 	   <li class="nav-item">
 	     <a class="nav-link" href="/departments?{{query "tpl_layout" "base" "tpl_content" "departments"}}">Dipartimenti</a>
 	   </li>

+ 30 - 0
templates/operators.html.tpl

@@ -0,0 +1,30 @@
+{{ define "content" }}
+
+<div class="container">  
+
+  {{$options := `
+  title: "Operatori"
+  buttonTitle: "Crea nuovo operatore"
+  `}}
+  
+  {{template "read_all_header" dict  "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "Operator")}}
+  {{template "search_input"}}
+    
+  {{if not .}}
+  {{template "display_no_elements"}}
+  {{else}}
+  <div class="list-group" id="myUL">
+    {{range $operator := .Data}}
+    <a class="list-group-item list-group-item-action" href={{$operator.ID|show "Operator"}}>
+      <span class="fa fa-user"></span>
+      {{$operator|string}}
+    </a>
+    {{end}}
+    {{end}}
+  </div>
+
+</div>
+
+{{ end }}
+
+

+ 41 - 0
templates/operators_add_update.html.tpl

@@ -0,0 +1,41 @@
+{{ define "content" }}
+
+<div class="container">
+
+  {{$update := .Options.Get "update"}}
+
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Operatori" (all "Operator") (.Data|string) (.Data.ID|show "Operator") "Aggiorna" "current"}}
+  {{else}}
+  {{template "breadcrumb" toSlice "Operatori" (all "Operator") "Aggiungi" "current"}}
+  {{end}}
+  
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo operatore" "updateTitle" (printf "Aggiorna operatore %s" (.Data|string))}}
+
+  {{$form := "form_operators_add_update"}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Operator"}}{{else}}{{create "Operator"}}{{end}}"
+    method="POST"
+    role="form"
+    id={{$form}}>
+
+    {{$options := ` { name: "Firstname",id: "operator_firstname",label: "Nome",placeholder: "Nome ",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Firstname") "update" $update}}
+
+    {{$options := ` { name: "Lastname",id: "operator_lastname",label: "Cognome",placeholder: "Cognome",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Lastname") "update" $update}}
+
+    {{$options := ` { name: "Email",id: "operator_email",label: "Email",placeholder: "Email",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Email") "update" $update}}
+
+    {{$options := ` { name: "Description",id: "operator_description",label: "Descrizione",placeholder: "Descrizione",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Description") "update" $update}}
+
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Student"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}  
+  </form>
+  
+</div>
+
+{{ end }}

+ 21 - 0
templates/operators_show.html.tpl

@@ -0,0 +1,21 @@
+{{ define "content" }}
+
+<div class="container">
+
+  {{template "breadcrumb" toSlice "Operatori" (all "Operator") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Operator") "deletePath" (.Data.ID|delete "Operator")}}
+
+  <h2 class="karmen-relation-header">Informazioni generali</h2>
+  <dl class="row">
+    <dt class="col-sm-3">Nome</dt>
+    <dd class="col-sm-9">{{.Data.Firstname}}</dd>
+    <dt class="col-sm-3">Cognome</dt>
+    <dd class="col-sm-9">{{.Data.Lastname}}</dd>
+    <dt class="col-sm-3">Email</dt>
+    <dd class="col-sm-9"><a href="mailto:{{.Data.Email}}">{{.Data.Email}}</a></dd>
+    <dt class="col-sm-3">Descrizione</dt>
+    <dd class="col-sm-9">{{.Data.Description}}</dd>
+  </dl>
+</div>    
+
+{{ end }}

+ 30 - 0
templates/students_add_update.html.tpl

@@ -41,6 +41,36 @@
     {{$options := ` { name: "BES",id: "student_bes",label: "BES (L. 170/10)",formClass: "form-group form-check" } `}}
     {{template "checkbox" dict "options" ($options|yaml) "value" (.Data|field "BES") "update" $update}}
 
+    {{$options := ` { name: "operator_ids", id: "operator_ids", label: "Operatori", title: "Seleziona gli operatori associati allo studente", multiple: "true"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllOperators") "selected" (.Data|field "SelectedOperator") "update" $update "form" $form}}
+
+    {{$options := ` { name: "FatherLastname",id: "student_fatherlastname",label: "Cognome del padre",placeholder: "Cognome del padre",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "FatherLastname") "update" $update}}
+
+    {{$options := ` { name: "FatherFirstname",id: "student_fatherfirstname",label: "Nome del padre",placeholder: "Nome del padre",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "FatherFirstname") "update" $update}}
+
+    {{$options := ` { name: "FatherEmail",id: "student_fatheremail",label: "Email del padre",placeholder: "Email del padre",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "FatherEmail") "update" $update}}
+
+    {{$options := ` { name: "MotherLastname",id: "student_motherlastname",label: "Cognome della madre",placeholder: "Cognome della madre",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "MotherLastname") "update" $update}}
+
+    {{$options := ` { name: "MotherFirstname",id: "student_motherfirstname",label: "Nome della madre",placeholder: "Nome della madre",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "MotherFirstname") "update" $update}}
+
+    {{$options := ` { name: "MotherEmail",id: "student_motheremail",label: "Email della madre",placeholder: "Email della madre",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "MotherEmail") "update" $update}}
+
+    {{$options := ` { name: "LegalGuardianLastname",id: "student_legalguardianlastname",label: "Cognome del tutore legale",placeholder: "Cognome del tutore legale",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "LegalGuardianLastname") "update" $update}}
+
+    {{$options := ` { name: "LegalGuardianFirstname",id: "student_legalguardianfirstname",label: "Nome del tutore legale",placeholder: "Nome del tutore legale",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "LegalGuardianFirstname") "update" $update}}
+
+    {{$options := ` { name: "LegalGuardianEmail",id: "student_legalguardianemail",label: "Email del tutore legale",placeholder: "Email del tutore legale",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "LegalGuardianEmail") "update" $update}}
+
     {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Student"} ` }}
     {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}  
   </form>

+ 16 - 1
templates/students_show.html.tpl

@@ -26,7 +26,22 @@
     
     </div>
   </div>
-  
+
+  <div class="row">
+    <div class="col-md-12">
+
+      {{$options := `
+      title: "Operatori associati allo studente"
+      model: "Operator"
+      icon: "fa fa-user"
+      `}}
+      
+      {{$noElements := "Nessun operatore associato allo studente."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Operators "noElements" $noElements}}
+      
+    </div>
+  </div>
+
 </div>    
 
 {{ end }}