From de0403a8b1e07b20b3d5da655b8b8ad29b5bac74 Mon Sep 17 00:00:00 2001 From: Danyal Faheem <138459282+Danyal-Faheem@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:33:26 +0500 Subject: [PATCH] Add a new service to allow Anonymous Users to vote on xblock-poll (#314) * feat: Add a new service to allow Anonymous Users to vote on xblock-polls * refactor: remove extra blank lines * refactor: add tally_updated as return value to vote --- lms/djangoapps/courseware/module_render.py | 3 +- lms/djangoapps/courseware/services.py | 53 ++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index c8e8e1a14e4..ca129ba8ddd 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -54,7 +54,7 @@ from lms.djangoapps.courseware.model_data import DjangoKeyValueStore, FieldDataCache from edxmako.shortcuts import render_to_string from lms.djangoapps.courseware.field_overrides import OverrideFieldData -from lms.djangoapps.courseware.services import UserStateService +from lms.djangoapps.courseware.services import UserStateService, AnonymousUserPollService from lms.djangoapps.grades.api import GradesUtilService from lms.djangoapps.grades.api import signals as grades_signals from lms.djangoapps.lms_xblock.field_data import LmsFieldData @@ -819,6 +819,7 @@ def rebind_noauth_module_to_user(module, real_user): 'gating': GatingService(), 'grade_utils': GradesUtilService(course_id=course_id), 'user_state': UserStateService(), + 'anonymous_user_poll': AnonymousUserPollService(), }, get_user_role=lambda: get_user_role(user, course_id), descriptor_runtime=descriptor._runtime, # pylint: disable=protected-access diff --git a/lms/djangoapps/courseware/services.py b/lms/djangoapps/courseware/services.py index 32f21a79959..3f69d4c760b 100644 --- a/lms/djangoapps/courseware/services.py +++ b/lms/djangoapps/courseware/services.py @@ -10,6 +10,9 @@ from lms.djangoapps.courseware.models import StudentModule from student.models import get_user_by_username_or_email +from xblock.reference.plugins import Service +from lms.djangoapps.courseware.models import XModuleUserStateSummaryField + class UserStateService(object): """ @@ -39,3 +42,53 @@ def get_state_as_dict(self, username_or_email, block_id): return json.loads(student_module.state) except StudentModule.DoesNotExist: return {} + + + + +class AnonymousUserPollService(Service): + """ + Service to allow anonymous users to vote on xblock polls + """ + + def vote(self, choice, result, usage_id): + """ + Updates the tally in the database for the anonymous users votes on polls + Also, clears the dirty fields so the LMS does not try to update as well + + Args: + choice (string): The choice of vote selected by user + result (dict): The response dictionary to return to frontend + usage_id (UsageKey): usage_id of the poll + + Returns: + dict: Return the result to the handler function + """ + tally = self.get_tally(usage_id) + # If tally does not exist, do not update and allow the LMS to handle it + if not tally: + return result, False + tally[choice] += 1 + # Update tally in the db + XModuleUserStateSummaryField.objects.filter(usage_id=usage_id, field_name="tally").update(value=json.dumps(tally)) + result['success'] = True + result['can_vote'] = True + result['submissions_count'] = 1 + + return result, True + + def get_tally(self, usage_id): + """ + Get the tally of the poll from the database + + Args: + usage_id (UsageKey): the usage_id of the poll to filter by + + Returns: + dict: Tally of the poll that calls this function + """ + query_set = XModuleUserStateSummaryField.objects.filter(usage_id=usage_id, field_name="tally").first() + if not query_set: + return None + # Tally is a dict stored as string, convert to json + return json.loads(query_set.value)