diff --git a/admin/api/claim.go b/admin/api/claim.go
new file mode 100644
index 00000000..a5e815fc
--- /dev/null
+++ b/admin/api/claim.go
@@ -0,0 +1,189 @@
+package api
+
+import (
+ "encoding/json"
+ "time"
+
+ "srs.epita.fr/fic-server/libfic"
+
+ "github.com/julienschmidt/httprouter"
+)
+
+func init() {
+ // Tasks
+ router.GET("/api/claims/", apiHandler(getClaims))
+ router.POST("/api/claims/", apiHandler(newClaim))
+ router.DELETE("/api/claims/", apiHandler(clearClaims))
+
+ router.GET("/api/claims/:cid", apiHandler(claimHandler(showClaim)))
+ router.PUT("/api/claims/:cid", apiHandler(claimHandler(updateClaim)))
+ router.POST("/api/claims/:cid", apiHandler(claimHandler(addClaimDescription)))
+ router.DELETE("/api/claims/:cid", apiHandler(claimHandler(deleteClaim)))
+
+ // Assignees
+ router.GET("/api/claims-assignees/", apiHandler(getAssignees))
+ router.POST("/api/claims-assignees/", apiHandler(newAssignee))
+
+ router.GET("/api/claims-assignees/:aid", apiHandler(claimAssigneeHandler(showClaimAssignee)))
+ router.PUT("/api/claims-assignees/:aid", apiHandler(claimAssigneeHandler(updateClaimAssignee)))
+ router.DELETE("/api/claims-assignees/:aid", apiHandler(claimAssigneeHandler(deleteClaimAssignee)))
+}
+
+func getClaims(_ httprouter.Params, _ []byte) (interface{}, error) {
+ return fic.GetClaims()
+}
+
+type ClaimExported struct {
+ Id int64 `json:"id"`
+ Subject string `json:"subject"`
+ IdTeam *int64 `json:"id_team"`
+ Team *fic.Team `json:"team"`
+ IdAssignee *int64 `json:"id_assignee"`
+ Assignee *fic.ClaimAssignee `json:"assignee"`
+ Creation time.Time `json:"creation"`
+ LastUpdate time.Time `json:"last_update"`
+ State string `json:"state"`
+ Priority string `json:"priority"`
+ Descriptions []fic.ClaimDescription `json:"descriptions"`
+}
+
+func showClaim(claim fic.Claim, _ []byte) (interface{}, error) {
+ var e ClaimExported
+ var err error
+ if e.Team, err = claim.GetTeam(); err != nil {
+ return nil, err
+ }
+ if e.Assignee, err = claim.GetAssignee(); err != nil {
+ return nil, err
+ }
+ if e.Descriptions, err = claim.GetDescriptions(); err != nil {
+ return nil, err
+ }
+
+ e.LastUpdate = e.Creation
+ for _, d := range e.Descriptions {
+ if d.Date.After(e.LastUpdate) {
+ e.LastUpdate = d.Date
+ }
+ }
+
+ e.Id = claim.Id
+ e.IdAssignee = claim.IdAssignee
+ e.IdTeam = claim.IdTeam
+ e.Subject = claim.Subject
+ e.Creation = claim.Creation
+ e.State = claim.State
+ e.Priority = claim.Priority
+ return e, nil
+}
+
+type ClaimUploaded struct {
+ Subject string `json:"subject"`
+ Team *int `json:"id_team"`
+ Assignee *int64 `json:"id_assignee"`
+ Priority string `json:"priority"`
+}
+
+func newClaim(_ httprouter.Params, body []byte) (interface{}, error) {
+ var uc ClaimUploaded
+ if err := json.Unmarshal(body, &uc); err != nil {
+ return nil, err
+ }
+
+ var t *fic.Team
+ if uc.Team != nil {
+ if team, err := fic.GetTeam(*uc.Team); err != nil {
+ return nil, err
+ } else {
+ t = &team
+ }
+ } else {
+ t = nil
+ }
+
+ var a *fic.ClaimAssignee
+ if uc.Assignee != nil {
+ if assignee, err := fic.GetAssignee(*uc.Assignee); err != nil {
+ return nil, err
+ } else {
+ a = &assignee
+ }
+ } else {
+ a = nil
+ }
+
+ return fic.NewClaim(uc.Subject, t, a, uc.Priority)
+}
+
+func clearClaims(_ httprouter.Params, _ []byte) (interface{}, error) {
+ return fic.ClearClaims()
+}
+
+
+func addClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
+ var ud fic.ClaimDescription
+ if err := json.Unmarshal(body, &ud); err != nil {
+ return nil, err
+ }
+
+ if assignee, err := fic.GetAssignee(ud.IdAssignee); err != nil {
+ return nil, err
+ } else {
+ return claim.AddDescription(ud.Content, assignee)
+ }
+}
+
+func updateClaim(claim fic.Claim, body []byte) (interface{}, error) {
+ var uc fic.Claim
+ if err := json.Unmarshal(body, &uc); err != nil {
+ return nil, err
+ }
+
+ uc.Id = claim.Id
+
+ if _, err := uc.Update(); err != nil {
+ return nil, err
+ } else {
+ return uc, nil
+ }
+}
+
+func deleteClaim(claim fic.Claim, _ []byte) (interface{}, error) {
+ return claim.Delete()
+}
+
+
+func getAssignees(_ httprouter.Params, _ []byte) (interface{}, error) {
+ return fic.GetAssignees()
+}
+
+func showClaimAssignee(assignee fic.ClaimAssignee, _ []byte) (interface{}, error) {
+ return assignee, nil
+}
+func newAssignee(_ httprouter.Params, body []byte) (interface{}, error) {
+ var ua fic.ClaimAssignee
+ if err := json.Unmarshal(body, &ua); err != nil {
+ return nil, err
+ }
+
+ return fic.NewClaimAssignee(ua.Name)
+}
+
+func updateClaimAssignee(assignee fic.ClaimAssignee, body []byte) (interface{}, error) {
+ var ua fic.ClaimAssignee
+ if err := json.Unmarshal(body, &ua); err != nil {
+ return nil, err
+ }
+
+ ua.Id = assignee.Id
+
+ if _, err := ua.Update(); err != nil {
+ return nil, err
+ } else {
+ return ua, nil
+ }
+}
+
+func deleteClaimAssignee(assignee fic.ClaimAssignee, _ []byte) (interface{}, error) {
+ return assignee.Delete()
+}
diff --git a/admin/api/handlers.go b/admin/api/handlers.go
index 49a2ccd8..854cbf21 100644
--- a/admin/api/handlers.go
+++ b/admin/api/handlers.go
@@ -248,6 +248,30 @@ func eventHandler(f func(fic.Event,[]byte) (interface{}, error)) func (httproute
}
}
+func claimHandler(f func(fic.Claim,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
+ return func (ps httprouter.Params, body []byte) (interface{}, error) {
+ if cid, err := strconv.Atoi(string(ps.ByName("cid"))); err != nil {
+ return nil, err
+ } else if claim, err := fic.GetClaim(cid); err != nil {
+ return nil, err
+ } else {
+ return f(claim, body)
+ }
+ }
+}
+
+func claimAssigneeHandler(f func(fic.ClaimAssignee,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
+ return func (ps httprouter.Params, body []byte) (interface{}, error) {
+ if aid, err := strconv.Atoi(string(ps.ByName("aid"))); err != nil {
+ return nil, err
+ } else if assignee, err := fic.GetAssignee(int64(aid)); err != nil {
+ return nil, err
+ } else {
+ return f(assignee, body)
+ }
+ }
+}
+
func fileHandler(f func(fic.EFile,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
return func (ps httprouter.Params, body []byte) (interface{}, error) {
if fileid, err := strconv.Atoi(string(ps.ByName("fileid"))); err != nil {
diff --git a/admin/index.go b/admin/index.go
index d1efd3fb..939b9250 100644
--- a/admin/index.go
+++ b/admin/index.go
@@ -36,6 +36,7 @@ const indextpl = `
Fichiers
Public
Événements
+ Tâches
Paramètres
diff --git a/admin/static.go b/admin/static.go
index 75127168..6a62d747 100644
--- a/admin/static.go
+++ b/admin/static.go
@@ -13,6 +13,9 @@ func init() {
api.Router().GET("/", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
+ api.Router().GET("/claims/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
+ http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
+ })
api.Router().GET("/exercices/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
diff --git a/admin/static/index.html b/admin/static/index.html
index 391af203..85900057 100644
--- a/admin/static/index.html
+++ b/admin/static/index.html
@@ -34,6 +34,7 @@
Fichiers
Public
Événements
+ Tâches
Paramètres
diff --git a/admin/static/js/app.js b/admin/static/js/app.js
index ca12158d..9c54537f 100644
--- a/admin/static/js/app.js
+++ b/admin/static/js/app.js
@@ -61,12 +61,46 @@ angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"])
controller: "EventController",
templateUrl: "views/event.html"
})
+ .when("/claims", {
+ controller: "ClaimsListController",
+ templateUrl: "views/claim-list.html"
+ })
+ .when("/claims/:claimId", {
+ controller: "ClaimController",
+ templateUrl: "views/claim.html"
+ })
.when("/", {
templateUrl: "views/home.html"
});
$locationProvider.html5Mode(true);
});
+function setCookie(name, value, days) {
+ var expires;
+
+ if (days) {
+ var date = new Date();
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
+ expires = "; expires=" + date.toGMTString();
+ } else {
+ expires = "";
+ }
+ document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
+}
+
+function getCookie(name) {
+ var nameEQ = encodeURIComponent(name) + "=";
+ var ca = document.cookie.split(';');
+ for (var i = 0; i < ca.length; i++) {
+ var c = ca[i];
+ while (c.charAt(0) === ' ')
+ c = c.substring(1, c.length);
+ if (c.indexOf(nameEQ) === 0)
+ return decodeURIComponent(c.substring(nameEQ.length, c.length));
+ }
+ return null;
+}
+
angular.module("FICApp")
.directive('autofocus', ['$timeout', function($timeout) {
return {
@@ -88,6 +122,16 @@ angular.module("FICApp")
'update': {method: 'PUT'},
})
})
+ .factory("Claim", function($resource) {
+ return $resource("/api/claims/:claimId", { claimId: '@id' }, {
+ 'update': {method: 'PUT'},
+ })
+ })
+ .factory("ClaimAssignee", function($resource) {
+ return $resource("/api/claims-assignees/:assigneeId", { assigneeId: '@id' }, {
+ 'update': {method: 'PUT'},
+ })
+ })
.factory("File", function($resource) {
return $resource("/api/files/:fileId", { fileId: '@id' })
})
@@ -616,6 +660,134 @@ angular.module("FICApp")
}
})
+ .controller("AssigneesListController", function($scope, ClaimAssignee, $location) {
+ $scope.assignees = ClaimAssignee.query();
+
+ $scope.setMyAId = function(aid) {
+ setCookie("myassignee", aid, 5);
+ $location.url("/claims/");
+ }
+ $scope.whoami = getCookie("myassignee");
+ $scope.newAssignee = function() {
+ $scope.assignees.push(new ClaimAssignee());
+ }
+ $scope.edit = function(a) {
+ a.edit = true;
+ }
+ $scope.updateAssignee = function(a) {
+ if (a.id) {
+ a.$update(function() { $location.url("/claims/");});
+ } else {
+ a.$save()
+ }
+ }
+ $scope.removeAssignee = function(a) {
+ a.$remove(function() { $location.url("/claims/");});
+ }
+ })
+ .controller("ClaimsListController", function($scope, Claim, ClaimAssignee, Teams, $location) {
+ $scope.claims = Claim.query();
+ $scope.assignees = ClaimAssignee.query();
+ $scope.whoami = getCookie("myassignee");
+ $scope.teams = Teams.get();
+ $scope.fields = ["id", "state", "subject", "creation", "id_team", "id_assignee"];
+
+ $scope.order = "priority";
+ $scope.chOrder = function(no) {
+ $scope.order = no;
+ };
+
+ $scope.clearClaims = function(id) {
+ Claim.delete(function() {
+ $scope.claims = [];
+ });
+ };
+ $scope.show = function(id) {
+ $location.url("/claims/" + id);
+ };
+ })
+ .controller("ClaimController", function($scope, Claim, ClaimAssignee, Teams, $routeParams, $location, $http) {
+ $scope.claim = Claim.get({ claimId: $routeParams.claimId }, function(v) {
+ v.id_team = "" + v.id_team;
+ if (!v.priority)
+ v.priority = "medium";
+ });
+ if ($routeParams.claimId == "new")
+ $scope.fields = ["id_team", "subject", "priority", "id_assignee"];
+ else
+ $scope.fields = ["state", "subject", "priority", "id_assignee", "id_team", "creation"];
+ $scope.assignees = ClaimAssignee.query();
+ $scope.whoami = Math.floor(getCookie("myassignee"));
+ $scope.teams = Teams.get();
+ $scope.namedFields = {
+ "subject": "Objet",
+ "id_assignee": "Assigné a",
+ "state": "État",
+ "id_team": "Équipe",
+ "creation": "Création",
+ "priority": "Priorité",
+ "description": "Description",
+ };
+ $scope.states = {
+ "new": "Nouveau",
+ "need-info": "Besoin d'infos",
+ "confirmed": "Confirmé",
+ "in-progress": "En cours",
+ "need-review": "Fait",
+ "closed": "Clos",
+ "invalid": "Invalide",
+ };
+ $scope.priorities = {
+ "low": "Basse",
+ "medium": "Moyenne",
+ "high": "Haute",
+ "critical": "Critique",
+ };
+
+ $scope.assignToMe = function() {
+ this.claim.id_assignee = $scope.whoami;
+ if (this.claim.id)
+ this.saveClaim();
+ }
+ $scope.saveDescription = function() {
+ $http({
+ url: "/api/claims/" + $scope.claim.id,
+ method: "POST",
+ data: {
+ "id_assignee": $scope.whoami,
+ "content": $scope.ndescription
+ }
+ }).then(function() {
+ $location.url("/claims/" + $scope.claim.id);
+ });
+ }
+ $scope.saveClaim = function() {
+ if (this.claim.id_team) {
+ this.claim.id_team = Math.floor(this.claim.id_team);
+ } else {
+ this.claim.id_team = null;
+ }
+ if (this.claim.id) {
+ this.claim.$update(function(v) {
+ v.id_team = "" + v.id_team;
+ if ($scope.ndescription)
+ $scope.saveDescription();
+ else
+ $location.url("/claims/");
+ });
+ } else {
+ this.claim.$save(function() {
+ if (!this.ndescription)
+ this.ndescription = "Création de la tâche";
+ $scope.saveDescription();
+ });
+ }
+ }
+ $scope.deleteClaim = function() {
+ this.claim.$remove(function() { $location.url("/claims/");});
+ }
+ })
+
.controller("ThemesListController", function($scope, Theme, $location, $rootScope, $http) {
$scope.themes = Theme.query();
$scope.fields = ["id", "name"];
diff --git a/admin/static/views/claim-list.html b/admin/static/views/claim-list.html
new file mode 100644
index 00000000..85a17bfa
--- /dev/null
+++ b/admin/static/views/claim-list.html
@@ -0,0 +1,61 @@
+
+ Tâches et réclammations ({{ claims.length }})
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ field }}
+ |
+
+
+
+
+
+ {{ claim[field] }}
+ |
+
+
+
+
+
+
+
+
+ Assignables à
+
+
+
+
diff --git a/admin/static/views/claim.html b/admin/static/views/claim.html
new file mode 100644
index 00000000..69e4521a
--- /dev/null
+++ b/admin/static/views/claim.html
@@ -0,0 +1,36 @@
+Tâche
+
+
+
+
+
+
+ Par anonymous {{ assignee.name }} le {{ description.date | date:"mediumTime" }} :
+ {{ description.content }}
+
diff --git a/libfic/db.go b/libfic/db.go
index 9ff54422..79b209a0 100644
--- a/libfic/db.go
+++ b/libfic/db.go
@@ -229,6 +229,42 @@ CREATE TABLE IF NOT EXISTS team_hints(
FOREIGN KEY(id_hint) REFERENCES exercice_hints(id_hint),
FOREIGN KEY(id_team) REFERENCES teams(id_team)
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
+`); err != nil {
+ return err
+ }
+ if _, err := db.Exec(`
+CREATE TABLE IF NOT EXISTS claim_assignees(
+ id_assignee INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ name VARCHAR(255) NOT NULL UNIQUE
+) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
+`); err != nil {
+ return err
+ }
+ if _, err := db.Exec(`
+CREATE TABLE IF NOT EXISTS claims(
+ id_claim INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ subject VARCHAR(255) NOT NULL,
+ id_team INTEGER,
+ id_assignee INTEGER,
+ creation TIMESTAMP NOT NULL,
+ state ENUM('new', 'need-info', 'confirmed', 'in-progress', 'need-review', 'closed', 'invalid') NOT NULL,
+ priority ENUM('low', 'medium', 'high', 'critical') NOT NULL,
+ FOREIGN KEY(id_assignee) REFERENCES claim_assignees(id_assignee),
+ FOREIGN KEY(id_team) REFERENCES teams(id_team)
+) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
+`); err != nil {
+ return err
+ }
+ if _, err := db.Exec(`
+CREATE TABLE IF NOT EXISTS claim_descriptions(
+ id_description INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ id_claim INTEGER NOT NULL,
+ id_assignee INTEGER NOT NULL,
+ date TIMESTAMP NOT NULL,
+ content TEXT NOT NULL,
+ FOREIGN KEY(id_assignee) REFERENCES claim_assignees(id_assignee),
+ FOREIGN KEY(id_claim) REFERENCES claims(id_claim)
+) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
`); err != nil {
return err
}
diff --git a/libfic/todo.go b/libfic/todo.go
new file mode 100644
index 00000000..1d2a64bd
--- /dev/null
+++ b/libfic/todo.go
@@ -0,0 +1,268 @@
+package fic
+
+import (
+ "database/sql"
+ "time"
+)
+
+type Claim struct {
+ Id int64 `json:"id"`
+ Subject string `json:"subject"`
+ IdTeam *int64 `json:"id_team"`
+ IdAssignee *int64 `json:"id_assignee"`
+ Creation time.Time `json:"creation"`
+ State string `json:"state"`
+ Priority string `json:"priority"`
+}
+
+func GetClaim(id int) (c Claim, err error) {
+ err = DBQueryRow("SELECT id_claim, subject, id_team, id_assignee, creation, state, priority FROM claims WHERE id_claim = ?", id).Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdAssignee, &c.Creation, &c.State, &c.Priority)
+ return
+}
+
+func GetClaims() (res []Claim, err error) {
+ var rows *sql.Rows
+ if rows, err = DBQuery("SELECT id_claim, subject, id_team, id_assignee, creation, state, priority FROM claims"); err != nil {
+ return
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var c Claim
+ if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil {
+ return
+ }
+ res = append(res, c)
+ }
+ err = rows.Err()
+
+ return
+}
+
+func (t Team) GetClaims() (res []Claim, err error) {
+ var rows *sql.Rows
+ if rows, err = DBQuery("SELECT id_claim, subject, IdTeam, id_assignee, creation, state, priority FROM claims WHERE IdTeam = ?", t.Id); err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var c Claim
+ if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil {
+ return
+ }
+ res = append(res, c)
+ }
+ err = rows.Err()
+
+ return
+}
+
+func NewClaim(subject string, team *Team, assignee *ClaimAssignee, priority string) (Claim, error) {
+ var tid *int64
+ if team == nil {
+ tid = nil
+ } else {
+ tid = &team.Id
+ }
+
+ var aid *int64
+ if assignee == nil {
+ aid = nil
+ } else {
+ aid = &assignee.Id
+ }
+
+ if res, err := DBExec("INSERT INTO claims (subject, id_team, id_assignee, creation, state, priority) VALUES (?, ?, ?, ?, ?, ?)", subject, tid, aid, time.Now(), "new", priority); err != nil {
+ return Claim{}, err
+ } else if cid, err := res.LastInsertId(); err != nil {
+ return Claim{}, err
+ } else {
+ return Claim{cid, subject, tid, aid, time.Now(), "new", priority}, nil
+ }
+}
+
+func (c Claim) GetTeam() (*Team, error) {
+ if c.IdTeam == nil {
+ return nil, nil
+ } else if t, err := GetTeam(int(*c.IdTeam)); err != nil {
+ return nil, err
+ } else {
+ return &t, nil
+ }
+}
+
+func (c Claim) SetTeam(t Team) {
+ c.IdTeam = &t.Id
+}
+
+func (c Claim) Update() (int64, error) {
+ if res, err := DBExec("UPDATE claims SET subject = ?, id_team = ?, id_assignee = ?, creation = ?, state = ?, priority = ? WHERE id_claim = ?", c.Subject, c.IdTeam, c.IdAssignee, c.Creation, c.State, c.Priority, c.Id); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+func (c Claim) Delete() (int64, error) {
+ if res, err := DBExec("DELETE FROM claims WHERE id_claim = ?", c.Id); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+func ClearClaims() (int64, error) {
+ if res, err := DBExec("DELETE FROM claims"); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+
+type ClaimDescription struct {
+ Id int64 `json:"id"`
+ IdAssignee int64 `json:"id_assignee"`
+ Content string `json:"content"`
+ Date time.Time `json:"date"`
+}
+
+func (c Claim) GetDescriptions() (res []ClaimDescription, err error) {
+ var rows *sql.Rows
+ if rows, err = DBQuery("SELECT id_description, id_assignee, content, date FROM claim_descriptions WHERE id_claim = ?", c.Id); err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var d ClaimDescription
+ if err = rows.Scan(&d.Id, &d.IdAssignee, &d.Content, &d.Date); err != nil {
+ return
+ }
+ res = append(res, d)
+ }
+ err = rows.Err()
+
+ return
+}
+
+func (c Claim) AddDescription(content string, assignee ClaimAssignee) (ClaimDescription, error) {
+ if res, err := DBExec("INSERT INTO claim_descriptions (id_claim, id_assignee, content, date) VALUES (?, ?, ?, ?)", c.Id, assignee.Id, content, time.Now()); err != nil {
+ return ClaimDescription{}, err
+ } else if did, err := res.LastInsertId(); err != nil {
+ return ClaimDescription{}, err
+ } else {
+ return ClaimDescription{did, assignee.Id, content, time.Now()}, nil
+ }
+}
+
+func (d ClaimDescription) Update() (int64, error) {
+ if res, err := DBExec("UPDATE claim_descriptions SET id_assignee = ?, content = ?, date = ? WHERE id_description = ?", d.IdAssignee, d.Content, d.Date, d.Id); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+func (d ClaimDescription) Delete() (int64, error) {
+ if res, err := DBExec("DELETE FROM claim_descriptions WHERE id_description = ?", d.Id); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+
+type ClaimAssignee struct {
+ Id int64 `json:"id"`
+ Name string `json:"name"`
+}
+
+func GetAssignee(id int64) (a ClaimAssignee, err error) {
+ err = DBQueryRow("SELECT id_assignee, name FROM claim_assignees WHERE id_assignee = ?", id).Scan(&a.Id, &a.Name)
+ return
+}
+
+func GetAssignees() (res []ClaimAssignee, err error) {
+ var rows *sql.Rows
+ if rows, err = DBQuery("SELECT id_assignee, name FROM claim_assignees"); err != nil {
+ return
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var a ClaimAssignee
+ if err = rows.Scan(&a.Id, &a.Name); err != nil {
+ return
+ }
+ res = append(res, a)
+ }
+ err = rows.Err()
+
+ return
+}
+
+func NewClaimAssignee(name string) (ClaimAssignee, error) {
+ if res, err := DBExec("INSERT INTO claim_assignees (name) VALUES (?)", name); err != nil {
+ return ClaimAssignee{}, err
+ } else if aid, err := res.LastInsertId(); err != nil {
+ return ClaimAssignee{}, err
+ } else {
+ return ClaimAssignee{aid, name}, nil
+ }
+}
+
+func (a ClaimAssignee) Update() (int64, error) {
+ if res, err := DBExec("UPDATE claim_assignees SET name = ? WHERE id_assignee = ?", a.Name, a.Id); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+func (a ClaimAssignee) Delete() (int64, error) {
+ if res, err := DBExec("DELETE FROM claim_assignees WHERE id_assignee = ?", a.Id); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+func ClearAssignees() (int64, error) {
+ if res, err := DBExec("DELETE FROM claim_assignees"); err != nil {
+ return 0, err
+ } else if nb, err := res.RowsAffected(); err != nil {
+ return 0, err
+ } else {
+ return nb, err
+ }
+}
+
+func (c Claim) GetAssignee() (*ClaimAssignee, error) {
+ if c.IdAssignee == nil {
+ return nil, nil
+ } else if a, err := GetAssignee(*c.IdAssignee); err != nil {
+ return nil, err
+ } else {
+ return &a, nil
+ }
+}
+
+func (c Claim) SetAssignee(a ClaimAssignee) {
+ c.IdAssignee = &a.Id
+}