2020-03-04 11:07:12 +00:00
package main
import (
2021-03-01 16:47:00 +00:00
"fmt"
2022-07-09 17:42:00 +00:00
"log"
2020-03-04 11:07:12 +00:00
"net/http"
"strconv"
2022-02-21 07:53:27 +00:00
"strings"
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-02-28 16:45:30 +00:00
var (
_score_cache = map [ int64 ] map [ int64 ] * float64 { }
)
2022-07-09 17:42:00 +00:00
func declareAPISurveysRoutes ( router * gin . RouterGroup ) {
router . GET ( "/surveys" , func ( c * gin . Context ) {
u := c . MustGet ( "LoggedUser" ) . ( * User )
2022-02-21 07:53:27 +00:00
2022-07-09 17:42:00 +00:00
var response [ ] * Survey
var err error
if u == nil {
response , err = getSurveys ( fmt . Sprintf ( "WHERE (shown = TRUE OR direct IS NOT NULL) AND NOW() > start_availability AND promo = %d ORDER BY start_availability ASC" , currentPromo ) )
} else if u . IsAdmin {
response , err = getSurveys ( "ORDER BY promo DESC, start_availability ASC" )
} else {
var surveys [ ] * Survey
surveys , err = getSurveys ( fmt . Sprintf ( "WHERE (shown = TRUE OR direct IS NOT NULL) AND promo = %d ORDER BY start_availability ASC" , u . Promo ) )
if err == nil {
2022-02-21 07:53:27 +00:00
for _ , s := range surveys {
if s . Group == "" || strings . Contains ( u . Groups , "," + s . Group + "," ) {
2022-07-09 18:52:22 +00:00
s . Group = ""
2022-02-21 07:53:27 +00:00
response = append ( response , s )
}
}
2022-07-09 17:42:00 +00:00
}
}
if err != nil {
c . AbortWithStatusJSON ( http . StatusBadRequest , gin . H { "errmsg" : "Impossible de lister les questionnaires. Veuillez réessayer dans quelques instants" } )
log . Printf ( "Unable to list surveys: %s" , err . Error ( ) )
} else {
c . JSON ( http . StatusOK , response )
}
} )
surveysRoutes := router . Group ( "/surveys/:sid" )
surveysRoutes . Use ( surveyHandler )
surveysRoutes . GET ( "" , func ( c * gin . Context ) {
u := c . MustGet ( "LoggedUser" ) . ( * User )
if u == nil {
c . AbortWithStatusJSON ( http . StatusUnauthorized , gin . H { "errmsg" : "Veuillez vous connecter pour accéder à cette page." } )
return
}
s := c . MustGet ( "survey" ) . ( * Survey )
if ( s . Promo == u . Promo && ( s . Group == "" || strings . Contains ( u . Groups , "," + s . Group + "," ) && s . Shown ) ) || u . IsAdmin {
c . JSON ( http . StatusOK , s )
} else {
c . AbortWithStatusJSON ( http . StatusForbidden , gin . H { "errmsg" : "Not accessible" } )
}
} )
}
func declareAPIAuthSurveysRoutes ( router * gin . RouterGroup ) {
surveysRoutes := router . Group ( "/surveys/:sid" )
surveysRoutes . Use ( surveyHandler )
surveysRoutes . GET ( "/score" , func ( c * gin . Context ) {
var u * User
if user , ok := c . Get ( "user" ) ; ok {
u = user . ( * User )
} else {
u = c . MustGet ( "LoggedUser" ) . ( * User )
}
s := c . MustGet ( "survey" ) . ( * Survey )
if ( s . Promo == u . Promo && s . Shown ) || ( u != nil && u . IsAdmin ) {
score , err := s . GetScore ( u )
if err != nil {
log . Printf ( "Unable to GetScore(uid=%d;sid=%d): %s" , u . Id , s . Id , err . Error ( ) )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : "An error occurs when trying to retrieve score." } )
return
}
2022-02-21 07:53:27 +00:00
2022-07-09 17:42:00 +00:00
if score == nil {
c . JSON ( http . StatusOK , map [ string ] string { "score" : "N/A" } )
} else {
c . JSON ( http . StatusOK , map [ string ] float64 { "score" : * score } )
2020-03-04 11:07:12 +00:00
}
2022-07-09 17:42:00 +00:00
} else {
c . AbortWithStatusJSON ( http . StatusForbidden , gin . H { "errmsg" : "Not accessible" } )
return
}
} )
declareAPIAuthAsksRoutes ( surveysRoutes )
declareAPIAuthDirectRoutes ( surveysRoutes )
declareAPIAuthGradesRoutes ( surveysRoutes )
declareAPIAuthQuestionsRoutes ( surveysRoutes )
declareAPIAuthResponsesRoutes ( surveysRoutes )
}
func declareAPIAdminSurveysRoutes ( router * gin . RouterGroup ) {
router . POST ( "/surveys" , func ( c * gin . Context ) {
2020-03-04 11:07:12 +00:00
var new Survey
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
2020-03-04 11:07:12 +00:00
}
2021-03-01 16:47:00 +00:00
if new . Promo == 0 {
new . Promo = currentPromo
}
2022-07-09 17:42:00 +00:00
if s , err := NewSurvey ( new . Title , new . Promo , new . Group , new . Shown , new . Direct , new . StartAvailability , new . EndAvailability ) ; err != nil {
log . Println ( "Unable to NewSurvey:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : fmt . Sprintf ( "An error occurs during survey creation: %s" , err . Error ( ) ) } )
return
} else {
c . JSON ( http . StatusOK , s )
}
} )
surveysRoutes := router . Group ( "/surveys/:sid" )
surveysRoutes . Use ( surveyHandler )
surveysRoutes . PUT ( "" , func ( c * gin . Context ) {
current := c . MustGet ( "survey" ) . ( * Survey )
2020-03-04 11:07:12 +00:00
var new Survey
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
2020-03-04 11:07:12 +00:00
}
new . Id = current . Id
2022-02-28 18:00:30 +00:00
if new . Direct != current . Direct {
if new . Direct == nil {
current . WSCloseAll ( "" )
} else if * new . Direct == 0 {
current . WSWriteAll ( WSMessage {
Action : "pause" ,
} )
} else {
current . WSWriteAll ( WSMessage {
Action : "new_question" ,
QuestionId : new . Direct ,
} )
}
}
2022-07-09 17:42:00 +00:00
if survey , err := new . Update ( ) ; err != nil {
log . Println ( "Unable to Update survey:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : fmt . Sprintf ( "An error occurs during survey updation: %s" , err . Error ( ) ) } )
return
2020-03-04 11:07:12 +00:00
} else {
2022-07-09 17:42:00 +00:00
c . JSON ( http . StatusOK , survey )
2020-03-04 11:07:12 +00:00
}
2022-07-09 17:42:00 +00:00
} )
surveysRoutes . DELETE ( "" , func ( c * gin . Context ) {
survey := c . MustGet ( "survey" ) . ( * Survey )
2020-03-04 11:07:12 +00:00
2022-07-09 17:42:00 +00:00
if _ , err := survey . Delete ( ) ; err != nil {
log . Println ( "Unable to Delete survey:" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "errmsg" : fmt . Sprintf ( "An error occurs during survey deletion: %s" , err . Error ( ) ) } )
return
2020-03-04 11:07:12 +00:00
} else {
2022-07-09 17:42:00 +00:00
c . JSON ( http . StatusOK , nil )
2020-03-04 11:07:12 +00:00
}
2022-07-09 17:42:00 +00:00
} )
declareAPIAdminAsksRoutes ( surveysRoutes )
declareAPIAdminDirectRoutes ( surveysRoutes )
declareAPIAdminQuestionsRoutes ( surveysRoutes )
}
func surveyHandler ( c * gin . Context ) {
if sid , err := strconv . Atoi ( string ( c . Param ( "sid" ) ) ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusBadRequest , gin . H { "errmsg" : "Bad survey identifier." } )
return
} else if survey , err := getSurvey ( sid ) ; err != nil {
c . AbortWithStatusJSON ( http . StatusNotFound , gin . H { "errmsg" : "Survey not found." } )
return
} else {
c . Set ( "survey" , survey )
c . Next ( )
2020-03-04 11:07:12 +00:00
}
}
type Survey struct {
Id int64 ` json:"id" `
Title string ` json:"title" `
2021-03-01 16:47:00 +00:00
Promo uint ` json:"promo" `
2022-02-21 07:53:27 +00:00
Group string ` json:"group" `
2020-03-04 11:07:12 +00:00
Shown bool ` json:"shown" `
2022-02-28 18:00:30 +00:00
Direct * int64 ` json:"direct" `
2020-03-08 00:06:44 +00:00
Corrected bool ` json:"corrected" `
2020-03-04 11:07:12 +00:00
StartAvailability time . Time ` json:"start_availability" `
EndAvailability time . Time ` json:"end_availability" `
}
2022-07-09 17:42:00 +00:00
func getSurveys ( cnd string , param ... interface { } ) ( surveys [ ] * Survey , err error ) {
2022-02-28 18:00:30 +00:00
if rows , errr := DBQuery ( "SELECT id_survey, title, promo, grp, shown, direct, corrected, start_availability, end_availability FROM surveys " + cnd , param ... ) ; errr != nil {
2020-03-04 11:07:12 +00:00
return nil , errr
} else {
defer rows . Close ( )
for rows . Next ( ) {
var s Survey
2022-02-28 18:00:30 +00:00
if err = rows . Scan ( & s . Id , & s . Title , & s . Promo , & s . Group , & s . Shown , & s . Direct , & s . Corrected , & s . StartAvailability , & s . EndAvailability ) ; err != nil {
2020-03-04 11:07:12 +00:00
return
}
2022-07-09 17:42:00 +00:00
surveys = append ( surveys , & s )
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 getSurvey ( id int ) ( s * Survey , err error ) {
s = new ( Survey )
2022-02-28 18:00:30 +00:00
err = DBQueryRow ( "SELECT id_survey, title, promo, grp, shown, direct, corrected, start_availability, end_availability FROM surveys WHERE id_survey=?" , id ) . Scan ( & s . Id , & s . Title , & s . Promo , & s . Group , & s . Shown , & s . Direct , & s . Corrected , & s . StartAvailability , & s . EndAvailability )
2020-03-04 11:07:12 +00:00
return
}
2022-02-28 18:00:30 +00:00
func NewSurvey ( title string , promo uint , group string , shown bool , direct * int64 , startAvailability time . Time , endAvailability time . Time ) ( * Survey , error ) {
if res , err := DBExec ( "INSERT INTO surveys (title, promo, grp, shown, direct, start_availability, end_availability) VALUES (?, ?, ?, ?, ?, ?, ?)" , title , promo , group , shown , direct , startAvailability , endAvailability ) ; err != nil {
2022-02-21 06:13:39 +00:00
return nil , err
2020-03-04 11:07:12 +00:00
} else if sid , err := res . LastInsertId ( ) ; err != nil {
2022-02-21 06:13:39 +00:00
return nil , err
2020-03-04 11:07:12 +00:00
} else {
2022-02-28 18:00:30 +00:00
return & Survey { sid , title , promo , group , shown , direct , false , startAvailability , endAvailability } , nil
2020-03-04 11:07:12 +00:00
}
}
2020-09-13 14:37:30 +00:00
func ( s Survey ) GetScore ( u * User ) ( score * float64 , err error ) {
2022-02-28 16:45:30 +00:00
if _ , ok := _score_cache [ u . Id ] ; ! ok {
_score_cache [ u . Id ] = map [ int64 ] * float64 { }
}
if v , ok := _score_cache [ u . Id ] [ s . Id ] ; ok {
score = v
} else {
err = DBQueryRow ( "SELECT SUM(score)/COUNT(*) FROM student_scores WHERE id_survey=? AND id_user=?" , s . Id , u . Id ) . Scan ( & score )
if score != nil {
* score = * score / 5.0
}
_score_cache [ u . Id ] [ s . Id ] = score
2020-09-13 14:37:30 +00:00
}
2020-11-20 14:46:52 +00:00
return
}
2020-09-13 14:37:30 +00:00
2020-11-20 14:46:52 +00:00
func ( s Survey ) GetScores ( ) ( scores map [ int64 ] * float64 , err error ) {
if rows , errr := DBQuery ( "SELECT id_user, SUM(score)/COUNT(*) FROM student_scores WHERE id_survey=? GROUP BY id_user" , s . Id ) ; err != nil {
return nil , errr
} else {
defer rows . Close ( )
2020-09-13 14:37:30 +00:00
2020-11-20 14:46:52 +00:00
scores = map [ int64 ] * float64 { }
for rows . Next ( ) {
var id_user int64
var score * float64
if err = rows . Scan ( & id_user , & score ) ; err != nil {
return
}
scores [ id_user ] = score
}
if err = rows . Err ( ) ; err != nil {
return
}
}
2020-09-13 14:37:30 +00:00
2020-03-08 00:06:44 +00:00
return
}
2022-02-21 06:13:39 +00:00
func ( s * Survey ) Update ( ) ( * Survey , error ) {
2022-02-28 18:00:30 +00:00
if _ , err := DBExec ( "UPDATE surveys SET title = ?, promo = ?, grp = ?, shown = ?, direct = ?, corrected = ?, start_availability = ?, end_availability = ? WHERE id_survey = ?" , s . Title , s . Promo , s . Group , s . Shown , s . Direct , s . Corrected , s . StartAvailability , s . EndAvailability , s . Id ) ; err != nil {
2022-02-21 06:13:39 +00:00
return nil , err
2020-03-04 11:07:12 +00:00
} else {
2022-02-21 06:13:39 +00:00
return s , err
2020-03-04 11:07:12 +00:00
}
}
func ( s Survey ) Delete ( ) ( int64 , error ) {
if res , err := DBExec ( "DELETE FROM surveys WHERE id_survey = ?" , s . Id ) ; err != nil {
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
return nb , err
}
}
func ClearSurveys ( ) ( int64 , error ) {
if res , err := DBExec ( "DELETE FROM surveys" ) ; err != nil {
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
return nb , err
}
}