diff --git a/direct.go b/direct.go index 02eb44e..a239512 100644 --- a/direct.go +++ b/direct.go @@ -98,9 +98,16 @@ func msgCurrentState(survey *Survey) (msg WSMessage) { Action: "pause", } } else { + var correction map[string]int + if survey.Corrected { + correction = getCorrectionString(*survey.Direct) + } + msg = WSMessage{ - Action: "new_question", - QuestionId: survey.Direct, + Action: "new_question", + QuestionId: survey.Direct, + Corrected: survey.Corrected, + Corrections: correction, } } return @@ -146,13 +153,15 @@ func WSWriteAll(message WSMessage) { } type WSMessage struct { - Action string `json:"action"` - SurveyId *int64 `json:"survey,omitempty"` - QuestionId *int64 `json:"question,omitempty"` - Stats map[string]interface{} `json:"stats,omitempty"` - UserId *int64 `json:"user,omitempty"` - Response string `json:"value,omitempty"` - Timer uint `json:"timer,omitempty"` + Action string `json:"action"` + SurveyId *int64 `json:"survey,omitempty"` + QuestionId *int64 `json:"question,omitempty"` + Stats map[string]interface{} `json:"stats,omitempty"` + UserId *int64 `json:"user,omitempty"` + Response string `json:"value,omitempty"` + Corrected bool `json:"corrected,omitempty"` + Corrections map[string]int `json:"corrections,omitempty"` + Timer uint `json:"timer,omitempty"` } func (s *Survey) WSWriteAll(message WSMessage) { @@ -229,6 +238,25 @@ loopadmin: log.Println(u.Login, "admin disconnected") } +func getCorrectionString(qid int64) (ret map[string]int) { + q, err := getQuestion(int(qid)) + if err != nil { + return + } + + cts, err := q.GetCorrectionTemplates() + if err != nil { + return + } + + ret = map[string]int{} + for _, ct := range cts { + ret[ct.RegExp] = ct.Score + } + + return +} + func SurveyWSAdmin(c *gin.Context) { u := c.MustGet("LoggedUser").(*User) survey := c.MustGet("survey").(*Survey) @@ -274,15 +302,29 @@ func SurveyWSAdmin(c *gin.Context) { if *survey.Direct != 0 { var z int64 = 0 survey.Direct = &z + survey.Corrected = false survey.Update() } - go func() { + go func(corrected bool) { time.Sleep(time.Duration(OffsetQuestionTimer+v.Timer) * time.Millisecond) - survey.WSWriteAll(WSMessage{Action: "pause"}) - WSAdminWriteAll(WSMessage{Action: "pause", SurveyId: &survey.Id}) - }() + + if corrected { + survey.Corrected = v.Corrected + survey.Update() + + survey.WSWriteAll(WSMessage{Action: "new_question", QuestionId: v.QuestionId, Corrected: true, Corrections: getCorrectionString(*v.QuestionId)}) + } else { + survey.WSWriteAll(WSMessage{Action: "pause"}) + WSAdminWriteAll(WSMessage{Action: "pause", SurveyId: &survey.Id}) + } + }(v.Corrected) + v.Corrected = false } else { survey.Direct = v.QuestionId + survey.Corrected = v.Corrected + if v.Corrected { + v.Corrections = getCorrectionString(*v.QuestionId) + } } _, err = survey.Update() if err != nil { diff --git a/help.go b/help.go index 53e85ca..181ae7e 100644 --- a/help.go +++ b/help.go @@ -1,8 +1,10 @@ package main import ( + "fmt" "log" "net/http" + "strconv" "time" "github.com/gin-gonic/gin" @@ -10,7 +12,7 @@ import ( func declareAPIAdminHelpRoutes(router *gin.RouterGroup) { router.GET("/help", func(c *gin.Context) { - nhs, err := getNeedHelps() + nhs, err := getNeedHelps("WHERE date_treated IS NULL") if err != nil { log.Println("Unable to getNeedHelps:", err) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during need helps retrieval. Please retry."}) @@ -19,6 +21,29 @@ func declareAPIAdminHelpRoutes(router *gin.RouterGroup) { c.JSON(http.StatusOK, nhs) }) + + needhelpsRoutes := router.Group("/help/:hid") + needhelpsRoutes.Use(needHelpHandler) + + needhelpsRoutes.PUT("", func(c *gin.Context) { + current := c.MustGet("needhelp").(*NeedHelp) + + var new NeedHelp + if err := c.ShouldBindJSON(&new); err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) + return + } + + new.Id = current.Id + + if err := new.Update(); err != nil { + log.Println("Unable to Update needhelp:", err) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("An error occurs during needhelp entry updation: %s", err.Error())}) + return + } else { + c.JSON(http.StatusOK, new) + } + }) } func declareAPIAuthHelpRoutes(router *gin.RouterGroup) { @@ -36,6 +61,19 @@ func declareAPIAuthHelpRoutes(router *gin.RouterGroup) { }) } +func needHelpHandler(c *gin.Context) { + if hid, err := strconv.Atoi(string(c.Param("hid"))); err != nil { + c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad need help identifier."}) + return + } else if nh, err := getNeedHelp(hid); err != nil { + c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Need help entry not found."}) + return + } else { + c.Set("needhelp", nh) + c.Next() + } +} + type NeedHelp struct { Id int64 `json:"id"` IdUser int64 `json:"id_user"` @@ -44,8 +82,8 @@ type NeedHelp struct { DateTreated *time.Time `json:"treated,omitempty"` } -func getNeedHelps() (nh []NeedHelp, err error) { - if rows, errr := DBQuery("SELECT id_need_help, id_user, date, comment, date_treated FROM user_need_help"); errr != nil { +func getNeedHelps(cond string) (nh []NeedHelp, err error) { + if rows, errr := DBQuery("SELECT id_need_help, id_user, date, comment, date_treated FROM user_need_help " + cond); errr != nil { return nil, errr } else { defer rows.Close() @@ -65,6 +103,12 @@ func getNeedHelps() (nh []NeedHelp, err error) { } } +func getNeedHelp(id int) (n *NeedHelp, err error) { + n = new(NeedHelp) + err = DBQueryRow("SELECT id_need_help, id_user, date, comment, date_treated FROM user_need_help WHERE id_need_help=?", id).Scan(&n.Id, &n.IdUser, &n.Date, &n.Comment, &n.DateTreated) + return +} + func (u *User) NewNeedHelp() (NeedHelp, error) { if res, err := DBExec("INSERT INTO user_need_help (id_user, comment) VALUES (?, ?)", u.Id, ""); err != nil { return NeedHelp{}, err diff --git a/responses.go b/responses.go index 4db50bb..9e0e809 100644 --- a/responses.go +++ b/responses.go @@ -1,6 +1,8 @@ package main import ( + "database/sql" + "errors" "log" "net/http" "strconv" @@ -27,7 +29,7 @@ func declareAPIAuthResponsesRoutes(router *gin.RouterGroup) { } var responses []Response - if err := c.ShouldBindJSON(responses); err != nil { + if err := c.ShouldBindJSON(&responses); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } @@ -45,7 +47,7 @@ func declareAPIAuthResponsesRoutes(router *gin.RouterGroup) { } for _, response := range responses { - if !uauth.IsAdmin && !s.Shown && (s.Direct == nil || *s.Direct != response.IdQuestion) { + if !uauth.IsAdmin && !s.Shown && (s.Corrected || s.Direct == nil || *s.Direct != response.IdQuestion) { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Cette question n'est pas disponible"}) return } else if len(response.Answer) > 0 { @@ -142,7 +144,7 @@ func declareAPIAuthQuestionResponsesRoutes(router *gin.RouterGroup) { q := c.MustGet("question").(*Question) res, err := q.GetMyResponse(u, false) - if err != nil { + if err != nil && !errors.Is(err, sql.ErrNoRows) { log.Printf("Unable to GetMyResponse(uid=%d;qid=%d;false): %s", u.Id, q.Id, err.Error()) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during response retrieval."}) return diff --git a/ui/src/components/CorrectionPieChart.svelte b/ui/src/components/CorrectionPieChart.svelte index f203a23..2a1eed3 100644 --- a/ui/src/components/CorrectionPieChart.svelte +++ b/ui/src/components/CorrectionPieChart.svelte @@ -31,34 +31,41 @@ return req; } let req_proposals = null; + export let proposals = null; let req_responses = null; + let mean = null; - if (question.kind == "int") { - req_responses = question.getResponses(); - req_responses.then((responses) => { - const proposal_idx = { }; - for (const res of responses) { - if (proposal_idx[res.value]) { - data.datasets[0].values[proposal_idx[res.value]] += 1; - } else { - data.labels.push(res.value); - data.datasets[0].values.push(1); - proposal_idx[res.value] = new String(data.labels.length - 1); - } - } - }); - } else { - req_proposals = refreshProposals(); - } - - let data = { + export let data = { labels: [], datasets: [ { values: [] } ] - }; + }; + + if (!proposals) { + if (question.kind == "int") { + req_responses = question.getResponses(); + req_responses.then((responses) => { + const values = []; + const proposal_idx = { }; + for (const res of responses) { + if (proposal_idx[res.value]) { + data.datasets[0].values[proposal_idx[res.value]] += 1; + values.push(Number(res.value)); + } else { + data.labels.push(res.value); + data.datasets[0].values.push(1); + proposal_idx[res.value] = new String(data.labels.length - 1); + } + } + mean = Math.trunc(values.reduce((p, e) => p + e) / values.length*10)/10; + }); + } else { + req_proposals = refreshProposals(); + } + }
Demande d'aide :
- {#await getUserNeedingHelp()} + {#await users_needing_help} {:then nhs}