Refactor `LearningMentor` model to flat `AgentParticipantRelation` model
This commit is contained in:
parent
3f02fd254a
commit
cdfb9d2c5b
|
|
@ -8,9 +8,9 @@ import LoadingSpinner from "@/components/ui/LoadingSpinner.vue";
|
|||
const courseSession = useCurrentCourseSession();
|
||||
const { isLoading, summary, fetchData } = useLearningMentees(courseSession.value.id);
|
||||
|
||||
const removeMyMentee = async (menteeId: string) => {
|
||||
const removeMyMentee = async (relationId: string) => {
|
||||
await useCSRFFetch(
|
||||
`/api/mentor/${courseSession.value.id}/mentors/${summary.value?.mentor_id}/remove/${menteeId}`
|
||||
`/api/mentor/${courseSession.value.id}/mentors/${relationId}/delete`
|
||||
).delete();
|
||||
fetchData();
|
||||
};
|
||||
|
|
@ -28,25 +28,31 @@ const noMenteesText = computed(() =>
|
|||
</div>
|
||||
<div v-else>
|
||||
<h2 class="heading-2 py-6">{{ $t("a.Personen, die du begleitest") }}</h2>
|
||||
<div v-if="(summary?.participants?.length ?? 0) > 0" class="bg-white px-4 py-2">
|
||||
<div
|
||||
v-if="(summary?.participant_relations.length ?? 0) > 0"
|
||||
class="bg-white px-4 py-2"
|
||||
>
|
||||
<div
|
||||
v-for="participant in summary?.participants ?? []"
|
||||
:key="participant.id"
|
||||
v-for="relation in summary?.participant_relations ?? []"
|
||||
:key="relation.id"
|
||||
data-cy="lm-my-mentee-list-item"
|
||||
class="flex flex-col items-start justify-between gap-4 border-b py-2 last:border-b-0 md:flex-row md:items-center md:gap-16"
|
||||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<img
|
||||
:alt="participant.last_name"
|
||||
:alt="relation.participant_user.last_name"
|
||||
class="h-11 w-11 rounded-full"
|
||||
:src="participant.avatar_url || '/static/avatars/myvbv-default-avatar.png'"
|
||||
:src="
|
||||
relation.participant_user.avatar_url ||
|
||||
'/static/avatars/myvbv-default-avatar.png'
|
||||
"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-bold">
|
||||
{{ participant.first_name }}
|
||||
{{ participant.last_name }}
|
||||
{{ relation.participant_user.first_name }}
|
||||
{{ relation.participant_user.last_name }}
|
||||
</div>
|
||||
{{ participant.email }}
|
||||
{{ relation.participant_user.email }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-x-5">
|
||||
|
|
@ -55,7 +61,7 @@ const noMenteesText = computed(() =>
|
|||
:to="{
|
||||
name: 'profileLearningPath',
|
||||
params: {
|
||||
userId: participant.id,
|
||||
userId: relation.participant_user.id,
|
||||
courseSlug: courseSession.course.slug,
|
||||
},
|
||||
}"
|
||||
|
|
@ -66,7 +72,7 @@ const noMenteesText = computed(() =>
|
|||
<button
|
||||
class="underline"
|
||||
data-cy="lm-my-mentee-remove"
|
||||
@click="removeMyMentee(participant.id)"
|
||||
@click="removeMyMentee(relation.id)"
|
||||
>
|
||||
{{ $t("a.Entfernen") }}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -51,11 +51,9 @@ const removeInvitation = async (invitationId: string) => {
|
|||
await refreshInvitations();
|
||||
};
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const removeMyMentor = async (mentorId: string) => {
|
||||
const removeMyMentor = async (relationId: string) => {
|
||||
await useCSRFFetch(
|
||||
`/api/mentor/${courseSession.value.id}/mentors/${mentorId}/remove/${userStore.id}`
|
||||
`/api/mentor/${courseSession.value.id}/mentors/${relationId}/delete`
|
||||
).delete();
|
||||
await refreshMentors();
|
||||
};
|
||||
|
|
@ -138,16 +136,16 @@ const noLearningMentors = computed(() =>
|
|||
>
|
||||
<div class="flex items-center space-x-2">
|
||||
<img
|
||||
:alt="learningMentor.mentor.last_name"
|
||||
:alt="learningMentor.agent.last_name"
|
||||
class="h-11 w-11 rounded-full"
|
||||
:src="learningMentor.mentor.avatar_url"
|
||||
:src="learningMentor.agent.avatar_url"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-bold">
|
||||
{{ learningMentor.mentor.first_name }}
|
||||
{{ learningMentor.mentor.last_name }}
|
||||
{{ learningMentor.agent.first_name }}
|
||||
{{ learningMentor.agent.last_name }}
|
||||
</div>
|
||||
{{ learningMentor.mentor.email }}
|
||||
{{ learningMentor.agent.email }}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -74,9 +74,9 @@ const onSubmit = async () => {
|
|||
<option
|
||||
v-for="learningMentor in learningMentors"
|
||||
:key="learningMentor.id"
|
||||
:value="learningMentor.mentor.id"
|
||||
:value="learningMentor.agent.id"
|
||||
>
|
||||
{{ learningMentor.mentor.first_name }} {{ learningMentor.mentor.last_name }}
|
||||
{{ learningMentor.agent.first_name }} {{ learningMentor.agent.last_name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ import type {
|
|||
CourseSessionDetail,
|
||||
DashboardPersonsPageMode,
|
||||
LearningContentWithCompletion,
|
||||
LearningMentor,
|
||||
AgentParticipantRelation,
|
||||
LearningPathType,
|
||||
LearningUnitPerformanceCriteria,
|
||||
PerformanceCriteria,
|
||||
|
|
@ -489,7 +489,7 @@ export function useFileUpload() {
|
|||
}
|
||||
|
||||
export function useMyLearningMentors() {
|
||||
const learningMentors = ref<LearningMentor[]>([]);
|
||||
const learningMentors = ref<AgentParticipantRelation[]>([]);
|
||||
const currentCourseSessionId = useCurrentCourseSession().value.id;
|
||||
const loading = ref(false);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import type { Assignment, Participant } from "@/services/learningMentees";
|
||||
import type { Assignment, UserShort } from "@/services/learningMentees";
|
||||
import { useLearningMentees } from "@/services/learningMentees";
|
||||
import { computed, onMounted, type Ref } from "vue";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
|
|
@ -11,13 +11,16 @@ const props = defineProps<{
|
|||
|
||||
const courseSession = useCurrentCourseSession();
|
||||
const learningMentees = useLearningMentees(courseSession.value.id);
|
||||
const participants = computed(() => learningMentees.summary.value?.participants);
|
||||
const praxisAssignment: Ref<Assignment | null> = computed(() =>
|
||||
learningMentees.getAssignmentById(props.praxisAssignmentId)
|
||||
);
|
||||
|
||||
const getParticipantById = (id: string): Participant | null => {
|
||||
return participants.value?.find((participant) => participant.id === id) || null;
|
||||
const getParticipantById = (id: string): UserShort | undefined => {
|
||||
return (learningMentees.summary.value?.participant_relations ?? [])
|
||||
.map((rel) => {
|
||||
return rel.participant_user;
|
||||
})
|
||||
.find((user) => user.id === id);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import type { Assignment, Participant } from "@/services/learningMentees";
|
||||
import type { Assignment, UserShort } from "@/services/learningMentees";
|
||||
import { useLearningMentees } from "@/services/learningMentees";
|
||||
import { computed, type Ref } from "vue";
|
||||
import { useCurrentCourseSession } from "@/composables";
|
||||
|
|
@ -15,14 +15,12 @@ const selfEvaluationFeedback: Ref<Assignment | null> = computed(() =>
|
|||
learningMentees.getAssignmentById(props.learningUnitId)
|
||||
);
|
||||
|
||||
const getParticipantById = (id: string): Participant | null => {
|
||||
if (learningMentees.summary.value?.participants) {
|
||||
const found = learningMentees.summary.value.participants.find(
|
||||
(item) => item.id === id
|
||||
);
|
||||
return found || null;
|
||||
}
|
||||
return null;
|
||||
const getParticipantById = (id: string): UserShort | undefined => {
|
||||
return (learningMentees.summary.value?.participant_relations ?? [])
|
||||
.map((rel) => {
|
||||
return rel.participant_user;
|
||||
})
|
||||
.find((user) => user.id === id);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ const isMentorsLoading = computed(() => learningMentors.loading.value);
|
|||
|
||||
const mentors = computed(() => {
|
||||
return learningMentors.learningMentors.value.map((mentor) => ({
|
||||
id: mentor.mentor.id,
|
||||
name: `${mentor.mentor.first_name} ${mentor.mentor.last_name}`,
|
||||
id: mentor.agent.id,
|
||||
name: `${mentor.agent.first_name} ${mentor.agent.last_name}`,
|
||||
}));
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { itGet } from "@/fetchHelpers";
|
|||
import type { Ref } from "vue";
|
||||
import { ref, watchEffect } from "vue";
|
||||
|
||||
export interface Participant {
|
||||
export interface UserShort {
|
||||
id: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
|
|
@ -12,6 +12,14 @@ export interface Participant {
|
|||
language: string;
|
||||
}
|
||||
|
||||
export interface AgentParticipantRelation {
|
||||
id: string;
|
||||
role: "LEARNING_MENTOR";
|
||||
course_session_id: number;
|
||||
agent: UserShort;
|
||||
participant_user: UserShort;
|
||||
}
|
||||
|
||||
interface Circle {
|
||||
id: number;
|
||||
title: string;
|
||||
|
|
@ -40,9 +48,8 @@ export interface Assignment {
|
|||
type: string;
|
||||
}
|
||||
|
||||
export interface Summary {
|
||||
mentor_id: string;
|
||||
participants: Participant[];
|
||||
export interface LearningMentorSummary {
|
||||
participant_relations: AgentParticipantRelation[];
|
||||
circles: Circle[];
|
||||
assignments: Assignment[];
|
||||
}
|
||||
|
|
@ -51,7 +58,7 @@ export const useLearningMentees = (
|
|||
courseSessionId: string | Ref<string> | (() => string)
|
||||
) => {
|
||||
const isLoading = ref(false);
|
||||
const summary: Ref<Summary | null> = ref(null);
|
||||
const summary: Ref<LearningMentorSummary | null> = ref(null);
|
||||
const error = ref(null);
|
||||
|
||||
const getAssignmentById = (id: string): Assignment | null => {
|
||||
|
|
|
|||
|
|
@ -468,15 +468,16 @@ export interface ExpertSessionUser extends CourseSessionUser {
|
|||
role: "EXPERT";
|
||||
}
|
||||
|
||||
export interface Mentor {
|
||||
export interface Agent {
|
||||
id: number;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
}
|
||||
|
||||
export interface LearningMentor {
|
||||
export interface AgentParticipantRelation {
|
||||
id: number;
|
||||
mentor: Mentor;
|
||||
role: "LEARNING_MENTOR";
|
||||
agent: Agent;
|
||||
}
|
||||
|
||||
export type CourseSessionDetail = CourseSessionObjectType;
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ def send_learning_mentor_invitation():
|
|||
recipient_email="daniel.egger+sendgrid@gmail.com",
|
||||
template=EmailTemplate.LEARNING_MENTOR_INVITATION,
|
||||
template_data={
|
||||
"inviter_name": f"Daniel Egger",
|
||||
"inviter_name": "Daniel Egger",
|
||||
"inviter_email": "daniel.egger@example.com",
|
||||
"target_url": f"https://stage.vbv-afa.ch/foobar",
|
||||
"target_url": "https://stage.vbv-afa.ch/foobar",
|
||||
},
|
||||
template_language="de",
|
||||
fail_silently=True,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,10 @@ from vbv_lernwelt.course.services import mark_course_completion
|
|||
from vbv_lernwelt.course_session.models import CourseSessionAttendanceCourse
|
||||
from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus
|
||||
from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
MentorInvitation,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import (
|
||||
LearningContentAttendanceCourse,
|
||||
LearningContentFeedbackUK,
|
||||
|
|
@ -144,7 +147,8 @@ def command(
|
|||
SelfEvaluationFeedback.objects.all().delete()
|
||||
CourseCompletionFeedback.objects.all().delete()
|
||||
|
||||
LearningMentor.objects.all().delete()
|
||||
AgentParticipantRelation.objects.all().delete()
|
||||
# LearningMentor.objects.all().delete()
|
||||
MentorInvitation.objects.all().delete()
|
||||
User.objects.all().update(organisation=Organisation.objects.first())
|
||||
User.objects.all().update(language="de")
|
||||
|
|
@ -414,48 +418,40 @@ def command(
|
|||
|
||||
if create_learning_mentor:
|
||||
cs_bern = CourseSession.objects.get(id=TEST_COURSE_SESSION_BERN_ID)
|
||||
|
||||
uk_mentor = LearningMentor.objects.create(
|
||||
mentor=User.objects.get(id=TEST_MENTOR1_USER_ID),
|
||||
course_session=cs_bern,
|
||||
)
|
||||
uk_mentor.participants.add(
|
||||
CourseSessionUser.objects.get(
|
||||
user__id=TEST_STUDENT1_USER_ID,
|
||||
course_session=cs_bern,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=User.objects.get(id=TEST_MENTOR1_USER_ID),
|
||||
participant=CourseSessionUser.objects.get(
|
||||
user__id=TEST_STUDENT1_USER_ID, course_session=cs_bern
|
||||
),
|
||||
role="LEARNING_MENTOR",
|
||||
)
|
||||
|
||||
vv_course = Course.objects.get(id=COURSE_VERSICHERUNGSVERMITTLERIN_ID)
|
||||
vv_course_session = CourseSession.objects.get(course=vv_course)
|
||||
vv_mentor = LearningMentor.objects.create(
|
||||
mentor=User.objects.get(id=TEST_MENTOR1_USER_ID),
|
||||
course_session=vv_course_session,
|
||||
)
|
||||
|
||||
vv_mentor.participants.add(
|
||||
CourseSessionUser.objects.get(
|
||||
user__id=TEST_STUDENT1_VV_USER_ID, course_session=vv_course_session
|
||||
)
|
||||
)
|
||||
|
||||
vv_mentor.participants.add(
|
||||
CourseSessionUser.objects.get(
|
||||
user__id=TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID,
|
||||
course_session=vv_course_session,
|
||||
)
|
||||
)
|
||||
|
||||
vv_student_and_mentor = LearningMentor.objects.create(
|
||||
mentor=User.objects.get(id=TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID),
|
||||
course_session=vv_course_session,
|
||||
)
|
||||
|
||||
vv_student_and_mentor.participants.add(
|
||||
CourseSessionUser.objects.get(
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=User.objects.get(id=TEST_MENTOR1_USER_ID),
|
||||
participant=CourseSessionUser.objects.get(
|
||||
user__id=TEST_STUDENT1_VV_USER_ID,
|
||||
course_session=vv_course_session,
|
||||
)
|
||||
),
|
||||
role="LEARNING_MENTOR",
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=User.objects.get(id=TEST_MENTOR1_USER_ID),
|
||||
participant=CourseSessionUser.objects.get(
|
||||
user__id=TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID,
|
||||
course_session=vv_course_session,
|
||||
),
|
||||
role="LEARNING_MENTOR",
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=User.objects.get(id=TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID),
|
||||
participant=CourseSessionUser.objects.get(
|
||||
user__id=TEST_STUDENT1_VV_USER_ID,
|
||||
course_session=vv_course_session,
|
||||
),
|
||||
role="LEARNING_MENTOR",
|
||||
)
|
||||
|
||||
course = Course.objects.get(id=COURSE_TEST_ID)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ from vbv_lernwelt.course_session.models import (
|
|||
)
|
||||
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
|
||||
from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import Circle
|
||||
from vbv_lernwelt.notify.models import Notification
|
||||
|
||||
|
|
@ -71,7 +74,7 @@ def create_or_update_uk(language="de"):
|
|||
cs = CourseSession.objects.get(import_id=data["ID"])
|
||||
|
||||
members, trainer, regionenleiter = get_or_create_users_uk()
|
||||
delete_cs_data(cs, members + [trainer, regionenleiter])
|
||||
delete_cs_data(cs)
|
||||
|
||||
add_to_course_session(cs, members)
|
||||
add_trainers_to_course_session(cs, [trainer], uk_circle_keys, language)
|
||||
|
|
@ -89,13 +92,13 @@ def create_or_update_vv(language="de"):
|
|||
|
||||
create_or_update_assignment_course_session(cs)
|
||||
members, member_with_mentor, mentor = get_or_create_users_vv()
|
||||
delete_cs_data(cs, members + [member_with_mentor, mentor])
|
||||
delete_cs_data(cs)
|
||||
|
||||
add_to_course_session(cs, members + [member_with_mentor])
|
||||
add_mentor_to_course_session(cs, [(mentor, member_with_mentor)])
|
||||
|
||||
|
||||
def delete_cs_data(cs: CourseSession, users: list[User]):
|
||||
def delete_cs_data(cs: CourseSession):
|
||||
if cs:
|
||||
CourseCompletion.objects.filter(course_session=cs).delete()
|
||||
Notification.objects.filter(course_session=cs).delete()
|
||||
|
|
@ -105,16 +108,8 @@ def delete_cs_data(cs: CourseSession, users: list[User]):
|
|||
)
|
||||
CourseSessionEdoniqTest.objects.filter(course_session=cs).delete()
|
||||
CourseSessionUser.objects.filter(course_session=cs).delete()
|
||||
learning_mentor_ids = (
|
||||
LearningMentor.objects.filter(participants__course_session=cs)
|
||||
.values_list("id", flat=True)
|
||||
.distinct()
|
||||
| LearningMentor.objects.filter(mentor__in=users)
|
||||
.values_list("id", flat=True)
|
||||
.distinct()
|
||||
)
|
||||
# cannot call delete on distinct objects
|
||||
LearningMentor.objects.filter(id__in=list(learning_mentor_ids)).delete()
|
||||
|
||||
AgentParticipantRelation.objects.filter(course_session=cs).delete()
|
||||
else:
|
||||
logger.info("no_course_session_found", import_id=cs.import_id)
|
||||
|
||||
|
|
@ -138,15 +133,12 @@ def add_mentor_to_course_session(
|
|||
course_session: CourseSession, mentor_mentee_pairs: list[tuple[User, User]]
|
||||
):
|
||||
for mentor, mentee in mentor_mentee_pairs:
|
||||
lm = LearningMentor.objects.create(
|
||||
course_session=course_session,
|
||||
mentor=mentor,
|
||||
)
|
||||
lm.participants.add(
|
||||
CourseSessionUser.objects.get(
|
||||
user__id=mentee.id,
|
||||
course_session=course_session,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor,
|
||||
participant=CourseSessionUser.objects.get(
|
||||
user__id=mentee.id, course_session=course_session
|
||||
),
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -131,6 +131,20 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
return instance
|
||||
|
||||
|
||||
class UserShortSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
"id",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"email",
|
||||
"username",
|
||||
"avatar_url",
|
||||
"language",
|
||||
]
|
||||
|
||||
|
||||
class CypressUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
|
|
|
|||
|
|
@ -41,7 +41,10 @@ from vbv_lernwelt.course_session.models import (
|
|||
)
|
||||
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
|
||||
from vbv_lernwelt.duedate.models import DueDate
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import (
|
||||
Circle,
|
||||
LearningContentAssignment,
|
||||
|
|
@ -101,13 +104,13 @@ def create_course_session(
|
|||
|
||||
|
||||
def add_learning_mentor(
|
||||
course_session: CourseSession, mentor: User, mentee: CourseSessionUser
|
||||
) -> LearningMentor:
|
||||
learning_mentor = LearningMentor.objects.create(
|
||||
course_session=course_session, mentor=mentor
|
||||
mentor: User, mentee: CourseSessionUser
|
||||
) -> AgentParticipantRelation:
|
||||
return AgentParticipantRelation.objects.create(
|
||||
agent=mentor,
|
||||
participant=mentee,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
learning_mentor.participants.add(mentee)
|
||||
return learning_mentor
|
||||
|
||||
|
||||
def add_course_session_user(
|
||||
|
|
|
|||
|
|
@ -45,10 +45,7 @@ from vbv_lernwelt.competence.create_vv_new_competence_profile import (
|
|||
create_vv_new_competence_profile,
|
||||
)
|
||||
from vbv_lernwelt.competence.models import PerformanceCriteria
|
||||
from vbv_lernwelt.core.constants import (
|
||||
TEST_MENTOR1_USER_ID,
|
||||
TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID,
|
||||
)
|
||||
from vbv_lernwelt.core.constants import TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID
|
||||
from vbv_lernwelt.core.create_default_users import default_users
|
||||
from vbv_lernwelt.core.models import User
|
||||
from vbv_lernwelt.course.consts import (
|
||||
|
|
@ -95,7 +92,6 @@ from vbv_lernwelt.importer.services import (
|
|||
import_students_from_excel,
|
||||
import_trainers_from_excel_for_training,
|
||||
)
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learnpath.create_vv_new_learning_path import (
|
||||
create_vv_motorfahrzeug_pruefung_learning_path,
|
||||
create_vv_new_learning_path,
|
||||
|
|
@ -243,6 +239,11 @@ def create_versicherungsvermittlerin_course(
|
|||
course_session=cs,
|
||||
user=User.objects.get(username="student-vv@eiger-versicherungen.ch"),
|
||||
)
|
||||
mentor_and_student_2_learning_csu = CourseSessionUser.objects.create(
|
||||
course_session=cs,
|
||||
user=User.objects.get(id=TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID),
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
CourseSessionUser.objects.create(
|
||||
course_session=cs,
|
||||
|
|
@ -262,30 +263,6 @@ def create_versicherungsvermittlerin_course(
|
|||
role=CourseSessionUser.Role.EXPERT,
|
||||
)
|
||||
|
||||
mentor_and_student_2_learning_csu = CourseSessionUser.objects.create(
|
||||
course_session=cs,
|
||||
user=User.objects.get(id=TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID),
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
# TEST_MENTOR1_USER_ID is only mentor
|
||||
just_mentor = LearningMentor.objects.create(
|
||||
mentor=User.objects.get(id=TEST_MENTOR1_USER_ID),
|
||||
course_session=cs,
|
||||
)
|
||||
|
||||
just_mentor.participants.add(student_1_csu)
|
||||
just_mentor.participants.add(mentor_and_student_2_learning_csu)
|
||||
|
||||
# TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID is both student and mentor
|
||||
|
||||
mentor_and_student_learning_mentor = LearningMentor.objects.create(
|
||||
mentor=User.objects.get(id=TEST_STUDENT2_VV_AND_VV_MENTOR_USER_ID),
|
||||
course_session=cs,
|
||||
)
|
||||
|
||||
mentor_and_student_learning_mentor.participants.add(student_1_csu)
|
||||
|
||||
for admin_email in ADMIN_EMAILS:
|
||||
CourseSessionUser.objects.create(
|
||||
course_session=cs,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
# Generated by Django 3.2.25 on 2024-07-17 14:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
import vbv_lernwelt.course.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("course", "0008_auto_20240403_1132"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="coursecompletion",
|
||||
name="completion_status",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("SUCCESS", "Success"),
|
||||
("FAIL", "Fail"),
|
||||
("UNKNOWN", "Unknown"),
|
||||
],
|
||||
default=vbv_lernwelt.course.models.CourseCompletionStatus["UNKNOWN"],
|
||||
max_length=255,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
@ -27,7 +27,7 @@ from vbv_lernwelt.iam.permissions import (
|
|||
has_course_access_by_page_request,
|
||||
is_circle_expert,
|
||||
)
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
|
@ -155,9 +155,10 @@ def get_course_sessions(request):
|
|||
|
||||
# enrich with mentor course sessions
|
||||
mentor_course_sessions = CourseSession.objects.filter(
|
||||
id__in=LearningMentor.objects.filter(mentor=request.user).values_list(
|
||||
"course_session", flat=True
|
||||
)
|
||||
id__in=[
|
||||
rel.participant.course_session_id
|
||||
for rel in AgentParticipantRelation.objects.filter(agent=request.user)
|
||||
]
|
||||
).prefetch_related("course")
|
||||
|
||||
all_to_serialize = (
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ from vbv_lernwelt.iam.permissions import (
|
|||
can_view_course_session_group_statistics,
|
||||
can_view_course_session_progress,
|
||||
)
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import Circle
|
||||
|
||||
|
||||
|
|
@ -95,12 +98,15 @@ class DashboardQuery(graphene.ObjectType):
|
|||
mentees_ids = set()
|
||||
course_session_ids = set()
|
||||
|
||||
mentees = CourseSessionUser.objects.filter(
|
||||
participants__mentor=user, course_session__course=course
|
||||
).values_list("user", "course_session")
|
||||
for user_id, course_session_id in mentees:
|
||||
mentees_ids.add(user_id)
|
||||
course_session_ids.add(course_session_id)
|
||||
relations_qs = AgentParticipantRelation.objects.filter(
|
||||
agent=user,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
participant__course_session__course=course,
|
||||
)
|
||||
|
||||
for relation in relations_qs:
|
||||
mentees_ids.add(relation.participant.user_id)
|
||||
course_session_ids.add(relation.participant.course_session_id)
|
||||
|
||||
return CourseStatisticsType(
|
||||
_id=f"mentor:{course.id}", # noqa
|
||||
|
|
@ -249,29 +255,31 @@ def get_user_statistics_dashboards(user: User) -> Tuple[List[Dict[str, str]], Se
|
|||
def get_learning_mentor_dashboards(
|
||||
user: User, exclude_course_ids: Set[int]
|
||||
) -> Tuple[List[Dict[str, str]], Set[int]]:
|
||||
learning_mentor = LearningMentor.objects.filter(mentor=user).exclude(
|
||||
course_session__course__id__in=exclude_course_ids
|
||||
)
|
||||
learning_mentor_relation_qs = AgentParticipantRelation.objects.filter(
|
||||
agent=user, role=AgentParticipantRoleType.LEARNING_MENTOR.value
|
||||
).exclude(participant__course_session__course__id__in=exclude_course_ids)
|
||||
|
||||
dashboards = []
|
||||
course_ids = set()
|
||||
|
||||
for mentor in learning_mentor:
|
||||
course = mentor.course_session.course
|
||||
course_ids.add(course.id)
|
||||
for rel in learning_mentor_relation_qs:
|
||||
course = rel.participant.course_session.course
|
||||
if course.id in UK_COURSE_IDS:
|
||||
dashboard_type = DashboardType.PRAXISBILDNER_DASHBOARD
|
||||
else:
|
||||
dashboard_type = DashboardType.MENTOR_DASHBOARD
|
||||
dashboards.append(
|
||||
{
|
||||
"id": str(course.id),
|
||||
"name": course.title,
|
||||
"slug": course.slug,
|
||||
"dashboard_type": dashboard_type,
|
||||
"course_configuration": course.configuration,
|
||||
}
|
||||
)
|
||||
|
||||
if course.id not in course_ids:
|
||||
course_ids.add(course.id)
|
||||
dashboards.append(
|
||||
{
|
||||
"id": str(course.id),
|
||||
"name": course.title,
|
||||
"slug": course.slug,
|
||||
"dashboard_type": dashboard_type,
|
||||
"course_configuration": course.configuration,
|
||||
}
|
||||
)
|
||||
|
||||
return dashboards, course_ids
|
||||
|
||||
|
|
|
|||
|
|
@ -110,22 +110,22 @@ class DashboardTestCase(GraphQLTestCase):
|
|||
|
||||
self.client.force_login(member)
|
||||
|
||||
query = f"""query($course_id: ID!) {{
|
||||
course_progress(course_id: $course_id) {{
|
||||
query = """query($course_id: ID!) {
|
||||
course_progress(course_id: $course_id) {
|
||||
course_id
|
||||
session_to_continue_id
|
||||
competence {{
|
||||
competence {
|
||||
total_count
|
||||
success_count
|
||||
fail_count
|
||||
}}
|
||||
assignment {{
|
||||
}
|
||||
assignment {
|
||||
total_count
|
||||
points_max_count
|
||||
points_achieved_count
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
variables = {"course_id": str(course.id)}
|
||||
|
|
@ -268,7 +268,7 @@ class DashboardTestCase(GraphQLTestCase):
|
|||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
add_learning_mentor(course_session=cs_1, mentor=mentor, mentee=csu)
|
||||
add_learning_mentor(mentor=mentor, mentee=csu)
|
||||
|
||||
self.client.force_login(mentor)
|
||||
|
||||
|
|
@ -287,6 +287,7 @@ class DashboardTestCase(GraphQLTestCase):
|
|||
|
||||
# THEN
|
||||
self.assertResponseNoErrors(response)
|
||||
print(response.json())
|
||||
|
||||
self.assertEqual(len(response.json()["data"]["dashboard_config"]), 1)
|
||||
self.assertEqual(
|
||||
|
|
@ -314,7 +315,7 @@ class DashboardTestCase(GraphQLTestCase):
|
|||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
add_learning_mentor(course_session=cs, mentor=mentor_and_member, mentee=mentee)
|
||||
add_learning_mentor(mentor=mentor_and_member, mentee=mentee)
|
||||
|
||||
# WHEN
|
||||
self.client.force_login(mentor_and_member)
|
||||
|
|
@ -350,11 +351,11 @@ class DashboardTestCase(GraphQLTestCase):
|
|||
|
||||
self.client.force_login(disallowed_user)
|
||||
|
||||
query = f"""query($course_id: ID!) {{
|
||||
course_statistics(course_id: $course_id) {{
|
||||
query = """query($course_id: ID!) {
|
||||
course_statistics(course_id: $course_id) {
|
||||
course_id
|
||||
}}
|
||||
}}
|
||||
}
|
||||
}
|
||||
"""
|
||||
variables = {"course_id": str(course.id)}
|
||||
|
||||
|
|
@ -384,13 +385,13 @@ class DashboardTestCase(GraphQLTestCase):
|
|||
|
||||
self.client.force_login(supervisor)
|
||||
|
||||
query = f"""query($course_id: ID!) {{
|
||||
course_statistics(course_id: $course_id) {{
|
||||
query = """query($course_id: ID!) {
|
||||
course_statistics(course_id: $course_id) {
|
||||
course_id
|
||||
course_title
|
||||
course_slug
|
||||
}}
|
||||
}}
|
||||
}
|
||||
}
|
||||
"""
|
||||
variables = {"course_id": str(course_2.id)}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from vbv_lernwelt.assignment.models import (
|
|||
from vbv_lernwelt.course.creators.test_utils import add_course_session_user, create_user
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.dashboard.tests.test_views import BaseMentorAssignmentTestCase
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
|
||||
|
||||
class MentorStatisticsTestCase(BaseMentorAssignmentTestCase, GraphQLTestCase):
|
||||
|
|
@ -19,15 +19,13 @@ class MentorStatisticsTestCase(BaseMentorAssignmentTestCase, GraphQLTestCase):
|
|||
self.course.configuration.save()
|
||||
|
||||
self.mentor = create_user("mentor")
|
||||
self.lm = LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
)
|
||||
self.participants = [create_user(f"participant{i}") for i in range(4)]
|
||||
|
||||
def test_assignment_statistics(self):
|
||||
# WHEN
|
||||
has_lb = [True, True, True, False]
|
||||
has_passed = [True, False, True, False]
|
||||
|
||||
for i in range(4):
|
||||
csu = add_course_session_user(
|
||||
self.course_session,
|
||||
|
|
@ -35,7 +33,9 @@ class MentorStatisticsTestCase(BaseMentorAssignmentTestCase, GraphQLTestCase):
|
|||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
if has_lb[i]:
|
||||
self.lm.participants.add(csu)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
AssignmentCompletion.objects.create(
|
||||
course_session=self.course_session,
|
||||
|
|
@ -47,22 +47,22 @@ class MentorStatisticsTestCase(BaseMentorAssignmentTestCase, GraphQLTestCase):
|
|||
)
|
||||
# THEN
|
||||
# WHEN
|
||||
query = f"""query ($courseId: ID!) {{
|
||||
mentor_course_statistics(course_id: $courseId) {{
|
||||
query = """query ($courseId: ID!) {
|
||||
mentor_course_statistics(course_id: $courseId) {
|
||||
course_session_selection_ids
|
||||
user_selection_ids
|
||||
assignments {{
|
||||
assignments {
|
||||
_id
|
||||
summary {{
|
||||
summary {
|
||||
_id
|
||||
completed_count
|
||||
average_passed
|
||||
total_passed
|
||||
total_failed
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
}}"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
# THEN
|
||||
variables = {"courseId": str(self.course.id)}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ from vbv_lernwelt.dashboard.views import (
|
|||
get_course_config,
|
||||
get_course_sessions_with_roles_for_user,
|
||||
)
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
from vbv_lernwelt.learnpath.models import Circle, LearningUnit
|
||||
from vbv_lernwelt.self_evaluation_feedback.models import SelfEvaluationFeedback
|
||||
|
||||
|
|
@ -98,14 +98,16 @@ class GetCourseSessionsForUserTestCase(TestCase):
|
|||
|
||||
def test_learning_mentor_get_sessions(self):
|
||||
mentor = create_user("mentor")
|
||||
LearningMentor.objects.create(mentor=mentor, course_session=self.course_session)
|
||||
|
||||
participant = create_user("participant")
|
||||
add_course_session_user(
|
||||
csu = add_course_session_user(
|
||||
self.course_session,
|
||||
participant,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
sessions = get_course_sessions_with_roles_for_user(mentor)
|
||||
|
||||
|
|
@ -187,7 +189,16 @@ class GetDashboardConfig(TestCase):
|
|||
def test_mentor_uk_get_config(self):
|
||||
# GIVEN
|
||||
mentor = create_user("mentor")
|
||||
LearningMentor.objects.create(mentor=mentor, course_session=self.course_session)
|
||||
|
||||
participant = create_user("participant")
|
||||
csu = add_course_session_user(
|
||||
self.course_session,
|
||||
participant,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
self.course.configuration.is_uk = True
|
||||
self.course.configuration.save()
|
||||
|
|
@ -205,7 +216,15 @@ class GetDashboardConfig(TestCase):
|
|||
def test_mentor_vv_get_config(self):
|
||||
# GIVEN
|
||||
mentor = create_user("mentor")
|
||||
LearningMentor.objects.create(mentor=mentor, course_session=self.course_session)
|
||||
participant = create_user("participant")
|
||||
csu = add_course_session_user(
|
||||
self.course_session,
|
||||
participant,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
self.course.configuration.is_vv = True
|
||||
self.course.configuration.save()
|
||||
|
|
@ -228,7 +247,16 @@ class GetDashboardConfig(TestCase):
|
|||
mentor,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
LearningMentor.objects.create(mentor=mentor, course_session=self.course_session)
|
||||
|
||||
participant = create_user("participant")
|
||||
csu = add_course_session_user(
|
||||
self.course_session,
|
||||
participant,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
self.course.configuration.is_vv = True
|
||||
self.course.configuration.save()
|
||||
|
|
@ -264,9 +292,6 @@ class GetMenteeCountTestCase(TestCase):
|
|||
participants_with_mentor = [create_user(f"participant{i}") for i in range(2)]
|
||||
participant = create_user("participant")
|
||||
mentor = create_user("mentor")
|
||||
lm = LearningMentor.objects.create(
|
||||
mentor=mentor, course_session=self.course_session
|
||||
)
|
||||
|
||||
# WHEN
|
||||
for p in participants_with_mentor:
|
||||
|
|
@ -275,7 +300,9 @@ class GetMenteeCountTestCase(TestCase):
|
|||
p,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
lm.participants.add(csu)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
add_course_session_user(
|
||||
self.course_session,
|
||||
|
|
@ -305,9 +332,6 @@ class GetMentorOpenTasksTestCase(BaseMentorAssignmentTestCase):
|
|||
self.course.configuration.save()
|
||||
|
||||
self.mentor = create_user("mentor")
|
||||
self.lm = LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
)
|
||||
self.participants = [create_user(f"participant{i}") for i in range(2)]
|
||||
|
||||
def create_and_test_count(
|
||||
|
|
@ -337,7 +361,10 @@ class GetMentorOpenTasksTestCase(BaseMentorAssignmentTestCase):
|
|||
self.participants[0],
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
self.lm.participants.add(csu)
|
||||
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
add_course_session_user(
|
||||
self.course_session,
|
||||
|
|
@ -367,7 +394,9 @@ class GetMentorOpenTasksTestCase(BaseMentorAssignmentTestCase):
|
|||
self.participants[0],
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
self.lm.participants.add(csu)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
add_course_session_user(
|
||||
self.course_session,
|
||||
|
|
@ -389,8 +418,9 @@ class GetMentorOpenTasksTestCase(BaseMentorAssignmentTestCase):
|
|||
self.participants[0],
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
self.lm.participants.add(csu)
|
||||
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
SelfEvaluationFeedback.objects.create(
|
||||
feedback_submitted=False,
|
||||
feedback_requester_user=self.participants[0],
|
||||
|
|
@ -411,8 +441,9 @@ class GetMentorOpenTasksTestCase(BaseMentorAssignmentTestCase):
|
|||
self.participants[0],
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
self.lm.participants.add(csu)
|
||||
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
SelfEvaluationFeedback.objects.create(
|
||||
feedback_submitted=True,
|
||||
feedback_requester_user=self.participants[0],
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ from vbv_lernwelt.feedback.export import (
|
|||
export_feedback_with_circle_restriction,
|
||||
FEEDBACK_EXPORT_FILE_NAME,
|
||||
)
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import Circle
|
||||
from vbv_lernwelt.self_evaluation_feedback.models import SelfEvaluationFeedback
|
||||
|
||||
|
|
@ -118,15 +121,15 @@ def get_course_sessions_with_roles_for_user(user: User) -> List[CourseSessionWit
|
|||
result_course_sessions[cs.id] = cs
|
||||
|
||||
# enrich with mentor course sessions
|
||||
lm_qs = LearningMentor.objects.filter(mentor=user).prefetch_related(
|
||||
"course_session", "course_session__course"
|
||||
lm_qs = AgentParticipantRelation.objects.filter(agent=user).prefetch_related(
|
||||
"participant__course_session", "participant__course_session__course"
|
||||
)
|
||||
for lm in lm_qs:
|
||||
cs = lm.course_session
|
||||
cs = lm.participant.course_session
|
||||
cs.roles = set()
|
||||
cs = result_course_sessions.get(cs.id, cs)
|
||||
|
||||
cs.roles.add("LEARNING_MENTOR")
|
||||
cs.roles.add(lm.role)
|
||||
result_course_sessions[cs.id] = cs
|
||||
|
||||
return [
|
||||
|
|
@ -197,46 +200,46 @@ def _create_person_list_with_roles(user):
|
|||
# add persons where request.user is mentor
|
||||
for cs in course_sessions:
|
||||
if "LEARNING_MENTOR" in cs.roles:
|
||||
lm = LearningMentor.objects.filter(
|
||||
mentor=user, course_session=cs.id
|
||||
).first()
|
||||
|
||||
for participant in lm.participants.all():
|
||||
for relation in AgentParticipantRelation.objects.filter(
|
||||
agent=user, participant__course_session_id=cs.id
|
||||
):
|
||||
course_session_entry = _create_course_session_dict(
|
||||
cs,
|
||||
"LEARNING_MENTOR",
|
||||
"LEARNING_MENTEE",
|
||||
)
|
||||
participant_user = relation.participant.user
|
||||
|
||||
if participant.user.id not in result_persons:
|
||||
person_data = create_user_dict(participant.user)
|
||||
if participant_user.id not in result_persons:
|
||||
person_data = create_user_dict(participant_user)
|
||||
person_data["course_sessions"] = [course_session_entry]
|
||||
result_persons[participant.user.id] = person_data
|
||||
result_persons[participant_user] = person_data
|
||||
else:
|
||||
# user is already in result_persons
|
||||
result_persons[participant.user.id]["course_sessions"].append(
|
||||
result_persons[participant_user]["course_sessions"].append(
|
||||
course_session_entry
|
||||
)
|
||||
|
||||
# add persons where request.user is mentee
|
||||
mentor_relation_qs = LearningMentor.objects.filter(
|
||||
participants__user=user
|
||||
).prefetch_related("mentor", "course_session")
|
||||
mentor_relation_qs = AgentParticipantRelation.objects.filter(
|
||||
participant__user=user,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
).prefetch_related("agent")
|
||||
for mentor_relation in mentor_relation_qs:
|
||||
cs = mentor_relation.course_session
|
||||
cs = mentor_relation.participant.course_session
|
||||
course_session_entry = _create_course_session_dict(
|
||||
cs,
|
||||
"LEARNING_MENTEE",
|
||||
"LEARNING_MENTOR",
|
||||
)
|
||||
|
||||
if mentor_relation.mentor.id not in result_persons:
|
||||
person_data = create_user_dict(mentor_relation.mentor)
|
||||
if mentor_relation.agent.id not in result_persons:
|
||||
person_data = create_user_dict(mentor_relation.agent)
|
||||
person_data["course_sessions"] = [course_session_entry]
|
||||
result_persons[mentor_relation.mentor.id] = person_data
|
||||
result_persons[mentor_relation.agent.id] = person_data
|
||||
else:
|
||||
# user is already in result_persons
|
||||
result_persons[mentor_relation.mentor.id]["course_sessions"].append(
|
||||
result_persons[mentor_relation.agent.id]["course_sessions"].append(
|
||||
course_session_entry
|
||||
)
|
||||
|
||||
|
|
@ -495,8 +498,10 @@ def get_mentee_count(request, course_id: str):
|
|||
|
||||
|
||||
def _get_mentee_count(course_id: str, mentor: User) -> int:
|
||||
return CourseSessionUser.objects.filter(
|
||||
participants__mentor=mentor, course_session__course__id=course_id
|
||||
return AgentParticipantRelation.objects.filter(
|
||||
agent=mentor,
|
||||
participant__course_session__course_id=course_id,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
).count()
|
||||
|
||||
|
||||
|
|
@ -524,17 +529,26 @@ def _get_mentor_open_tasks_count(course_id: str, mentor: User) -> int:
|
|||
|
||||
course_configuration = CourseConfiguration.objects.get(course_id=course_id)
|
||||
|
||||
learning_meentee_ids = [
|
||||
str(relation.participant.user_id)
|
||||
for relation in AgentParticipantRelation.objects.filter(
|
||||
agent=mentor,
|
||||
participant__course_session__course_id=course_id,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
).prefetch_related("participant")
|
||||
]
|
||||
|
||||
if course_configuration.is_vv:
|
||||
open_assigment_count = AssignmentCompletion.objects.filter(
|
||||
course_session__course__id=course_id,
|
||||
completion_status=AssignmentCompletionStatus.SUBMITTED.value,
|
||||
evaluation_user=mentor, # noqa
|
||||
assignment_user__coursesessionuser__participants__mentor=mentor,
|
||||
assignment_user_id__in=learning_meentee_ids,
|
||||
).count()
|
||||
|
||||
open_feedback_qs = SelfEvaluationFeedback.objects.filter(
|
||||
feedback_provider_user=mentor, # noqa
|
||||
feedback_requester_user__coursesessionuser__participants__mentor=mentor,
|
||||
feedback_requester_user_id__in=learning_meentee_ids,
|
||||
feedback_submitted=False,
|
||||
)
|
||||
# filter open feedbacks for course_id (-> not possible with queryset)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
from vbv_lernwelt.core.models import User
|
||||
from vbv_lernwelt.course.models import Course, CourseSession, CourseSessionUser
|
||||
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import LearningSequence
|
||||
|
||||
|
||||
|
|
@ -22,8 +25,8 @@ def has_course_access(user, course_id):
|
|||
).exists():
|
||||
return True
|
||||
|
||||
if LearningMentor.objects.filter(
|
||||
course_session__course_id=course_id, mentor=user
|
||||
if AgentParticipantRelation.objects.filter(
|
||||
agent=user, participant__course_session__course_id=course_id
|
||||
).exists():
|
||||
return True
|
||||
|
||||
|
|
@ -72,8 +75,9 @@ def is_course_session_learning_mentor(mentor: User, course_session_id: int):
|
|||
if course_session is None:
|
||||
return False
|
||||
|
||||
return LearningMentor.objects.filter(
|
||||
mentor=mentor, course_session=course_session
|
||||
return AgentParticipantRelation.objects.filter(
|
||||
agent=mentor,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
).exists()
|
||||
|
||||
|
||||
|
|
@ -87,9 +91,11 @@ def is_learning_mentor_for_user(
|
|||
if csu is None:
|
||||
return False
|
||||
|
||||
return LearningMentor.objects.filter(
|
||||
course_session_id=course_session_id, mentor=mentor, participants=csu
|
||||
).exists()
|
||||
return AgentParticipantRelation.objects.filter(
|
||||
agent=mentor,
|
||||
participant=csu,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
|
||||
def is_course_session_supervisor(user, course_session_id: int):
|
||||
|
|
@ -222,8 +228,8 @@ def has_role_in_course(user: User, course: Course) -> bool:
|
|||
).exists():
|
||||
return True
|
||||
|
||||
if LearningMentor.objects.filter(
|
||||
course_session__course=course, mentor=user
|
||||
if AgentParticipantRelation.objects.filter(
|
||||
agent=user, participant__course_session__course=course
|
||||
).exists():
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from vbv_lernwelt.course.creators.test_utils import (
|
|||
)
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.iam.permissions import course_session_permissions
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
|
||||
|
||||
class ActionTestCase(TestCase):
|
||||
|
|
@ -21,14 +21,16 @@ class ActionTestCase(TestCase):
|
|||
def test_course_session_permissions(self):
|
||||
# GIVEN
|
||||
lm = create_user("mentor")
|
||||
LearningMentor.objects.create(mentor=lm, course_session=self.course_session)
|
||||
|
||||
participant = create_user("participant")
|
||||
add_course_session_user(
|
||||
csu = add_course_session_user(
|
||||
self.course_session,
|
||||
participant,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=lm, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
trainer = create_user("trainer")
|
||||
add_course_session_user(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from vbv_lernwelt.course.creators.test_utils import (
|
|||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
|
||||
from vbv_lernwelt.iam.permissions import has_role_in_course, is_learning_mentor_for_user
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
|
||||
|
||||
class RoleTestCase(TestCase):
|
||||
|
|
@ -48,9 +48,14 @@ class RoleTestCase(TestCase):
|
|||
|
||||
def test_has_role_mentor(self):
|
||||
# GIVEN
|
||||
LearningMentor.objects.create(
|
||||
mentor=self.user,
|
||||
course_session=self.course_session,
|
||||
participant = create_user("participant")
|
||||
csu = add_course_session_user(
|
||||
self.course_session,
|
||||
participant,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.user, participant=csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
# WHEN
|
||||
|
|
@ -73,14 +78,10 @@ class RoleTestCase(TestCase):
|
|||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
learning_mentor = LearningMentor.objects.create(
|
||||
mentor=mentor,
|
||||
course_session=course_session,
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor, participant=member_csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
learning_mentor.participants.add(member_csu)
|
||||
learning_mentor.save()
|
||||
|
||||
# WHEN
|
||||
is_mentor = is_learning_mentor_for_user(
|
||||
mentor=mentor,
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class CreateOrUpdateCourseSessionTestCase(TestCase):
|
|||
attendance_course.due_date.end.isoformat(), "2023-06-06T13:00:00+00:00"
|
||||
)
|
||||
self.assertEqual(
|
||||
f"E64, HKV Aarau, Bahnhofstrasse 460, 5001, Aarau",
|
||||
"E64, HKV Aarau, Bahnhofstrasse 460, 5001, Aarau",
|
||||
attendance_course.location,
|
||||
)
|
||||
self.assertEqual("", attendance_course.trainer)
|
||||
|
|
@ -183,7 +183,7 @@ class CreateOrUpdateCourseSessionTestCase(TestCase):
|
|||
attendance_course.due_date.end.isoformat(), "2023-06-06T15:00:00+00:00"
|
||||
)
|
||||
self.assertEqual(
|
||||
f"E666, HKV Aarau2, Bahnhofstrasse 460, 5002, Aarau",
|
||||
"E666, HKV Aarau2, Bahnhofstrasse 460, 5002, Aarau",
|
||||
attendance_course.location,
|
||||
)
|
||||
self.assertEqual(
|
||||
|
|
|
|||
|
|
@ -1,34 +1,29 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
MentorInvitation,
|
||||
)
|
||||
|
||||
|
||||
@admin.register(LearningMentor)
|
||||
class LearningMentorAdmin(admin.ModelAdmin):
|
||||
def participant_count(self, obj):
|
||||
return obj.participants.count()
|
||||
@admin.register(AgentParticipantRelation)
|
||||
class TrainerParticipantRelationAdmin(admin.ModelAdmin):
|
||||
list_display = ["agent", "participant", "role"]
|
||||
|
||||
participant_count.short_description = "Participants"
|
||||
|
||||
list_display = ["mentor", "course_session", "participant_count"]
|
||||
|
||||
search_fields = ["mentor__email"]
|
||||
|
||||
raw_id_fields = [
|
||||
"mentor",
|
||||
"course_session",
|
||||
search_fields = [
|
||||
"agent__email",
|
||||
"agent__first_name",
|
||||
"agent__last_name",
|
||||
"participant__user__email",
|
||||
"participant__user__first_name",
|
||||
"participant__user__last_name",
|
||||
]
|
||||
|
||||
def formfield_for_manytomany(self, db_field, request, **kwargs):
|
||||
if db_field.name == "participants":
|
||||
if request.resolver_match.kwargs.get("object_id"):
|
||||
object_id = str(request.resolver_match.kwargs.get("object_id"))
|
||||
lm = LearningMentor.objects.get(id=object_id)
|
||||
kwargs["queryset"] = CourseSessionUser.objects.filter(
|
||||
course_session=lm.course_session
|
||||
)
|
||||
return super().formfield_for_manytomany(db_field, request, **kwargs)
|
||||
raw_id_fields = [
|
||||
"agent",
|
||||
"participant",
|
||||
# "course_session",
|
||||
]
|
||||
|
||||
|
||||
@admin.register(MentorInvitation)
|
||||
|
|
|
|||
|
|
@ -6,4 +6,8 @@ class LearningMentorConfig(AppConfig):
|
|||
name = "vbv_lernwelt.learning_mentor"
|
||||
|
||||
def ready(self):
|
||||
import vbv_lernwelt.learning_mentor.signals # noqa F401
|
||||
try:
|
||||
# pylint: disable=unused-import,import-outside-toplevel
|
||||
import vbv_lernwelt.learning_mentor.signals # noqa F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
# Generated by Django 3.2.20 on 2024-07-18 13:33
|
||||
|
||||
import uuid
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("course", "0009_alter_coursecompletion_completion_status"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("learning_mentor", "0007_mentorinvitation_target_url"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="AgentParticipantRelation",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"role",
|
||||
models.CharField(
|
||||
choices=[("LEARNING_MENTOR", "LEARNING_MENTOR")],
|
||||
default="LEARNING_MENTOR",
|
||||
max_length=255,
|
||||
),
|
||||
),
|
||||
(
|
||||
"agent",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"participant",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="course.coursesessionuser",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"unique_together": {("agent", "participant")},
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2.20 on 2024-07-18 13:33
|
||||
from django.db import migrations
|
||||
from django.db.migrations import RunPython
|
||||
|
||||
|
||||
def refactor_mentor_to_agent_participant(apps=None, schema_editor=None):
|
||||
LearningMentor = apps.get_model("learning_mentor", "LearningMentor")
|
||||
AgentParticipantRelation = apps.get_model(
|
||||
"learning_mentor", "AgentParticipantRelation"
|
||||
)
|
||||
|
||||
for mentor in LearningMentor.objects.all():
|
||||
for participant in mentor.participants.all():
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=mentor.mentor,
|
||||
participant=participant,
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("learning_mentor", "0008_agentparticipantrelation"),
|
||||
]
|
||||
|
||||
operations = [RunPython(refactor_mentor_to_agent_participant)]
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import uuid
|
||||
from enum import Enum
|
||||
|
||||
from django.db import models
|
||||
from django_extensions.db.models import TimeStampedModel
|
||||
|
|
@ -30,6 +31,26 @@ class LearningMentor(models.Model):
|
|||
return self.participants.values_list("course_session", flat=True).distinct()
|
||||
|
||||
|
||||
class AgentParticipantRoleType(Enum):
|
||||
LEARNING_MENTOR = "LEARNING_MENTOR" # Lernbegleiter
|
||||
|
||||
|
||||
class AgentParticipantRelation(models.Model):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
|
||||
agent = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
participant = models.ForeignKey(CourseSessionUser, on_delete=models.CASCADE)
|
||||
|
||||
role = models.CharField(
|
||||
max_length=255,
|
||||
choices=[(t.value, t.value) for t in AgentParticipantRoleType],
|
||||
default=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
unique_together = [("agent", "participant")]
|
||||
|
||||
|
||||
class MentorInvitation(TimeStampedModel):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
email = models.EmailField()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from vbv_lernwelt.core.serializers import UserSerializer
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation
|
||||
from vbv_lernwelt.core.serializers import UserShortSerializer
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
MentorInvitation,
|
||||
)
|
||||
|
||||
|
||||
class MentorAssignmentCompletionSerializer(serializers.Serializer):
|
||||
|
|
@ -39,10 +42,24 @@ class InvitationSerializer(serializers.ModelSerializer):
|
|||
return invitation
|
||||
|
||||
|
||||
class MentorSerializer(serializers.ModelSerializer):
|
||||
mentor = UserSerializer(read_only=True)
|
||||
class AgentParticipantRelationSerializer(serializers.ModelSerializer):
|
||||
agent = UserShortSerializer(read_only=True)
|
||||
participant_user = serializers.SerializerMethodField()
|
||||
course_session_id = serializers.SerializerMethodField()
|
||||
|
||||
def get_participant_user(self, obj):
|
||||
return UserShortSerializer(obj.participant.user).data
|
||||
|
||||
def get_course_session_id(self, obj):
|
||||
return obj.participant.course_session_id
|
||||
|
||||
class Meta:
|
||||
model = LearningMentor
|
||||
fields = ["id", "mentor"]
|
||||
model = AgentParticipantRelation
|
||||
fields = [
|
||||
"id",
|
||||
"role",
|
||||
"course_session_id",
|
||||
"agent",
|
||||
"participant_user",
|
||||
]
|
||||
read_only_fields = ["id"]
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.db.models.signals import m2m_changed
|
||||
from django.dispatch import receiver
|
||||
|
||||
from .models import LearningMentor
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=LearningMentor.participants.through)
|
||||
def validate_student(sender, instance, action, reverse, model, pk_set, **kwargs):
|
||||
if action == "pre_add":
|
||||
participants = model.objects.filter(pk__in=pk_set)
|
||||
for participant in participants:
|
||||
if participant.course_session != instance.course_session:
|
||||
raise ValidationError(
|
||||
"Participant (CourseSessionUser) does not match the course for this mentor."
|
||||
)
|
||||
if participant.user == instance.mentor:
|
||||
raise ValidationError("You cannot mentor yourself.")
|
||||
|
|
@ -11,7 +11,11 @@ from vbv_lernwelt.course.creators.test_utils import (
|
|||
create_user,
|
||||
)
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
MentorInvitation,
|
||||
)
|
||||
from vbv_lernwelt.notify.email.email_services import EmailTemplate
|
||||
|
||||
|
||||
|
|
@ -254,13 +258,14 @@ class LearningMentorInvitationTest(APITestCase):
|
|||
# THEN
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertFalse(MentorInvitation.objects.filter(id=invitation.id).exists())
|
||||
self.assertTrue(
|
||||
LearningMentor.objects.filter(
|
||||
mentor=invitee,
|
||||
course_session=self.course_session,
|
||||
participants=participant_cs_user,
|
||||
).exists()
|
||||
)
|
||||
|
||||
relation_qs = AgentParticipantRelation.objects.all()
|
||||
self.assertEqual(relation_qs.count(), 1)
|
||||
relation = relation_qs.first()
|
||||
self.assertEqual(relation.agent, invitee)
|
||||
self.assertEqual(relation.participant, participant_cs_user)
|
||||
self.assertEqual(relation.participant.course_session, self.course_session)
|
||||
self.assertEqual(relation.role, AgentParticipantRoleType.LEARNING_MENTOR.value)
|
||||
|
||||
user = response.data["user"]
|
||||
self.assertEqual(user["id"], str(self.participant.id))
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ from vbv_lernwelt.course.creators.test_utils import (
|
|||
create_user,
|
||||
)
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.self_evaluation_feedback.models import SelfEvaluationFeedback
|
||||
|
||||
|
||||
|
|
@ -71,63 +74,56 @@ class LearningMentorAPITest(APITestCase):
|
|||
response = self.client.get(self.url)
|
||||
|
||||
# THEN
|
||||
print(response.data)
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_api_no_participants(self) -> None:
|
||||
# GIVEN
|
||||
self.client.force_login(self.mentor)
|
||||
LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
)
|
||||
|
||||
# WHEN
|
||||
response = self.client.get(self.url)
|
||||
|
||||
# THEN
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data["participants"], [])
|
||||
self.assertEqual(response.data["assignments"], [])
|
||||
print(response.data)
|
||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
def test_api_participants(self) -> None:
|
||||
# GIVEN
|
||||
participants = [self.participant_1, self.participant_2, self.participant_3]
|
||||
self.client.force_login(self.mentor)
|
||||
mentor = LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
)
|
||||
mentor.participants.set(participants)
|
||||
|
||||
for participant in participants:
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
# WHEN
|
||||
self.client.force_login(self.mentor)
|
||||
response = self.client.get(self.url)
|
||||
|
||||
# THEN
|
||||
print(response.data)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data["participants"]), len(participants))
|
||||
self.assertEqual(len(response.data["participant_relations"]), len(participants))
|
||||
|
||||
participant_1 = [
|
||||
p
|
||||
for p in response.data["participants"]
|
||||
if p["id"] == str(self.participant_1.user.id)
|
||||
][0]
|
||||
self.assertEqual(participant_1["email"], "participant_1@example.com")
|
||||
self.assertEqual(participant_1["first_name"], "Test")
|
||||
self.assertEqual(participant_1["last_name"], "Participant_1")
|
||||
rel1 = AgentParticipantRelation.objects.get(participant=self.participant_1)
|
||||
|
||||
self.assertEqual(
|
||||
response.data["mentor_id"],
|
||||
mentor.id,
|
||||
)
|
||||
self.assertEqual(rel1.participant.user.email, "participant_1@example.com")
|
||||
self.assertEqual(rel1.participant.user.first_name, "Test")
|
||||
self.assertEqual(rel1.participant.user.last_name, "Participant_1")
|
||||
|
||||
def test_api_self_evaluation_feedback(self) -> None:
|
||||
# GIVEN
|
||||
participants = [self.participant_1, self.participant_2, self.participant_3]
|
||||
self.client.force_login(self.mentor)
|
||||
|
||||
mentor = LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
)
|
||||
|
||||
mentor.participants.set(participants)
|
||||
for participant in participants:
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
learning_unit = create_learning_unit(
|
||||
circle=self.circle,
|
||||
|
|
@ -154,6 +150,7 @@ class LearningMentorAPITest(APITestCase):
|
|||
# ...
|
||||
|
||||
# WHEN
|
||||
self.client.force_login(self.mentor)
|
||||
response = self.client.get(self.url)
|
||||
|
||||
# THEN
|
||||
|
|
@ -194,7 +191,6 @@ class LearningMentorAPITest(APITestCase):
|
|||
|
||||
def test_api_praxis_assignments(self) -> None:
|
||||
# GIVEN
|
||||
self.client.force_login(self.mentor)
|
||||
|
||||
assignment = create_assignment(
|
||||
course=self.course, assignment_type=AssignmentType.PRAXIS_ASSIGNMENT
|
||||
|
|
@ -205,13 +201,13 @@ class LearningMentorAPITest(APITestCase):
|
|||
course_session=self.course_session, learning_content_assignment=lca
|
||||
)
|
||||
|
||||
mentor = LearningMentor.objects.create(
|
||||
mentor=self.mentor,
|
||||
course_session=self.course_session,
|
||||
)
|
||||
|
||||
participants = [self.participant_1, self.participant_2, self.participant_3]
|
||||
mentor.participants.set(participants)
|
||||
for participant in participants:
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
AssignmentCompletion.objects.create(
|
||||
assignment_user=self.participant_1.user,
|
||||
|
|
@ -230,6 +226,7 @@ class LearningMentorAPITest(APITestCase):
|
|||
)
|
||||
|
||||
# WHEN
|
||||
self.client.force_login(self.mentor)
|
||||
response = self.client.get(self.url)
|
||||
|
||||
# THEN
|
||||
|
|
@ -267,12 +264,12 @@ class LearningMentorAPITest(APITestCase):
|
|||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
learning_mentor = LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
db_relation = AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant_cs_user,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
learning_mentor.participants.add(participant_cs_user)
|
||||
|
||||
list_url = reverse(
|
||||
"list_user_mentors", kwargs={"course_session_id": self.course_session.id}
|
||||
)
|
||||
|
|
@ -281,12 +278,13 @@ class LearningMentorAPITest(APITestCase):
|
|||
response = self.client.get(list_url)
|
||||
|
||||
# THEN
|
||||
print(response.data)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
mentor = response.data[0]
|
||||
self.assertEqual(mentor["id"], learning_mentor.id)
|
||||
mentor_relation = response.data[0]
|
||||
self.assertEqual(mentor_relation["id"], str(db_relation.id))
|
||||
|
||||
mentor_user = mentor["mentor"]
|
||||
mentor_user = mentor_relation["agent"]
|
||||
self.assertEqual(mentor_user["email"], self.mentor.email)
|
||||
self.assertEqual(mentor_user["id"], str(self.mentor.id))
|
||||
|
||||
|
|
@ -300,18 +298,17 @@ class LearningMentorAPITest(APITestCase):
|
|||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
learning_mentor = LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
relation = AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant_cs_user,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
learning_mentor.participants.add(participant_cs_user)
|
||||
|
||||
remove_url = reverse(
|
||||
"remove_participant_from_mentor",
|
||||
"delete_agent_participant_relation",
|
||||
kwargs={
|
||||
"course_session_id": self.course_session.id,
|
||||
"mentor_id": learning_mentor.id,
|
||||
"participant_user_id": participant_cs_user.user.id,
|
||||
"relation_id": relation.id,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -320,9 +317,7 @@ class LearningMentorAPITest(APITestCase):
|
|||
|
||||
# THEN
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
self.assertFalse(
|
||||
LearningMentor.objects.filter(participants=participant_cs_user).exists()
|
||||
)
|
||||
self.assertEqual(AgentParticipantRelation.objects.count(), 0)
|
||||
|
||||
def test_remove_myself_from_mentor(self) -> None:
|
||||
# GIVEN
|
||||
|
|
@ -335,18 +330,17 @@ class LearningMentorAPITest(APITestCase):
|
|||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
learning_mentor = LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=self.course_session
|
||||
relation = AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant_cs_user,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
learning_mentor.participants.add(participant_cs_user)
|
||||
|
||||
remove_url = reverse(
|
||||
"remove_participant_from_mentor",
|
||||
"delete_agent_participant_relation",
|
||||
kwargs={
|
||||
"course_session_id": self.course_session.id,
|
||||
"mentor_id": learning_mentor.id,
|
||||
"participant_user_id": participant_cs_user.user.id,
|
||||
"relation_id": relation.id,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -355,26 +349,54 @@ class LearningMentorAPITest(APITestCase):
|
|||
|
||||
# THEN
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
self.assertFalse(
|
||||
LearningMentor.objects.filter(participants=participant_cs_user).exists()
|
||||
)
|
||||
self.assertEqual(AgentParticipantRelation.objects.count(), 0)
|
||||
|
||||
def test_mentor_multiple_courses(self) -> None:
|
||||
# GIVEN
|
||||
course_a, _ = create_course("Course A")
|
||||
course_session_a = create_course_session(course=course_a, title="Test A")
|
||||
participant_a = create_user("participant_a")
|
||||
participant_course_session_a = add_course_session_user(
|
||||
course_session_a,
|
||||
participant_a,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
course_b, _ = create_course("Course B")
|
||||
course_session_b = create_course_session(course=course_b, title="Test B")
|
||||
participant_b = create_user("participant_b")
|
||||
participant_course_session_b = add_course_session_user(
|
||||
course_session_b,
|
||||
participant_b,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
|
||||
# WHEN
|
||||
LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=course_session_a
|
||||
relation_a = AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant_course_session_a,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
relation_b = AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor,
|
||||
participant=participant_course_session_b,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
LearningMentor.objects.create(
|
||||
mentor=self.mentor, course_session=course_session_b
|
||||
self.client.force_login(self.mentor)
|
||||
|
||||
response_a = self.client.get(
|
||||
reverse("mentor_summary", kwargs={"course_session_id": course_session_a.id})
|
||||
)
|
||||
self.assertEqual(len(response_a.data["participant_relations"]), 1)
|
||||
self.assertEqual(
|
||||
response_a.data["participant_relations"][0]["id"], str(relation_a.id)
|
||||
)
|
||||
|
||||
# THEN
|
||||
self.assertEqual(LearningMentor.objects.count(), 2)
|
||||
response_b = self.client.get(
|
||||
reverse("mentor_summary", kwargs={"course_session_id": course_session_b.id})
|
||||
)
|
||||
self.assertEqual(len(response_b.data["participant_relations"]), 1)
|
||||
self.assertEqual(
|
||||
response_b.data["participant_relations"][0]["id"], str(relation_b.id)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ urlpatterns = [
|
|||
path("summary", views.mentor_summary, name="mentor_summary"),
|
||||
path("mentors", views.list_user_mentors, name="list_user_mentors"),
|
||||
path(
|
||||
"mentors/<int:mentor_id>/remove/<uuid:participant_user_id>",
|
||||
views.remove_participant_from_mentor,
|
||||
name="remove_participant_from_mentor",
|
||||
"mentors/<uuid:relation_id>/delete",
|
||||
views.delete_agent_participant_relation,
|
||||
name="delete_agent_participant_relation",
|
||||
),
|
||||
path("invitations", views.list_invitations, name="list_invitations"),
|
||||
path("invitations/create", views.create_invitation, name="create_invitation"),
|
||||
|
|
|
|||
|
|
@ -16,11 +16,15 @@ from vbv_lernwelt.learning_mentor.content.praxis_assignment import (
|
|||
from vbv_lernwelt.learning_mentor.content.self_evaluation_feedback import (
|
||||
get_self_feedback_evaluation,
|
||||
)
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor, MentorInvitation
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
MentorInvitation,
|
||||
)
|
||||
from vbv_lernwelt.learning_mentor.serializers import (
|
||||
AgentParticipantRelationSerializer,
|
||||
InvitationSerializer,
|
||||
MentorAssignmentStatusSerializer,
|
||||
MentorSerializer,
|
||||
)
|
||||
from vbv_lernwelt.learnpath.models import Circle
|
||||
from vbv_lernwelt.notify.email.email_services import EmailTemplate, send_email
|
||||
|
|
@ -31,12 +35,16 @@ from vbv_lernwelt.notify.email.email_services import EmailTemplate, send_email
|
|||
def mentor_summary(request, course_session_id: int):
|
||||
course_session = CourseSession.objects.get(id=course_session_id)
|
||||
|
||||
mentor = get_object_or_404(
|
||||
LearningMentor, mentor=request.user, course_session=course_session
|
||||
participant_qs = AgentParticipantRelation.objects.filter(
|
||||
agent=request.user,
|
||||
participant__course_session=course_session,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
participants = mentor.participants.filter(course_session=course_session)
|
||||
users = [p.user for p in participants]
|
||||
if participant_qs.count() == 0:
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
users = [p.participant.user for p in participant_qs]
|
||||
|
||||
assignments = []
|
||||
circle_ids = set()
|
||||
|
|
@ -71,8 +79,9 @@ def mentor_summary(request, course_session_id: int):
|
|||
)
|
||||
return Response(
|
||||
{
|
||||
"mentor_id": mentor.id,
|
||||
"participants": [UserSerializer(user).data for user in users],
|
||||
"participant_relations": AgentParticipantRelationSerializer(
|
||||
participant_qs, many=True
|
||||
).data,
|
||||
"circles": list(
|
||||
Circle.objects.filter(id__in=circle_ids).values("id", "title")
|
||||
),
|
||||
|
|
@ -176,27 +185,24 @@ def list_user_mentors(request, course_session_id: int):
|
|||
CourseSessionUser, user=request.user, course_session=course_session
|
||||
)
|
||||
|
||||
mentors = LearningMentor.objects.filter(
|
||||
course_session=course_session, participants=course_session_user
|
||||
mentors = AgentParticipantRelation.objects.filter(
|
||||
participant=course_session_user,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
return Response(MentorSerializer(mentors, many=True).data)
|
||||
return Response(AgentParticipantRelationSerializer(mentors, many=True).data)
|
||||
|
||||
|
||||
@api_view(["DELETE"])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def remove_participant_from_mentor(
|
||||
request, course_session_id: int, mentor_id: int, participant_user_id: uuid.UUID
|
||||
def delete_agent_participant_relation(
|
||||
request, course_session_id: int, relation_id: uuid.UUID
|
||||
):
|
||||
requester_user = request.user
|
||||
mentor = get_object_or_404(
|
||||
LearningMentor, id=mentor_id, course_session_id=course_session_id
|
||||
)
|
||||
relation = get_object_or_404(AgentParticipantRelation, id=relation_id)
|
||||
|
||||
is_requester_mentor = requester_user.id == mentor.mentor_id
|
||||
is_requester_participant = mentor.participants.filter(
|
||||
user=requester_user, course_session_id=course_session_id
|
||||
).exists()
|
||||
is_requester_mentor = requester_user.id == relation.agent.id
|
||||
is_requester_participant = requester_user.id == relation.participant.user.id
|
||||
|
||||
if not is_requester_mentor and not is_requester_participant:
|
||||
return Response(
|
||||
|
|
@ -204,12 +210,7 @@ def remove_participant_from_mentor(
|
|||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
course_session = get_object_or_404(CourseSession, id=course_session_id)
|
||||
course_session_user = get_object_or_404(
|
||||
CourseSessionUser, user=participant_user_id, course_session=course_session
|
||||
)
|
||||
|
||||
mentor.participants.remove(course_session_user)
|
||||
relation.delete()
|
||||
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
|
@ -228,11 +229,12 @@ def accept_invitation(request, course_session_id: int):
|
|||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
mentor, _ = LearningMentor.objects.get_or_create(
|
||||
mentor=request.user, course_session=course_session
|
||||
AgentParticipantRelation.objects.get_or_create(
|
||||
agent=request.user,
|
||||
participant=invitation.participant,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
)
|
||||
|
||||
mentor.participants.add(invitation.participant)
|
||||
invitation.delete()
|
||||
|
||||
return Response(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import imghdr
|
|||
from wsgiref.util import FileWrapper
|
||||
|
||||
import structlog
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponse, StreamingHttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
|
@ -21,6 +22,16 @@ def user_image(request, image_id):
|
|||
|
||||
try:
|
||||
rendition = image.get_rendition(filter_spec)
|
||||
|
||||
rendition.file.open("rb")
|
||||
image_format = imghdr.what(rendition.file)
|
||||
|
||||
return StreamingHttpResponse(
|
||||
FileWrapper(rendition.file),
|
||||
content_type=(
|
||||
f"image/{image_format}" if image_format else "binary/octet-stream"
|
||||
),
|
||||
)
|
||||
except SourceImageIOError:
|
||||
return HttpResponse(
|
||||
"Source image file not found", content_type="text/plain", status=410
|
||||
|
|
@ -31,11 +42,14 @@ def user_image(request, image_id):
|
|||
content_type="text/plain",
|
||||
status=400,
|
||||
)
|
||||
|
||||
rendition.file.open("rb")
|
||||
image_format = imghdr.what(rendition.file)
|
||||
|
||||
return StreamingHttpResponse(
|
||||
FileWrapper(rendition.file),
|
||||
content_type=f"image/{image_format}" if image_format else "binary/octet-stream",
|
||||
)
|
||||
except Exception:
|
||||
if settings.APP_ENVIRONMENT.startswith("local"):
|
||||
# do not spam the console
|
||||
logger.warning("Error while serving image")
|
||||
else:
|
||||
logger.exception(
|
||||
"Error while serving image", exc_info=True, label="s3_mediafiles"
|
||||
)
|
||||
return HttpResponse(
|
||||
"Error while serving image", content_type="text/plain", status=400
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from vbv_lernwelt.course.creators.test_utils import (
|
|||
)
|
||||
from vbv_lernwelt.course.models import CourseCompletionStatus, CourseSessionUser
|
||||
from vbv_lernwelt.course.services import mark_course_completion
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
from vbv_lernwelt.self_evaluation_feedback.models import (
|
||||
CourseCompletionFeedback,
|
||||
SelfEvaluationFeedback,
|
||||
|
|
@ -51,13 +51,10 @@ class SelfEvaluationFeedbackAPI(APITestCase):
|
|||
title="Test Circle", course_page=self.course_page
|
||||
)
|
||||
|
||||
learning_mentor = LearningMentor.objects.create(
|
||||
mentor=self.mentor,
|
||||
course_session=self.course_session,
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.mentor, participant=member_csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
learning_mentor.participants.add(member_csu)
|
||||
|
||||
@patch(
|
||||
"vbv_lernwelt.notify.services.NotificationService.send_self_evaluation_feedback_request_feedback_notification"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from vbv_lernwelt.core.models import User
|
|||
from vbv_lernwelt.core.serializers import UserSerializer
|
||||
from vbv_lernwelt.course.models import CourseCompletion, CourseSession
|
||||
from vbv_lernwelt.iam.permissions import can_view_course_completions
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
from vbv_lernwelt.learnpath.models import Circle, LearningUnit
|
||||
from vbv_lernwelt.notify.services import NotificationService
|
||||
from vbv_lernwelt.self_evaluation_feedback.models import (
|
||||
|
|
@ -38,10 +38,9 @@ def start_self_evaluation_feedback(request, learning_unit_id):
|
|||
learning_unit = get_object_or_404(LearningUnit, id=learning_unit_id)
|
||||
feedback_provider_user = get_object_or_404(User, id=feedback_provider_user_id)
|
||||
|
||||
if not LearningMentor.objects.filter(
|
||||
course_session__course=learning_unit.get_course(),
|
||||
mentor=feedback_provider_user,
|
||||
participants__user=request.user,
|
||||
if not AgentParticipantRelation.objects.filter(
|
||||
agent=feedback_provider_user,
|
||||
participant__user=request.user,
|
||||
).exists():
|
||||
raise PermissionDenied()
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 3.2.25 on 2024-07-17 14:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("shop", "0015_cembra_fields"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="checkoutinformation",
|
||||
name="refno2",
|
||||
field=models.CharField(max_length=255),
|
||||
),
|
||||
]
|
||||
|
|
@ -5,7 +5,10 @@ from keycloak.exceptions import KeycloakDeleteError, KeycloakPostError
|
|||
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.sso.models import SsoSyncError, SsoUser
|
||||
from vbv_lernwelt.sso.role_sync.services import (
|
||||
create_and_update_user,
|
||||
|
|
@ -20,7 +23,7 @@ def create_sso_user_from_admin(user: User, request):
|
|||
create_and_update_user(user) # noqa
|
||||
user.save()
|
||||
messages.add_message(
|
||||
request, messages.SUCCESS, f"Der Bentuzer wurde in Keycloak erstellt."
|
||||
request, messages.SUCCESS, "Der Bentuzer wurde in Keycloak erstellt."
|
||||
)
|
||||
except KeycloakPostError as e:
|
||||
messages.add_message(
|
||||
|
|
@ -31,24 +34,26 @@ def create_sso_user_from_admin(user: User, request):
|
|||
|
||||
|
||||
def sync_sso_roles_from_admin(user: User, request):
|
||||
course_roles = [
|
||||
course_roles = {
|
||||
(csu.course_session.course.slug, csu.role)
|
||||
for csu in CourseSessionUser.objects.filter(user=user)
|
||||
]
|
||||
}
|
||||
|
||||
course_roles += [
|
||||
(lm.course_session.course.slug, "LEARNING_MENTOR")
|
||||
for lm in LearningMentor.objects.filter(mentor=user)
|
||||
]
|
||||
course_roles += {
|
||||
(relation.participant.course_session.course.slug, "LEARNING_MENTOR")
|
||||
for relation in AgentParticipantRelation.objects.filter(
|
||||
agent=user, role=AgentParticipantRoleType.LEARNING_MENTOR.value
|
||||
)
|
||||
}
|
||||
|
||||
for csg in CourseSessionGroup.objects.filter(supervisor=user):
|
||||
for course_session in csg.course_session.all():
|
||||
course_roles.append((course_session.course.slug, "SUPERVISOR"))
|
||||
course_roles.add((course_session.course.slug, "SUPERVISOR"))
|
||||
|
||||
try:
|
||||
sync_roles_for_user(user, course_roles)
|
||||
messages.add_message(
|
||||
request, messages.SUCCESS, f"Die Daten wurden mit Keycloak synchronisiert."
|
||||
request, messages.SUCCESS, "Die Daten wurden mit Keycloak synchronisiert."
|
||||
)
|
||||
except KeycloakDeleteError as e:
|
||||
messages.add_message(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import unicodedata
|
||||
from typing import Dict, List, Tuple
|
||||
from typing import Dict, List, Set, Tuple
|
||||
|
||||
import structlog
|
||||
from django.conf import settings
|
||||
|
|
@ -12,7 +12,7 @@ from vbv_lernwelt.sso.role_sync.roles import ROLE_IDS, SSO_ROLES
|
|||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
CourseRolesType = List[Tuple[str, str]]
|
||||
CourseRolesType = Set[Tuple[str, str]]
|
||||
KeyCloakRolesType = List[Dict[str, str]]
|
||||
|
||||
keycloak_admin = None # Needed for pytest
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ from keycloak.exceptions import KeycloakDeleteError, KeycloakError, KeycloakPost
|
|||
from vbv_lernwelt.core.models import User
|
||||
from vbv_lernwelt.course.models import CourseSessionUser
|
||||
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import (
|
||||
AgentParticipantRelation,
|
||||
AgentParticipantRoleType,
|
||||
)
|
||||
from vbv_lernwelt.sso.role_sync.services import (
|
||||
add_roles_to_user,
|
||||
remove_roles_from_user,
|
||||
|
|
@ -78,21 +81,39 @@ def update_sso_roles_in_csg(sender, instance, action, reverse, model, pk_set, **
|
|||
|
||||
|
||||
# LearningMentor
|
||||
@receiver(post_delete, sender=LearningMentor, dispatch_uid="delete_sso_roles_in_lm")
|
||||
def remove_sso_roles_in_lm(sender, instance: LearningMentor, **kwargs):
|
||||
if not LearningMentor.objects.filter(
|
||||
mentor=instance.mentor, course_session__course=instance.course_session.course
|
||||
@receiver(
|
||||
post_delete, sender=AgentParticipantRelation, dispatch_uid="delete_sso_roles_in_lm"
|
||||
)
|
||||
def remove_sso_roles_in_lm(sender, instance: AgentParticipantRelation, **kwargs):
|
||||
if not AgentParticipantRelation.objects.filter(
|
||||
agent=instance.agent,
|
||||
participant__course_session__course=instance.participant.course_session.course,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
).exists():
|
||||
_remove_sso_role(
|
||||
instance.mentor, instance.course_session.course.slug, "LEARNING_MENTOR"
|
||||
instance.agent,
|
||||
instance.participant.course_session.course.slug,
|
||||
"LEARNING_MENTOR",
|
||||
)
|
||||
|
||||
|
||||
@receiver(pre_save, sender=LearningMentor, dispatch_uid="update_sso_roles_in_lm")
|
||||
def update_sso_roles_in_lm(sender, instance: LearningMentor, **kwargs):
|
||||
if not instance.pk:
|
||||
@receiver(
|
||||
pre_save, sender=AgentParticipantRelation, dispatch_uid="update_sso_roles_in_lm"
|
||||
)
|
||||
def update_sso_roles_in_lm(sender, instance: AgentParticipantRelation, **kwargs):
|
||||
if (
|
||||
instance.role == AgentParticipantRoleType.LEARNING_MENTOR.value
|
||||
and AgentParticipantRelation.objects.filter(
|
||||
agent=instance.agent,
|
||||
participant__course_session__course=instance.participant.course_session.course,
|
||||
role=AgentParticipantRoleType.LEARNING_MENTOR.value,
|
||||
).count()
|
||||
== 0
|
||||
):
|
||||
_add_sso_role(
|
||||
instance.mentor, instance.course_session.course.slug, "LEARNING_MENTOR"
|
||||
instance.agent,
|
||||
instance.participant.course_session.course.slug,
|
||||
"LEARNING_MENTOR",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ from vbv_lernwelt.course.creators.test_utils import (
|
|||
)
|
||||
from vbv_lernwelt.course.models import Course, CourseSessionUser
|
||||
from vbv_lernwelt.course_session_group.models import CourseSessionGroup
|
||||
from vbv_lernwelt.learning_mentor.models import LearningMentor
|
||||
from vbv_lernwelt.learning_mentor.models import AgentParticipantRelation
|
||||
from vbv_lernwelt.sso.signals import update_sso_roles_in_cs
|
||||
|
||||
|
||||
|
|
@ -217,10 +217,16 @@ class LearningMentorTests(TestCase):
|
|||
def setUp(self):
|
||||
self.course, self.course_page = create_course("Test Course")
|
||||
self.course_session = create_course_session(course=self.course, title="Test VV")
|
||||
|
||||
self.user = create_user("mentor")
|
||||
self.mentor = LearningMentor.objects.create(
|
||||
mentor=self.user, course_session=self.course_session
|
||||
|
||||
participant = create_user("participant")
|
||||
self.csu = add_course_session_user(
|
||||
self.course_session,
|
||||
participant,
|
||||
role=CourseSessionUser.Role.MEMBER,
|
||||
)
|
||||
self.relation = AgentParticipantRelation.objects.create(
|
||||
agent=self.user, participant=self.csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
@patch("vbv_lernwelt.sso.signals.remove_roles_from_user")
|
||||
|
|
@ -229,7 +235,7 @@ class LearningMentorTests(TestCase):
|
|||
):
|
||||
mock_remove_roles_from_user.return_value = None
|
||||
|
||||
self.mentor.delete()
|
||||
self.relation.delete()
|
||||
|
||||
self.assertEqual(mock_remove_roles_from_user.call_count, 1)
|
||||
|
||||
|
|
@ -240,10 +246,10 @@ class LearningMentorTests(TestCase):
|
|||
@patch("vbv_lernwelt.sso.signals.add_roles_to_user")
|
||||
def test_add_roles_for_learning_mentor_on_create(self, mock_add_roles_from_user):
|
||||
mock_add_roles_from_user.return_value = None
|
||||
self.mentor.delete()
|
||||
self.relation.delete()
|
||||
|
||||
LearningMentor.objects.create(
|
||||
mentor=self.user, course_session=self.course_session
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.user, participant=self.csu, role="LEARNING_MENTOR"
|
||||
)
|
||||
|
||||
self.assertEqual(mock_add_roles_from_user.call_count, 1)
|
||||
|
|
@ -263,5 +269,8 @@ class LearningMentorTests(TestCase):
|
|||
)
|
||||
|
||||
mock_add_roles_from_user.reset_mock()
|
||||
self.mentor.participants.set([participant_1])
|
||||
|
||||
AgentParticipantRelation.objects.create(
|
||||
agent=self.user, participant=participant_1, role="LEARNING_MENTOR"
|
||||
)
|
||||
self.assertEqual(mock_add_roles_from_user.call_count, 0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue