diff --git a/questions.go b/questions.go index 19a4a25..d742e1b 100644 --- a/questions.go +++ b/questions.go @@ -39,7 +39,7 @@ func declareAPIAuthQuestionsRoutes(router *gin.RouterGroup) { c.JSON(http.StatusOK, questions) } } else { - if (!s.Shown || s.Direct != nil) && !u.IsAdmin { + if s.Direct != nil && !u.IsAdmin { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible"}) return } @@ -62,24 +62,7 @@ func declareAPIAuthQuestionsRoutes(router *gin.RouterGroup) { questionsRoutes.Use(questionHandler) questionsRoutes.GET("", func(c *gin.Context) { - q := c.MustGet("question").(*Question) - u := c.MustGet("LoggedUser").(*User) - - if !u.IsAdmin { - s, err := getSurvey(int(q.IdSurvey)) - if err != nil { - log.Println("Unable to getSurvey:", err) - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during survey retrieval. Please try again later."}) - return - } - - if !s.Shown || (s.Direct != nil && *s.Direct != q.Id) { - c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not authorized"}) - return - } - } - - c.JSON(http.StatusOK, q) + c.JSON(http.StatusOK, c.MustGet("question").(*Question)) }) declareAPIAuthProposalsRoutes(questionsRoutes) @@ -171,6 +154,8 @@ func declareAPIAdminUserQuestionsRoutes(router *gin.RouterGroup) { } func questionHandler(c *gin.Context) { + u := c.MustGet("LoggedUser").(*User) + var survey *Survey if s, ok := c.Get("survey"); ok { survey = s.(*Survey) @@ -190,6 +175,15 @@ func questionHandler(c *gin.Context) { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Question not found"}) return } + + s, err := getSurvey(int(question.IdSurvey)) + if err != nil { + log.Println("Unable to getSurvey:", err) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during survey retrieval. Please try again later."}) + return + } + + survey = s } else { question, err = survey.GetQuestion(qid) if err != nil { @@ -198,6 +192,15 @@ func questionHandler(c *gin.Context) { } } + if !u.IsAdmin && (!survey.checkUserAccessToSurvey(u) || (survey.Direct != nil && *survey.Direct != question.Id)) { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not authorized"}) + return + } + if !u.IsAdmin && survey.StartAvailability.After(time.Now()) { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible yet"}) + return + } + c.Set("question", question) c.Next() diff --git a/surveys.go b/surveys.go index 48df3eb..81a0185 100644 --- a/surveys.go +++ b/surveys.go @@ -62,26 +62,22 @@ func declareAPISurveysRoutes(router *gin.RouterGroup) { 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"}) - } + c.JSON(http.StatusOK, c.MustGet("survey").(*Survey)) }) } func declareAPIAuthSurveysRoutes(router *gin.RouterGroup) { surveysRoutes := router.Group("/surveys/:sid") surveysRoutes.Use(surveyHandler) + surveysRoutes.Use(surveyUserAccessHandler) surveysRoutes.GET("/score", func(c *gin.Context) { + loggedUser := c.MustGet("LoggedUser").(*User) var u *User if user, ok := c.Get("user"); ok { u = user.(*User) } else { - u = c.MustGet("LoggedUser").(*User) + u = loggedUser } s := c.MustGet("survey").(*Survey) @@ -93,10 +89,29 @@ func declareAPIAuthSurveysRoutes(router *gin.RouterGroup) { return } - if score == nil { - c.JSON(http.StatusOK, map[string]string{"score": "N/A"}) - } else { + if score != nil { c.JSON(http.StatusOK, map[string]float64{"score": *score}) + } else if _, ok := c.Get("user"); !ok && loggedUser.IsAdmin { + // Admin retrieve mean score + scores, err := s.GetGrades() + if err != nil { + log.Printf("Unable to GetGrades(sid=%d): %s", s.Id, err.Error()) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to retrieve grades."}) + return + } + + *score = 0 + nbGrades := 0 + for _, s := range scores { + *score += *s + nbGrades += 1 + } + + *score /= float64(nbGrades) + + c.JSON(http.StatusOK, map[string]float64{"score": *score}) + } else { + c.JSON(http.StatusOK, map[string]string{"score": "N/A"}) } } else { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible"}) @@ -199,18 +214,20 @@ func surveyHandler(c *gin.Context) { } } +func (s *Survey) checkUserAccessToSurvey(u *User) bool { + return u.IsAdmin || (u.Promo == s.Promo && s.Shown && (s.Group == "" || strings.Contains(u.Groups, ","+s.Group+","))) +} + func surveyUserAccessHandler(c *gin.Context) { u := c.MustGet("LoggedUser").(*User) - w := c.MustGet("survey").(*Survey) + s := c.MustGet("survey").(*Survey) - if u.IsAdmin { - c.Next() - } else if w.Shown && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",")) { - c.Next() - } else { + if !s.checkUserAccessToSurvey(u) { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Survey not found."}) return } + + c.Next() } type Survey struct { diff --git a/ui/src/components/AuthButton.svelte b/ui/src/lib/components/AuthButton.svelte similarity index 100% rename from ui/src/components/AuthButton.svelte rename to ui/src/lib/components/AuthButton.svelte diff --git a/ui/src/components/BuildState.svelte b/ui/src/lib/components/BuildState.svelte similarity index 100% rename from ui/src/components/BuildState.svelte rename to ui/src/lib/components/BuildState.svelte diff --git a/ui/src/components/Correction.svelte b/ui/src/lib/components/Correction.svelte similarity index 100% rename from ui/src/components/Correction.svelte rename to ui/src/lib/components/Correction.svelte diff --git a/ui/src/components/CorrectionPieChart.svelte b/ui/src/lib/components/CorrectionPieChart.svelte similarity index 100% rename from ui/src/components/CorrectionPieChart.svelte rename to ui/src/lib/components/CorrectionPieChart.svelte diff --git a/ui/src/components/CorrectionReference.svelte b/ui/src/lib/components/CorrectionReference.svelte similarity index 98% rename from ui/src/components/CorrectionReference.svelte rename to ui/src/lib/components/CorrectionReference.svelte index f1c51e1..110f6f9 100644 --- a/ui/src/components/CorrectionReference.svelte +++ b/ui/src/lib/components/CorrectionReference.svelte @@ -1,5 +1,5 @@ diff --git a/ui/src/components/SubmissionStatus.svelte b/ui/src/lib/components/SubmissionStatus.svelte similarity index 94% rename from ui/src/components/SubmissionStatus.svelte rename to ui/src/lib/components/SubmissionStatus.svelte index b7ad14a..5af55c9 100644 --- a/ui/src/components/SubmissionStatus.svelte +++ b/ui/src/lib/components/SubmissionStatus.svelte @@ -1,8 +1,8 @@
diff --git a/ui/src/components/UserKeys.svelte b/ui/src/lib/components/UserKeys.svelte similarity index 97% rename from ui/src/components/UserKeys.svelte rename to ui/src/lib/components/UserKeys.svelte index 7f383cb..f616b8e 100644 --- a/ui/src/components/UserKeys.svelte +++ b/ui/src/lib/components/UserKeys.svelte @@ -1,5 +1,5 @@ diff --git a/ui/src/components/UserSurveys.svelte b/ui/src/lib/components/UserSurveys.svelte similarity index 94% rename from ui/src/components/UserSurveys.svelte rename to ui/src/lib/components/UserSurveys.svelte index dad0bb3..5d9a8ed 100644 --- a/ui/src/components/UserSurveys.svelte +++ b/ui/src/lib/components/UserSurveys.svelte @@ -1,8 +1,8 @@ diff --git a/ui/src/routes/grades/index.svelte b/ui/src/routes/grades/index.svelte index 026f5ce..b016fbb 100644 --- a/ui/src/routes/grades/index.svelte +++ b/ui/src/routes/grades/index.svelte @@ -1,5 +1,5 @@ diff --git a/ui/src/routes/help.svelte b/ui/src/routes/help.svelte index 6b4a8c8..e87598a 100644 --- a/ui/src/routes/help.svelte +++ b/ui/src/routes/help.svelte @@ -1,6 +1,6 @@
diff --git a/ui/src/routes/surveys/new.svelte b/ui/src/routes/surveys/new.svelte index 2a4f626..9aaf369 100644 --- a/ui/src/routes/surveys/new.svelte +++ b/ui/src/routes/surveys/new.svelte @@ -1,10 +1,10 @@ diff --git a/ui/src/routes/users/[uid]/index.svelte b/ui/src/routes/users/[uid]/index.svelte index f6fbaee..d5c9e99 100644 --- a/ui/src/routes/users/[uid]/index.svelte +++ b/ui/src/routes/users/[uid]/index.svelte @@ -9,11 +9,11 @@ diff --git a/ui/src/routes/works/new.svelte b/ui/src/routes/works/new.svelte index efbcfd0..3a635fb 100644 --- a/ui/src/routes/works/new.svelte +++ b/ui/src/routes/works/new.svelte @@ -1,10 +1,10 @@ diff --git a/works.go b/works.go index 3b0a106..2ca25ee 100644 --- a/works.go +++ b/works.go @@ -43,7 +43,11 @@ func declareAPIWorksRoutes(router *gin.RouterGroup) { } else { for _, w := range works { if w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",") { + // Remove informations not needed on front page for students + w.Promo = 0 w.Group = "" + w.DescriptionRaw = "" + response = append(response, w) } } @@ -79,7 +83,10 @@ func declareAPIWorksRoutes(router *gin.RouterGroup) { } else { for _, w := range works { if w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",") { + // Remove informations not needed on front page for students + w.Promo = 0 w.Group = "" + response = append(response, w) } } @@ -193,16 +200,7 @@ func declareAPIAuthWorksRoutes(router *gin.RouterGroup) { worksRoutes.Use(workUserAccessHandler) worksRoutes.GET("", func(c *gin.Context) { - u := c.MustGet("LoggedUser").(*User) - w := c.MustGet("work").(*Work) - - if u.IsAdmin { - c.JSON(http.StatusOK, w) - } else if w.Shown && w.StartAvailability.Before(time.Now()) && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",")) { - c.JSON(http.StatusOK, w) - } else { - c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Permission denied"}) - } + c.JSON(http.StatusOK, c.MustGet("work").(*Work)) }) // Grades related to works @@ -239,18 +237,24 @@ func workHandler(c *gin.Context) { } } +func (w *Work) checkUserAccessToWork(u *User) bool { + return u.IsAdmin || (u.Promo == w.Promo && w.Shown && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+","))) +} + func workUserAccessHandler(c *gin.Context) { u := c.MustGet("LoggedUser").(*User) w := c.MustGet("work").(*Work) - if u.IsAdmin { - c.Next() - } else if w.Shown && (w.Group == "" || strings.Contains(u.Groups, ","+w.Group+",")) { - c.Next() - } else { + if !w.checkUserAccessToWork(u) { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Work not found."}) return } + if !u.IsAdmin && w.StartAvailability.After(time.Now()) { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"errmsg": "Not accessible yet"}) + return + } + + c.Next() } type OneWork struct { @@ -291,14 +295,14 @@ func allWorks(cnd string, param ...interface{}) (items []*OneWork, err error) { type Work struct { Id int64 `json:"id"` Title string `json:"title"` - Promo uint `json:"promo"` - Group string `json:"group"` + Promo uint `json:"promo,omitempty"` + Group string `json:"group,omitempty"` Shown bool `json:"shown"` - Description string `json:"description"` + Description string `json:"description,omitempty"` DescriptionRaw string `json:"descr_raw,omitempty"` - Tag string `json:"tag"` - SubmissionURL *string `json:"submission_url"` - Corrected bool `json:"corrected"` + Tag string `json:"tag,omitempty"` + SubmissionURL *string `json:"submission_url,omitempty"` + Corrected bool `json:"corrected,omitempty"` StartAvailability time.Time `json:"start_availability"` EndAvailability time.Time `json:"end_availability"` }