qa: Add todo list on home page
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
a237936feb
commit
42d594ccac
11
libfic/db.go
11
libfic/db.go
@ -446,6 +446,17 @@ CREATE TABLE IF NOT EXISTS qa_comments(
|
|||||||
FOREIGN KEY(id_qa) REFERENCES exercices_qa(id_qa),
|
FOREIGN KEY(id_qa) REFERENCES exercices_qa(id_qa),
|
||||||
FOREIGN KEY(id_team) REFERENCES teams(id_team)
|
FOREIGN KEY(id_team) REFERENCES teams(id_team)
|
||||||
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS teams_qa_todo(
|
||||||
|
id_todo INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
id_team INTEGER NOT NULL,
|
||||||
|
id_exercice INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice),
|
||||||
|
FOREIGN KEY(id_team) REFERENCES teams(id_team)
|
||||||
|
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||||
`); err != nil {
|
`); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
55
libfic/qa.go
55
libfic/qa.go
@ -64,6 +64,26 @@ func (e Exercice) GetQAQueries() (res []QAQuery, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetQAQueries returns a list of all QAQuery registered for the Exercice.
|
||||||
|
func (t Team) GetQAQueries() (res []QAQuery, err error) {
|
||||||
|
var rows *sql.Rows
|
||||||
|
if rows, err = DBQuery("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_team = ?", t.Id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var q QAQuery
|
||||||
|
if err = rows.Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res = append(res, q)
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// GetQAQuery retrieves the query with the given identifier.
|
// GetQAQuery retrieves the query with the given identifier.
|
||||||
func (e Exercice) GetQAQuery(id int64) (q QAQuery, err error) {
|
func (e Exercice) GetQAQuery(id int64) (q QAQuery, err error) {
|
||||||
err = DBQueryRow("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_qa = ? AND id_exercice = ?", id, e.Id).Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed)
|
err = DBQueryRow("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_qa = ? AND id_exercice = ?", id, e.Id).Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed)
|
||||||
@ -181,3 +201,38 @@ func (c QAComment) Delete() (int64, error) {
|
|||||||
return nb, err
|
return nb, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type QATodo struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdTeam int64 `json:"id_team,omitempty"`
|
||||||
|
IdExercice int64 `json:"id_exercice"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Team) GetQATodo() (res []QATodo, err error) {
|
||||||
|
var rows *sql.Rows
|
||||||
|
if rows, err = DBQuery("SELECT id_todo, id_exercice FROM teams_qa_todo WHERE id_team = ?", t.Id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var t QATodo
|
||||||
|
if err = rows.Scan(&t.Id, &t.IdExercice); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res = append(res, t)
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Team) NewQATodo(idExercice int64) (QATodo, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO teams_qa_todo (id_team, id_exercice) VALUES (?, ?)", t.Id, idExercice); err != nil {
|
||||||
|
return QATodo{}, err
|
||||||
|
} else if tid, err := res.LastInsertId(); err != nil {
|
||||||
|
return QATodo{}, err
|
||||||
|
} else {
|
||||||
|
return QATodo{tid, t.Id, idExercice}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
49
qa/api/todo.go
Normal file
49
qa/api/todo.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.GET("/api/qa_mywork.json", apiHandler(getQAWork))
|
||||||
|
router.GET("/api/qa_work.json", apiHandler(getQATodo))
|
||||||
|
router.POST("/api/qa_work.json", apiHandler(createQATodo))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getQAWork(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
|
||||||
|
if team, err := fic.GetTeam(u.TeamId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return team.GetQAQueries()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getQATodo(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
|
||||||
|
if team, err := fic.GetTeam(u.TeamId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return team.GetQATodo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createQATodo(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
|
||||||
|
if u.User != "nemunaire" {
|
||||||
|
return nil, errors.New("Restricted")
|
||||||
|
}
|
||||||
|
|
||||||
|
var ut fic.QATodo
|
||||||
|
if err := json.Unmarshal(body, &ut); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if team, err := fic.GetTeam(ut.IdTeam); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return team.NewQATodo(ut.IdExercice)
|
||||||
|
}
|
||||||
|
}
|
@ -90,6 +90,12 @@ angular.module("FICApp")
|
|||||||
.factory("Version", function($resource) {
|
.factory("Version", function($resource) {
|
||||||
return $resource("/api/version")
|
return $resource("/api/version")
|
||||||
})
|
})
|
||||||
|
.factory("Todo", function($resource) {
|
||||||
|
return $resource("/api/qa_work.json")
|
||||||
|
})
|
||||||
|
.factory("TodoWorked", function($resource) {
|
||||||
|
return $resource("/api/qa_mywork.json")
|
||||||
|
})
|
||||||
.factory("Team", function($resource) {
|
.factory("Team", function($resource) {
|
||||||
return $resource("/api/teams/:teamId", { teamId: '@id' }, {
|
return $resource("/api/teams/:teamId", { teamId: '@id' }, {
|
||||||
'update': {method: 'PUT'},
|
'update': {method: 'PUT'},
|
||||||
@ -216,6 +222,20 @@ angular.module("FICApp")
|
|||||||
$scope.v = Version.get();
|
$scope.v = Version.get();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.controller("ToDoController", function($scope, Todo, TodoWorked, $location) {
|
||||||
|
$scope.todos = Todo.query();
|
||||||
|
$scope.tododone = {}
|
||||||
|
$scope.work = TodoWorked.query(function(tw) {
|
||||||
|
tw.forEach(function(t) {
|
||||||
|
$scope.tododone[t.id_exercice] = t
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.show = function(id) {
|
||||||
|
$location.url("/exercices/" + id);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
.controller("ThemesListController", function($scope, Theme, $location, $rootScope, $http) {
|
.controller("ThemesListController", function($scope, Theme, $location, $rootScope, $http) {
|
||||||
$scope.themes = Theme.query();
|
$scope.themes = Theme.query();
|
||||||
$scope.fields = ["name", "authors", "headline"];
|
$scope.fields = ["name", "authors", "headline"];
|
||||||
@ -286,6 +306,13 @@ angular.module("FICApp")
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.controller("MyTodoExerciceController", function($scope, Exercice, ExerciceQA, Theme) {
|
||||||
|
$scope.mytheme = null
|
||||||
|
$scope.myexercice = Exercice.get({ exerciceId: $scope.todo.id_exercice }, function(e) {
|
||||||
|
$scope.mytheme = Theme.get({ themeId: e.id_theme })
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
.controller("ExerciceController", function($scope, $rootScope, Exercice, ThemedExercice, $routeParams, $location, $http) {
|
.controller("ExerciceController", function($scope, $rootScope, Exercice, ThemedExercice, $routeParams, $location, $http) {
|
||||||
if ($routeParams.themeId && $routeParams.exerciceId == "new") {
|
if ($routeParams.themeId && $routeParams.exerciceId == "new") {
|
||||||
$scope.exercice = new ThemedExercice();
|
$scope.exercice = new ThemedExercice();
|
||||||
|
@ -1,7 +1,23 @@
|
|||||||
<div class="jumbotron text-light bg-dark">
|
<div class="jumbotron text-light bg-dark">
|
||||||
<h1 class="display-5">Interface QA du challenge</h1>
|
<h1 class="display-5">Interface QA du challenge</h1>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col" ng-controller="ToDoController">
|
||||||
|
<table class="table table-stripped">
|
||||||
|
<tr ng-repeat="todo in todos" ng-controller="MyTodoExerciceController" ng-class="{'bg-warning': !tododone[todo.id_exercice], 'bg-success': tododone[todo.id_exercice]}" ng-click="show(todo.id_exercice)">
|
||||||
|
<td ng-if="!tododone[todo.id_exercice]">
|
||||||
|
À tester
|
||||||
|
</td>
|
||||||
|
<td ng-if="tododone[todo.id_exercice]">
|
||||||
|
Testé
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ mytheme.name }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ myexercice.title }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user