Commit de585e2c by Bridger Maxwell

Merged with profile changes again. Last time was backwards

parents b7fe049f 9b38e8c5
import json
import hashlib
import logging
from lxml import etree
from mako.template import Template
......@@ -11,14 +12,14 @@ try: # This lets us do __name__ == ='__main__'
except:
settings = None
''' This file will eventually form an abstraction layer between the
course XML file and the rest of the system.
TODO: Shift everything from xml.dom.minidom to XPath (or XQuery)
'''
log = logging.getLogger("mitx.courseware")
def fasthash(string):
m = hashlib.new("md4")
m.update(string)
......@@ -83,11 +84,40 @@ def id_tag(course):
if elem.get('id'):
pass
elif elem.get(default_ids[elem.tag]):
new_id = elem.get(default_ids[elem.tag]) # Convert to alphanumeric
new_id = "".join([a for a in new_id if a.isalnum()])
new_id = elem.get(default_ids[elem.tag])
new_id = "".join([a for a in new_id if a.isalnum()]) # Convert to alphanumeric
# Without this, a conflict may occur between an hmtl or youtube id
new_id = default_ids[elem.tag] + new_id
elem.set('id', new_id)
else:
elem.set('id', fasthash(etree.tostring(elem)))
elem.set('id', fasthash(etree.tostring(elem)))
def propogate_downward_tag(element, attribute_name, parent_attribute = None):
''' This call is to pass down an attribute to all children. If an element
has this attribute, it will be "inherited" by all of its children. If a
child (A) already has that attribute, A will keep the same attribute and
all of A's children will inherit A's attribute. This is a recursive call.'''
if (parent_attribute == None): #This is the entry call. Select all due elements
all_attributed_elements = element.xpath("//*[@" + attribute_name +"]")
for attributed_element in all_attributed_elements:
attribute_value = attributed_element.get(attribute_name)
for child_element in attributed_element:
propogate_downward_tag(child_element, attribute_name, attribute_value)
else:
'''The hack below is because we would get _ContentOnlyELements from the
iterator that can't have due dates set. We can't find API for it. If we
ever have an element which subclasses BaseElement, we will not tag it'''
if not element.get(attribute_name) and type(element) == etree._Element:
element.set(attribute_name, parent_attribute)
for child_element in element:
propogate_downward_tag(child_element, attribute_name, parent_attribute)
else:
#This element would have already been found by Xpath, so we return
#for now and trust that this element will get its turn to propogate
#to its children later.
return
template_lookup = TemplateLookup(directories = [settings.DATA_DIR],
module_directory = settings.MAKO_MODULE_DIR)
......@@ -101,6 +131,8 @@ def course_file(user):
tree = etree.XML(data_template.render(**options))
id_tag(tree)
propogate_downward_tag(tree, "due")
propogate_downward_tag(tree, "graded")
return tree
def module_xml(coursefile, module, id_tag, module_id):
......
......@@ -24,7 +24,7 @@ class StudentModule(models.Model):
module_id = models.CharField(max_length=255, db_index=True) # Filename for homeworks, etc.
student = models.ForeignKey(User, db_index=True)
class Meta:
unique_together = (('student', 'module_id', 'module_type'),)
unique_together = (('student', 'module_id'),)
## Internal state of the object
state = models.TextField(null=True, blank=True)
......
import StringIO
import json
import logging
import os
import sys
import sys
......@@ -32,6 +33,8 @@ import courseware.modules.seq_module
import courseware.modules.vertical_module
import courseware.modules.video_module
log = logging.getLogger("mitx.courseware")
## TODO: Add registration mechanism
modx_modules={'problem':courseware.modules.capa_module.LoncapaModule,
'video':courseware.modules.video_module.VideoModule,
......@@ -59,11 +62,10 @@ def make_track_function(request):
def modx_dispatch(request, module=None, dispatch=None, id=None):
''' Generic view for extensions. '''
# Grab the student information for the module from the database
s = StudentModule.objects.filter(module_type=module,
student=request.user,
s = StudentModule.objects.filter(student=request.user,
module_id=id)
if len(s) == 0:
print "ls404", module, request.user, id
log.debug("Couldnt find module for user and id " + str(module) + " " + str(request.user) + " "+ str(id))
raise Http404
s=s[0]
......
......@@ -46,13 +46,13 @@ class LoncapaModule(XModule):
def get_html(self):
return render_to_string('problem_ajax.html',
{'id':self.filename,
{'id':self.item_id,
'ajax_url':self.ajax_url,
})
def get_init_js(self):
return render_to_string('problem.js',
{'id':self.filename,
{'id':self.item_id,
'ajax_url':self.ajax_url,
})
......@@ -100,7 +100,7 @@ class LoncapaModule(XModule):
html=render_to_string('problem.html',
{'problem' : content,
'id' : self.filename,
'id' : self.item_id,
'check_button' : check_button,
'reset_button' : reset_button,
'save_button' : save_button,
......
......@@ -43,6 +43,12 @@ def profile(request):
chapters = dom.xpath('//course[@name=$course]/chapter', course=course)
responses=StudentModule.objects.filter(student=request.user)
response_by_id = {}
for response in responses:
response_by_id[response.module_id] = response
total_scores = {}
for c in chapters:
chname=c.get('name')
......@@ -53,31 +59,124 @@ def profile(request):
scores=[]
if len(problems)>0:
for p in problems:
id = p.get('filename')
id = p.get('id')
correct = 0
for response in responses:
if response.module_id == id:
if response.grade!=None:
correct=response.grade
else:
correct=0
if id in response_by_id:
response = response_by_id[id]
if response.grade!=None:
correct=response.grade
total=courseware.modules.capa_module.LoncapaModule(etree.tostring(p), "id").max_score() # TODO: Add state. Not useful now, but maybe someday problems will have randomized max scores?
scores.append((int(correct),total))
scores.append((int(correct),total, ( True if s.get('graded') == "True" else False ) ))
section_total = (sum([score[0] for score in scores]),
sum([score[1] for score in scores]))
graded_total = (sum([score[0] for score in scores if score[2]]),
sum([score[1] for score in scores if score[2]]))
#Add the graded total to total_scores
format = s.get('format') if s.get('format') else ""
if format and graded_total[1] > 0:
format_scores = total_scores[ format ] if format in total_scores else []
format_scores.append( graded_total )
total_scores[ format ] = format_scores
score={'course':course,
'section':s.get("name"),
'chapter':c.get("name"),
'scores':scores,
'section_total' : section_total,
'format' : format,
}
hw.append(score)
def totalWithDrops(scores, drop_count):
sorted_scores = sorted( enumerate(scores), key=lambda x: -x[1]['percentage'] ) #Note that this key will sort the list descending
dropped_indices = [score[0] for score in sorted_scores[-drop_count:]] # A list of the indices of the dropped scores
aggregate_score = 0
for index, score in enumerate(scores):
if index not in dropped_indices:
aggregate_score += score['percentage']
aggregate_score /= len(scores) - drop_count
return aggregate_score, dropped_indices
#Figure the homework scores
homework_scores = total_scores['Homework'] if 'Homework' in total_scores else []
homework_percentages = []
for i in range(12):
if i < len(homework_scores):
percentage = homework_scores[i][0] / float(homework_scores[i][1])
summary = "{:.0%} ({}/{})".format( percentage, homework_scores[i][0], homework_scores[i][1] )
else:
percentage = 0
summary = "0% (?/?)"
summary = "Homework {} - {}".format(i + 1, summary)
homework_percentages.append( {'percentage': percentage, 'summary': summary} )
homework_total, homework_dropped_indices = totalWithDrops(homework_percentages, 2)
#Figure the lab scores
lab_scores = total_scores['Lab'] if 'Lab' in total_scores else []
lab_percentages = []
for i in range(12):
if i < len(lab_scores):
percentage = lab_scores[i][0] / float(lab_scores[i][1])
summary = "{:.0%} ({}/{})".format( percentage, lab_scores[i][0], lab_scores[i][1] )
else:
percentage = 0
summary = "0% (?/?)"
summary = "Lab {} - {}".format(i + 1, summary)
lab_percentages.append( {'percentage': percentage, 'summary': summary} )
lab_total, lab_dropped_indices = totalWithDrops(lab_percentages, 2)
midterm_score = (120, 150)
midterm_percentage = midterm_score[0] / float(midterm_score[1])
final_score = (200, 300)
final_percentage = final_score[0] / float(final_score[1])
grade_summary = [
{
'category': 'Homework',
'subscores' : homework_percentages,
'dropped_indices' : homework_dropped_indices,
'totalscore' : {'score' : homework_total, 'summary' : "Homework Average - {:.0%}".format(homework_total)},
'weight' : 0.15,
},
{
'category': 'Labs',
'subscores' : lab_percentages,
'dropped_indices' : lab_dropped_indices,
'totalscore' : {'score' : lab_total, 'summary' : "Lab Average - {:.0%}".format(lab_total)},
'weight' : 0.15,
},
{
'category': 'Midterm',
'totalscore' : {'score' : midterm_percentage, 'summary' : "Midterm - {:.0%} ({}/{})".format(midterm_percentage, midterm_score[0], midterm_score[1])},
'weight' : 0.30,
},
{
'category': 'Final',
'totalscore' : {'score' : final_percentage, 'summary' : "Final - {:.0%} ({}/{})".format(final_percentage, final_score[0], final_score[1])},
'weight' : 0.40,
}
]
user_info=UserProfile.objects.get(user=request.user)
context={'name':user_info.name,
'username':request.user.username,
'location':user_info.location,
'language':user_info.language,
'email':request.user.email,
'homeworks':hw,
'homeworks':hw,
'grade_summary' : grade_summary,
'csrf':csrf(request)['csrf_token']
}
return render_to_response('profile.html', context)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment