瀏覽代碼

Refactor document/job

Andrea Fazzi 5 年之前
父節點
當前提交
08098a5761

+ 2 - 0
main.go

@@ -40,6 +40,8 @@ var (
 		&orm.Activity{},
 		&orm.Office{},
 		&orm.Administrative{},
+		&orm.Group{},
+		&orm.Document{},
 	}
 )
 

+ 20 - 0
orm/administrative.go

@@ -3,6 +3,7 @@ package orm
 import (
 	"fmt"
 	"net/http"
+	"time"
 
 	"gogs.carducci-dante.gov.it/karmen/core/renderer"
 )
@@ -88,6 +89,25 @@ func (a *Administrative) Update(args map[string]string, r *http.Request) (interf
 			return nil, err
 		}
 
+		// FIXME: Should not be hard set.
+		administrative.(*Administrative).Regenerate = false
+
+		// FIXME: Should not be hard set.
+		administrative.(*Administrative).Exclude = false
+
+		// FIXME: Should not be hard set.
+		administrative.(*Administrative).NotInvited = false
+
+		if len(args["DateFrom"]) == 0 {
+			// FIXME: Should not be hard set.
+			administrative.(*Administrative).DateFrom = time.Time{}
+		}
+
+		if len(args["DateTo"]) == 0 {
+			// FIXME: Should not be hard set.
+			administrative.(*Administrative).DateTo = time.Time{}
+		}
+
 		err = renderer.Decode(administrative, r)
 		if err != nil {
 			return nil, err

+ 66 - 96
orm/document.go

@@ -36,33 +36,37 @@ type Document struct {
 	CompletedJobs []*Job
 
 	LastJob *Job `gorm:"-"`
-}
-
-type DocumentForUpdate struct {
-	Document
 
-	AllGeneratorTypes []*GeneratorType
-
-	SelectedGeneratorType map[uint]string
+	AllGeneratorTypes     []*GeneratorType
+	SelectedGeneratorType map[uint]string `gorm:"-"`
 }
 
-type DocumentForAdd struct {
-	Document
-
-	AllGeneratorTypes []*GeneratorType
-}
+func (s *Document) GetID() uint    { return s.ID }
+func (d *Document) String() string { return d.Name }
 
-func (s *Document) GetID() uint { return s.ID }
+func (d *Document) Create(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		document := new(Document)
+		if err := DB().Find(&document.AllGeneratorTypes).Error; err != nil {
+			return nil, err
+		}
+		return document, nil
+	} else {
+		document := new(Document)
+		err := renderer.Decode(document, r)
+		if err != nil {
+			return nil, err
+		}
+		document, err = CreateDocument(document)
+		if err != nil {
+			return nil, err
+		}
 
-func GetDocument(args map[string]string) (interface{}, error) {
-	var document Document
-	if err := DB().First(&document, args["id"]).Error; err != nil {
-		return nil, err
+		return document, nil
 	}
-	return &document, nil
 }
 
-func GetDocumentAll(args map[string]string) (interface{}, error) {
+func (d *Document) Read(args map[string]string, r *http.Request) (interface{}, error) {
 	var document Document
 
 	id := args["id"]
@@ -80,79 +84,60 @@ func GetDocumentAll(args map[string]string) (interface{}, error) {
 	return &document, nil
 }
 
-func GetDocuments(args map[string]string) (interface{}, error) {
+func (d *Document) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
 	var documents []*Document
-	if err := DB().Order("name").Find(&documents).Error; err != nil {
-		return nil, err
-	}
-	return documents, nil
-}
 
-func GetDocumentsAll(args map[string]string) (interface{}, error) {
-	var documents []*Document
 	if err := DB().Preload("GeneratorType").Order("name").Find(&documents).Error; err != nil {
 		return nil, err
 	}
 	return documents, nil
 }
 
-func SaveDocument(document interface{}) (interface{}, error) {
-	if err := DB().Save(document).Error; err != nil {
-		return nil, err
-	}
-	return document, nil
-}
-
-func UpdateDocument(args map[string]string, r *http.Request) (IDer, error) {
-	document, err := GetDocument(args)
-	if err != nil {
-		return nil, err
-	}
-
-	// FIXME: Should not be hard set.
-	document.(*Document).KeepArtifacts = false
+func (d *Document) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := d.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-	err = renderer.Decode(document, r)
-	if err != nil {
-		return nil, err
-	}
+		document := result.(*Document)
 
-	_, err = SaveDocument(document)
-	if err != nil {
-		return nil, err
-	}
+		if err := DB().Find(&document.AllGeneratorTypes).Error; err != nil {
+			return nil, err
+		}
 
-	document, err = GetDocument(args)
-	if err != nil {
-		return nil, err
-	}
+		document.SelectedGeneratorType = make(map[uint]string)
+		document.SelectedGeneratorType[document.GeneratorTypeID] = "selected"
 
-	return document.(*Document), nil
-}
+		return document, nil
+	} else {
+		document, err := d.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-func AddDocument(args map[string]string, r *http.Request) (IDer, error) {
-	document := new(Document)
-	err := renderer.Decode(document, r)
-	if err != nil {
-		return nil, err
-	}
-	document, err = CreateDocument(document)
-	if err != nil {
-		return nil, err
-	}
+		// FIXME: Should not be hard set.
+		document.(*Document).KeepArtifacts = false
 
-	return document, nil
-}
+		err = renderer.Decode(document, r)
+		if err != nil {
+			return nil, err
+		}
+		_, err = SaveDocument(document)
+		if err != nil {
+			return nil, err
+		}
+		document, err = d.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-func CreateDocument(document *Document) (*Document, error) {
-	if err := DB().Create(document).Error; err != nil {
-		return nil, err
+		return document.(*Document), nil
 	}
-	return document, nil
 }
 
-func DeleteDocument(args map[string]string, r *http.Request) (IDer, error) {
-	document, err := GetDocument(args)
+func (d *Document) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	document, err := d.Read(args, r)
 	if err != nil {
 		return nil, err
 	}
@@ -162,29 +147,18 @@ func DeleteDocument(args map[string]string, r *http.Request) (IDer, error) {
 	return document.(*Document), nil
 }
 
-func GetDocumentForUpdate(args map[string]string) (interface{}, error) {
-	var data DocumentForUpdate
-
-	id := args["id"]
-
-	if err := DB().First(&data.Document, id).Error; err != nil {
+func SaveDocument(document interface{}) (interface{}, error) {
+	if err := DB().Save(document).Error; err != nil {
 		return nil, err
 	}
+	return document, nil
+}
 
-	if err := DB().Find(&data.AllGeneratorTypes).Error; err != nil {
+func CreateDocument(document *Document) (*Document, error) {
+	if err := DB().Create(document).Error; err != nil {
 		return nil, err
 	}
-
-	data.SelectedGeneratorType = make(map[uint]string)
-	data.SelectedGeneratorType[data.GeneratorTypeID] = "selected"
-
-	return data, nil
-}
-
-func GetDocumentForAdd(args map[string]string) (interface{}, error) {
-	var data DocumentForAdd
-
-	return data, nil
+	return document, nil
 }
 
 func GetDocumentExecute(args map[string]string) (interface{}, error) {
@@ -213,7 +187,3 @@ func GetDocumentExecute(args map[string]string) (interface{}, error) {
 
 	return &document, nil
 }
-
-func (t *Document) RestAPIPath() string {
-	return "documents"
-}

+ 77 - 107
orm/group.go

@@ -20,48 +20,37 @@ type Group struct {
 	TeacherIDs []uint `schema:"teacher_ids" gorm:"-"`
 
 	Teachers []*Teacher `gorm:"many2many:group_teachers"`
-}
 
-type GroupForAdd struct {
-	AllTeachers []*Teacher
-}
-
-type GroupForUpdate struct {
-	Group Group
-
-	AllTeachers []*Teacher
-
-	SelectedTeacher map[uint]string
+	AllTeachers     []*Teacher
+	SelectedTeacher map[uint]string `gorm:"-"`
 }
 
 func (g *Group) GetID() uint    { return g.ID }
 func (g *Group) String() string { return g.Name }
 
-func GetGroups(args map[string]string) (interface{}, error) {
-	return GetGroupsAll(args)
-}
-
-func GetGroupsAll(args map[string]string) (interface{}, error) {
-	var groups []*Group
-
-	if err := DB().Preload("Teachers").Order("name").Find(&groups).Error; err != nil {
-		return nil, err
-	}
-
-	for _, group := range groups {
-		if group.Query != "" {
-			err := group.updateTeachersAssociation()
-			if err != nil {
-				return nil, err
-			}
+func (g *Group) Create(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		group := new(Group)
+		if err := DB().Find(&group.AllTeachers).Error; err != nil {
+			return nil, err
+		}
+		return group, nil
+	} else {
+		group := new(Group)
+		err := renderer.Decode(group, r)
+		if err != nil {
+			return nil, err
+		}
+		group, err = CreateGroup(group)
+		if err != nil {
+			return nil, err
 		}
 
+		return group, nil
 	}
-
-	return groups, nil
 }
 
-func GetGroupAll(args map[string]string) (interface{}, error) {
+func (g *Group) Read(args map[string]string, r *http.Request) (interface{}, error) {
 	var group Group
 
 	id := args["id"]
@@ -77,95 +66,86 @@ func GetGroupAll(args map[string]string) (interface{}, error) {
 		}
 	}
 
-	return group, nil
+	return &group, nil
 }
 
-func GetGroupForUpdate(args map[string]string) (interface{}, error) {
-	var data GroupForUpdate
-
-	id := args["id"]
-
-	if err := DB().Preload("Teachers").First(&data.Group, id).Error; err != nil {
-		return nil, err
-	}
+func (g *Group) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
+	var groups []*Group
 
-	if err := DB().Find(&data.AllTeachers).Error; err != nil {
+	if err := DB().Preload("Teachers").Order("name").Find(&groups).Error; err != nil {
 		return nil, err
 	}
 
-	data.SelectedTeacher = make(map[uint]string)
-	for _, t := range data.Group.Teachers {
-		data.SelectedTeacher[t.ID] = "selected"
-	}
-
-	return data, nil
-}
-
-func GetGroupForAdd(args map[string]string) (interface{}, error) {
-	var data GroupForAdd
+	for _, group := range groups {
+		if group.Query != "" {
+			err := group.updateTeachersAssociation()
+			if err != nil {
+				return nil, err
+			}
+		}
 
-	if err := DB().Find(&data.AllTeachers).Error; err != nil {
-		return nil, err
 	}
 
-	return data, nil
+	return groups, nil
 }
 
-func GetGroup(args map[string]string) (interface{}, error) {
-	var group Group
+func (g *Group) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := g.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-	id := args["id"]
+		group := result.(*Group)
 
-	if err := DB().Preload("Teachers").Where("id = ?", id).Find(&group).Error; err != nil {
-		return nil, err
-	}
+		if err := DB().Find(&group.AllTeachers).Error; err != nil {
+			return nil, err
+		}
 
-	return &group, nil
+		group.SelectedTeacher = make(map[uint]string)
+		for _, t := range group.Teachers {
+			group.SelectedTeacher[t.ID] = "selected"
+		}
 
-}
+		return group, nil
+	} else {
+		group, err := g.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+		err = renderer.Decode(group, r)
+		if err != nil {
+			return nil, err
+		}
 
-func UpdateGroup(args map[string]string, r *http.Request) (IDer, error) {
-	group, err := GetGroup(args)
-	if err != nil {
-		return nil, err
-	}
-	err = renderer.Decode(group, r)
-	if err != nil {
-		return nil, err
-	}
+		if err := DB().Where(group.(*Group).TeacherIDs).Find(&group.(*Group).Teachers).Error; err != nil {
+			return nil, err
+		}
 
-	if err := DB().Where(group.(*Group).TeacherIDs).Find(&group.(*Group).Teachers).Error; err != nil {
-		return nil, err
-	}
+		teachers, err := group.(*Group).executeTeacherQuery()
 
-	teachers, err := group.(*Group).executeTeacherQuery()
+		group.(*Group).Teachers = append(group.(*Group).Teachers, teachers...)
 
-	group.(*Group).Teachers = append(group.(*Group).Teachers, teachers...)
+		_, err = SaveGroup(group)
+		if err != nil {
+			return nil, err
+		}
 
-	_, err = SaveGroup(group)
-	if err != nil {
-		return nil, err
-	}
-	if err := DB().Model(group).Association("Teachers").Replace(group.(*Group).Teachers).Error; err != nil {
-		return nil, err
-	}
+		if err := DB().Model(group).Association("Teachers").Replace(group.(*Group).Teachers).Error; err != nil {
+			return nil, err
+		}
 
-	group, err = GetGroup(args)
-	if err != nil {
-		return nil, err
-	}
-	return group.(*Group), nil
-}
+		group, err = g.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
 
-func SaveGroup(group interface{}) (interface{}, error) {
-	if err := DB().Save(group).Error; err != nil {
-		return nil, err
+		return group.(*Group), nil
 	}
-	return group, nil
 }
 
-func DeleteGroup(args map[string]string, r *http.Request) (IDer, error) {
-	group, err := GetGroup(args)
+func (g *Group) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	group, err := g.Read(args, r)
 	if err != nil {
 		return nil, err
 	}
@@ -175,14 +155,8 @@ func DeleteGroup(args map[string]string, r *http.Request) (IDer, error) {
 	return group.(*Group), nil
 }
 
-func AddGroup(args map[string]string, r *http.Request) (IDer, error) {
-	group := new(Group)
-	err := renderer.Decode(group, r)
-	if err != nil {
-		return nil, err
-	}
-	group, err = CreateGroup(group)
-	if err != nil {
+func SaveGroup(group interface{}) (interface{}, error) {
+	if err := DB().Save(group).Error; err != nil {
 		return nil, err
 	}
 	return group, nil
@@ -212,10 +186,6 @@ func CreateGroup(group *Group) (*Group, error) {
 	return group, nil
 }
 
-func (group *Group) RestAPIPath() string {
-	return "groupes"
-}
-
 func (group *Group) updateTeachersAssociation() error {
 	teachers, err := group.executeTeacherQuery()
 	if err != nil {

+ 60 - 30
orm/job.go

@@ -1,6 +1,7 @@
 package orm
 
 import (
+	"fmt"
 	"net/http"
 	"strconv"
 	"time"
@@ -41,7 +42,8 @@ type Job struct {
 	End   time.Time
 }
 
-func (s *Job) GetID() uint { return s.ID }
+func (s *Job) GetID() uint    { return s.ID }
+func (j *Job) String() string { return fmt.Sprintf("Lavoro ID %d", j.ID) }
 
 func GetFile(args map[string]string) (interface{}, error) {
 	var job Job
@@ -55,15 +57,25 @@ func GetFile(args map[string]string) (interface{}, error) {
 	}, nil
 }
 
-func GetJobs(args map[string]string) (interface{}, error) {
-	var jobs []*Job
-	if err := DB().Preload("Document").Order("start DESC").Find(&jobs).Error; err != nil {
-		return nil, err
-	}
-	return jobs, nil
-}
-
-func GetJob(args map[string]string) (interface{}, error) {
+// func (j *Job) Create(args map[string]string, r *http.Request) (interface{}, error) {
+// 	if r.Method == "GET" {
+// 		return nil, nil
+// 	} else {
+// 		job := new(Job)
+// 		err := renderer.Decode(job, r)
+// 		if err != nil {
+// 			return nil, err
+// 		}
+// 		job, err = CreateJob(job)
+// 		if err != nil {
+// 			return nil, err
+// 		}
+
+// 		return job, nil
+// 	}
+// }
+
+func (j *Job) Read(args map[string]string, r *http.Request) (interface{}, error) {
 	var job Job
 	if err := DB().Preload("Document").Preload("Files").Preload("Logs").First(&job, args["id"]).Error; err != nil {
 		return nil, err
@@ -71,23 +83,52 @@ func GetJob(args map[string]string) (interface{}, error) {
 	return &job, nil
 }
 
-func UpdateJob(args map[string]string, r *http.Request) (IDer, error) {
-	job, err := GetJob(args)
-	if err != nil {
+func (j *Job) ReadAll(args map[string]string, r *http.Request) (interface{}, error) {
+	var jobs []*Job
+	if err := DB().Preload("Document").Order("start DESC").Find(&jobs).Error; err != nil {
 		return nil, err
 	}
+	return jobs, nil
+}
 
-	err = renderer.Decode(job, r)
-	if err != nil {
-		return nil, err
+func (j *Job) Update(args map[string]string, r *http.Request) (interface{}, error) {
+	if r.Method == "GET" {
+		result, err := j.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		job := result.(*Job)
+
+		return job, nil
+	} else {
+		job, err := j.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+		err = renderer.Decode(job, r)
+		if err != nil {
+			return nil, err
+		}
+		_, err = SaveJob(job)
+		if err != nil {
+			return nil, err
+		}
+		job, err = j.Read(args, r)
+		if err != nil {
+			return nil, err
+		}
+
+		return job.(*Job), nil
 	}
+}
 
-	_, err = SaveJob(job)
+func (j *Job) Delete(args map[string]string, r *http.Request) (interface{}, error) {
+	job, err := j.Read(args, r)
 	if err != nil {
 		return nil, err
 	}
-	job, err = GetJob(args)
-	if err != nil {
+	if err := DB().Unscoped().Delete(job.(*Job)).Error; err != nil {
 		return nil, err
 	}
 	return job.(*Job), nil
@@ -99,14 +140,3 @@ func SaveJob(job interface{}) (interface{}, error) {
 	}
 	return job, nil
 }
-
-func DeleteJob(args map[string]string, r *http.Request) (IDer, error) {
-	job, err := GetJob(args)
-	if err != nil {
-		return nil, err
-	}
-	if err := DB().Unscoped().Delete(job.(*Job)).Error; err != nil {
-		return nil, err
-	}
-	return job.(*Job), nil
-}

+ 5 - 5
templates/administratives_add_update.html.tpl

@@ -5,12 +5,12 @@
   {{$update := .Options.Get "update"}}
 
   {{if $update}}
-  {{template "breadcrumb" toSlice "Docenti" (all "Administrative") (.Data|string) (.Data.ID|show "Administrative") "Aggiorna" "current"}}
+  {{template "breadcrumb" toSlice "Personale ATA" (all "Administrative") (.Data|string) (.Data.ID|show "Administrative") "Aggiorna" "current"}}
   {{else}}
-  {{template "breadcrumb" toSlice "Docenti" (all "Administrative") "Aggiungi" "current"}}
+  {{template "breadcrumb" toSlice "Personale ATA" (all "Administrative") "Aggiungi" "current"}}
   {{end}}
   
-  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo docente" "updateTitle" (printf "Aggiorna docente %s" (.Data|string))}}
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo ATA" "updateTitle" (printf "Aggiorna ATA %s" (.Data|string))}}
 
   <form
     class="needs-validation"
@@ -22,8 +22,8 @@
     {{$options := ` { name: "Surname",id: "administrative_surname",label: "Cognome",placeholder: "Cognome",type: "text" } `}}
     {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Surname") "update" $update}}
 
-    {{$options := ` { name: "Hours",id: "administrative_hours",label: "Numero di ore",placeholder: "",type: "number" } `}}
-    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Hours") "update" $update}}
+    {{$options := ` { name: "InternalTelephoneNumber",id: "administrative_internal_telephone_number",label: "Numero di telefono interno",placeholder: "",type: "text" } `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "InternalTelephoneNumber") "update" $update}}
 
     {{$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}}

+ 1 - 0
templates/departments_show.html.tpl

@@ -5,6 +5,7 @@
   {{template "breadcrumb" toSlice "Dipartimenti" (all "Department") (.Data|string) "current"}}
   {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Department") "deletePath" (.Data.ID|delete "Department")}}
 
+  <h2 class="karmen-relation-header">Informazioni</h2>
   {{if .Data.Coordinator}}
   <p>Il coordinatore di questo dipartimento è {{(.Data.Coordinator.ID|show "Teacher")|anchor (.Data.Coordinator|string)}}.</p>
   {{else}}

+ 17 - 28
templates/documents.html.tpl

@@ -1,43 +1,32 @@
 {{ define "content" }}
 
-<div class="container">
-  
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Documenti ({{len .Data}})</h1>
-      </div>
-      <div class="col-md-4">
-	<a href="/documents/add/?{{query "tpl_layout" "base" "tpl_content" "documents_add_update"}}" class="btn btn-primary float-right">
-          <span class="fa fa-plus-circle" aria-hidden="true"></span>
-	  Crea nuovo documento
-	</a>
-      </div>
-    </div>
-  </div>
+<div class="container">  
 
-  <div class="input-group" style="margin-bottom: 20px">
-    <span class="input-group-addon" id="search-query"><span class="glyphicon glyphicon-search"></span></span>
-    <input type="text" id="myInput" class="form-control" aria-describedby="search-query">
-  </div>
+  {{$options := `
+  title: "Documenti"
+  buttonTitle: "Crea nuovo documento"
+  `}}
   
-  {{if not .Data}}
-  <p>Non c'è alcun elemento da visualizzare</p>
+  {{template "read_all_header" dict  "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "Document")}}
+  {{template "search_input"}}
+    
+  {{if not .}}
+  {{template "display_no_elements"}}
   {{else}}
   <div class="list-group" id="myUL">
     {{range $document := .Data}}
-    <a class="list-group-item list-group-item-action" href="/documents/{{$document.ID}}?{{query "tpl_layout" "base" "tpl_content" "documents_show"}}">
-      <span class="fa fa-file"></span>
+    <a class="list-group-item list-group-item-action" href={{$document.ID|show "Document"}}>
+      <span class="fa fa-file-alt"></span>
       {{$document.Name}}
-      {{if $document.GeneratorType}}
       <div class="text-right">
-	<small>{{$document.GeneratorType.Name}}</small>
+        {{$options := `noElements: "nessun tipo"`}}
+        {{template "small" dict "options" ($options | yaml) "data" $document.GeneratorType}}
       </div>
-      {{end}}
     </a>
     {{end}}
+    {{end}}
   </div>
-  {{end}}
+
 </div>
-  
+
 {{ end }}

+ 23 - 67
templates/documents_show.html.tpl

@@ -2,84 +2,40 @@
 
 <div class="container">
 
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/documents?{{query "tpl_layout" "base" "tpl_content" "documents"}}">Documenti</a></li>
-      <li class="breadcrumb-item active"><a href="#">{{.Data.Name}}</a></li>
-    </ol>
-  </nav>
-
-  <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 float-right" role="group">
-          
-	  <a href="/documents/add/?{{query "tpl_layout" "base" "tpl_content" "documents_add_update"}}" class="btn btn-success">
-            <span class="fa fa-plus-circle" aria-hidden="true"></span>
-	    Crea
-	  </a>
-
-	  <a href="/documents/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "documents_add_update" "update" "true"}}"  class="btn btn-primary">
-            <span class="fa fa-edit" aria-hidden="true"></span>
-	    Modifica
-	  </a>
-	  <button href="/documents/{{.Data.ID}}/delete"
-		  data-url="/documents/{{.Data.ID}}/delete"
-		  class="btn btn-danger karmen-ajax-delete">
-            <span class="fa fa-trash" aria-hidden="true"></span>
-	    Elimina
-	  </button>
-	</div>
-
-      </div>
-    </div>
-  </div>
-
+  {{template "breadcrumb" toSlice "Dipartimenti" (all "Document") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Document") "deletePath" (.Data.ID|delete "Document")}}
+  
   <div class="row">
     <div class="col-md-12">
+
+      {{$options := `
+      title: "Lavori in esecuzione"
+      model: "Job"
+      icon: "fa fa-file-alt"
+      `}}
       
-      <h2 class="karmen-relation-header">Lavori in esecuzione</h2>
-      {{if .Data.RunningJobs}}
-      <div class="list-group" id="jobs_list_group">
-    	{{range $job := .Data.RunningJobs}}
-    	<a href="/jobs/{{$job.ID}}?{{query "tpl_layout" "base" "tpl_content" "jobs_show"}}" class="list-group-item list-group-item-action">
-    	  <span class="fa fa-file-alt"></span>
-    	  Il lavoro con ID {{$job.ID}} è in esecuzione.
-    	  {{end}}
-    	</a>
-      </div>
-      {{else}}
-      <p>Nessun lavoro è attualmente in esecuzione. Clicca <a href="/documents/{{.Data.ID}}/execute?{{query "tpl_layout" "base" "tpl_content" "documents_execute"}}">qui</a> per avviare l'esecuzione di un nuovo lavoro.</p>
-      {{end}}
-    </div>
+      {{$noElements := "Nessun lavoro in esecuzione."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.RunningJobs "noElements" $noElements}}
     
+    </div>
   </div>
 
-  <div class="row">
+    <div class="row">
     <div class="col-md-12">
+
+      {{$options := `
+      title: "Lavori completati di recente"
+      model: "Job"
+      icon: "fa fa-file-alt"
+      `}}
       
-      <h2 class="karmen-relation-header">Lavori terminati di recente</h2>
-      {{if .Data.CompletedJobs}}
-      <div class="list-group" id="jobs_list_group">
-    	{{range $job := .Data.CompletedJobs}}
-    	<a href="/jobs/{{$job.ID}}?{{query "tpl_layout" "base" "tpl_content" "jobs_show"}}" class="list-group-item list-group-item-action">
-    	  <span class="fa fa-file-alt"></span>
-    	  Il lavoro con ID {{$job.ID}} è stato completato in data {{$job.End}}.
-    	  {{end}}
-    	</a>
-      </div>
-      {{else}}
-      <p>Nessun lavoro è stato terminato di recente.</p>
-      {{end}}
-    </div>
+      {{$noElements := "Nessun lavoro è stato completato di recente."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.CompletedJobs "noElements" $noElements}}
     
+    </div>
   </div>
-  
 
+  
 </div>    
 
 {{ end }}

+ 17 - 28
templates/groups.html.tpl

@@ -1,43 +1,32 @@
 {{ define "content" }}
 
-<div class="container">
-  
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Gruppi ({{len .Data}})</h1>
-      </div>
-      <div class="col-md-4">
-	<a href="/groups/add/?{{query "tpl_layout" "base" "tpl_content" "groups_add_update"}}" class="btn btn-primary float-right">
-	  <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
-	  Crea nuovo gruppo
-	</a>
-      </div>
-    </div>
-  </div>
+<div class="container">  
 
-  <div class="input-group" style="margin-bottom: 20px">
-    <span class="input-group-addon" id="search-query"><span class="glyphicon glyphicon-search"></span></span>
-    <input type="text" id="myInput" class="form-control" aria-describedby="search-query">
-  </div>
+  {{$options := `
+  title: "Gruppi"
+  buttonTitle: "Crea nuovo gruppo"
+  `}}
   
-  {{if not .Data}}
-  <p>Non c'è alcun elemento da visualizzare</p>
+  {{template "read_all_header" dict  "options" ($options | yaml) "lengthData" (len .Data) "modelPath" (create "Group")}}
+  {{template "search_input"}}
+    
+  {{if not .}}
+  {{template "display_no_elements"}}
   {{else}}
   <div class="list-group" id="myUL">
     {{range $group := .Data}}
-    <a class="list-group-item list-group-item-action" href="/groups/{{$group.ID}}?{{query "tpl_layout" "base" "tpl_content" "groups_show"}}">
-      <span class="fa fa-users"></span>
+    <a class="list-group-item list-group-item-action" href={{$group.ID|show "Group"}}>
+      <span class="fa fa-user"></span>
       {{$group.Name}}
       <div class="text-right">
- 	{{range $teacher := $group.Teachers}}
-	<small>{{$teacher.Surname}}</small>
-	{{end}}
+        {{$options := `noElements: "nessun elemento"`}}
+        {{template "small" dict "options" ($options | yaml) "data" $group.Teachers}}
       </div>
     </a>
     {{end}}
+    {{end}}
   </div>
-  {{end}}
+
 </div>
-  
+
 {{ end }}

+ 23 - 65
templates/groups_add_update.html.tpl

@@ -1,80 +1,38 @@
 {{ define "content" }}
 
 <div class="container">
+  
+  {{$update := .Options.Get "update"}}
 
-  {{if .Options.Get "update"}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/groups?{{query "tpl_layout" "base" "tpl_content" "groups"}}">Gruppi</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiorna gruppo</a></li>
-    </ol>
-  </nav>
+  {{if $update}}
+  {{template "breadcrumb" toSlice "Gruppi" (all "Group") (.Data|string) (.Data.ID|show "Group") "Aggiorna" "current"}}
   {{else}}
-  <nav aria-label="breadcrumb">
-    <ol class="breadcrumb">
-      <li class="breadcrumb-item"><a href="/groups?{{query "tpl_layout" "base" "tpl_content" "groups"}}">Gruppi</a></li>
-      <li class="breadcrumb-item active"><a href="#">Aggiungi</a></li>
-    </ol>
-  </nav>
+  {{template "breadcrumb" toSlice "Gruppi" (all "Group") "Aggiungi" "current"}}
   {{end}}
-
-  {{if .Options.Get "update"}}
-  <div class="karmen-info-header">
-    <div class="row">
-      <div class="col-md-8">
-	<h1>Aggiorna gruppo</h1>
-      </div>
-    </div>
-  </div>
   
-  {{else}}
-  <h1 class="karmen-info-header">Crea nuovo gruppo</h1>
-  {{end}}
-
-  {{if .Options.Get "update"}}
-  <form id="form_groups_add_update" action="/groups/{{.Data.Group.ID}}/update" method="POST" role="form" data-toggle="validator">
-    {{else}}
-    <form id="form_groups_add_update" action="/groups/add/" method="POST" role="form" data-toggle="validator">
-      {{end}}
+  {{template "add_update_header" dict "update" $update "addTitle" "Crea nuovo gruppo" "updateTitle" (printf "Aggiorna gruppo %s" (.Data|string))}}
 
-      <div class="form-group has-feedback">
-        <label class="control-label" for="group_name">Nome</label>
-        <input type="text" name="Name" class="form-control" id="group_name" placeholder="Nome" {{if .Options.Get "update"}} value="{{.Data.Group.Name}}" {{end}} required>
-      </div>
+  {{$form := "form_groups_add_update"}}
+  <form
+    class="needs-validation"
+    action="{{if $update}}{{.Data.ID|update "Group"}}{{else}}{{create "Group"}}{{end}}"
+    method="POST"
+    role="form"
+    id={{$form}}>
 
-      <div class="form-group has-feedback">
-        <label class="control-label" for="group_query">Stringa di popolamento</label>
-        <input type="text" name="Query" class="form-control" id="group_query" placeholder="surname:*" {{if .Options.Get "update"}} value="{{.Data.Group.Query}}" {{end}}>
-      </div>
+    {{$options := ` { name: "Name",id: "group_name",label: "Nome",placeholder: "Nome",type: "text",required: "true"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Name") "update" $update}}
 
-      <div class="form-group">
-        <label class="control-label" for="teacher_id">Docenti</label>
-        <select name="teacher_ids" class="form-control selectpicker" id="teacher_ids" placeholder="Docenti" data-live-search="true" form="form_groups_add_update" title="Seleziona i nomi dei docenti" data-dropup-auto="false" multiple>
-          <option value="0"></option>
-          {{range $teacher := .Data.AllTeachers}}
-          {{if $.Options.Get "update"}}
-          <option
-	    value="{{$teacher.ID}}"
-	    {{index $.Data.SelectedTeacher $teacher.ID}}>{{$teacher.CompleteName}}
-          </option>
-          {{else}}
-          <option value="{{$teacher.ID}}">{{$teacher.CompleteName}}</option>
-          {{end}}
-          {{end}}
-        </select>
-      </div>
+    {{$options := ` { name: "Query",id: "group_query",label: "Stringa di popolamento",placeholder: "surname:*",type: "text"} `}}
+    {{template "input" dict "options" ($options|yaml) "value" (.Data|field "Query") "update" $update}}
 
-      <div class="form-group">
-        <button type="submit" class="btn btn-primary">Salva</button>
-        {{if .Options.Get "update"}}
-        <a href="/groups/{{.Data.Group.ID}}?{{query "tpl_layout" "base" "tpl_content" "groups_show"}}" class="btn btn-default">Annulla</a>
-        {{else}}
-        <a href="/groups?{{query "tpl_layout" "base" "tpl_content" "groups"}}" class="btn btn-default">Annulla</a>
-        {{end}}
-      </div>
-    
-    </form>
+    {{$options := ` { name: "teacher_ids", id: "teacher_ids", label: "Docenti", title: "Seleziona i docenti", multiple: "true"}`}}
+    {{template "select" dict "options" ($options|yaml) "data" (.Data|field "AllTeachers") "selected" (.Data|field "SelectedTeacher") "update" $update "form" $form}}
 
+    {{ $options := ` { cancelTitle: "Annulla", saveTitle: "Salva", model: "Group"} ` }}
+    {{template "submit_cancel_buttons" dict "options" ($options|yaml) "id" (.Data|field "ID") "update" $update}}  
+  </form>
+  
 </div>
 
 {{ end }}

+ 12 - 47
templates/groups_show.html.tpl

@@ -2,59 +2,24 @@
 
 <div class="container">
 
-  <nav aria-label="breadcrumb">
-  <ol class="breadcrumb">
-    <li class="breadcrumb-item"><a href="/groups?{{query "tpl_layout" "base" "tpl_content" "groups"}}">Gruppi</a></li>
-    <li class="breadcrumb-item active"><a href="#">{{.Data.Name}}</a></li>
-  </ol>
-  </nav>
-
-  <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 float-right" role="group">
-	  <a href="/groups/add/?{{query "tpl_layout" "base" "tpl_content" "groups_add_update"}}" class="btn btn-success">
-	    <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
-	    Crea
-	  </a>
-	  <a href="/groups/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "groups_add_update" "update" "true"}}"  class="btn btn-primary">
-	    <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
-	    Modifica
-	  </a>
-	  <button href="/groups/{{.Data.ID}}/delete"
-		  data-url="/groups/{{.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>
+  {{template "breadcrumb" toSlice "Gruppi" (all "Group") (.Data|string) "current"}}
+  {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Group") "deletePath" (.Data.ID|delete "Group")}}
   
   <div class="row">
     <div class="col-md-12">
+
+      {{$options := `
+      title: "Docenti appartenenti al gruppo"
+      model: "Teacher"
+      icon: "fa fa-user"
+      `}}
       
-      <h2 class="karmen-relation-header">Docenti associati al gruppo</h2>
-      {{if .Data.Teachers}}
-      <div class="list-group" id="students_list_group">
-	{{range $teacher := .Data.Teachers}}
-	<a href="/teachers/{{$teacher.ID}}?{{query "tpl_layout" "base" "tpl_content" "teachers_show"}}" class="list-group-item list-group-item-action">
-	  <span class="fa fa-user"></span>
-	  {{$teacher.CompleteName}}
-	  {{end}}
-	  </a>
-      </div>
-      {{else}}
-      <p>Al gruppo non è associato alcun docente. Clicca <a href="/groups/{{.Data.ID}}/update?{{query "tpl_layout" "base" "tpl_content" "groups_add_update"}}">qui</a> per modificare questo gruppo.</p>
-      {{end}}
-    </div>
+      {{$noElements := "Al gruppo non è associato nessun docente."}}
+      {{template "relation_list" dict "options" ($options|yaml) "data" .Data.Teachers "noElements" $noElements}}
     
+    </div>
   </div>
-
+  
 </div>    
 
 {{ end }}

+ 1 - 1
templates/layout/select.html.tpl

@@ -8,7 +8,7 @@
           data-live-search="true"
           form="{{.form}}"
           title="{{.options.title}}"
-          data-dropup-auto="false">
+          data-dropup-auto="false" {{if .options.multiple}}multiple{{end}}>
     <option value="0"></option>
     {{range $el := .data}}
     {{if $.update}}

+ 1 - 1
templates/offices_show.html.tpl

@@ -5,7 +5,7 @@
   {{template "breadcrumb" toSlice "Uffici" (all "Office") (.Data|string) "current"}}
   {{template "show_header" dict "title" (.Data|string) "updatePath" (.Data.ID|update "Office") "deletePath" (.Data.ID|delete "Office")}}
 
-  <h2 class="karmen-relation-header">Informazioni generali</h2>
+  <h2 class="karmen-relation-header">Informazioni</h2>
   {{if .Data.Email}}
   <p>L'indirizzo di posta elettronica dell'ufficio è <a href="mailto:{{.Data.Email}}">{{.Data.Email}}</a></p>
   {{else}}