diff --git a/admin/api/exercice.go b/admin/api/exercice.go index 30b7aff6..d7c7ebd6 100644 --- a/admin/api/exercice.go +++ b/admin/api/exercice.go @@ -22,6 +22,7 @@ func init() { router.PATCH("/api/exercices/:eid", apiHandler(exerciceHandler(partUpdateExercice))) router.DELETE("/api/exercices/:eid", apiHandler(exerciceHandler(deleteExercice))) + router.GET("/api/exercices/:eid/stats", apiHandler(exerciceHandler(getExerciceStats))) router.GET("/api/exercices/:eid/history.json", apiHandler(exerciceHandler(getExerciceHistory))) router.DELETE("/api/exercices/:eid/history.json", apiHandler(exerciceHandler(delExerciceHistory))) @@ -136,6 +137,15 @@ func showExercice(exercice fic.Exercice, body []byte) (interface{}, error) { return exercice, nil } +func getExerciceStats(exercice fic.Exercice, body []byte) (interface{}, error) { + team_tries, tries := exercice.TriesByTeam() + return map[string]interface{}{ + "solved": exercice.SolvedTeams(), + "total_tried": tries, + "team_tries": team_tries, + }, nil +} + func getExerciceHistory(exercice fic.Exercice, body []byte) (interface{}, error) { return exercice.GetHistory() } diff --git a/admin/static/js/app.js b/admin/static/js/app.js index ebf32265..e5bea0ab 100644 --- a/admin/static/js/app.js +++ b/admin/static/js/app.js @@ -1197,6 +1197,12 @@ angular.module("FICApp") } else { $scope.exercice = Exercice.get({ exerciceId: $routeParams.exerciceId }); } + $http({ + url: "/api/exercices/" + $routeParams.exerciceId + "/stats", + method: "GET" + }).then(function(response) { + $scope.stats = response.data; + }); $http({ url: "/api/themes.json", method: "GET" diff --git a/libfic/exercice.go b/libfic/exercice.go index ea2a3795..efce52b1 100644 --- a/libfic/exercice.go +++ b/libfic/exercice.go @@ -330,6 +330,21 @@ func (e Exercice) SolvedCount() int64 { } } +// SolvedTeams returns the list of Team that already have solved the challenge. +func (e Exercice) SolvedTeams() (teams []int64) { + if rows, err := DBQuery("SELECT id_team FROM exercice_solved WHERE id_exercice = ?", e.Id); err == nil { + defer rows.Close() + + for rows.Next() { + var tid int64 + if err := rows.Scan(&tid); err == nil { + teams = append(teams, tid) + } + } + } + return +} + // TriedTeamCount returns the number of Team that attempted to solve the exercice. func (e Exercice) TriedTeamCount() int64 { tries_table := "exercice_tries" @@ -345,6 +360,32 @@ func (e Exercice) TriedTeamCount() int64 { } } +type TbT struct { + IdTeam int64 `json:"id_team"` + Tries int64 `json:"tries"` +} + +// TriesByTeam returns the number of tries by Team. +func (e Exercice) TriesByTeam() (ts []TbT, sum int64) { + tries_table := "exercice_tries" + if SubmissionUniqueness { + tries_table = "exercice_distinct_tries" + } + + if rows, err := DBQuery("SELECT id_team, COUNT(id_team) FROM " + tries_table + " WHERE id_exercice = ? GROUP BY id_team", e.Id); err == nil { + defer rows.Close() + + for rows.Next() { + var tbt TbT + if err := rows.Scan(&tbt.IdTeam, &tbt.Tries); err == nil { + sum += tbt.Tries + ts = append(ts, tbt) + } + } + } + return +} + // TriedCount returns the number of cumulative attempts, all Team combined, for the exercice. func (e Exercice) TriedCount() int64 { tries_table := "exercice_tries"