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 {
2022-10-20 15:53:33 +00:00
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
}
2021-11-19 20:41:01 +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
}
2021-11-19 20:41:01 +00:00
}
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 )
2020-11-28 17:59:14 +00:00
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 )
}
2020-11-28 17:59:14 +00:00
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-03-15 01:31:43 +00:00
2022-07-09 17:42:00 +00:00
// Remove from cache
2022-03-15 01:31:43 +00:00
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
}
}
2022-03-15 01:31:43 +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
}
}