frontend: display issues related to the team
This commit is contained in:
parent
7bec409ab8
commit
a3ffdeae17
@ -3,6 +3,9 @@ package api
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
"srs.epita.fr/fic-server/libfic"
|
||||||
@ -11,6 +14,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
router.GET("/api/teams/:tid/issue.json", apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, _ []byte) (interface{}, error) {
|
||||||
|
return team.MyIssueFile()
|
||||||
|
})))
|
||||||
|
|
||||||
// Tasks
|
// Tasks
|
||||||
router.GET("/api/claims", apiHandler(getClaims))
|
router.GET("/api/claims", apiHandler(getClaims))
|
||||||
router.POST("/api/claims", apiHandler(newClaim))
|
router.POST("/api/claims", apiHandler(newClaim))
|
||||||
@ -24,6 +32,8 @@ func init() {
|
|||||||
router.POST("/api/claims/:cid", apiHandler(claimHandler(addClaimDescription)))
|
router.POST("/api/claims/:cid", apiHandler(claimHandler(addClaimDescription)))
|
||||||
router.DELETE("/api/claims/:cid", apiHandler(claimHandler(deleteClaim)))
|
router.DELETE("/api/claims/:cid", apiHandler(claimHandler(deleteClaim)))
|
||||||
|
|
||||||
|
router.PUT("/api/claims/:cid/descriptions", apiHandler(claimHandler(updateClaimDescription)))
|
||||||
|
|
||||||
// Assignees
|
// Assignees
|
||||||
router.GET("/api/claims-assignees", apiHandler(getAssignees))
|
router.GET("/api/claims-assignees", apiHandler(getAssignees))
|
||||||
router.POST("/api/claims-assignees", apiHandler(newAssignee))
|
router.POST("/api/claims-assignees", apiHandler(newAssignee))
|
||||||
@ -157,6 +167,17 @@ func clearClaims(_ httprouter.Params, _ []byte) (interface{}, error) {
|
|||||||
return fic.ClearClaims()
|
return fic.ClearClaims()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateTeamIssuesFile(team fic.Team) error {
|
||||||
|
if my, err := team.MyIssueFile(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if j, err := json.Marshal(my); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err = ioutil.WriteFile(path.Join(TeamsDir, fmt.Sprintf("%d", team.Id), "issues.json"), j, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func addClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
|
func addClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
|
||||||
var ud fic.ClaimDescription
|
var ud fic.ClaimDescription
|
||||||
if err := json.Unmarshal(body, &ud); err != nil {
|
if err := json.Unmarshal(body, &ud); err != nil {
|
||||||
@ -165,8 +186,31 @@ func addClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
|
|||||||
|
|
||||||
if assignee, err := fic.GetAssignee(ud.IdAssignee); err != nil {
|
if assignee, err := fic.GetAssignee(ud.IdAssignee); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
} else if description, err := claim.AddDescription(ud.Content, assignee, ud.Publish); err != nil {
|
||||||
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
return claim.AddDescription(ud.Content, assignee)
|
if team, _ := claim.GetTeam(); team != nil {
|
||||||
|
err = generateTeamIssuesFile(*team)
|
||||||
|
}
|
||||||
|
|
||||||
|
return description, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
|
||||||
|
var ud fic.ClaimDescription
|
||||||
|
if err := json.Unmarshal(body, &ud); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := ud.Update(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
if team, _ := claim.GetTeam(); team != nil {
|
||||||
|
err = generateTeamIssuesFile(*team)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ud, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +225,11 @@ func updateClaim(claim fic.Claim, body []byte) (interface{}, error) {
|
|||||||
if _, err := uc.Update(); err != nil {
|
if _, err := uc.Update(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
return uc, nil
|
if team, _ := claim.GetTeam(); team != nil {
|
||||||
|
err = generateTeamIssuesFile(*team)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uc, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,13 +1133,26 @@ angular.module("FICApp")
|
|||||||
$scope.changeState = function(state) {
|
$scope.changeState = function(state) {
|
||||||
this.claim.state = state;
|
this.claim.state = state;
|
||||||
if (this.claim.id)
|
if (this.claim.id)
|
||||||
this.saveClaim(false);
|
this.saveClaim(state == "invalid" || state == "closed");
|
||||||
}
|
}
|
||||||
$scope.assignToMe = function() {
|
$scope.assignToMe = function() {
|
||||||
this.claim.id_assignee = $scope.whoami;
|
this.claim.id_assignee = $scope.whoami;
|
||||||
if (this.claim.id)
|
if (this.claim.id)
|
||||||
this.saveClaim(false);
|
this.saveClaim(false);
|
||||||
}
|
}
|
||||||
|
$scope.updateDescription = function(description) {
|
||||||
|
$http({
|
||||||
|
url: "/api/claims/" + $scope.claim.id + "/descriptions",
|
||||||
|
method: "PUT",
|
||||||
|
data: description
|
||||||
|
}).then(function(response) {
|
||||||
|
$scope.claim = Claim.get({ claimId: $routeParams.claimId }, function(v) {
|
||||||
|
v.id_team = "" + v.id_team;
|
||||||
|
if (!v.priority)
|
||||||
|
v.priority = "medium";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
$scope.saveDescription = function() {
|
$scope.saveDescription = function() {
|
||||||
$http({
|
$http({
|
||||||
url: "/api/claims/" + $scope.claim.id,
|
url: "/api/claims/" + $scope.claim.id,
|
||||||
@ -1152,7 +1165,7 @@ angular.module("FICApp")
|
|||||||
$location.url("/claims/" + $scope.claim.id + "/");
|
$location.url("/claims/" + $scope.claim.id + "/");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$scope.saveClaim = function(backToList) {
|
$scope.saveClaim = function(backToList) {
|
||||||
if (this.claim.id_team) {
|
if (this.claim.id_team) {
|
||||||
this.claim.id_team = parseInt(this.claim.id_team, 10);
|
this.claim.id_team = parseInt(this.claim.id_team, 10);
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,6 +62,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-repeat="description in claim.descriptions | orderBy:'id':true" class="alert" ng-class="{'alert-info': '' + description.id_assignee != whoami, 'alert-dark': '' + description.id_assignee == whoami}">
|
<div ng-repeat="description in claim.descriptions | orderBy:'id':true" class="alert" ng-class="{'alert-info': '' + description.id_assignee != whoami, 'alert-dark': '' + description.id_assignee == whoami}">
|
||||||
|
<div class="float-right btn-group-toggle" data-toggle="buttons">
|
||||||
|
<label class="btn btn-sm" ng-class="{'btn-outline-secondary':!description.publish, 'btn-success':description.publish}">
|
||||||
|
<input type="checkbox" ng-model="description.publish" ng-change="updateDescription(description)"><i class="glyphicon" ng-class="{'glyphicon-eye-open':description.publish,'glyphicon-eye-close':!description.publish}"></i>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<strong>Par <span ng-repeat="assignee in assignees" ng-if="assignee.id == description.id_assignee">{{ assignee.name }}</span> le {{ description.date | date:"mediumTime" }} :</strong>
|
<strong>Par <span ng-repeat="assignee in assignees" ng-if="assignee.id == description.id_assignee">{{ assignee.name }}</span> le {{ description.date | date:"mediumTime" }} :</strong>
|
||||||
<span style="white-space: pre-line">{{ description.content }}</span>
|
<span style="white-space: pre-line">{{ description.content }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,6 +96,27 @@ func consumer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate issues.json for a given team
|
||||||
|
func genTeamIssuesFile(team fic.Team) error {
|
||||||
|
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
|
||||||
|
|
||||||
|
if s, err := os.Stat(dirPath); os.IsNotExist(err) {
|
||||||
|
os.MkdirAll(dirPath, 0777)
|
||||||
|
} else if !s.IsDir() {
|
||||||
|
return errors.New(fmt.Sprintf("%s is not a directory", dirPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
if my, err := team.MyIssueFile(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if j, err := json.Marshal(my); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err = ioutil.WriteFile(path.Join(dirPath, "issues.json"), j, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Generate my.json and wait.json for a given team
|
// Generate my.json and wait.json for a given team
|
||||||
func genTeamMyFile(team *fic.Team) error {
|
func genTeamMyFile(team *fic.Team) error {
|
||||||
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
|
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
|
||||||
|
@ -44,7 +44,7 @@ func treatIssue(pathname string, team fic.Team) {
|
|||||||
if claim, err := fic.NewClaim(issue.Subject, &team, exercice, nil, "medium"); err != nil {
|
if claim, err := fic.NewClaim(issue.Subject, &team, exercice, nil, "medium"); err != nil {
|
||||||
log.Printf("%s [ERR] Unable to create new issue: %s\n", id, err)
|
log.Printf("%s [ERR] Unable to create new issue: %s\n", id, err)
|
||||||
} else if len(issue.Description) > 0 {
|
} else if len(issue.Description) > 0 {
|
||||||
if _, err := claim.AddDescription(issue.Description, fic.ClaimAssignee{Id: 0}); err != nil {
|
if _, err := claim.AddDescription(issue.Description, fic.ClaimAssignee{Id: 0}, true); err != nil {
|
||||||
log.Printf("%s [WRN] Unable to add description to issue: %s\n", id, err)
|
log.Printf("%s [WRN] Unable to add description to issue: %s\n", id, err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("%s [OOK] New issue created: id=%d\n", id, claim.Id)
|
log.Printf("%s [OOK] New issue created: id=%d\n", id, claim.Id)
|
||||||
@ -53,5 +53,6 @@ func treatIssue(pathname string, team fic.Team) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
genTeamIssuesFile(team)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,13 @@ server {
|
|||||||
rewrite ^/.* /wait.json;
|
rewrite ^/.* /wait.json;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
location /issues.json {
|
||||||
|
include fic-auth.conf;
|
||||||
|
|
||||||
|
root /srv/TEAMS/$team/;
|
||||||
|
expires epoch;
|
||||||
|
add_header Cache-Control no-cache;
|
||||||
|
}
|
||||||
location = /events.json {
|
location = /events.json {
|
||||||
root /srv/TEAMS/;
|
root /srv/TEAMS/;
|
||||||
expires epoch;
|
expires epoch;
|
||||||
|
@ -133,6 +133,13 @@ server {
|
|||||||
rewrite ^/.* /wait.json;
|
rewrite ^/.* /wait.json;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
location /issues.json {
|
||||||
|
include fic-auth.conf;
|
||||||
|
|
||||||
|
root /srv/TEAMS/$team/;
|
||||||
|
expires epoch;
|
||||||
|
add_header Cache-Control no-cache;
|
||||||
|
}
|
||||||
location = /events.json {
|
location = /events.json {
|
||||||
root /srv/TEAMS/;
|
root /srv/TEAMS/;
|
||||||
expires epoch;
|
expires epoch;
|
||||||
|
@ -390,6 +390,9 @@ files:
|
|||||||
- path: www/htdocs-frontend/views/home.html
|
- path: www/htdocs-frontend/views/home.html
|
||||||
source: frontend/static/views/home.html
|
source: frontend/static/views/home.html
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
|
- path: www/htdocs-frontend/views/issue.html
|
||||||
|
source: frontend/static/views/issue.html
|
||||||
|
mode: "0644"
|
||||||
- path: www/htdocs-frontend/views/rank.html
|
- path: www/htdocs-frontend/views/rank.html
|
||||||
source: frontend/static/views/rank.html
|
source: frontend/static/views/rank.html
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
|
@ -108,6 +108,7 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"])
|
|||||||
$rootScope.current_exercice = 0;
|
$rootScope.current_exercice = 0;
|
||||||
$rootScope.current_tag = undefined;
|
$rootScope.current_tag = undefined;
|
||||||
$rootScope.notify_field = 0;
|
$rootScope.notify_field = 0;
|
||||||
|
$rootScope.issues_known_responses = 0;
|
||||||
|
|
||||||
if ('Notification' in window)
|
if ('Notification' in window)
|
||||||
Notification.requestPermission(function(result) {
|
Notification.requestPermission(function(result) {
|
||||||
@ -219,6 +220,23 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"])
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var refreshIssuesInterval
|
||||||
|
var refreshIssues = function() {
|
||||||
|
if (refreshIssuesInterval)
|
||||||
|
$interval.cancel(refreshIssuesInterval);
|
||||||
|
refreshIssuesInterval = $interval(refreshIssues, Math.floor(Math.random() * 24000) + 32000);
|
||||||
|
|
||||||
|
$http.get("issues.json").then(function(response) {
|
||||||
|
$rootScope.issues_nb_responses = 0;
|
||||||
|
$rootScope.issues_need_info = 0;
|
||||||
|
$rootScope.issues = response.data;
|
||||||
|
$rootScope.issues.forEach(function(issue) {
|
||||||
|
$rootScope.issues_nb_responses += issue.texts.length;
|
||||||
|
if (issue.state == 'need-info') $rootScope.issues_need_info++;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var refreshThemesInterval
|
var refreshThemesInterval
|
||||||
var refreshThemes = function() {
|
var refreshThemes = function() {
|
||||||
if (refreshThemesInterval)
|
if (refreshThemesInterval)
|
||||||
@ -443,6 +461,7 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"])
|
|||||||
refreshThemes();
|
refreshThemes();
|
||||||
$rootScope.refreshTeams();
|
$rootScope.refreshTeams();
|
||||||
refreshEvents();
|
refreshEvents();
|
||||||
|
refreshIssues();
|
||||||
}
|
}
|
||||||
else if (justSettings) {
|
else if (justSettings) {
|
||||||
refreshSettings();
|
refreshSettings();
|
||||||
@ -647,6 +666,7 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"])
|
|||||||
.controller("IssueController", function($scope, $http, $rootScope, $routeParams) {
|
.controller("IssueController", function($scope, $http, $rootScope, $routeParams) {
|
||||||
$rootScope.current_tag = undefined;
|
$rootScope.current_tag = undefined;
|
||||||
$rootScope.current_exercice = $routeParams.eid;
|
$rootScope.current_exercice = $routeParams.eid;
|
||||||
|
$rootScope.issues_known_responses = $rootScope.issues_nb_responses;
|
||||||
|
|
||||||
$scope.issue = {
|
$scope.issue = {
|
||||||
id_exercice: parseInt($routeParams.eid, 10),
|
id_exercice: parseInt($routeParams.eid, 10),
|
||||||
|
@ -1,3 +1,31 @@
|
|||||||
|
|
||||||
|
<div class="card niceborder border-warning bg-primary text-light" ng-if="issues.length > 0">
|
||||||
|
<table class="table table-hover table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Objet</th>
|
||||||
|
<th>État / Priorité</th>
|
||||||
|
<th>Géré par</th>
|
||||||
|
<th>Messages</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="issue in issues">
|
||||||
|
<td>{{ issue.subject }} <span ng-if="issue.exercice">(challenge {{ issue.exercice }})</span></td>
|
||||||
|
<td>{{ issue.state }} / {{ issue.priority }}</td>
|
||||||
|
<td>{{ issue.assignee }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="row" ng-repeat="text in issue.texts | orderBy:'date':'reverse'">
|
||||||
|
<span ng-if="text.assignee == null || text.assignee == '$team'">Vous</span>
|
||||||
|
<span ng-if="text.assignee != null && text.assignee != '$team'" ng-bind="text.assignee"></span> à {{ text.date | date:"mediumTime" }} :
|
||||||
|
<span style="white-space: pre-line">{{ text.cnt }}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card border-warning mt-3" ng-if="!settings.acceptNewIssue">
|
<div class="card border-warning mt-3" ng-if="!settings.acceptNewIssue">
|
||||||
<div class="card-header bg-warning text-light">Rapporter une anomalie sur un exercice</div>
|
<div class="card-header bg-warning text-light">Rapporter une anomalie sur un exercice</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
@ -412,6 +412,7 @@ CREATE TABLE IF NOT EXISTS claim_descriptions(
|
|||||||
id_assignee INTEGER NOT NULL,
|
id_assignee INTEGER NOT NULL,
|
||||||
date TIMESTAMP NOT NULL,
|
date TIMESTAMP NOT NULL,
|
||||||
content TEXT NOT NULL,
|
content TEXT NOT NULL,
|
||||||
|
publish BOOLEAN NOT NULL DEFAULT 0,
|
||||||
FOREIGN KEY(id_assignee) REFERENCES claim_assignees(id_assignee),
|
FOREIGN KEY(id_assignee) REFERENCES claim_assignees(id_assignee),
|
||||||
FOREIGN KEY(id_claim) REFERENCES claims(id_claim)
|
FOREIGN KEY(id_claim) REFERENCES claims(id_claim)
|
||||||
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||||
|
@ -189,19 +189,21 @@ type ClaimDescription struct {
|
|||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
// Date is the timestamp when the description was written.
|
// Date is the timestamp when the description was written.
|
||||||
Date time.Time `json:"date"`
|
Date time.Time `json:"date"`
|
||||||
|
// Publish indicates wether it is shown back to the team.
|
||||||
|
Publish bool `json:"publish"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDescriptions returns a list of all descriptions stored in the database for the Claim.
|
// GetDescriptions returns a list of all descriptions stored in the database for the Claim.
|
||||||
func (c Claim) GetDescriptions() (res []ClaimDescription, err error) {
|
func (c Claim) GetDescriptions() (res []ClaimDescription, err error) {
|
||||||
var rows *sql.Rows
|
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 {
|
if rows, err = DBQuery("SELECT id_description, id_assignee, content, date, publish FROM claim_descriptions WHERE id_claim = ?", c.Id); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var d ClaimDescription
|
var d ClaimDescription
|
||||||
if err = rows.Scan(&d.Id, &d.IdAssignee, &d.Content, &d.Date); err != nil {
|
if err = rows.Scan(&d.Id, &d.IdAssignee, &d.Content, &d.Date, &d.Publish); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res = append(res, d)
|
res = append(res, d)
|
||||||
@ -212,19 +214,25 @@ func (c Claim) GetDescriptions() (res []ClaimDescription, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddDescription append in the database a new description; then returns the corresponding structure.
|
// AddDescription append in the database a new description; then returns the corresponding structure.
|
||||||
func (c Claim) AddDescription(content string, assignee ClaimAssignee) (ClaimDescription, error) {
|
func (c Claim) AddDescription(content string, assignee ClaimAssignee, publish bool) (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 {
|
if res, err := DBExec("INSERT INTO claim_descriptions (id_claim, id_assignee, content, date, publish) VALUES (?, ?, ?, ?, ?)", c.Id, assignee.Id, content, time.Now(), publish); err != nil {
|
||||||
return ClaimDescription{}, err
|
return ClaimDescription{}, err
|
||||||
} else if did, err := res.LastInsertId(); err != nil {
|
} else if did, err := res.LastInsertId(); err != nil {
|
||||||
return ClaimDescription{}, err
|
return ClaimDescription{}, err
|
||||||
} else {
|
} else {
|
||||||
return ClaimDescription{did, assignee.Id, content, time.Now()}, nil
|
return ClaimDescription{did, assignee.Id, content, time.Now(), publish}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAssignee retrieves an assignee from its identifier.
|
||||||
|
func (d ClaimDescription) GetAssignee() (a ClaimAssignee, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_assignee, name FROM claim_assignees WHERE id_assignee = ?", d.IdAssignee).Scan(&a.Id, &a.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Update applies modifications back to the database
|
// Update applies modifications back to the database
|
||||||
func (d ClaimDescription) Update() (int64, error) {
|
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 {
|
if res, err := DBExec("UPDATE claim_descriptions SET id_assignee = ?, content = ?, date = ?, publish = ? WHERE id_description = ?", d.IdAssignee, d.Content, d.Date, d.Publish, d.Id); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else if nb, err := res.RowsAffected(); err != nil {
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@ -335,3 +343,67 @@ func (c Claim) GetAssignee() (*ClaimAssignee, error) {
|
|||||||
func (c Claim) SetAssignee(a ClaimAssignee) {
|
func (c Claim) SetAssignee(a ClaimAssignee) {
|
||||||
c.IdAssignee = &a.Id
|
c.IdAssignee = &a.Id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type teamIssueText struct {
|
||||||
|
Content string `json:"cnt"`
|
||||||
|
Assignee string `json:"assignee"`
|
||||||
|
Date time.Time `json:"date"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type teamIssueFile struct {
|
||||||
|
Subject string `json:"subject"`
|
||||||
|
Exercice *string `json:"exercice,omitempty"`
|
||||||
|
Assignee *string `json:"assignee,omitempty"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Priority string `json:"priority"`
|
||||||
|
Texts []teamIssueText `json:"texts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Team) MyIssueFile() (ret []teamIssueFile, err error) {
|
||||||
|
var claims []Claim
|
||||||
|
if claims, err = t.GetClaims(); err == nil {
|
||||||
|
for _, claim := range claims {
|
||||||
|
var exercice *string = nil
|
||||||
|
|
||||||
|
if exo, err := claim.GetExercice(); err == nil && exo != nil {
|
||||||
|
exercice = &exo.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
var assignee *string = nil
|
||||||
|
if a, err := claim.GetAssignee(); err == nil && a != nil {
|
||||||
|
assignee = &a.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if descriptions, err := claim.GetDescriptions(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
tif := teamIssueFile{
|
||||||
|
Subject: claim.Subject,
|
||||||
|
Exercice: exercice,
|
||||||
|
Assignee: assignee,
|
||||||
|
State: claim.State,
|
||||||
|
Priority: claim.Priority,
|
||||||
|
Texts: []teamIssueText{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, description := range descriptions {
|
||||||
|
if description.Publish {
|
||||||
|
if people, err := description.GetAssignee(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
tif.Texts = append(tif.Texts, teamIssueText{
|
||||||
|
Content: description.Content,
|
||||||
|
Assignee: people.Name,
|
||||||
|
Date: description.Date,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(ret, tif)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user