Skip to content

Commit

Permalink
feat: show submission information to students
Browse files Browse the repository at this point in the history
  • Loading branch information
BryanttV committed Sep 19, 2023
1 parent 6dffdee commit 236d762
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 23 deletions.
98 changes: 82 additions & 16 deletions mindmap/mindmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import json
import logging
from enum import Enum

import pkg_resources
from django.core.exceptions import PermissionDenied
Expand All @@ -14,6 +15,7 @@
from xblock.fields import Boolean, DateTime, Dict, Float, Integer, Scope, String
from xblockutils.resources import ResourceLoader

from lms.djangoapps.courseware.models import StudentModule
from mindmap.edxapp_wrapper.student import user_by_anonymous_id
from mindmap.edxapp_wrapper.xmodule import get_extended_due_date
from mindmap.utils import _, utcnow
Expand All @@ -27,6 +29,12 @@
ATTR_KEY_USER_ROLE = 'edx-platform.user_role'


class SubmissionStatus(Enum):
NOT_ATTEMPTED = "Not attempted"
SUBMITTED = "Submitted"
COMPLETED = "Completed"


@XBlock.wants("user")
@XBlock.needs("i18n")
class MindMapXBlock(XBlock):
Expand Down Expand Up @@ -105,10 +113,10 @@ class MindMapXBlock(XBlock):
scope=Scope.settings,
)

submitted = Boolean(
submission_status = String(
display_name=_("Submitted"),
help=_("Whether the student has submitted their submission."),
default=False,
default=SubmissionStatus.NOT_ATTEMPTED.value,
scope=Scope.user_state,
)

Expand Down Expand Up @@ -204,6 +212,7 @@ def get_context(self, user):
"can_submit_assignment": self.submit_allowed(),
"score": self.score,
"max_score": self.max_score(),
"submission_status": self.submission_status,
}

def get_js_context(self, user, context):
Expand Down Expand Up @@ -393,12 +402,38 @@ def submit_assignment(self, data, _suffix="") -> dict:
student_item_dict = self.get_student_item_dict()
create_submission(student_item_dict, answer)

self.submitted = True
self.submission_status = SubmissionStatus.SUBMITTED.value

return {
"success": True,
}

def get_or_create_student_module(self, user):
"""
Gets or creates a StudentModule for the given user for this block
Returns:
StudentModule: A StudentModule object
"""
# pylint: disable=no-member
student_module, created = StudentModule.objects.get_or_create(
course_id=self.course_id,
module_state_key=self.location,
student=user,
defaults={
"state": "{}",
"module_type": self.category,
},
)
if created:
log.info(
"Created student module %s [course: %s] [student: %s]",
student_module.module_state_key,
student_module.course_id,
student_module.student.username,
)
return student_module

@XBlock.json_handler
def get_instructor_grading_data(self, _, _suffix="") -> dict:
"""Return student assignment information for display on the grading screen.
Expand Down Expand Up @@ -429,25 +464,44 @@ def get_student_data() -> dict:
if not submission:
continue
user = user_by_anonymous_id(student.student_id)
student_module = self.get_or_create_student_module(user)
state = json.loads(student_module.state)
score = self.get_score(student.student_id)
yield {
"student_id": student.student_id,
"submission_id": submission["uuid"],
"answer_body": submission["answer"],
"username": user.username,
"timestamp": submission["created_at"].strftime(
DateTime.DATETIME_FORMAT
),
"score": score,
"submitted": self.submitted,
}

if state.get("submission_status") in [
SubmissionStatus.COMPLETED.value, SubmissionStatus.SUBMITTED.value
]:
yield {
"module_id": student_module.id,
"student_id": student.student_id,
"submission_id": submission["uuid"],
"answer_body": submission["answer"],
"username": user.username,
"timestamp": submission["created_at"].strftime(
DateTime.DATETIME_FORMAT
),
"score": score,
"submission_status": state.get("submission_status"),
}

return {
"assignments": list(get_student_data()),
"max_score": self.max_score(),
"display_name": self.display_name,
}

def get_student_module(self, module_id):
"""
Returns a StudentModule that matches the given id
Args:
module_id (int): The module id
Returns:
StudentModule: A StudentModule object
"""
return StudentModule.objects.get(pk=module_id)

@XBlock.json_handler
def enter_grade(self, data, _suffix="") -> dict:
"""
Expand All @@ -474,6 +528,12 @@ def enter_grade(self, data, _suffix="") -> dict:

set_score(uuid, score, self.max_score())

module = self.get_student_module(data.get("module_id"))
state = json.loads(module.state)
state["submission_status"] = SubmissionStatus.COMPLETED.value
module.state = json.dumps(state)
module.save()

return {
"success": True,
}
Expand Down Expand Up @@ -501,6 +561,12 @@ def remove_grade(self, data, _suffix="") -> dict:

