Gradation: add route to add missing users

This commit is contained in:
nemunaire 2023-03-06 12:53:03 +01:00
parent 107b17c11f
commit 3397b9f123
4 changed files with 104 additions and 6 deletions

View File

@ -109,6 +109,18 @@ export class Work {
}
}
async addMissingGrades() {
const res = await fetch(`api/works/${this.id}/grades`, {
method: 'PATCH',
headers: {'Accept': 'application/json'},
});
if (res.status == 200) {
return (await res.json()).map((g) => new Grade(g));
} else {
throw new Error((await res.json()).errmsg);
}
}
async getSubmission(uid) {
const res = await fetch(uid?`api/users/${uid}/works/${this.id}/submission`:`api/works/${this.id}/submission`, {
headers: {'Accept': 'application/json'}

View File

@ -40,6 +40,11 @@
stats.mean = sum / grades.length;
});
}
async function addMissingStudents(w) {
await w.addMissingGrades();
refresh_grades(w);
}
</script>
{#if $user && $user.is_admin}
@ -72,12 +77,22 @@
{#if stats.mean > 0}(moyenne&nbsp;: {Math.round(stats.mean*100)/100}, min&nbsp;: {stats.min}, max&nbsp;: {stats.max}){/if}
</small>
</h3>
<button
class="btn btn-light"
on:click={() => refresh_grades(w)}
>
<i class="bi bi-arrow-clockwise"></i>
</button>
<div>
<button
class="btn btn-outline-info"
title="Ajouter les étudiants manquant"
on:click={() => addMissingStudents(w)}
>
<i class="bi bi-people"></i>
</button>
<button
class="btn btn-light"
title="Rafraîchir l'affichage des notes"
on:click={() => refresh_grades(w)}
>
<i class="bi bi-arrow-clockwise"></i>
</button>
</div>
</div>
<div class="card mt-3 mb-5">
{#await gradesP}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"log"
"net/http"
"regexp"
"strconv"
"strings"
"time"
@ -169,6 +170,33 @@ func getUsers() (users []User, err error) {
}
}
func getFilteredUsers(promo uint, group string) (users []User, err error) {
// Avoid SQL injection: check group name doesn't contains harmful content
var validGroup = regexp.MustCompile(`^[a-z0-9-]*$`)
if !validGroup.MatchString(group) {
return nil, fmt.Errorf("%q is not a valid group name", group)
}
if rows, errr := DBQuery("SELECT id_user, login, email, firstname, lastname, time, promo, groups, is_admin FROM users WHERE promo = ? AND groups LIKE '%,"+group+",%' ORDER BY promo DESC, id_user DESC", promo); errr != nil {
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var u User
if err = rows.Scan(&u.Id, &u.Login, &u.Email, &u.Firstname, &u.Lastname, &u.Time, &u.Promo, &u.Groups, &u.IsAdmin); err != nil {
return
}
users = append(users, u)
}
if err = rows.Err(); err != nil {
return
}
return
}
}
func getPromos() (promos []uint, err error) {
if rows, errr := DBQuery("SELECT DISTINCT promo FROM users ORDER BY promo DESC"); errr != nil {
return nil, errr

View File

@ -179,6 +179,49 @@ func declareAPIAdminWorksRoutes(router *gin.RouterGroup) {
c.JSON(http.StatusOK, grades)
})
worksRoutes.PATCH("/grades", func(c *gin.Context) {
w := c.MustGet("work").(*Work)
// Fetch existing grades
grades, err := w.GetGrades("")
if err != nil {
log.Printf("Unable to GetGrades(wid=%d): %s", w.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during grades retrieval."})
return
}
// Create an index
known_users := map[int64]bool{}
for _, g := range grades {
known_users[g.IdUser] = true
}
// Fetch students list registered for this course
users, err := getFilteredUsers(w.Promo, w.Group)
if err != nil {
log.Printf("Unable to getFilteredUsers(%d, %s): %s", w.Promo, w.Group, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during users retrieval."})
return
}
var toAdd []WorkGrade
for _, user := range users {
if _, ok := known_users[user.Id]; !ok {
toAdd = append(toAdd, WorkGrade{
IdUser: user.Id,
Login: user.Login,
Grade: 0,
Comment: "- Non rendu -",
})
}
}
if len(toAdd) > 0 {
w.AddGrades(toAdd)
}
c.JSON(http.StatusOK, toAdd)
})
worksRoutes.PUT("/grades", func(c *gin.Context) {
w := c.MustGet("work").(*Work)