diff --git a/backend/issue.go b/backend/issue.go index c04cb564..01d07e51 100644 --- a/backend/issue.go +++ b/backend/issue.go @@ -13,6 +13,7 @@ import ( ) type IssueUpload struct { + Id int64 `json:"id"` IdExercice int64 `json:"id_exercice"` Subject string `json:"subject"` Description string `json:"description"` @@ -32,9 +33,35 @@ func treatIssue(pathname string, team fic.Team) { } else if err := json.Unmarshal(cnt_raw, &issue); err != nil { log.Printf("%s [ERR] %s\n", id, err) } else if len(issue.Subject) == 0 && len(issue.Description) == 0 { + if err = os.Remove(pathname); err != nil { + log.Printf("%s [ERR] %s\n", id, err) + } log.Printf("%s Empty issue: not treated.\n", id) } else if len(issue.Subject) == 0 { - log.Printf("%s Issue with no subject: not treated.\n", id) + if issue.Id <= 0 { + if err = os.Remove(pathname); err != nil { + log.Printf("%s [ERR] %s\n", id, err) + } + log.Printf("%s Issue with no subject: not treated.\n", id) + } else if claim, err := team.GetClaim(issue.Id); err != nil { + log.Printf("%s [ERR] Team id=%d,name=%q tries to access issue id=%d, but not granted: %s.\n", id, team.Id, team.Name, issue.Id, err) + } else if len(issue.Description) == 0 { + if err = os.Remove(pathname); err != nil { + log.Printf("%s [ERR] %s\n", id, err) + } + log.Printf("%s Empty issue: not treated.\n", id) + } else if desc, 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) + } else { + claim.State = "new" + claim.Update() + + log.Printf("%s [OOK] New comment added to issue id=%d: id_description=%s\n", id, claim.Id, desc.Id) + if err = os.Remove(pathname); err != nil { + log.Printf("%s [ERR] %s\n", id, err) + } + genTeamIssuesFile(team) + } } else { var exercice *fic.Exercice = nil if e, err := fic.GetExercice(issue.IdExercice); err == nil { diff --git a/configs/nginx-demo.conf b/configs/nginx-demo.conf index a66995d9..cfd45ce5 100644 --- a/configs/nginx-demo.conf +++ b/configs/nginx-demo.conf @@ -91,6 +91,11 @@ server { rewrite ^/.*$ /index.html; } + location /issues { + include fic-auth.conf; + + rewrite ^/.*$ /index.html; + } location /rank { include fic-auth.conf; diff --git a/configs/nginx-prod.conf b/configs/nginx-prod.conf index bc1591d0..9f5be5bc 100644 --- a/configs/nginx-prod.conf +++ b/configs/nginx-prod.conf @@ -83,6 +83,11 @@ server { rewrite ^/.*$ /index.html; } + location /issues { + include fic-auth.conf; + + rewrite ^/.*$ /index.html; + } location /rank { include fic-auth.conf; diff --git a/frontend/settings.go b/frontend/settings.go index c1b4adda..b5c2a743 100644 --- a/frontend/settings.go +++ b/frontend/settings.go @@ -75,5 +75,6 @@ func reloadSettings(config settings.FICSettings) { enableResolutionRoute = config.EnableResolutionRoute denyNameChange = config.DenyNameChange + acceptNewIssues = config.AcceptNewIssue allowRegistration = config.AllowRegistration } diff --git a/frontend/static/index.html b/frontend/static/index.html index c5f14d16..2c5fd3bd 100644 --- a/frontend/static/index.html +++ b/frontend/static/index.html @@ -103,7 +103,7 @@ Classement diff --git a/frontend/static/js/challenge.js b/frontend/static/js/challenge.js index 0b80d6d3..fad7eee9 100644 --- a/frontend/static/js/challenge.js +++ b/frontend/static/js/challenge.js @@ -57,11 +57,15 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) controller: "MyTeamController", templateUrl: "views/team-edit.html" }) - .when("/issue", { + .when("/issue/:eid", { controller: "IssueController", templateUrl: "views/issue.html" }) - .when("/issue/:eid", { + .when("/issues", { + controller: "IssueController", + templateUrl: "views/issue.html" + }) + .when("/issues/:iid", { controller: "IssueController", templateUrl: "views/issue.html" }) @@ -227,10 +231,12 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) refreshIssuesInterval = $interval(refreshIssues, Math.floor(Math.random() * 24000) + 32000); $http.get("issues.json").then(function(response) { + $rootScope.issues_idx = {}; $rootScope.issues_nb_responses = 0; $rootScope.issues_need_info = 0; $rootScope.issues = response.data; $rootScope.issues.forEach(function(issue) { + $rootScope.issues_idx[issue.id] = issue; $rootScope.issues_nb_responses += issue.texts.length; if (issue.state == 'need-info') $rootScope.issues_need_info++; }) @@ -468,6 +474,7 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) } refreshMy(); } + $rootScope.refreshIssues = refreshIssues; $rootScope.refresh(); }) .controller("ExerciceController", function($scope, $routeParams, $http, $rootScope, $timeout) { @@ -669,6 +676,7 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) $rootScope.issues_known_responses = $rootScope.issues_nb_responses; $scope.issue = { + id: parseInt($routeParams.iid, 10), id_exercice: parseInt($routeParams.eid, 10), subject: "", description: "", @@ -676,9 +684,9 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) $scope.isubmit = function() { $rootScope.sberr = ""; - if ($scope.issue.subject.length < 3) { + if (!$scope.issue.id && $scope.issue.subject.length < 3) { $rootScope.messageClass = {"text-danger": true}; - $rootScope.sberr = "L'object de votre rapport d'anomalie est trop court !"; + $rootScope.sberr = "L'objet de votre rapport d'anomalie est trop court !"; return false; } @@ -691,6 +699,7 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) $rootScope.message = response.data.errmsg; $scope.issue.subject = ""; $scope.issue.description = ""; + setTimeout($rootScope.refreshIssues, 1750); }, function(response) { $rootScope.messageClass = {"text-danger": true}; $rootScope.message = response.data.errmsg; diff --git a/frontend/static/views/issue.html b/frontend/static/views/issue.html index 7a379093..a7bb9647 100644 --- a/frontend/static/views/issue.html +++ b/frontend/static/views/issue.html @@ -15,11 +15,14 @@ {{ issue.state }} / {{ issue.priority }} {{ issue.assignee }} -
+

Vous -  à {{ text.date | date:"mediumTime" }} :  +  à {{ text.date | date:"mediumTime" }} : {{ text.cnt }} -

+

+ + + @@ -33,8 +36,9 @@ -
-
Rapporter une anomalie sur un exercice
+
+
Rapporter une anomalie sur un exercice
+
Répondre à un rapport d'anomalie

Votre rapport a bien été envoyé !{{ sberr }} {{ message }}

@@ -49,7 +53,14 @@
-
+
+ +
+ +
+
+ +
diff --git a/libfic/todo.go b/libfic/todo.go index 7322a25d..0ea147ca 100644 --- a/libfic/todo.go +++ b/libfic/todo.go @@ -2,6 +2,7 @@ package fic import ( "database/sql" + "path" "time" ) @@ -43,6 +44,12 @@ func GetClaims() (res []Claim, err error) { return } +// GetClaim retrieves the claim with the given identifier and registered for the given Team. +func (t Team) GetClaim(id int64) (c Claim, err error) { + err = DBQueryRow("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_claim = ? AND id_team = ?", id, t.Id).Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority) + return +} + // GetClaims returns a list of all Claim registered for the Team. func (t Team) GetClaims() (res []Claim, err error) { var rows *sql.Rows @@ -357,8 +364,10 @@ type teamIssueText struct { } type teamIssueFile struct { + Id int64 `json:"id"` Subject string `json:"subject"` Exercice *string `json:"exercice,omitempty"` + ExerciceURL string `json:"url,omitempty"` Assignee *string `json:"assignee,omitempty"` State string `json:"state"` Priority string `json:"priority"` @@ -370,9 +379,13 @@ func (t Team) MyIssueFile() (ret []teamIssueFile, err error) { if claims, err = t.GetClaims(); err == nil { for _, claim := range claims { var exercice *string = nil + var url string if exo, err := claim.GetExercice(); err == nil && exo != nil { exercice = &exo.Title + if theme, err := GetTheme(exo.IdTheme); err == nil { + url = path.Join(theme.URLId, exo.URLId) + } } var assignee *string = nil @@ -384,8 +397,10 @@ func (t Team) MyIssueFile() (ret []teamIssueFile, err error) { return nil, err } else { tif := teamIssueFile{ + Id: claim.Id, Subject: claim.Subject, Exercice: exercice, + ExerciceURL: url, Assignee: assignee, State: claim.State, Priority: claim.Priority,