# -*- coding: utf-8
# $Id: Kodutoo.py 327 2005-09-06 21:40:47Z vahur $
#
# Copyright 2001, 2002 by IVA Team and contributors
#
# This file is part of IVA.
#
# IVA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# IVA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with IVA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
__version__ = "$Revision: 327 $"[11:-2]
import AccessControl
import OFS, Globals
from OFS import SimpleItem
import types
import time
import re
from TraversableWrapper import Traversable
from Globals import Persistent, PersistentMapping
from AccessControl import ClassSecurityInfo
from AccessControl import allow_module, allow_class, allow_type
from Cruft import Cruft
from common import add_dtml, translate, perm_edit, perm_view
class Kodutoo(
OFS.SimpleItem.Item,
Persistent,
AccessControl.Role.RoleManager,
Traversable,
Cruft
):
meta_type = 'Assignment'
security = ClassSecurityInfo()
""" Assignment object """
def __init__(self, REQUEST, tyyp, kirjeldus="",
normPunkte=0,kalendriID=None):
""" init """
self.tyyp=int(tyyp)
self.kirjeldus=kirjeldus
self.pealkiri = ""
#self.loppaeg=None #Esituspiiri pole määratud. no deadline
# now we always have deadline
self.loppaeg = time.time()
self.normPunkte=normPunkte
self.kalendriID=None #kalendrisyndmuse id. event id.
self.ylesanded=None #list of exercises. for Dist. set of Exerc. only
self.hwID = None #assignment id. for peer review only.
self.testiID = None #quiz id. for quiz type assignment only.
self.reviewMapping = PersistentMapping()
self.lockingFolder = None
def manage_afterAdd(self, item, container):
container.grades[self.id] = {}
def lockFolder(self):
""" lock folder """
return getattr(self, 'lockingFolder', 0)
def getAssignmentID(self):
return getattr(self, 'hwID', "")
security.declareProtected(perm_edit, 'setAssignmentID')
def setAssignmentID(self,hwID):
self.hwID = hwID
def get_id(self):
return self.id
def getDeadline(self, REQUEST):
return time.strftime(translate(self,'timestamp_format',default="%H:%M %Y-%m-%d",target=self.giveLanguage(REQUEST)), time.localtime(self.loppaeg))
def getGrades(self,user,detail='', individual=1):
""" doc string """
if self.tyyp == 2 and not individual:
user = 'subgroup_'+user
gradesObj = getattr(self, 'grades')
if not gradesObj.has_key(self.get_id()):
gradesObj[self.get_id()] = {}
grades = gradesObj[self.get_id()]
if not grades.has_key(user):
value = float(0)
self.setUserPoints(self.get_id(), user, detail, value)
if not gradesObj['Overall'].has_key(user):
gradesObj['Overall'][user] = {}
return grades[user][detail]
def getRawType(self):
""" return assignment type as integer """
return self.tyyp
def getType(self, REQUEST):
""" get assignment type word """
return self.getTypes(REQUEST)[self.tyyp]
def getPoints(self):
""" get assignment value in points """
return self.normPunkte
def quizID(self):
return getattr(self, 'testiID', None)
def getTitle(self, REQUEST=None):
"Antakse kui on"
if len(self.pealkiri.strip())==0:
return "(untitled)"
return self.pealkiri
def getGroups(self):
""" gets groupwork groups"""
if not hasattr(self, 'grupid'):
self.grupid = []
return self.grupid
def kodutooMaterjal(self,bs, tulem='',level=1):
i=1
aste=""
if not hasattr(self, 'juhend'):
self.juhend = ""
while i!=level:
aste += "--"
i=i+1
for obj in bs.list_contents(criteria='weight'):
s=obj.absolute_url()[len(self.fle_root().absolute_url()):]
tulem += "\n"
if obj.meta_type == 'WebtopFolder' and not obj.kasWikiKaust():
tulem = self.kodutooMaterjal(obj,tulem,level+1)
return tulem
def getReviewers(self,uname):
""" return a list who's work users must review """
if not hasattr(self, 'reviewMapping'):
self.reviewMapping = PersistentMapping()
try:
return self.reviewMapping[uname]
except KeyError:
return []
def maxReviewers(self):
max = -1
for x in self.reviewMapping.keys():
if len(self.reviewMapping[x])>max:
max = len(self.reviewMapping[x])
return max
def countReviewer(self,uname):
count = 0
for x in self.reviewMapping.keys():
if uname in self.reviewMapping[x]:
count = count +1
return count
def numberOfAnswers(self, uname, c_id, hwObj):
""" return numbers of user responses """
try:
path = getattr(self.fle_root().fle_users, uname).webtop
path = getattr(path, 'c'+c_id)
path = getattr(path, 'testivastused')
path = getattr(path, hwObj.testiID)
except AttributeError:
return 0
return len(path.objectValues())
def getLinkToAssignment(self, uname, c_id, asID, hwObj=None, tID=None):
""" return url to user's webtop. tyyp==4 """
url = ""
if hwObj:
hwType = hwObj.tyyp
else:
hwType = None
if asID is None:
return ""
try:
path = getattr(self.fle_root().fle_users, uname).webtop
path = getattr(path, 'c'+c_id)
except AttributeError:
path = None
if hwType in (1,4) and path:
try:
path = getattr(path, 'portfolio')
path = getattr(path, asID)
except AttributeError:
return ""
if hwType == 1 and path:
if not len(path.objectValues()):
path = None
if hwType == 0 and path:
try:
path = getattr(path, 'testivastused')
path = getattr(path, hwObj.testiID)
try:
if tID is not None:
path = getattr(path, path.objectValues()[tID].get_id())
except IndexError:
return ""
#test0 -> variant1
except AttributeError:
return ""
# XXX:FIX: needs testing
# AttributeError: 'NoneType' object has no attribute 'absolute_url'
try:
if path:
url = path.absolute_url()+'/'
except AttributeError:
return ""
return url
security.declareProtected(perm_edit, 'automaticMatching')
def automaticMatching(self, REQUEST, courseid, randomize, number, number2):
""" automatically divide users """
course = getattr(self.fle_root().courses, courseid)
users = course.get_all_users()
from random import choice
for x in users:
self.reviewMapping[x.get_uname()] = []
for i in range(0,number):
nameObj = choice(users)
ring = 1
stopp = 0
while (x.get_uname() == nameObj.get_uname() or self.countReviewer(nameObj.get_uname())>number2-1) and stopp==0:
nameObj = choice(users)
ring = ring + 1
if ring>70:
stopp = 1
if not stopp:
self.addPeerReviewMatching(0,x.get_uname(),nameObj.get_uname(),r_add=1)
else:
#XXX: try finding available person
for j in users:
if self.countReviewer(j.get_uname())"+ translate(self,'Deadline updated: ',target=self.giveLanguage(REQUEST))
if self.loppaeg !=None:
s_pikk += time.strftime(translate(self,'timestamp_format',default="%H:%M %Y-%m-%d",target=self.giveLanguage(REQUEST)), time.localtime(self.loppaeg))
else:
s_pikk += translate(self, 'No deadline',target=self.giveLanguage(REQUEST))
s_end = self.loppaeg
if eelmine_punktid != self.normPunkte:
s_pikk += " "+translate(self,'Points changed:',target=self.giveLanguage(REQUEST))+" "+str(self.normPunkte)
syndmused._delObject(too_syndmus.id)
wiga = 0
except:
pass
if wiga:
s_end = time.time()
if hasattr(REQUEST, 'kasLoppaeg'):
s_end = abi.ajaPyydmisLeht(REQUEST, 'loppaeg')
s_pikk = translate(self,'New task added', target=self.giveLanguage(REQUEST))+" "+self.pealkiri+"("+kt_tyyp+") "+self.kirjeldus+" "
s_pikk += translate(self,'Points:',target=self.giveLanguage(REQUEST))+" "+str(self.normPunkte)
if self.tyyp != 0 and self.tyyp != 3:
s_pikk += " "+translate(self,'Deadline:',target=self.giveLanguage(REQUEST))
s_pikk += time.strftime(translate(self,'timestamp_format',default="%H:%M %Y-%m-%d",target=self.giveLanguage(REQUEST)), time.localtime(s_end))
try:
s_algus = s_end
except:
s_algus = time.time()
s_end = time.time()
too_syndmus = syndmused.lisaSyndmusKohe(s_nimi,s_pikk,s_algus,s_end,'',self.juhend,s_status)
too_syndmus.setIconTag('images/kodune')
if self.tyyp == 2:
uusID.append(too_syndmus.id)
else:
uusID = too_syndmus.id
#self.kalendriID = too_syndmus.id
self.kalendriID = uusID
REQUEST.RESPONSE.redirect('../manage_assignments')
def assignmentGrading_handler(self, REQUEST, save, user, points, comment):
""" assignmentGrading form handler. Saves user grade """
try:
points = float(points)
except:
return self.message_dialog(message='Invalid value for points. Must be numerical!')
if self.tyyp!=2:
self.setUserPoints(self.get_id(), user, 'points', points)
self.setUserPoints(self.get_id(), user, 'comment', comment)
if self.tyyp==2:
self.setUserPoints(self.get_id(), 'subgroup_'+user, 'points', points)
self.setUserPoints(self.get_id(), 'subgroup_'+user, 'comment', comment)
subgroups = getattr(self, 'subgroups', None)
if subgroups is None:
# TODO: problem - no subgroups around
pass
subgroup = subgroups.getSubgroupByName(user)
for x in subgroup.subgroup_members():
self.setUserPoints(self.get_id(), x, 'points', points)
self.setUserPoints(self.get_id(), x, 'comment', comment)
return REQUEST.RESPONSE.redirect(self.absolute_url()+'/manage_gradeAssignment')
class KodutoodeKataloog(
OFS.Folder.Folder,
OFS.SimpleItem.Item,
Persistent,
AccessControl.Role.RoleManager,
Traversable,
Cruft
):
""" Assignments folder """
meta_type = "Assignments folder"
security = ClassSecurityInfo()
security.declareObjectPublic()
# XXX:Migration needed for Persistent mapping
def __init__(self):
""" self.grades mapping example:
grades = {
'too1':{
'Vahur':{
'points':'55.3',
'comment':'comment box',
'teacherComment':'teacher comment box'
}
}
'Overall':{
'Vahur':{
'TotPoints':'90.1',
'TotPointsCom':'Total points comment',
'grade':'F',
'gradeCom':'Total grade comment',
'OverallComment':'Overall comment'
}
}
}
"""
self.grades = PersistentMapping()
self.grades['Overall'] = {}
self.grades = self.grades
self.hindeTahised=["A", "B", "C", "D", "E", "F"]
self.hindePiirid=[90, 80, 70, 60, 50]
self.tooNr=0
def getTypes(self, REQUEST):
"Assignment types"
t = [translate(self, 'Quiz',target=self.giveLanguage(REQUEST)), translate(self, 'Product',target=self.giveLanguage(REQUEST)), translate(self, 'Groupwork',target=self.giveLanguage(REQUEST)), translate(self,'Presentation',target=self.giveLanguage(REQUEST)), translate(self,'Peer review',target=self.giveLanguage(REQUEST)), translate(self,'Distributable set of exercises',target=self.giveLanguage(REQUEST))]
return t
security.declareProtected(perm_edit,'kysiCSV')
def kysiCSV(self, REQUEST):
""" return users grades in a csv file """
REQUEST.RESPONSE.setHeader('Content-disposition','attachment; filename=grades.csv')
users = self.get_all_users()
t = "name;"
for x in self.listAssignments():
t += x.getTitle()+';'
t += "total;grade;\n"
for x in users:
t+= self.firstAndLast(x.get_uname())+";"
for too in self.listAssignments():
t+=str(too.getGrades(x.get_uname(),'points'))+";"
t+= str(self.getOverallDetails(x.get_uname(),'TotPoints'))+';';
t+= str(self.getOverallDetails(x.get_uname(),'grade'))+";\n"
return t
def getOverallDetails(self, user, detail=''):
""" return things """
gradesObj = getattr(self, 'grades')
try:
return gradesObj['Overall'][user][detail]
except KeyError:
return
def index_html(self,REQUEST):
""" redirect to manage_assignments """
return REQUEST.RESPONSE.redirect('manage_assignments')
security.declareProtected(perm_edit,'lisaKodutoo')
def lisaKodutoo(self, REQUEST, tyyp,preferred_id=''):
"Luuakse vastava tüübiga kodutöö ja väljastatakse selle eksemplar"
self.tooNr=self.tooNr+1
if preferred_id:
id = preferred_id
else:
id='too'+str(self.tooNr)
print "kodutoo id: ",id
while hasattr(self,id):
self.tooNr = self.tooNr+1
id = 'too'+str(self.tooNr)
too=Kodutoo(REQUEST, tyyp)
too.id = id
self._setObject(too.id, too)
return too
security.declareProtected(perm_edit, 'addAssignment_handler')
def addAssignment_handler(self, REQUEST):
"Andmete salvestus"
too=self.lisaKodutoo(REQUEST, REQUEST.tyyp)
if too.tyyp==2:
too.grupid = []
REQUEST.RESPONSE.redirect(self.absolute_url()+'/'+too.id+'/manage_changeAssignment')
security.declareProtected(perm_edit, 'manageAssignFormHandler')
def manageAssignFormHandler(self, REQUEST, kustuta='', salvesta='', tooID=()):
"Toiming vastavalt nupule"
if kustuta:
if type(tooID)==types.StringType:
tooID=(tooID,)
for x in tooID:
self._delObject(x)
if salvesta:
self.hindeTahised=[]
self.hindePiirid=[]
kokku=len(REQUEST.hindePiir)
veel=1
i=0
while veel and i0) and (self.hindePiirid[i]<=self.hindePiirid[i-1]):
# veel=0
except:
veel=0
i=i+1
#self.aq_parent.kontrolliHinneteKaustad(REQUEST)
REQUEST.RESPONSE.redirect('manage_assignments')
def normpunktideSumma(self, REQUEST=None):
"Kataloogis olevate tööde normpunktide summa"
summa=0
for x in self.objectValues():
summa+=x.normPunkte
return summa
def punktideleVastavHinne(self, REQUEST, punkte):
"Arvutatakse tähis punktide järgi"
if not hasattr(self, 'hindePiirid'): return translate(self, 'No scale',target=self.giveLanguage(REQUEST))
if len(self.hindePiirid)==0: return translate(self, 'No grades', target=self.giveLanguage(REQUEST))
if self.normpunktideSumma(REQUEST)<=0:
return ""
try:
protsent=float(punkte)*100/self.normpunktideSumma(REQUEST)
except:
return ""
i=0
while i= self.hindePiirid[i]:
return self.hindeTahised[i]
i+=1
if i