reset_score(student_id, self.block_course_id, self.block_id)

module = self.get_student_module(data.get("module_id"))
state = json.loads(module.state)
state["submission_status"] = SubmissionStatus.SUBMITTED.value
module.state = json.dumps(state)
module.save()

return {
"success": True,
}
Expand Down Expand Up @@ -546,7 +612,7 @@ def submit_allowed(self) -> bool:
return (
not self.past_due()
and self.score is None
and not self.submitted
and self.submission_status == SubmissionStatus.NOT_ATTEMPTED.value
)

def get_score(self, student_id=None) -> int:
Expand All @@ -566,7 +632,7 @@ def get_score(self, student_id=None) -> int:
if score:
return score["points_earned"]

return None
return 0

def get_submission(self, student_id=None) -> dict:
"""
Expand Down
4 changes: 1 addition & 3 deletions mindmap/public/html/mindmap.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@
<button id="submit_button_{{xblock_id}}">{% trans "Submit" %}</button>
{% endif %}

{% if score %}
<p>{% trans "Your score is:" %} {{ score }}.</p>
{% endif %}
<p>({{ score }}/{{ max_score }} {% trans "points" %}) {% trans submission_status %}</p>

{% if is_instructor and in_student_view and not is_static %}
<button id="get_grade_submissions_button_{{xblock_id}}">{% trans "Grade submissions" %}</button>
Expand Down
11 changes: 9 additions & 2 deletions mindmap/public/js/src/mindmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function MindMapXBlock(runtime, element, context) {
const dataTableHeaderColumns = [
gettext("Username"),
gettext("Uploaded"),
gettext("Submission Status"),
gettext("Grade"),
gettext("Actions"),
];
Expand Down Expand Up @@ -125,7 +126,7 @@ function MindMapXBlock(runtime, element, context) {
columns: [
{ data: "username" },
{ data: "timestamp" },
// TODO: add this line { data: "submitted" },
{ data: "submission_status" },
{ data: "score" },
{
data: null,
Expand Down Expand Up @@ -226,7 +227,7 @@ function MindMapXBlock(runtime, element, context) {
e.preventDefault();
const typeAction = $(this).attr("data-type");
const grade = $("#grade_value").val();
const { submission_id, student_id } = submissionData;
const { submission_id, student_id, module_id } = submissionData;
const invalidGradeMessage = gettext("Invalid grade must be a number");
const maxGradeMessage = gettext("Please enter a lower grade, maximum grade allowed is:");
const gradeParsed = parseInt(grade, 10);
Expand All @@ -253,13 +254,15 @@ function MindMapXBlock(runtime, element, context) {
data = {
grade: grade,
submission_id: submission_id,
module_id: module_id,
};
}

if (typeAction === "remove_grade") {
apiUrl = removeGradeURL;
data = {
student_id: student_id,
module_id: module_id,
};
}

Expand Down Expand Up @@ -295,9 +298,11 @@ function MindMapXBlock(runtime, element, context) {
.click(function () {
const grade = $(element).find(`#grade-input_${context.xblock_id}`).val();
const submission_id = $(element).find(`#submission-id-input_${context.xblock_id}`).val();
const module_id = $(element).find(`#module-id-input_${context.xblock_id}`).val();
const data = {
grade: grade,
submission_id: submission_id,
module_id: module_id,
};
console.log(data);
$.post(enterGradeURL, JSON.stringify(data))
Expand All @@ -313,8 +318,10 @@ function MindMapXBlock(runtime, element, context) {
.find(`#remove-grade-button_${context.xblock_id}`)
.click(function () {
const student_id = $(element).find(`#student-id-input_${context.xblock_id}`).val();
const module_id = $(element).find(`#module-id-input_${context.xblock_id}`).val();
const data = {
student_id: student_id,
module_id: module_id,
};
console.log(data);
$.post(removeGradeURL, JSON.stringify(data))
Expand Down
4 changes: 2 additions & 2 deletions mindmap/tests/test_mindmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ def test_get_instructor_grading_data(self, student_item_mock: Mock, user_by_anon
})
self.xblock.is_instructor = Mock(return_value=True)
user_by_anonymous_id_mock.return_value = Mock(username=self.student.student_id)
self.xblock.submitted = True
self.xblock.submission_status = True
expected_result = {
"assignments": [
{
Expand All @@ -465,7 +465,7 @@ def test_get_instructor_grading_data(self, student_item_mock: Mock, user_by_anon
"username": self.student.student_id,
"timestamp": current_datetime.strftime(DateTime.DATETIME_FORMAT),
"score": 50,
"submitted": self.xblock.submitted,
"submission_status": self.xblock.submission_status,

},
],
Expand Down

0 comments on commit 236d762

Please sign in to comment.