From 706e7861903ce06efc1407938a5d2092c82d0c0d Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sun, 5 Mar 2023 13:17:25 +0100 Subject: [PATCH] New route to delete grades --- grades.go | 16 ++++++++++++ ui/src/lib/grades.js | 31 ++++++++++++++++++++++ ui/src/lib/works.js | 4 ++- ui/src/routes/works/[wid]/+page.svelte | 36 +++++++++++++++++++++++--- works.go | 25 ++++++++++++++++++ 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 ui/src/lib/grades.js diff --git a/grades.go b/grades.go index 33818e1..891ba21 100644 --- a/grades.go +++ b/grades.go @@ -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 diff --git a/ui/src/lib/grades.js b/ui/src/lib/grades.js new file mode 100644 index 0000000..ec1548f --- /dev/null +++ b/ui/src/lib/grades.js @@ -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); + } + } + } +} diff --git a/ui/src/lib/works.js b/ui/src/lib/works.js index df100d8..9d83b98 100644 --- a/ui/src/lib/works.js +++ b/ui/src/lib/works.js @@ -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); } diff --git a/ui/src/routes/works/[wid]/+page.svelte b/ui/src/routes/works/[wid]/+page.svelte index de2915c..ab20d25 100644 --- a/ui/src/routes/works/[wid]/+page.svelte +++ b/ui/src/routes/works/[wid]/+page.svelte @@ -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; + }); + } {#if $user && $user.is_admin} @@ -46,17 +62,20 @@

Notes

- {#await w.getGrades()} -
+ {#await gradesP} +
Chargement des notes …
{:then grades} - +
- + @@ -75,6 +94,15 @@ + {/each} {/if} diff --git a/works.go b/works.go index c3c1268..6049adb 100644 --- a/works.go +++ b/works.go @@ -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
LoginNote + Note + {#if mean > 0}(moyenne : {Math.round(mean*100)/100}){/if} + Commentaire Date de la note
{grade.score} {#if grade.comment}{grade.comment}{:else}-{/if} {grade.date} + +