Compare commits

..

5 Commits

Author SHA1 Message Date
c21df9d93f Credit François on bounty page
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-19 11:44:47 +01:00
f675047ce8 Refactor permissions checks to avoid questions/works leaks between promotions/groups/start-availability
Thanks-To François Dautrême <francois.dautreme@epita.fr>
2022-11-19 11:44:31 +01:00
bf5b0e88dd Fix correction template mess 2022-11-19 11:44:31 +01:00
d7f679ce84 Display survey mean to admin 2022-11-19 11:44:31 +01:00
d6f620bc0d ui: Use $lib in imports 2022-11-19 11:44:31 +01:00
58 changed files with 245 additions and 205 deletions

View File

@ -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()

View File

@ -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 {

View File

@ -1,5 +1,5 @@
<script>
import { CorrectionTemplate } from '../lib/correctionTemplates';
import { CorrectionTemplate } from '$lib/correctionTemplates';
let className = '';
export { className as class };

View File

@ -1,6 +1,6 @@
<script>
import { user } from '../stores/user';
import { autoCorrection } from '../lib/correctionTemplates';
import { user } from '$lib/stores/user';
import { autoCorrection } from '$lib/correctionTemplates';
export let cts = null;
export let rid = 0;

View File

@ -4,8 +4,8 @@
import QuestionProposals from './QuestionProposals.svelte';
import ResponseCorrected from './ResponseCorrected.svelte';
import CorrectionResponseFooter from './CorrectionResponseFooter.svelte';
import { autoCorrection } from '../lib/correctionTemplates';
import { getUser } from '../lib/users';
import { autoCorrection } from '$lib/correctionTemplates';
import { getUser } from '$lib/users';
export let cts = null;
export let filter = "";

View File

@ -5,7 +5,7 @@
import QuestionHeader from './QuestionHeader.svelte';
import QuestionProposals from './QuestionProposals.svelte';
import ResponseCorrected from './ResponseCorrected.svelte';
import { user } from '../stores/user';
import { user } from '$lib/stores/user';
const dispatch = createEventDispatcher();

View File

@ -1,7 +1,7 @@
<script>
import { createEventDispatcher } from 'svelte';
import { user } from '../stores/user';
import { user } from '$lib/stores/user';
const dispatch = createEventDispatcher();

View File

@ -1,7 +1,7 @@
<script>
import { createEventDispatcher } from 'svelte';
import { QuestionProposal } from '../lib/questions';
import { QuestionProposal } from '$lib/questions';
export let edit = false;
export let proposals = [];

View File

@ -1,6 +1,6 @@
<script>
import { user } from '../stores/user';
import { ToastsStore } from '../stores/toasts';
import { user } from '$lib/stores/user';
import { ToastsStore } from '$lib/stores/toasts';
export let response = null;
export let survey = null;

View File

@ -1,6 +1,6 @@
<script>
import { getSurveys } from '../lib/surveys';
import { getUsers, getGrades, getPromos } from '../lib/users';
import { getSurveys } from '$lib/surveys';
import { getUsers, getGrades, getPromos } from '$lib/users';
export let promo = null;
</script>

View File

@ -1,8 +1,8 @@
<script>
import { createEventDispatcher } from 'svelte';
import DateFormat from '../components/DateFormat.svelte';
import { getUserRendu } from '../lib/works';
import DateFormat from '$lib/components/DateFormat.svelte';
import { getUserRendu } from '$lib/works';
let className = '';
export { className as class };

View File

@ -2,9 +2,9 @@
import { createEventDispatcher } from 'svelte';
import { goto } from '$app/navigation';
import { getQuestions } from '../lib/questions';
import { getQuestions } from '$lib/questions';
import DateTimeInput from './DateTimeInput.svelte';
import { ToastsStore } from '../stores/toasts';
import { ToastsStore } from '$lib/stores/toasts';
const dispatch = createEventDispatcher();
export let survey = null;

View File

@ -1,12 +1,12 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { user } from '../stores/user';
import DateFormat from '../components/DateFormat.svelte';
import SurveyBadge from '../components/SurveyBadge.svelte';
import SubmissionStatus from '../components/SubmissionStatus.svelte';
import { getSurveys } from '../lib/surveys';
import { getScore } from '../lib/users';
import { user } from '$lib/stores/user';
import DateFormat from '$lib/components/DateFormat.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import SubmissionStatus from '$lib/components/SubmissionStatus.svelte';
import { getSurveys } from '$lib/surveys';
import { getScore } from '$lib/users';
export let allworks = false;

View File

@ -1,8 +1,8 @@
<script>
import { user } from '../stores/user';
import { ToastsStore } from '../stores/toasts';
import QuestionForm from '../components/QuestionForm.svelte';
import { Question } from '../lib/questions';
import { user } from '$lib/stores/user';
import { ToastsStore } from '$lib/stores/toasts';
import QuestionForm from '$lib/components/QuestionForm.svelte';
import { Question } from '$lib/questions';
export let survey = null;
export let id_user = null;

View File

@ -1,5 +1,5 @@
<script>
import { ToastsStore } from '../stores/toasts';
import { ToastsStore } from '$lib/stores/toasts';
</script>
<div class="toast-container position-fixed top-0 end-0 p-3">

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { getKeys, getKey, Key } from '../lib/key';
import { getKeys, getKey, Key } from '$lib/key';
export let student = null;
</script>

View File

@ -1,8 +1,8 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { getSurveys } from '../lib/surveys';
import { getUser, getUserGrade, getUserScore } from '../lib/users';
import { getSurveys } from '$lib/surveys';
import { getUser, getUserGrade, getUserScore } from '$lib/users';
export let student = null;
export let allPromos = false;

View File

@ -1,6 +1,6 @@
<script>
import { user } from '../stores/user';
import DateFormat from '../components/DateFormat.svelte';
import { user } from '$lib/stores/user';
import DateFormat from '$lib/components/DateFormat.svelte';
let className = '';
export { className as class };

View File

@ -3,7 +3,7 @@
import { goto } from '$app/navigation';
import DateTimeInput from './DateTimeInput.svelte';
import { ToastsStore } from '../stores/toasts';
import { ToastsStore } from '$lib/stores/toasts';
const dispatch = createEventDispatcher();
export let work = null;

View File

@ -1,10 +1,10 @@
<script>
import { createEventDispatcher } from 'svelte';
import BuildState from '../components/BuildState.svelte';
import DateFormat from '../components/DateFormat.svelte';
import { WorkRepository, getRemoteRepositories, getRepositories } from '../lib/repositories';
import { ToastsStore } from '../stores/toasts';
import BuildState from '$lib/components/BuildState.svelte';
import DateFormat from '$lib/components/DateFormat.svelte';
import { WorkRepository, getRemoteRepositories, getRepositories } from '$lib/repositories';
import { ToastsStore } from '$lib/stores/toasts';
const dispatch = createEventDispatcher();

View File

@ -1,5 +1,5 @@
<script context="module">
import { user } from '../stores/user';
import { user } from '$lib/stores/user';
let stop_refresh = false;
let refresh_interval_auth = null;
@ -42,8 +42,8 @@
</script>
<script>
import AuthButton from '../components/AuthButton.svelte';
import Toaster from '../components/Toaster.svelte';
import AuthButton from '$lib/components/AuthButton.svelte';
import Toaster from '$lib/components/Toaster.svelte';
export let rroute = '';

View File

@ -2,9 +2,9 @@
import { goto } from '$app/navigation';
import { page } from '$app/stores'
import AuthButton from '../components/AuthButton.svelte';
import { ToastsStore } from '../stores/toasts';
import { user } from '../stores/user';
import AuthButton from '$lib/components/AuthButton.svelte';
import { ToastsStore } from '$lib/stores/toasts';
import { user } from '$lib/stores/user';
let auth = { username: "", password: "" };
let pleaseWait = false;

View File

@ -65,6 +65,22 @@
<h3 class="mt-5 mb-3">Hall of Fame</h3>
<div class="card mb-3">
<div class="card-header">
L'accès aux questionnaires n'était pas filtré selon les groupes ou les promos.
<span class="badge bg-success shadow-lg">+2&nbsp;pts</span>
</div>
<div class="card-body">
<div class="row row-cols-6">
<img class="img-thumbnail" src="//photos.cri.epita.fr/francois.dautreme" alt="francois.dautreme">
</div>
<p class="card-text mt-3">
Divulguée et corrigée le 19 novembre 2022.
<a href="https://git.nemunai.re/srs/atsebay.t/commit/f675047ce8f6636aa45336b56c069172330b050f" target="_blank">Commit</a>
</p>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
Il était toujours possible de répondre aux questionnaires après l'heure de clôture.

View File

@ -9,7 +9,7 @@
</script>
<script>
import StudentGrades from '../../components/StudentGrades.svelte';
import StudentGrades from '$lib/components/StudentGrades.svelte';
export let promo;
</script>

View File

@ -1,5 +1,5 @@
<script>
import StudentGrades from '../../components/StudentGrades.svelte';
import StudentGrades from '$lib/components/StudentGrades.svelte';
</script>
<StudentGrades />

View File

@ -1,6 +1,6 @@
<script>
import { user } from '../stores/user';
import { ToastsStore } from '../stores/toasts';
import { user } from '$lib/stores/user';
import { ToastsStore } from '$lib/stores/toasts';
function needhelp() {
fetch('api/help', {

View File

@ -1,9 +1,9 @@
<script lang="ts">
import { user } from '../stores/user';
import { getUser, getUserNeedingHelp } from '../lib/users';
import DateFormat from '../components/DateFormat.svelte';
import SurveyList from '../components/SurveyList.svelte';
import ValidateSubmissions from '../components/ValidateSubmissions.svelte';
import { user } from '$lib/stores/user';
import { getUser, getUserNeedingHelp } from '$lib/users';
import DateFormat from '$lib/components/DateFormat.svelte';
import SurveyList from '$lib/components/SurveyList.svelte';
import ValidateSubmissions from '$lib/components/ValidateSubmissions.svelte';
let direct = null;

View File

@ -1,7 +1,7 @@
<script>
import { deleteKey, getKeys, getKey, Key } from '../lib/key';
import { user } from '../stores/user';
import { ToastsStore } from '../stores/toasts';
import { deleteKey, getKeys, getKey, Key } from '$lib/key';
import { user } from '$lib/stores/user';
import { ToastsStore } from '$lib/stores/toasts';
let keysP = getKeys();

View File

@ -1,5 +1,5 @@
<script context="module">
import { getSurvey } from '../../../lib/surveys';
import { getSurvey } from '$lib/surveys';
export async function load({ params, stuff }) {
const survey = getSurvey(params.sid);

View File

@ -10,16 +10,16 @@
</script>
<script>
import { user } from '../../../stores/user';
import CorrectionPieChart from '../../../components/CorrectionPieChart.svelte';
import ListInputResponses from '../../../components/ListInputResponses.svelte';
import QuestionForm from '../../../components/QuestionForm.svelte';
import StartStopLiveSurvey from '../../../components/StartStopLiveSurvey.svelte';
import SurveyAdmin from '../../../components/SurveyAdmin.svelte';
import SurveyBadge from '../../../components/SurveyBadge.svelte';
import { getSurvey } from '../../../lib/surveys';
import { getQuestion, getQuestions, Question } from '../../../lib/questions';
import { getUsers } from '../../../lib/users';
import { user } from '$lib/stores/user';
import CorrectionPieChart from '$lib/components/CorrectionPieChart.svelte';
import ListInputResponses from '$lib/components/ListInputResponses.svelte';
import QuestionForm from '$lib/components/QuestionForm.svelte';
import StartStopLiveSurvey from '$lib/components/StartStopLiveSurvey.svelte';
import SurveyAdmin from '$lib/components/SurveyAdmin.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import { getSurvey } from '$lib/surveys';
import { getQuestion, getQuestions, Question } from '$lib/questions';
import { getUsers } from '$lib/users';
export let surveyP;
export let sid;

View File

@ -1,5 +1,5 @@
<script context="module">
import { getSurvey } from '../../../lib/surveys';
import { getSurvey } from '$lib/surveys';
export async function load({ params, stuff }) {
return {
@ -13,11 +13,11 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { user } from '../../../stores/user';
import SurveyAdmin from '../../../components/SurveyAdmin.svelte';
import SurveyBadge from '../../../components/SurveyBadge.svelte';
import SurveyQuestions from '../../../components/SurveyQuestions.svelte';
import { getQuestions } from '../../../lib/questions';
import { user } from '$lib/stores/user';
import SurveyAdmin from '$lib/components/SurveyAdmin.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import SurveyQuestions from '$lib/components/SurveyQuestions.svelte';
import { getQuestions } from '$lib/questions';
export let surveyP;

View File

@ -12,11 +12,11 @@
<script>
import { onDestroy } from 'svelte';
import { user } from '../../../stores/user';
import { ToastsStore } from '../../../stores/toasts';
import SurveyBadge from '../../../components/SurveyBadge.svelte';
import QuestionForm from '../../../components/QuestionForm.svelte';
import { getQuestion } from '../../../lib/questions';
import { user } from '$lib/stores/user';
import { ToastsStore } from '$lib/stores/toasts';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import QuestionForm from '$lib/components/QuestionForm.svelte';
import { getQuestion } from '$lib/questions';
export let surveyP;
export let sid;

View File

@ -1,5 +1,5 @@
<script context="module">
import { getSurvey } from '../../../../lib/surveys';
import { getSurvey } from '$lib/surveys';
export async function load({ params, stuff }) {
return {
@ -12,13 +12,13 @@
</script>
<script lang="ts">
import Correction from '../../../../components/Correction.svelte';
import CorrectionPieChart from '../../../../components/CorrectionPieChart.svelte';
import CorrectionReference from '../../../../components/CorrectionReference.svelte';
import SurveyBadge from '../../../../components/SurveyBadge.svelte';
import QuestionHeader from '../../../../components/QuestionHeader.svelte';
import { getCorrectionTemplates } from '../../../../lib/correctionTemplates';
import { getQuestion } from '../../../../lib/questions';
import Correction from '$lib/components/Correction.svelte';
import CorrectionPieChart from '$lib/components/CorrectionPieChart.svelte';
import CorrectionReference from '$lib/components/CorrectionReference.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import QuestionHeader from '$lib/components/QuestionHeader.svelte';
import { getCorrectionTemplates } from '$lib/correctionTemplates';
import { getQuestion } from '$lib/questions';
export let surveyP;
export let rid;
@ -85,7 +85,7 @@
<SurveyBadge class="ms-2" {survey} />
</div>
<div class="card sticky-top">
<div class="card sticky-top" style="overflow-y: auto; max-height: 70vh">
<QuestionHeader
{question}
nodescription={nodescription}
@ -180,4 +180,4 @@
{/await}
{/await}
<div class="mb-5"></div>
<div class="mb-5" style="min-height: 60vh"></div>

View File

@ -1,6 +1,6 @@
<script context="module">
import { getSurvey } from '../../../../lib/surveys';
import { getUsers } from '../../../../lib/users';
import { getSurvey } from '$lib/surveys';
import { getUsers } from '$lib/users';
export async function load({ params, stuff }) {
return {
@ -14,12 +14,12 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { user } from '../../../../stores/user';
import StartStopLiveSurvey from '../../../../components/StartStopLiveSurvey.svelte';
import SurveyAdmin from '../../../../components/SurveyAdmin.svelte';
import SurveyBadge from '../../../../components/SurveyBadge.svelte';
import SurveyQuestions from '../../../../components/SurveyQuestions.svelte';
import { getQuestions } from '../../../../lib/questions';
import { user } from '$lib/stores/user';
import StartStopLiveSurvey from '$lib/components/StartStopLiveSurvey.svelte';
import SurveyAdmin from '$lib/components/SurveyAdmin.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import SurveyQuestions from '$lib/components/SurveyQuestions.svelte';
import { getQuestions } from '$lib/questions';
export let surveyP;
let usersP = null;

View File

@ -1,6 +1,6 @@
<script lang="ts">
import { user } from '../../stores/user';
import SurveyList from '../../components/SurveyList.svelte';
import { user } from '$lib/stores/user';
import SurveyList from '$lib/components/SurveyList.svelte';
</script>
<div class="card bg-light">

View File

@ -1,10 +1,10 @@
<script>
import { goto } from '$app/navigation';
import { user } from '../../stores/user';
import SurveyAdmin from '../../components/SurveyAdmin.svelte';
import SurveyBadge from '../../components/SurveyBadge.svelte';
import { Survey } from '../../lib/surveys';
import { user } from '$lib/stores/user';
import SurveyAdmin from '$lib/components/SurveyAdmin.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import { Survey } from '$lib/surveys';
let survey = new Survey();
</script>

View File

@ -9,11 +9,11 @@
</script>
<script lang="ts">
import UserKeys from '../../../components/UserKeys.svelte';
import UserSurveys from '../../../components/UserSurveys.svelte';
import { user } from '../../../stores/user';
import { getSurveys } from '../../../lib/surveys';
import { getUser, getUserGrade, getUserScore } from '../../../lib/users';
import UserKeys from '$lib/components/UserKeys.svelte';
import UserSurveys from '$lib/components/UserSurveys.svelte';
import { user } from '$lib/stores/user';
import { getSurveys } from '$lib/surveys';
import { getUser, getUserGrade, getUserScore } from '$lib/users';
export let uid;

View File

@ -10,11 +10,11 @@
</script>
<script lang="ts">
import SurveyBadge from '../../../../components/SurveyBadge.svelte';
import SurveyQuestions from '../../../../components/SurveyQuestions.svelte';
import { getSurvey } from '../../../../lib/surveys';
import { getQuestions } from '../../../../lib/questions';
import { getUser } from '../../../../lib/users';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import SurveyQuestions from '$lib/components/SurveyQuestions.svelte';
import { getSurvey } from '$lib/surveys';
import { getQuestions } from '$lib/questions';
import { getUser } from '$lib/users';
export let sid;
export let uid;

View File

@ -9,10 +9,10 @@
</script>
<script lang="ts">
import UserSurveys from '../../../../components/UserSurveys.svelte';
import { user } from '../../../../stores/user';
import { getSurveys } from '../../../../lib/surveys';
import { getUser, getUserGrade, getUserScore } from '../../../../lib/users';
import UserSurveys from '$lib/components/UserSurveys.svelte';
import { user } from '$lib/stores/user';
import { getSurveys } from '$lib/surveys';
import { getUser, getUserGrade, getUserScore } from '$lib/users';
export let uid;

View File

@ -1,9 +1,9 @@
<script>
import { goto } from '$app/navigation';
import { user } from '../../stores/user';
import DateFormat from '../../components/DateFormat.svelte';
import { getUsers, getPromos } from '../../lib/users';
import { user } from '$lib/stores/user';
import DateFormat from '$lib/components/DateFormat.svelte';
import { getUsers, getPromos } from '$lib/users';
function showUser(user) {
goto(`users/${user.id}`)

View File

@ -1,5 +1,5 @@
<script context="module">
import { getWork } from '../../../lib/works';
import { getWork } from '$lib/works';
export async function load({ params, stuff }) {
const work = getWork(params.wid);

View File

@ -1,5 +1,5 @@
<script context="module">
import { getWork } from '../../../lib/works';
import { getWork } from '$lib/works';
export async function load({ params, stuff }) {
return {
@ -13,13 +13,13 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { user } from '../../../stores/user';
import DateFormat from '../../../components/DateFormat.svelte';
import SubmissionStatus from '../../../components/SubmissionStatus.svelte';
import SurveyBadge from '../../../components/SurveyBadge.svelte';
import WorkAdmin from '../../../components/WorkAdmin.svelte';
import WorkRepository from '../../../components/WorkRepository.svelte';
import { getScore } from '../../../lib/users';
import { user } from '$lib/stores/user';
import DateFormat from '$lib/components/DateFormat.svelte';
import SubmissionStatus from '$lib/components/SubmissionStatus.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import WorkAdmin from '$lib/components/WorkAdmin.svelte';
import WorkRepository from '$lib/components/WorkRepository.svelte';
import { getScore } from '$lib/users';
export let work = null;
let edit = false;

View File

@ -1,5 +1,5 @@
<script context="module">
import { getWork } from '../../../lib/works';
import { getWork } from '$lib/works';
export async function load({ params, stuff }) {
return {
@ -13,15 +13,15 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { user } from '../../../stores/user';
import BuildState from '../../../components/BuildState.svelte';
import DateFormat from '../../../components/DateFormat.svelte';
import SubmissionStatus from '../../../components/SubmissionStatus.svelte';
import SurveyBadge from '../../../components/SurveyBadge.svelte';
import WorkRepository from '../../../components/WorkRepository.svelte';
import { getRepositories } from '../../../lib/repositories';
import { ToastsStore } from '../../../stores/toasts';
import { getUsers } from '../../../lib/users';
import { user } from '$lib/stores/user';
import BuildState from '$lib/components/BuildState.svelte';
import DateFormat from '$lib/components/DateFormat.svelte';
import SubmissionStatus from '$lib/components/SubmissionStatus.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import WorkRepository from '$lib/components/WorkRepository.svelte';
import { getRepositories } from '$lib/repositories';
import { ToastsStore } from '$lib/stores/toasts';
import { getUsers } from '$lib/users';
export let work = null;
let usersP = null;

View File

@ -1,13 +1,13 @@
<script>
import { goto } from '$app/navigation';
import { user } from '../../stores/user';
import DateFormat from '../../components/DateFormat.svelte';
import SurveyBadge from '../../components/SurveyBadge.svelte';
import SubmissionStatus from '../../components/SubmissionStatus.svelte';
import { getWorks } from '../../lib/works';
import { getPromos } from '../../lib/users';
import { getScore } from '../../lib/users';
import { user } from '$lib/stores/user';
import DateFormat from '$lib/components/DateFormat.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import SubmissionStatus from '$lib/components/SubmissionStatus.svelte';
import { getWorks } from '$lib/works';
import { getPromos } from '$lib/users';
import { getScore } from '$lib/users';
let filterPromo = "";
</script>

View File

@ -1,10 +1,10 @@
<script>
import { goto } from '$app/navigation';
import { user } from '../../stores/user';
import WorkAdmin from '../../components/WorkAdmin.svelte';
import SurveyBadge from '../../components/SurveyBadge.svelte';
import { Work } from '../../lib/works';
import { user } from '$lib/stores/user';
import WorkAdmin from '$lib/components/WorkAdmin.svelte';
import SurveyBadge from '$lib/components/SurveyBadge.svelte';
import { Work } from '$lib/works';
let work = new Work();
</script>

View File

@ -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"`
}