New route to delete grades

This commit is contained in:
nemunaire 2023-03-05 13:17:25 +01:00
parent 6f9b83ef24
commit 706e786190
5 changed files with 107 additions and 5 deletions

View File

@ -3,6 +3,7 @@ package main
import (
"log"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
)
@ -65,6 +66,21 @@ func declareAPIAuthGradesRoutes(router *gin.RouterGroup) {
})
}
func gradeHandler(c *gin.Context) {
work := c.MustGet("work").(*Work)
if gid, err := strconv.Atoi(string(c.Param("gid"))); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad grade identifier."})
return
} else if grade, err := work.GetGrade(int64(gid)); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Grade not found."})
return
} else {
c.Set("grade", grade)
c.Next()
}
}
func GetAllGrades() (scores map[int64]map[int64]*float64, err error) {
if rows, errr := DBQuery("SELECT id_user, id_survey, SUM(score)/COUNT(*) FROM student_scores GROUP BY id_user, id_survey"); errr != nil {
return nil, errr

31
ui/src/lib/grades.js Normal file
View File

@ -0,0 +1,31 @@
export class Grade {
constructor(res) {
if (res) {
this.update(res);
}
}
update({ id, login, id_user, id_work, date, score, comment }) {
this.id = id;
this.login = login;
this.id_user = id_user;
this.id_work = id_work;
this.date = date;
this.score = score;
this.comment = comment;
}
async delete() {
if (this.id) {
const res = await fetch(`api/works/${this.id_work}/grades/${this.id}`, {
method: 'DELETE',
headers: {'Accept': 'application/json'},
});
if (res.status == 200) {
return true;
} else {
throw new Error((await res.json()).errmsg);
}
}
}
}

View File

@ -1,3 +1,5 @@
import { Grade } from '$lib/grades';
export class Work {
constructor(res) {
this.kind = "w";
@ -110,7 +112,7 @@ export class Work {
headers: {'Accept': 'application/json'},
});
if (res.status == 200) {
return await res.json();
return (await res.json()).map((g) => new Grade(g));
} else {
throw new Error((await res.json()).errmsg);
}

View File

@ -14,13 +14,29 @@
let my_submission = null;
let warn_already_used = false;
let w = null;
let gradesP = null;
let mean = 0;
$: w = data.work;
$: refresh_submission(data.work);
$: refresh_grades(data.work);
function refresh_submission(w) {
my_submission = w.getSubmission();
}
function refresh_grades(w) {
gradesP = w.getGrades();
gradesP.then((grades) => {
if (grades.length <= 0) return;
let sum = 0;
for (const grade of grades) {
sum += grade.score;
}
mean = sum / grades.length;
});
}
</script>
{#if $user && $user.is_admin}
@ -46,17 +62,20 @@
<hr>
<h3 class="mt-3">Notes</h3>
<div class="card mt-3 mb-5">
{#await w.getGrades()}
<div class="text-center">
{#await gradesP}
<div class="text-center mb-5">
<div class="spinner-border text-primary mx-3" role="status"></div>
<span>Chargement des notes &hellip;</span>
</div>
{:then grades}
<table class="table table-hover table-striped mb-0">
<table class="table table-hover table-striped table-sm mb-0">
<thead>
<tr>
<th>Login</th>
<th>Note</th>
<th>
Note
{#if mean > 0}(moyenne&nbsp;: {Math.round(mean*100)/100}){/if}
</th>
<th>Commentaire</th>
<th>Date de la note</th>
</tr>
@ -75,6 +94,15 @@
<td>{grade.score}</td>
<td>{#if grade.comment}{grade.comment}{:else}-{/if}</td>
<td>{grade.date}</td>
<td>
<button
class="btn btn-sm btn-danger mx-1"
title="Supprimer la note"
on:click={() => { grade.delete(); refresh_grades(w); }}
>
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
{/each}
{/if}

View File

@ -192,6 +192,15 @@ func declareAPIAdminWorksRoutes(router *gin.RouterGroup) {
c.JSON(http.StatusOK, true)
})
gradesRoutes := worksRoutes.Group("/grades/:gid")
gradesRoutes.Use(gradeHandler)
gradesRoutes.DELETE("", func(c *gin.Context) {
g := c.MustGet("grade").(*WorkGrade)
g.Delete()
c.JSON(http.StatusOK, true)
})
}
func declareAPIAuthWorksRoutes(router *gin.RouterGroup) {
@ -387,6 +396,16 @@ type WorkGrade struct {
Comment string `json:"comment,omitempty"`
}
func (g WorkGrade) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM user_work_grades WHERE id_gradation = ?", g.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func (w *Work) GetGrades(cnd string, param ...interface{}) (grades []WorkGrade, err error) {
param = append([]interface{}{w.Id}, param...)
@ -410,6 +429,12 @@ func (w *Work) GetGrades(cnd string, param ...interface{}) (grades []WorkGrade,
}
}
func (w *Work) GetGrade(id int64) (g *WorkGrade, err error) {
g = new(WorkGrade)
err = DBQueryRow("SELECT G.id_gradation, G.id_user, U.login, G.id_work, G.date, G.grade, G.comment FROM user_work_grades G INNER JOIN users U ON U.id_user = G.id_user WHERE id_work = ? AND id_gradation = ?", w.Id, id).Scan(&g.Id, &g.IdUser, &g.Login, &g.IdWork, &g.Date, &g.Grade, &g.Comment)
return
}
func (u *User) GetMyWorkGrade(w *Work) (g WorkGrade, err error) {
err = DBQueryRow("SELECT id_gradation, id_user, id_work, date, grade, comment FROM user_work_grades WHERE id_work = ? AND id_user = ? ORDER BY date DESC LIMIT 1", w.Id, u.Id).Scan(&g.Id, &g.IdUser, &g.IdWork, &g.Date, &g.Grade, &g.Comment)
return