from .requests import MoodleRequest
from .files import MoodleFile
import logging
logger = logging.getLogger('moodleteacher')
GRADED = 'graded'
NOT_GRADED = 'notgraded'
NEW = 'new'
SUBMITTED = 'submitted'
[docs]class MoodleSubmission():
"""
A single student submission in Moodle.
"""
def __init__(self, conn=None, submission_id=None, assignment=None, user_id=None, group_id=None, status=None, gradingstatus=None, textfield=None, files=[]):
self.conn = conn
self.id_ = submission_id
self.assignment = assignment
self.userid = user_id
self.groupid = group_id
self.status = status
self.gradingstatus = gradingstatus
self.textfield = textfield
self.files = files
[docs] @classmethod
def from_local_file(cls, assignment, fpath):
"""
Creation of a local-only fake submission object.
Mainly needed for the test suite.
"""
return cls(conn=assignment.conn, assignment=assignment, files=[MoodleFile.from_local_file(fpath)])
def __str__(self):
num_files = len(self.files)
text = "Submission {0.id_} by user {0.userid}, status: {0.gradingstatus}, files: {1}, ".format(
self, num_files)
if self.textfield:
text += "with notes"
else:
text += "without notes"
return(text)
[docs] def parse_plugin_json(self, raw_json):
"""
Parses a plugin block from Moodle JSON and updates the object
accordingly.
"""
files = []
textfield = None
for plugin in raw_json:
if plugin['type'] == 'file':
for fileinfo in plugin['fileareas'][0]['files']:
moodle_file = MoodleFile.from_url(
conn=self.conn,
url=fileinfo['fileurl'],
name=fileinfo['filename'],
time_modified=fileinfo['timemodified'],
mime_type=fileinfo['mimetype'])
files.append(moodle_file)
elif plugin['type'] == 'onlinetext':
textfield = plugin['editorfields'][0]['text']
self.files = files
self.textfield = textfield
def is_empty(self):
return len(self.files) == 0 and not self.textfield
def is_graded(self):
return self.gradingstatus == GRADED or self.load_grade() not in [None, "-"]
def is_group_submission(self):
return self.userid == 0 and self.groupid != 0
def get_group_members(self):
assert(self.is_group_submission())
return self.assignment.course.get_group_members(self.groupid)
[docs] def load_feedback(self):
"""
Retreives the current feedback for this submission from the Moodle server.
"""
params = {'assignid': self.assignment.id_,
'userid': self.userid}
response = MoodleRequest(
self.conn, 'mod_assign_get_submission_status').post(params=params).json()
try:
plugins = response['feedback']['plugins']
for plugin in plugins:
if plugin['type'] == 'comments':
return plugin['editorfields'][0]['text']
except Exception:
pass
return None
[docs] def save_feedback(self, feedback):
"""
Saves new feedback information on the Moodle server.
See also https://moodle.org/mod/forum/discuss.php?d=384108.
"""
logger.debug("Saving feedback information only.")
self.save_grade(grade=-99999, feedback=feedback)
return ""
[docs] def load_grade(self):
"""
Loads the grade currently set for this assignment.
"""
for grade in self.assignment.course.get_user_grades(self.userid):
if grade.item_name == self.assignment.name:
logger.debug("Existing grade: {}".format(grade.gradeformatted))
return grade.gradeformatted
return None
[docs] def save_grade(self, grade, feedback=None):
"""
Saves new grading information for this student on the Moodle server, and sets the workflow
state to "graded".
"""
# You can only give text feedback if your assignment is configured accordingly
if feedback is not None and not self.assignment.allows_feedback_comment:
logger.error("Could not save feedback, assignment does not allow feedback comments. Please check your assignment settings in Moodle.")
return
if self.is_group_submission():
userid = self.get_group_members()[0].id_
else:
userid = self.userid
data = {'assignmentid': self.assignment.id_,
'userid': userid,
'workflowstate': GRADED,
'attemptnumber': -1,
'addattempt': int(True),
'grade': float(grade) if grade else '',
# always apply grading to team
# if the assignment has no group submission, this has no effect.
'applytoall': int(True),
'plugindata[assignfeedbackcomments_editor][text]': str(feedback) if feedback else "",
# //content format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN)
'plugindata[assignfeedbackcomments_editor][format]': 1
}
response = MoodleRequest(
self.conn, 'mod_assign_save_grade').post(data=data).json()
logger.debug("Response from grading update: {0}".format(response))