Skip to content
Snippets Groups Projects
Verified Commit f3dae9f6 authored by Hangzhi Yu's avatar Hangzhi Yu Committed by Jonathan Weth
Browse files

Respect permissions in frontend for lesson notes part

parent 9f2e8cd3
No related branches found
No related tags found
1 merge request!398Resolve "Respect permissions in coursebook frontend"
......@@ -14,6 +14,7 @@ import {
} from "./participationStatus.graphql";
import SlideIterator from "aleksis.core/components/generic/SlideIterator.vue";
import PersonalNotes from "../personal_notes/PersonalNotes.vue";
import PersonalNoteChip from "../personal_notes/PersonalNoteChip.vue";
import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue";
import TardinessChip from "./TardinessChip.vue";
import TardinessField from "./TardinessField.vue";
......@@ -31,6 +32,7 @@ export default {
AbsenceReasonGroupSelect,
AbsenceReasonButtons,
PersonalNotes,
PersonalNoteChip,
LessonInformation,
MessageBox,
MobileFullscreenDialog,
......@@ -255,18 +257,12 @@ export default {
small
:absence-reason="item.absenceReason"
/>
<v-chip
<personal-note-chip
v-for="note in item.notesWithNote"
:key="'text-note-note-overview-' + note.id"
:note="note"
small
>
<v-avatar left>
<v-icon small>mdi-note-outline</v-icon>
</v-avatar>
<span class="text-truncate" style="max-width: 30ch">
{{ note.note }}
</span>
</v-chip>
/>
<extra-mark-chip
v-for="note in item.notesWithExtraMark"
:key="'extra-mark-note-overview-' + note.id"
......
......@@ -57,6 +57,17 @@ export default {
);
},
},
computed: {
showLabel() {
return !!this.labelKey || !this.canOpenParticipation;
},
innerLabelKey() {
if (this.documentation.futureNoticeParticipationStatus) {
return "alsijil.coursebook.notes.future";
}
return this.labelKey;
},
},
};
</script>
......@@ -77,9 +88,9 @@ export default {
v-on="on"
@click="touchDocumentation"
>
<v-icon :left="!!labelKey">mdi-account-edit-outline</v-icon>
<template v-if="labelKey">
{{ $t(labelKey) }}
<v-icon :left="showLabel">mdi-account-edit-outline</v-icon>
<template v-if="showLabel">
{{ $t(innerLabelKey) }}
</template>
</v-chip>
</template>
......
......@@ -112,6 +112,9 @@ query documentationsForCoursebook(
canEdit
futureNotice
canDelete
futureNoticeParticipationStatus
canEditParticipationStatus
canViewParticipationStatus
}
}
......
......@@ -2,14 +2,35 @@
import AbsenceReasonChip from "aleksis.apps.kolego/components/AbsenceReasonChip.vue";
import ExtraMarkChip from "../../extra_marks/ExtraMarkChip.vue";
import TardinessChip from "../absences/TardinessChip.vue";
import PersonalNoteChip from "../personal_notes/PersonalNoteChip.vue";
</script>
<template>
<div
class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
>
<v-chip dense color="success" outlined v-if="total > 0">
{{ $t("alsijil.coursebook.present_number", { present, total }) }}
<v-chip
dense
color="success"
outlined
v-if="total > 0 && documentation.canViewParticipationStatus"
>
{{
$t("alsijil.coursebook.participations.present_number", {
present,
total,
})
}}
</v-chip>
<v-chip
dense
color="success"
outlined
v-else-if="
total == 1 && present == 1 && !documentation.canViewParticipationStatus
"
>
{{ $t("alsijil.coursebook.participations.present") }}
</v-chip>
<absence-reason-chip
v-for="[reasonId, participations] in Object.entries(absences)"
......@@ -17,7 +38,7 @@ import TardinessChip from "../absences/TardinessChip.vue";
:absence-reason="participations[0].absenceReason"
dense
>
<template #append>
<template v-if="documentation.canViewParticipationStatus" #append>
<span
>:
<span>
......@@ -45,7 +66,7 @@ import TardinessChip from "../absences/TardinessChip.vue";
:extra-mark="mark"
dense
>
<template #append>
<template v-if="documentation.canViewParticipationStatus" #append>
<span
>:
<span>
......@@ -65,10 +86,20 @@ import TardinessChip from "../absences/TardinessChip.vue";
</template>
</extra-mark-chip>
<tardiness-chip v-if="tardyParticipations.length > 0">
{{ $t("alsijil.personal_notes.late") }}
<tardiness-chip
v-if="tardyParticipations.length > 0"
:tardiness="
!documentation.canViewParticipationStatus &&
tardyParticipations.length == 1
? tardyParticipations[0].tardiness
: undefined
"
>
<template v-if="documentation.canViewParticipationStatus" #default>
{{ $t("alsijil.personal_notes.late") }}
</template>
<template #append>
<template v-if="documentation.canViewParticipationStatus" #append>
<span
>:
{{
......@@ -87,8 +118,16 @@ import TardinessChip from "../absences/TardinessChip.vue";
</template>
</tardiness-chip>
<personal-note-chip
v-if="!documentation.canViewParticipationStatus && total == 1"
v-for="note in documentation?.participations[0]?.notesWithNote"
:key="'text-note-note-' + note.id"
:note="note"
/>
<manage-students-trigger
:label-key="total == 0 ? 'alsijil.coursebook.notes.show_list' : ''"
v-if="documentation.canEditParticipationStatus"
:label-key="manageStudentsLabelKey"
v-bind="documentationPartProps"
/>
</div>
......@@ -161,6 +200,12 @@ export default {
tardyParticipations() {
return this.documentation.participations.filter((p) => p.tardiness);
},
manageStudentsLabelKey() {
if (this.total == 0) {
return "alsijil.coursebook.notes.show_list";
}
return "";
},
},
};
</script>
......
<script>
export default {
name: "PersonalNoteChip",
props: {
note: {
type: Object,
required: true,
},
loading: {
type: Boolean,
required: false,
default: false,
},
},
extends: "v-chip",
};
</script>
<template>
<v-tooltip bottom>
<template #activator="{ on, attrs }">
<v-chip
dense
outlined
v-bind="{ ...$attrs, ...attrs }"
v-on="{ ...$listeners, ...on }"
>
<v-avatar left>
<v-icon small>mdi-note-outline</v-icon>
</v-avatar>
<slot name="prepend" />
<slot>
<span class="text-truncate" style="max-width: 30ch">
{{ note.note }}
</span>
</slot>
<slot name="append" />
<v-avatar right v-if="loading">
<v-progress-circular indeterminate :size="16" :width="2" />
</v-avatar>
</v-chip>
</template>
<span v-text="note.note" />
</v-tooltip>
</template>
......@@ -77,7 +77,8 @@
}
},
"notes": {
"show_list": "List of participants"
"show_list": "List of participants",
"future": "Lesson is in the future"
},
"notices": {
"future": "Editing this lesson isn't allowed as this lesson is in the future.",
......@@ -100,9 +101,12 @@
"field": "Edit subject"
}
},
"present_number": "{present}/{total} present",
"no_data": "No lessons for the selected groups and courses in this period",
"no_results": "No search results for {search}",
"participations": {
"present_number": "{present}/{total} present",
"present": "Present"
},
"absences": {
"action_for_selected": "Mark selected participant as: | Mark {count} selected participants as",
"title": "Register absences",
......
......@@ -4,7 +4,14 @@ import graphene
from graphene_django.types import DjangoObjectType
from reversion import create_revision, set_comment, set_user
from aleksis.apps.alsijil.util.predicates import can_edit_documentation, is_in_allowed_time_range
from aleksis.apps.alsijil.util.predicates import (
can_edit_documentation,
is_in_allowed_time_range,
is_in_allowed_time_range_for_participation_status,
)
from aleksis.apps.alsijil.util.predicates import (
can_edit_participation_status as can_edit_participation_status_predicate,
)
from aleksis.apps.chronos.schema import LessonEventType
from aleksis.apps.cursus.models import Subject
from aleksis.apps.cursus.schema import CourseType, SubjectType
......@@ -13,6 +20,7 @@ from aleksis.core.schema.base import (
DjangoFilterMixin,
PermissionsTypeMixin,
)
from aleksis.core.util.core_helpers import has_person
from ..models import Documentation
from .participation_status import ParticipationStatusType
......@@ -46,6 +54,10 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
participations = graphene.List(ParticipationStatusType, required=False)
future_notice = graphene.Boolean(required=False)
future_notice_participation_status = graphene.Boolean(required=False)
can_edit_participation_status = graphene.Boolean(required=False)
can_view_participation_status = graphene.Boolean(required=False)
old_id = graphene.ID(required=False)
......@@ -68,15 +80,36 @@ class DocumentationType(PermissionsTypeMixin, DjangoFilterMixin, DjangoObjectTyp
)
@staticmethod
def resolve_participations(root: Documentation, info, **kwargs):
if not info.context.user.has_perm(
def resolve_future_notice_participation_status(root: Documentation, info, **kwargs):
"""Shows whether the user can edit all participation statuses based on the current time.
This checks whether the documentation is in the future.
"""
return not is_in_allowed_time_range_for_participation_status(info.context.user, root)
@staticmethod
def resolve_can_edit_participation_status(root: Documentation, info, **kwargs):
"""Shows whether the user can edit all participation statuses of the documentation"""
return can_edit_participation_status_predicate(info.context.user, root)
@staticmethod
def resolve_can_view_participation_status(root: Documentation, info, **kwargs):
"""Shows whether the user can view all participation statuses of the documentation"""
return info.context.user.has_perm(
"alsijil.view_participation_status_for_documentation_rule", root
):
return []
)
@staticmethod
def resolve_participations(root: Documentation, info, **kwargs):
# A dummy documentation will not have any participations
if str(root.pk).startswith("DUMMY") or not hasattr(root, "participations"):
return []
elif not info.context.user.has_perm(
"alsijil.view_participation_status_for_documentation_rule", root
):
if has_person(info.context.user):
return root.participations.filter(person=info.context.user.person)
return []
return root.participations.all()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment