Gradation: add route to add missing users
This commit is contained in:
parent
107b17c11f
commit
3397b9f123
@ -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) {
|
async getSubmission(uid) {
|
||||||
const res = await fetch(uid?`api/users/${uid}/works/${this.id}/submission`:`api/works/${this.id}/submission`, {
|
const res = await fetch(uid?`api/users/${uid}/works/${this.id}/submission`:`api/works/${this.id}/submission`, {
|
||||||
headers: {'Accept': 'application/json'}
|
headers: {'Accept': 'application/json'}
|
||||||
|
@ -40,6 +40,11 @@
|
|||||||
stats.mean = sum / grades.length;
|
stats.mean = sum / grades.length;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function addMissingStudents(w) {
|
||||||
|
await w.addMissingGrades();
|
||||||
|
refresh_grades(w);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $user && $user.is_admin}
|
{#if $user && $user.is_admin}
|
||||||
@ -72,13 +77,23 @@
|
|||||||
{#if stats.mean > 0}(moyenne : {Math.round(stats.mean*100)/100}, min : {stats.min}, max : {stats.max}){/if}
|
{#if stats.mean > 0}(moyenne : {Math.round(stats.mean*100)/100}, min : {stats.min}, max : {stats.max}){/if}
|
||||||
</small>
|
</small>
|
||||||
</h3>
|
</h3>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="btn btn-outline-info"
|
||||||
|
title="Ajouter les étudiants manquant"
|
||||||
|
on:click={() => addMissingStudents(w)}
|
||||||
|
>
|
||||||
|
<i class="bi bi-people"></i>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-light"
|
class="btn btn-light"
|
||||||
|
title="Rafraîchir l'affichage des notes"
|
||||||
on:click={() => refresh_grades(w)}
|
on:click={() => refresh_grades(w)}
|
||||||
>
|
>
|
||||||
<i class="bi bi-arrow-clockwise"></i>
|
<i class="bi bi-arrow-clockwise"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="card mt-3 mb-5">
|
<div class="card mt-3 mb-5">
|
||||||
{#await gradesP}
|
{#await gradesP}
|
||||||
<div class="text-center mb-5">
|
<div class="text-center mb-5">
|
||||||
|
28
users.go
28
users.go
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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) {
|
func getPromos() (promos []uint, err error) {
|
||||||
if rows, errr := DBQuery("SELECT DISTINCT promo FROM users ORDER BY promo DESC"); errr != nil {
|
if rows, errr := DBQuery("SELECT DISTINCT promo FROM users ORDER BY promo DESC"); errr != nil {
|
||||||
return nil, errr
|
return nil, errr
|
||||||
|
43
works.go
43
works.go
@ -179,6 +179,49 @@ func declareAPIAdminWorksRoutes(router *gin.RouterGroup) {
|
|||||||
|
|
||||||
c.JSON(http.StatusOK, grades)
|
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) {
|
worksRoutes.PUT("/grades", func(c *gin.Context) {
|
||||||
w := c.MustGet("work").(*Work)
|
w := c.MustGet("work").(*Work)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user