This repository has been archived on 2024-03-28. You can view files and clone it, but cannot push or open issues or pull requests.
atsebay.t/responses.go

383 lines
13 KiB
Go
Raw Normal View History

2020-03-04 11:07:12 +00:00
package main
import (
2022-09-01 15:15:37 +00:00
"database/sql"
"errors"
2022-07-09 17:42:00 +00:00
"log"
2022-03-28 08:53:45 +00:00
"net/http"
2020-03-04 11:07:12 +00:00
"strconv"
2020-09-13 14:37:30 +00:00
"time"
2020-03-04 11:07:12 +00:00
2022-07-09 17:42:00 +00:00
"github.com/gin-gonic/gin"
2020-03-04 11:07:12 +00:00
)
2022-07-09 17:42:00 +00:00
func declareAPIAuthResponsesRoutes(router *gin.RouterGroup) {
router.POST("", func(c *gin.Context) {
s := c.MustGet("survey").(*Survey)
uauth := c.MustGet("LoggedUser").(*User)
var u *User
if user, ok := c.Get("user"); ok {
if !uauth.IsAdmin {
2022-07-09 17:42:00 +00:00
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not authorized"})
return
}
u = user.(*User)
} else {
u = uauth
}
2020-03-04 11:07:12 +00:00
var responses []Response
2022-07-09 17:42:00 +00:00
if err := c.ShouldBindJSON(&responses); err != nil {
2022-07-09 17:42:00 +00:00
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
2020-03-04 11:07:12 +00:00
}
// Check the survey is open
2022-07-09 17:42:00 +00:00
if !uauth.IsAdmin {
now := time.Now()
if now.Before(s.StartAvailability) {
c.AbortWithStatusJSON(http.StatusPaymentRequired, gin.H{"errmsg": "Le questionnaire n'a pas encore commencé"})
return
} else if now.After(s.EndAvailability.Add(5 * time.Minute)) {
c.AbortWithStatusJSON(http.StatusPaymentRequired, gin.H{"errmsg": "Le questionnaire n'est plus ouvert"})
return
}
}
2020-03-04 11:07:12 +00:00
for _, response := range responses {
2022-09-02 10:00:21 +00:00
if !uauth.IsAdmin && (!s.Shown || s.Corrected || (s.Direct != nil && *s.Direct != response.IdQuestion)) {
2022-07-09 17:42:00 +00:00
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Cette question n'est pas disponible"})
return
2022-02-28 18:00:30 +00:00
} else if len(response.Answer) > 0 {
2022-03-15 00:39:10 +00:00
// Check if the response has changed
if response.Id != 0 {
if res, err := s.GetResponse(int(response.Id)); err == nil {
if res.IdUser == u.Id && res.Answer == response.Answer {
continue
}
}
}
2020-03-08 00:06:44 +00:00
if _, err := s.NewResponse(response.IdQuestion, u.Id, response.Answer); err != nil {
2022-07-09 17:42:00 +00:00
log.Printf("Unable to NewResponse(uid=%d;sid=%d;qid=%d): %s", u.Id, s.Id, response.IdQuestion, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Une erreur s'est produite durant l'enregistrement des réponses. Veuillez réessayer dans quelques instants."})
return
2020-03-08 00:06:44 +00:00
}
2022-02-28 18:00:30 +00:00
if s.Direct != nil {
s.WSAdminWriteAll(WSMessage{Action: "new_response", UserId: &u.Id, QuestionId: &response.IdQuestion, Response: response.Answer})
}
2020-03-04 11:07:12 +00:00
}
}
2022-07-09 17:42:00 +00:00
c.JSON(http.StatusOK, true)
})
router.GET("/responses", func(c *gin.Context) {
u := c.MustGet("LoggedUser").(*User)
s := c.MustGet("survey").(*Survey)
2022-07-09 17:42:00 +00:00
if user, ok := c.Get("user"); ok {
if !u.IsAdmin {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not authorized"})
return
}
2022-03-15 00:39:10 +00:00
2022-07-09 17:42:00 +00:00
u = user.(*User)
}
2022-07-09 17:42:00 +00:00
responses, err := s.GetMyResponses(u, s.Corrected)
if err != nil {
log.Printf("Unable to GetMyResponses(uid=%d;sid=%d): %s", u.Id, s.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Une erreur s'est produite pendant la récupération des réponses."})
return
}
2022-03-28 08:53:45 +00:00
2022-07-09 17:42:00 +00:00
c.JSON(http.StatusOK, responses)
})
responsesRoutes := router.Group("/responses/:rid")
responsesRoutes.Use(responseHandler)
responsesRoutes.GET("", func(c *gin.Context) {
c.JSON(http.StatusOK, c.MustGet("response"))
})
responsesRoutes.POST("/report", func(c *gin.Context) {
s := c.MustGet("survey").(*Survey)
r := c.MustGet("response").(*Response)
u := c.MustGet("LoggedUser").(*User)
if user, ok := c.Get("user"); ok {
if !u.IsAdmin {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not authorized"})
return
2022-03-28 08:53:45 +00:00
}
2022-07-09 17:42:00 +00:00
u = user.(*User)
2020-03-04 11:07:12 +00:00
}
2022-07-09 17:42:00 +00:00
if s == nil || !s.Corrected || r.IdUser != u.Id {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Cette action est impossible pour l'instant"})
return
}
if r.TimeScored == nil || r.TimeReported == nil || r.TimeReported.Before(*r.TimeScored) {
2020-03-08 00:06:44 +00:00
now := time.Now()
2022-07-09 17:42:00 +00:00
r.TimeReported = &now
} else {
r.TimeReported = nil
}
if _, err := r.Update(); err != nil {
log.Printf("Unable to Update(uid=%d;rid=%d) response: %s", u.Id, r.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Une erreur s'est produite lors de la mise à jour du statut de la réponse. Veuillez réessayer dans quelques instants."})
return
2020-03-08 00:06:44 +00:00
}
2022-07-09 17:42:00 +00:00
c.JSON(http.StatusOK, r)
})
}
func declareAPIAuthQuestionResponsesRoutes(router *gin.RouterGroup) {
router.GET("/response", func(c *gin.Context) {
u := c.MustGet("LoggedUser").(*User)
q := c.MustGet("question").(*Question)
res, err := q.GetMyResponse(u, false)
2022-09-01 15:15:37 +00:00
if err != nil && !errors.Is(err, sql.ErrNoRows) {
2022-07-09 17:42:00 +00:00
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
}
c.JSON(http.StatusOK, res)
})
}
func declareAPIAdminResponsesRoutes(router *gin.RouterGroup) {
router.GET("/responses", func(c *gin.Context) {
q := c.MustGet("question").(*Question)
res, err := q.GetResponses()
if err != nil {
log.Printf("Unable to GetResponses(qid=%d): %s", q.Id, err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during responses retrieval."})
return
}
c.JSON(http.StatusOK, res)
})
responsesRoutes := router.Group("/responses/:rid")
responsesRoutes.Use(responseHandler)
responsesRoutes.PUT("", func(c *gin.Context) {
u := c.MustGet("LoggedUser").(*User)
current := c.MustGet("response").(*Response)
2022-02-28 09:52:27 +00:00
var new Response
2022-07-09 17:42:00 +00:00
if err := c.ShouldBindJSON(&new); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
2022-02-28 09:52:27 +00:00
}
if new.Score != nil && (current.Score == nil || *new.Score != *current.Score) {
now := time.Now()
new.IdCorrector = &u.Id
new.TimeScored = &now
2022-07-09 17:42:00 +00:00
// Remove from cache
if _, ok := _score_cache[current.IdUser]; ok {
if surveyId, err := current.GetSurveyId(); err == nil {
if _, ok = _score_cache[current.IdUser][surveyId]; ok {
delete(_score_cache[current.IdUser], surveyId)
}
}
}
2022-02-28 09:52:27 +00:00
}
2020-03-04 11:07:12 +00:00
new.Id = current.Id
new.IdUser = current.IdUser
2022-07-09 17:42:00 +00:00
response, err := new.Update()
if err != nil {
log.Println("Unable to Update response:", err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during response updating."})
return
}
c.JSON(http.StatusOK, response)
})
2022-03-28 08:53:45 +00:00
}
2022-07-09 17:42:00 +00:00
func responseHandler(c *gin.Context) {
var survey *Survey
2020-03-04 11:07:12 +00:00
2022-07-09 17:42:00 +00:00
if s, ok := c.Get("survey"); ok {
survey = s.(*Survey)
}
2020-03-04 11:07:12 +00:00
2022-07-09 17:42:00 +00:00
var response *Response
if rid, err := strconv.Atoi(string(c.Param("rid"))); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Bad response identifier."})
return
} else if survey == nil {
if response, err = getResponse(rid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Response not found."})
return
2020-03-04 11:07:12 +00:00
}
2022-07-09 17:42:00 +00:00
} else if response, err = survey.GetResponse(rid); err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Response not found."})
return
2020-03-04 11:07:12 +00:00
}
2022-07-09 17:42:00 +00:00
c.Set("response", response)
2022-03-28 08:53:45 +00:00
2022-07-09 17:42:00 +00:00
c.Next()
2020-03-04 11:07:12 +00:00
}
type Response struct {
2020-03-08 00:06:44 +00:00
Id int64 `json:"id"`
IdQuestion int64 `json:"id_question"`
IdUser int64 `json:"id_user"`
Answer string `json:"value"`
TimeSubmit time.Time `json:"time_submit"`
Score *int64 `json:"score,omitempty"`
ScoreExplaination *string `json:"score_explaination,omitempty"`
IdCorrector *int64 `json:"id_corrector,omitempty"`
TimeScored *time.Time `json:"time_scored,omitempty"`
2022-03-28 08:53:45 +00:00
TimeReported *time.Time `json:"time_reported,omitempty"`
2020-03-04 11:07:12 +00:00
}
2022-07-09 17:42:00 +00:00
func (s *Survey) GetResponses() (responses []*Response, err error) {
2022-03-28 08:53:45 +00:00
if rows, errr := DBQuery("SELECT R.id_response, R.id_question, R.id_user, R.answer, R.time_submit, R.score, R.score_explanation, R.id_corrector, R.time_scored, R.time_reported FROM survey_responses R INNER JOIN survey_quests Q ON Q.id_question = R.id_question WHERE Q.id_survey=?", s.Id); errr != nil {
2020-03-04 11:07:12 +00:00
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var r Response
2022-03-28 08:53:45 +00:00
if err = rows.Scan(&r.Id, &r.IdQuestion, &r.IdUser, &r.Answer, &r.TimeSubmit, &r.Score, &r.ScoreExplaination, &r.IdCorrector, &r.TimeScored, &r.TimeReported); err != nil {
2020-03-04 11:07:12 +00:00
return
}
2022-07-09 17:42:00 +00:00
responses = append(responses, &r)
2020-03-04 11:07:12 +00:00
}
if err = rows.Err(); err != nil {
return
}
return
}
}
2022-07-09 17:42:00 +00:00
func (s *Survey) GetMyResponses(u *User, showScore bool) (responses []*Response, err error) {
2022-03-28 08:53:45 +00:00
if rows, errr := DBQuery("SELECT R.id_response, R.id_question, R.id_user, R.answer, R.time_submit, R.score, R.score_explanation, R.id_corrector, R.time_scored, R.time_reported FROM survey_responses R INNER JOIN survey_quests Q ON Q.id_question = R.id_question WHERE Q.id_survey=? AND R.id_user=? ORDER BY time_submit DESC", s.Id, u.Id); errr != nil {
2020-03-04 11:07:12 +00:00
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var r Response
2022-03-28 08:53:45 +00:00
if err = rows.Scan(&r.Id, &r.IdQuestion, &r.IdUser, &r.Answer, &r.TimeSubmit, &r.Score, &r.ScoreExplaination, &r.IdCorrector, &r.TimeScored, &r.TimeReported); err != nil {
2020-03-08 00:06:44 +00:00
return
}
if !showScore {
r.Score = nil
r.ScoreExplaination = nil
}
2022-07-09 17:42:00 +00:00
responses = append(responses, &r)
2020-03-08 00:06:44 +00:00
}
if err = rows.Err(); err != nil {
return
}
return
}
}
2022-07-09 17:42:00 +00:00
func (q *Question) GetMyResponse(u *User, showScore bool) (r *Response, err error) {
r = new(Response)
2022-03-28 08:53:45 +00:00
err = DBQueryRow("SELECT R.id_response, R.id_question, R.id_user, R.answer, R.time_submit, R.score, R.score_explanation, R.id_corrector, R.time_scored, R.time_reported FROM survey_responses R WHERE R.id_question=? AND R.id_user=? ORDER BY time_submit DESC LIMIT 1", q.Id, u.Id).Scan(&r.Id, &r.IdQuestion, &r.IdUser, &r.Answer, &r.TimeSubmit, &r.Score, &r.ScoreExplaination, &r.IdCorrector, &r.TimeScored, &r.TimeReported)
2022-03-01 12:03:16 +00:00
if !showScore {
r.Score = nil
r.ScoreExplaination = nil
}
return
}
2022-07-09 17:42:00 +00:00
func (q *Question) GetResponses() (responses []*Response, err error) {
2022-03-28 08:53:45 +00:00
if rows, errr := DBQuery("SELECT id_response, id_question, S.id_user, answer, S.time_submit, score, score_explanation, id_corrector, time_scored, time_reported FROM (SELECT id_user, MAX(time_submit) AS time_submit FROM survey_responses WHERE id_question=? GROUP BY id_user) R INNER JOIN survey_responses S ON S.id_user = R.id_user AND S.time_submit = R.time_submit AND S.id_question=?", q.Id, q.Id); errr != nil {
2020-03-08 00:06:44 +00:00
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var r Response
2022-03-28 08:53:45 +00:00
if err = rows.Scan(&r.Id, &r.IdQuestion, &r.IdUser, &r.Answer, &r.TimeSubmit, &r.Score, &r.ScoreExplaination, &r.IdCorrector, &r.TimeScored, &r.TimeReported); err != nil {
2020-03-04 11:07:12 +00:00
return
}
2022-07-09 17:42:00 +00:00
responses = append(responses, &r)
2020-03-04 11:07:12 +00:00
}
if err = rows.Err(); err != nil {
return
}
return
}
}
2022-07-09 17:42:00 +00:00
func getResponse(id int) (r *Response, err error) {
r = new(Response)
2022-03-28 08:53:45 +00:00
err = DBQueryRow("SELECT id_response, id_question, id_user, answer, time_submit, score, score_explanation, id_corrector, time_scored, time_reported FROM survey_responses WHERE id_response=?", id).Scan(&r.Id, &r.IdQuestion, &r.IdUser, &r.Answer, &r.TimeSubmit, &r.Score, &r.ScoreExplaination, &r.IdCorrector, &r.TimeScored, &r.TimeReported)
2020-03-04 11:07:12 +00:00
return
}
2022-07-09 17:42:00 +00:00
func (s *Survey) GetResponse(id int) (r *Response, err error) {
r = new(Response)
2022-03-28 08:53:45 +00:00
err = DBQueryRow("SELECT R.id_response, R.id_question, R.id_user, R.answer, R.time_submit, R.score, R.score_explanation, R.id_corrector, R.time_scored, R.time_reported FROM survey_responses R INNER JOIN survey_quests Q ON Q.id_question = R.id_question WHERE R.id_response=? AND Q.id_survey=?", id, s.Id).Scan(&r.Id, &r.IdQuestion, &r.IdUser, &r.Answer, &r.TimeSubmit, &r.Score, &r.ScoreExplaination, &r.IdCorrector, &r.TimeScored, &r.TimeReported)
2020-03-04 11:07:12 +00:00
return
}
2022-07-09 17:42:00 +00:00
func (s *Survey) NewResponse(id_question int64, id_user int64, response string) (*Response, error) {
2020-03-04 11:07:12 +00:00
if res, err := DBExec("INSERT INTO survey_responses (id_question, id_user, answer, time_submit) VALUES (?, ?, ?, ?)", id_question, id_user, response, time.Now()); err != nil {
2022-07-09 17:42:00 +00:00
return nil, err
2020-03-04 11:07:12 +00:00
} else if rid, err := res.LastInsertId(); err != nil {
2022-07-09 17:42:00 +00:00
return nil, err
2020-03-04 11:07:12 +00:00
} else {
2022-07-09 17:42:00 +00:00
return &Response{rid, id_question, id_user, response, time.Now(), nil, nil, nil, nil, nil}, nil
2020-03-04 11:07:12 +00:00
}
}
func (r *Response) GetSurveyId() (int64, error) {
if q, err := getQuestion(int(r.IdQuestion)); err != nil {
return 0, err
} else {
return q.IdSurvey, err
}
}
2020-03-04 11:07:12 +00:00
func (r Response) Update() (Response, error) {
2022-03-28 08:53:45 +00:00
_, err := DBExec("UPDATE survey_responses SET id_question = ?, id_user = ?, answer = ?, time_submit = ?, score = ?, score_explanation = ?, id_corrector = ?, time_scored = ?, time_reported = ? WHERE id_response = ?", r.IdQuestion, r.IdUser, r.Answer, r.TimeSubmit, r.Score, r.ScoreExplaination, r.IdCorrector, r.TimeScored, r.TimeReported, r.Id)
2020-03-04 11:07:12 +00:00
return r, err
}
func (r Response) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM survey_responses WHERE id_response = ?", r.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func ClearResponses() (int64, error) {
if res, err := DBExec("DELETE FROM survey_responses"); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}