Skip to content

Commit

Permalink
Add option to display other student responses.
Browse files Browse the repository at this point in the history
  • Loading branch information
saharm1 committed Aug 31, 2018
1 parent 0e49f0a commit 356ccda
Show file tree
Hide file tree
Showing 15 changed files with 2,411 additions and 527 deletions.
150 changes: 0 additions & 150 deletions Gruntfile.js

This file was deleted.

78 changes: 74 additions & 4 deletions freetextresponse/freetextresponse.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This is the core logic for the Free-text Response XBlock
"""
from enum import Enum
import pkg_resources
from django.db import IntegrityError
from django.template.context import Context
from django.template.loader import get_template
Expand All @@ -18,11 +19,19 @@
from xblock.fragment import Fragment
from xblock.validation import ValidationMessage
from xblockutils.studio_editable import StudioEditableXBlockMixin
from .mixins import EnforceDueDates
from .mixins import EnforceDueDates, MissingDataFetcherMixin


MAX_RESPONSES = 3


@XBlock.needs("i18n")
class FreeTextResponse(EnforceDueDates, StudioEditableXBlockMixin, XBlock):
class FreeTextResponse(
EnforceDueDates,
MissingDataFetcherMixin,
StudioEditableXBlockMixin,
XBlock,
):
# pylint: disable=too-many-ancestors, too-many-instance-attributes
"""
Enables instructors to create questions with free-text responses.
Expand Down Expand Up @@ -86,6 +95,20 @@ def workbench_scenarios():
default=True,
scope=Scope.settings,
)
display_other_student_responses = Boolean(
display_name=_('Display Other Student Responses'),
help=_(
'This will display other student responses to the '
'student after they submit their response.'
),
default=False,
scope=Scope.settings,
)
displayable_answers = List(
default=[],
scope=Scope.user_state_summary,
help=_('System selected answers to give to students'),
)
display_name = String(
display_name=_('Display Name'),
help=_(
Expand Down Expand Up @@ -212,6 +235,7 @@ def workbench_scenarios():
'fullcredit_keyphrases',
'halfcredit_keyphrases',
'submitted_message',
'display_other_student_responses',
'saved_message',
)

Expand Down Expand Up @@ -269,6 +293,8 @@ def student_view(self, context={}):
'used_attempts_feedback': self._get_used_attempts_feedback(),
'visibility_class': self._get_indicator_visibility_class(),
'word_count_message': self._get_word_count_message(),
'display_other_responses': self.display_other_student_responses,
'other_responses': [],
}
)
template = get_template('freetextresponse_view.html')
Expand All @@ -277,10 +303,10 @@ def student_view(self, context={}):
context,
initialize_js_func='FreeTextResponseView',
additional_css=[
'public/view.less.min.css',
'public/view.css',
],
additional_js=[
'public/view.js.min.js',
'public/view.js',
],
)
return fragment
Expand Down Expand Up @@ -564,6 +590,8 @@ def submit(self, data, suffix=''):
# even if word count is invalid.
self.count_attempts += 1
self._compute_score()
if self.display_other_student_responses and data.get('can_record_response'):
self.store_student_response()
result = {
'status': 'success',
'problem_progress': self._get_problem_progress(),
Expand All @@ -574,6 +602,8 @@ def submit(self, data, suffix=''):
'user_alert': self._get_user_alert(
ignore_attempts=True,
),
'other_responses': self.get_other_answers(self.get_student_id()),
'display_other_responses': self.display_other_student_responses,
'visibility_class': self._get_indicator_visibility_class(),
}
return result
Expand All @@ -599,6 +629,46 @@ def save_reponse(self, data, suffix=''):
}
return result

def store_student_response(self):
"""
Submit a student answer to the answer pool by appending the given
answer to the end of the list.
"""
# if the answer is wrong, do not display it
if self.score != Credit.full.value:
return

student_id = self.get_student_id()
# remove any previous answers the student submitted
for index, response in enumerate(self.displayable_answers):
if response['student_id'] == student_id:
del self.displayable_answers[index]
break

self.displayable_answers.append({
'student_id': student_id,
'answer': self.student_answer,
})

# Want to store extra response so student can still see
# MAX_RESPONSES answers if their answer is in the pool.
self.displayable_answers = self.displayable_answers[-(MAX_RESPONSES+1):]

def get_other_answers(self, student_id):
"""
Returns at most MAX_RESPONSES answers from the pool.
Does not return answers the student had submitted.
"""
return_list = [
response
for response in self.displayable_answers
if response['student_id'] != student_id
]

return_list = return_list[-(MAX_RESPONSES):]
return return_list


class Credit(Enum):
# pylint: disable=too-few-public-methods
Expand Down
17 changes: 17 additions & 0 deletions freetextresponse/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,20 @@ def is_past_due(self):
due = due + graceperiod
return now > due
return False


class MissingDataFetcherMixin(object):
"""
The mixin used for getting the student_id of the current user.
"""
def get_student_id(self):
"""
Get the student id.
"""
if hasattr(self, 'xmodule_runtime'):
student_id = self.xmodule_runtime.anonymous_student_id
# pylint:disable=E1101
else:
student_id = self.scope_ids.user_id or ''
student_id = unicode(student_id)
return student_id
Loading

0 comments on commit 356ccda

Please sign in to comment.