fix: filter feedback users
This commit is contained in:
parent
69c56dfb9a
commit
577746bff1
|
|
@ -56,8 +56,8 @@ class CourseDashboardType(graphene.ObjectType):
|
||||||
for course_session in course_sessions:
|
for course_session in course_sessions:
|
||||||
course_session_data.append(
|
course_session_data.append(
|
||||||
CourseSessionData(
|
CourseSessionData(
|
||||||
session_id=course_session.id,
|
session_id=course_session.id, # noqa
|
||||||
session_title=course_session.title,
|
session_title=course_session.title, # noqa
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
generations.add(course_session.generation)
|
generations.add(course_session.generation)
|
||||||
|
|
@ -78,9 +78,9 @@ class CourseDashboardType(graphene.ObjectType):
|
||||||
for circle in circles:
|
for circle in circles:
|
||||||
circle_data.append(
|
circle_data.append(
|
||||||
CircleData(
|
CircleData(
|
||||||
circle_id=circle.id,
|
circle_id=circle.id, # noqa
|
||||||
circle_title=circle.title,
|
circle_title=circle.title, # noqa
|
||||||
experts=[
|
experts=[ # noqa
|
||||||
f"{su.user.first_name} {su.user.last_name}"
|
f"{su.user.first_name} {su.user.last_name}"
|
||||||
for su in circle.expert.all()
|
for su in circle.expert.all()
|
||||||
],
|
],
|
||||||
|
|
@ -88,7 +88,7 @@ class CourseDashboardType(graphene.ObjectType):
|
||||||
)
|
)
|
||||||
|
|
||||||
return CourseSessionProperties(
|
return CourseSessionProperties(
|
||||||
sessions=course_session_data,
|
sessions=course_session_data, # noqa
|
||||||
generations=list(generations),
|
generations=list(generations), # noqa
|
||||||
circles=circle_data,
|
circles=circle_data, # noqa
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,22 +5,25 @@ import graphene
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
|
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
|
||||||
from vbv_lernwelt.feedback.models import FeedbackResponse
|
from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||||
|
from vbv_lernwelt.feedback.utils import feedback_users
|
||||||
|
|
||||||
|
|
||||||
class FeedbackSummary(graphene.ObjectType):
|
class FeedbackSummary(graphene.ObjectType):
|
||||||
satisfaction_average = graphene.Float()
|
satisfaction_average = graphene.Float()
|
||||||
satisfaction_total = graphene.Int()
|
satisfaction_max = graphene.Int()
|
||||||
total_responses = graphene.Int()
|
total_responses = graphene.Int()
|
||||||
|
|
||||||
|
|
||||||
class Record(graphene.ObjectType):
|
class FeedbackRecord(graphene.ObjectType):
|
||||||
course_session_id = graphene.ID()
|
course_session_id = graphene.ID()
|
||||||
generation = graphene.String()
|
generation = graphene.String()
|
||||||
circle_id = graphene.ID()
|
circle_id = graphene.ID()
|
||||||
|
satisfaction_average = graphene.Float()
|
||||||
|
satisfaction_max = graphene.Int()
|
||||||
|
|
||||||
|
|
||||||
class FeedbackResponses(graphene.ObjectType):
|
class FeedbackResponses(graphene.ObjectType):
|
||||||
records = graphene.List(Record)
|
records = graphene.List(FeedbackRecord)
|
||||||
summary = graphene.Field(FeedbackSummary)
|
summary = graphene.Field(FeedbackSummary)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -32,22 +35,38 @@ def feedback_responses(course_id: graphene.String(), user: User):
|
||||||
course_id=course_id,
|
course_id=course_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
circle_feedbacks = []
|
||||||
|
|
||||||
for course_session in course_sessions:
|
for course_session in course_sessions:
|
||||||
fbs = FeedbackResponse.objects.filter(
|
fbs = FeedbackResponse.objects.filter(
|
||||||
submitted=True,
|
submitted=True,
|
||||||
course_session=course_session,
|
course_session=course_session,
|
||||||
# Only get feedbacks from members
|
feedback_user__in=feedback_users(course_session.id),
|
||||||
feedback_user__in=CourseSessionUser.objects.filter(
|
|
||||||
course_session=course_session, role=CourseSessionUser.Role.MEMBER
|
|
||||||
).values_list("user", flat=True),
|
|
||||||
)
|
)
|
||||||
circle_feedbacks = circle_feedback_average(fbs)
|
|
||||||
|
|
||||||
return FeedbackResponses()
|
circle_feedbacks.extend(
|
||||||
|
circle_feedback_average(fbs, course_session.id, course_session.generation)
|
||||||
|
)
|
||||||
|
|
||||||
|
avg = sum([fb.satisfaction_average for fb in circle_feedbacks]) / len(
|
||||||
|
circle_feedbacks
|
||||||
|
)
|
||||||
|
|
||||||
|
return FeedbackResponses(
|
||||||
|
records=circle_feedbacks, # noqa
|
||||||
|
summary=FeedbackSummary( # noqa
|
||||||
|
satisfaction_average=avg, # noqa
|
||||||
|
satisfaction_max=4, # noqa
|
||||||
|
total_responses=len(fbs), # noqa
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def circle_feedback_average(feedbacks: List[FeedbackResponse]):
|
def circle_feedback_average(
|
||||||
|
feedbacks: List[FeedbackResponse], course_session_id, generation: str
|
||||||
|
):
|
||||||
circle_data = {}
|
circle_data = {}
|
||||||
|
records = []
|
||||||
|
|
||||||
for fb in feedbacks:
|
for fb in feedbacks:
|
||||||
circle_id = fb.circle.id
|
circle_id = fb.circle.id
|
||||||
|
|
@ -60,6 +79,14 @@ def circle_feedback_average(feedbacks: List[FeedbackResponse]):
|
||||||
circle_data[circle_id] = {"total": satisfaction, "count": 1}
|
circle_data[circle_id] = {"total": satisfaction, "count": 1}
|
||||||
|
|
||||||
for circle_id, data in circle_data.items():
|
for circle_id, data in circle_data.items():
|
||||||
circle_data[circle_id]["avg_satisfaction"] = data["total"] / data["count"]
|
records.append(
|
||||||
|
FeedbackRecord(
|
||||||
|
course_session_id=course_session_id, # noqa
|
||||||
|
generation=generation, # noqa
|
||||||
|
circle_id=circle_id, # noqa
|
||||||
|
satisfaction_average=data["total"] / data["count"], # noqa
|
||||||
|
satisfaction_max=4, # noqa
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return circle_data
|
return records
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ class DashboardAttendanceTestCase(GraphQLTestCase):
|
||||||
attendance_day_presences{{
|
attendance_day_presences{{
|
||||||
summary{{
|
summary{{
|
||||||
days_completed
|
days_completed
|
||||||
participants_present
|
participants_present
|
||||||
}}
|
}}
|
||||||
records{{
|
records{{
|
||||||
course_session_id
|
course_session_id
|
||||||
|
|
@ -91,8 +91,8 @@ class DashboardAttendanceTestCase(GraphQLTestCase):
|
||||||
due_date
|
due_date
|
||||||
participants_present
|
participants_present
|
||||||
participants_total
|
participants_total
|
||||||
cockpit_url
|
cockpit_url
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -52,17 +52,17 @@ class DashboardTestCase(GraphQLTestCase):
|
||||||
course_dashboard {{
|
course_dashboard {{
|
||||||
course_id
|
course_id
|
||||||
course_title
|
course_title
|
||||||
course_session_properties{{
|
course_session_properties {{
|
||||||
sessions{{
|
sessions {{
|
||||||
session_id
|
session_id
|
||||||
session_title
|
session_title
|
||||||
}}
|
}}
|
||||||
generations
|
generations
|
||||||
circles{{
|
circles {{
|
||||||
circle_id
|
circle_id
|
||||||
circle_title
|
circle_title
|
||||||
experts
|
experts
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from graphene_django.utils import GraphQLTestCase
|
from graphene_django.utils import GraphQLTestCase
|
||||||
|
|
||||||
from vbv_lernwelt.course.models import CourseSessionUser
|
from vbv_lernwelt.course.models import CourseSessionUser
|
||||||
from vbv_lernwelt.dashboard.graphql.types.feedback import feedback_responses
|
|
||||||
from vbv_lernwelt.dashboard.tests.graphql.utils import (
|
from vbv_lernwelt.dashboard.tests.graphql.utils import (
|
||||||
add_course_session_user,
|
add_course_session_user,
|
||||||
create_circle,
|
create_circle,
|
||||||
|
|
@ -29,6 +28,11 @@ class DashboardFeedbackTestCase(GraphQLTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
member = create_user("member")
|
member = create_user("member")
|
||||||
|
add_course_session_user(
|
||||||
|
course_session=course_session,
|
||||||
|
user=member,
|
||||||
|
role=CourseSessionUser.Role.MEMBER,
|
||||||
|
)
|
||||||
|
|
||||||
circle1, _ = create_circle(title="Test Circle 1", course_page=course_page)
|
circle1, _ = create_circle(title="Test Circle 1", course_page=course_page)
|
||||||
circle2, _ = create_circle(title="Test Circle 2", course_page=course_page)
|
circle2, _ = create_circle(title="Test Circle 2", course_page=course_page)
|
||||||
|
|
@ -38,29 +42,83 @@ class DashboardFeedbackTestCase(GraphQLTestCase):
|
||||||
data={"satisfaction": 3},
|
data={"satisfaction": 3},
|
||||||
circle=circle1,
|
circle=circle1,
|
||||||
course_session=course_session,
|
course_session=course_session,
|
||||||
|
submitted=True,
|
||||||
)
|
)
|
||||||
FeedbackResponse.objects.create(
|
FeedbackResponse.objects.create(
|
||||||
feedback_user=member,
|
feedback_user=member,
|
||||||
data={"satisfaction": 4},
|
data={"satisfaction": 4},
|
||||||
circle=circle1,
|
circle=circle1,
|
||||||
course_session=course_session,
|
course_session=course_session,
|
||||||
|
submitted=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create Feedbacks for circle2
|
# Create Feedbacks for circle2
|
||||||
FeedbackResponse.objects.create(
|
FeedbackResponse.objects.create(
|
||||||
feedback_user=member,
|
feedback_user=member,
|
||||||
data={"satisfaction": 5},
|
data={"satisfaction": 1},
|
||||||
circle=circle2,
|
circle=circle2,
|
||||||
course_session=course_session,
|
course_session=course_session,
|
||||||
|
submitted=True,
|
||||||
)
|
)
|
||||||
FeedbackResponse.objects.create(
|
FeedbackResponse.objects.create(
|
||||||
feedback_user=member,
|
feedback_user=member,
|
||||||
data={"satisfaction": 2},
|
data={"satisfaction": 2},
|
||||||
circle=circle2,
|
circle=circle2,
|
||||||
course_session=course_session,
|
course_session=course_session,
|
||||||
|
submitted=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get average satisfaction per circle
|
self.client.force_login(supervisor)
|
||||||
result = feedback_responses(course.id, supervisor)
|
|
||||||
|
query = f"""query($course_id: ID) {{
|
||||||
|
course_dashboard(course_id: $course_id) {{
|
||||||
|
course_id
|
||||||
|
feedback_responses {{
|
||||||
|
records {{
|
||||||
|
course_session_id
|
||||||
|
generation
|
||||||
|
circle_id
|
||||||
|
satisfaction_average
|
||||||
|
satisfaction_max
|
||||||
|
}}
|
||||||
|
summary {{
|
||||||
|
satisfaction_average
|
||||||
|
satisfaction_max
|
||||||
|
total_responses
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
variables = {"course_id": str(course.id)}
|
||||||
|
|
||||||
|
# WHEN
|
||||||
|
response = self.query(query, variables=variables)
|
||||||
|
|
||||||
# THEN
|
# THEN
|
||||||
|
self.assertResponseNoErrors(response)
|
||||||
|
|
||||||
|
course_dashboard = response.json()["data"]["course_dashboard"]
|
||||||
|
feedback_responses = course_dashboard[0]["feedback_responses"]
|
||||||
|
|
||||||
|
records = feedback_responses["records"]
|
||||||
|
self.assertEqual(len(records), 2)
|
||||||
|
|
||||||
|
circle1_record = next(
|
||||||
|
(r for r in records if r["circle_id"] == str(circle1.id)), None
|
||||||
|
)
|
||||||
|
self.assertEqual(circle1_record["satisfaction_average"], 3.5)
|
||||||
|
self.assertEqual(circle1_record["course_session_id"], str(course_session.id))
|
||||||
|
self.assertEqual(circle1_record["generation"], "2023")
|
||||||
|
|
||||||
|
circle2_record = next(
|
||||||
|
(r for r in records if r["circle_id"] == str(circle2.id)), None
|
||||||
|
)
|
||||||
|
self.assertEqual(circle2_record["satisfaction_average"], 1.5)
|
||||||
|
self.assertEqual(circle2_record["course_session_id"], str(course_session.id))
|
||||||
|
self.assertEqual(circle2_record["generation"], "2023")
|
||||||
|
|
||||||
|
summary = feedback_responses["summary"]
|
||||||
|
self.assertEqual(summary["satisfaction_average"], 2.5)
|
||||||
|
self.assertEqual(summary["satisfaction_max"], 4)
|
||||||
|
self.assertEqual(summary["total_responses"], 4)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from vbv_lernwelt.core.constants import ADMIN_USER_ID
|
||||||
|
from vbv_lernwelt.course.models import CourseSessionUser
|
||||||
|
|
||||||
|
|
||||||
|
def feedback_users(course_session_id):
|
||||||
|
"""
|
||||||
|
Solely accept feedback originating from members of the course session and the illustrious
|
||||||
|
administrative user, who serves as the repository for feedbacks heretofore submitted anonymously ;-)
|
||||||
|
"""
|
||||||
|
return CourseSessionUser.objects.filter(
|
||||||
|
Q(course_session_id=course_session_id, role=CourseSessionUser.Role.MEMBER)
|
||||||
|
| Q(user__id=ADMIN_USER_ID)
|
||||||
|
).values_list("user", flat=True)
|
||||||
|
|
@ -5,9 +5,9 @@ from rest_framework.decorators import api_view
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from vbv_lernwelt.course.models import CourseSessionUser
|
|
||||||
from vbv_lernwelt.course.permissions import is_course_session_expert
|
from vbv_lernwelt.course.permissions import is_course_session_expert
|
||||||
from vbv_lernwelt.feedback.models import FeedbackResponse
|
from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||||
|
from vbv_lernwelt.feedback.utils import feedback_users
|
||||||
|
|
||||||
logger = structlog.get_logger(__name__)
|
logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
|
@ -58,10 +58,7 @@ def get_feedback_for_circle(request, course_session_id, circle_id):
|
||||||
course_session__id=course_session_id,
|
course_session__id=course_session_id,
|
||||||
submitted=True,
|
submitted=True,
|
||||||
circle_id=circle_id,
|
circle_id=circle_id,
|
||||||
# filter out experts that might have submitted just for testing
|
feedback_user__in=feedback_users(course_session_id),
|
||||||
feedback_user__in=CourseSessionUser.objects.filter(
|
|
||||||
course_session_id=course_session_id, role=CourseSessionUser.Role.MEMBER
|
|
||||||
).values_list("user", flat=True),
|
|
||||||
).order_by("created_at")
|
).order_by("created_at")
|
||||||
|
|
||||||
# I guess this is ok for the üK case
|
# I guess this is ok for the üK case
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue