# -*- coding: utf-8 # $Id: Course.py,v 1.6 2003/08/18 07:44:24 berlingo Exp $ # # 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 """Contains class Course, which represents one course, which has one or more CourseContexts, which in turn contain knowledge building conversations.""" __version__ = '$Revision: 1.6 $'[11:-2] import time import string, types import OFS, Globals from Globals import Persistent, Acquisition import AccessControl from AccessControl import ClassSecurityInfo import copy import re import Kodutoo try: from Products.ZWiki.ZWikiPage import ZWikiPage USE_ZWIKI = 1 except: USE_ZWIKI = 0 from Jamming import Jamming from TraversableWrapper import Traversable from common import add_dtml, reload_dtml, intersect_bool, make_action, get_roles, get_local_roles, translate from input_checks import strip_all, is_valid_title from CourseContext import CourseContext #from ThinkingTypeSetManager import ThinkingTypeSetManager as TTSM from Thread import Thread from Cruft import Cruft from TempObjectManager import TempObjectManager from input_checks import render, normal_entry_tags_and_link from common import perm_view, perm_edit, perm_manage, perm_add_lo from TestiHaldur import TestiHaldur import WebtopTrash # Each Course object contains (usually) one or more CourseContexts, which # represent different aspects of the course. # A Course contains information and services on one course implementation. class Course( Persistent, Traversable, Cruft, OFS.Folder.Folder, AccessControl.Role.RoleManager, OFS.SimpleItem.Item, Thread, ): """Course, contained within CourseManager, represents one course.""" meta_type = 'Course' security = ClassSecurityInfo() security.declareObjectPublic() # Call courses/course_html (This way we avoid copying index_html # to each instance of Course class.) # ATTENTION: We don't exactly know how this works (for example, # do we really need REQUEST ?) # #TODO: This could be done with a URL pointing to the course_html script. #But if we need this default implementation, we could use #restrictedTraverse('course_html') to activate Zope acquisition. #FIX:bla? security.declareProtected('View', 'index_html') def index_html(self, REQUEST=None): """Default script""" return REQUEST.RESPONSE.redirect('course_html') # Parameters: # #- parent: should be a CourseManager # #- name: name of the Course # #- tts: list of ThinkingTypeSets (copies are made in manage_afterAdd) # #- teachers: list of users (of class UserInfo?) that are granted #Teacher privileges # #- etc: other textual information def __init__( self, parent, # Whatever you do, dont bind this to self. name, teachers, description='', organisation='', methods='', starting_date='', ending_date='', tootoaMuutused = {} ): """Constructor of the course.""" # Overriding all_meta_types is not not beautiful...but, hey!, it works! #self.all_meta_types = ( # {'name': 'ThinkingTypeSet', # 'action': 'get_id'},) # Cache active members. self.active_memb_cache = [] # Remove all HTML tags from parameters name = strip_all(name) description = strip_all(description) methods = strip_all(methods) organisation = strip_all(organisation) Thread.__init__(self, parent) # Takes care of id and title. for teacher in teachers: self.set_roles(teacher, ('Teacher',)) self.__name = name # name of the course self.__organisation = organisation self.__description = description self.__methods = methods self.__starting_date = starting_date self.__ending_date = ending_date self.__credits = '' self.__courseID = '' self.course_category = 0 self.tootoaMuutused = tootoaMuutused self.wordmapnr=0 # This is for group folder path listings - show path up to course. self.toplevel = 1 security.declarePrivate('manage_afterAdd') #Each course should have its own copy of the ThinkingTypeSets, #as the course administrator (teacher) should be able to edit them, #create new ones and so forth. These changes must not propagate to #other courses: hence the copying of the set. def manage_afterAdd(self, item, container): """foo""" from common import roles_student, roles_tutor, roles_teacher from common import roles_admin #add subgroup folder from GroupFolder import GroupFolder sgwt = GroupFolder(None,'Subgroups') sgwt.id = 'subgroups' sgwt._subgr_head = 1 self._setObject('subgroups', sgwt) getattr(self, 'subgroups').manage_permission(perm_edit,('Manager',), 0) #add folder for qt self.manage_addProduct['OFSP'].manage_addFolder('testid') # self._setObject('testid', TestiHaldur()) self.testid.id='testid' # add jamming self._setObject('jamming', Jamming('jamming')) self.manage_addProduct['OFSP'].manage_addFolder('wordmaps') self.wordmaps.wordmapnr=0 # add folder for assignments #XXX: think not necessary to migrate since previous check was in for a long time k=Kodutoo.KodutoodeKataloog() k.id='kodutood' self._setObject(k.id, k) security.declareProtected(perm_view, 'addCourseWiki') def addCourseWiki(self): #We add wiki here if USE_ZWIKI: from Products.ZWiki.ZWikiPage import ZWikiPage wikiobj = ZWikiPage(source_string='', __name__='WelCome') wikiobj.NOT_CATALOGED = True #XXX: catalog gives error:TypeError: can only concatenate list (not "tuple") to list newid = self._setObject('WelCome',wikiobj) nw = getattr(self, newid) # nw.title = self.get_name() nw.manage_permission('Zwiki: Rename pages',[],0) nw.manage_permission('Zwiki: Delete pages',[],0) #XXX: change owner! return "Refresh page!" else: return "ZWiki not installed" security.declareProtected(perm_edit, 'lisa_grupp') def lisa_grupp(self, grupinimi): """Lisab kursusesise grupi""" from GroupFolder import GroupFolder import Kalender grupinimi=re.sub('[^a-zA-Z0-9]', '_', grupinimi) if grupinimi[0] == "_": grupinimi="x"+grupinimi if grupinimi[-2:] == "__": grupinimi += "x" fol=GroupFolder(None, grupinimi) while hasattr(self.subgroups, grupinimi): grupinimi+='y' fol.id=grupinimi fol._is_subgroup = 1 self.subgroups._setObject(grupinimi, fol) fol=fol.__of__(self.subgroups) # fol.toplevel=1 # fol._setObject('trash', WebtopTrash.WebtopTrash()) # self.lisaGrupiKaust(grupinimi) fol._setObject('syndmused', Kalender.KalendriSyndmusteKataloog()) fol.syndmused.id='syndmused' fol.manage_permission(perm_edit, ('Manager','IVAAdmin','Teacher','User'),0) # return "lisatud" + grupinimi return fol # security.declareProtected(perm_edit, 'add_subgroup_handler') #XXX: security check. anyone shouldn't be able to add subgroup! def add_subgroup_handler(self, REQUEST=None, subgroup_name='', add=1): """ creating subgroup """ if not subgroup_name or not add: return 0 sg = self.lisa_grupp(subgroup_name.strip()) if REQUEST is None: return sg else: REQUEST.set('grname',sg.id) return REQUEST.RESPONSE.redirect("workshop_subgroup_show?grname=%s" % sg.id) def getNewWordMapNr(self): "Return growing number" if not hasattr(self.wordmaps, 'wordmapnr'): self.wordmaps.wordmapnr=0 self.wordmaps.wordmapnr+=1 return self.wordmaps.wordmapnr def addNewWordMap(self): "Makes new course level wordmap" nr=self.getNewWordMapNr() from WordMap import WordMap m=WordMap() m.id='map'+str(nr) self.wordmaps._setObject(m.id, m) return m.id def kasKursuselMoistekaarte(self): "Is here wordmaps" return len(self.wordmaps.objectValues('WordMap'))>0 def getWordMaps(self): "Wordmaps in this course" return self.wordmaps.objectValues('WordMap') def addWordMap_handler(self, REQUEST): "Adds new wordmap and redirects to index page" self.addNewWordMap() REQUEST.RESPONSE.redirect(self.wordmaps.absolute_url()+'/wordmaps_index_html') security.declareProtected(perm_edit,'wordmaps_delete_handler') def wordmaps_delete_handler(self, REQUEST, wm=()): "Deleting selected wordmaps" if type(wm) is types.StringType: wm=(wm,) for w in wm: self.wordmaps._delObject(w) REQUEST.RESPONSE.redirect(self.wordmaps.absolute_url()+'/wordmaps_index_html') def is_courseContext(self): """ is course context? """ return def kasTeadmuspajasKontekste(self): "jah/ei" return len(self.objectValues('CourseContext'))>0 def kasMeediapajasProjekte(self): "jah/ei" return len(self.jamming.objectValues('JamSession'))>0 def kysiOotajad(self, REQUEST=None): "Kursusele registreerunud, keda pole veel kinnitatud" if hasattr(self, 'ootajad'): return self.ootajad return [] security.declareProtected(perm_edit,'manage_pendingUsers_handler') def manage_pendingUsers_handler(self, REQUEST, addtocourse='',deletefromlist='',pender=''): "Lisamine või kustutus" #from Kirjakast import Kirjakast temp = getattr(self.fle_root(), 'fle_users') if not pender: return self.message_dialog_error(self, REQUEST, title="Error", message='Please select some users first', action='manage_pendingUsers') if type(pender)==types.StringType: pender=(pender,) penders=self.kysiOotajad() new_penders = [] if deletefromlist: for x in pender: puser = getattr(temp, x) for y in penders: if y.get_uname() == x: continue new_penders.append(y) if addtocourse: print pender for x in pender: puser = getattr(temp, x) self.add_student(puser.get_uname()) #XXX: this is not in message catalog! mess_title = translate(self,'Added to course',target=self.giveLanguage(REQUEST)) mess_body = translate(self,'You have been added to course',target=self.giveLanguage(REQUEST))+' '+self.get_name() puser.kirjad.saadaKiri(REQUEST,puser.get_uname(),puser.get_uname(),mess_title,mess_body,999999) for x in penders: if x.get_uname() not in pender: print x.get_uname(), "---",pender print "lisan", x.get_uname() new_penders.append(x) self.ootajad=new_penders return REQUEST.RESPONSE.redirect('haldusleht') def ootajastKursuseLiikmeks(self, REQUEST, kasutaja): "Lisamine" self.add_student(kasutaja.get_uname()) return 1 def lisaOotaja(self, REQUEST, ootaja): "Kasutaja lisab end ootama" if self.kysiStaatus()=='4': #automaatregistreerumine self.ootajastKursuseLiikmeks(REQUEST, ootaja) else: m=self.kysiOotajad(REQUEST) if ootaja not in m: m.append(ootaja) self.ootajad=m return 0 def kasOotaja(self, nimi): "Kas jooksev kasutaja on kursusele ootaja" m=self.kysiOotajad() kas=0 for x in m: if nimi==x.get_uname(): kas=1 return kas def lisaYlTest(self, REQUEST): "Lisatakse ülesannete test" # XXX from YlTest import YlTest if not hasattr(self.testid, 'nr'): self.testid.nr=0 while hasattr(self.testid.aq_self, 'test'+str(self.testid.nr)): self.testid.nr=self.testid.nr+1 t=YlTest() t.id="test"+str(self.testid.nr) self.testid._setObject(t.id, t) t.meta.language=self.giveLanguage(REQUEST) # return str(t.id) REQUEST.RESPONSE.redirect('testihaldus') def testiMuutus(self, REQUEST, testinimi='', rename='', delete='', export='', importdata='', results='', showhide='', randomize='',confirmation='',cancel=''): "Testide haldus" if importdata: REQUEST.RESPONSE.redirect(self.find_URL_of_fle_root(REQUEST)+\ "/courses/"+ self.get_course_id_from_req(REQUEST)+"/testideImport") return if not testinimi: return if export: REQUEST.RESPONSE.redirect(self.find_URL_of_fle_root(REQUEST)+\ "/courses/"+ self.get_course_id_from_req(REQUEST)+"/iva_ims_export?testinimi="+testinimi) return if rename: if hasattr(self.testid, testinimi): # REQUEST.RESPONSE.redirect("testid/"+testinimi+"/pealkirjaMuutmisVormHTML?liikumisURL="+\ # self.find_URL_of_fle_root(REQUEST)+"/testihaldus") REQUEST.RESPONSE.redirect("testid/"+testinimi+"/ylTestSettingsForm?liikumisURL="+\ self.find_URL_of_fle_root(REQUEST)+"/testihaldus") if delete: if confirmation: if hasattr(self.testid, testinimi): self.testid._delObject(testinimi) elif cancel: return REQUEST.RESPONSE.redirect("testihaldus") else: return self.message_dialog2(self,REQUEST, title="Confirmation", message="Are you sure you want to delete quiz?", option1_name="cancel", option1_value="Cancel", option2_value="Delete", option2_name="confirmation", extra_value_name='delete', extra_values = ('yes',), item_name='testinimi', item_value=testinimi, handler="testiMuutus") REQUEST.RESPONSE.redirect("testihaldus") if importdata: REQUEST.RESPONSE.redirect("testid/"+testinimi+"/vahendus/tekstistYlesanneteLaadimiseVorm") if export: REQUEST.RESPONSE.redirect("testid/"+testinimi+"/vahendus/ylesandedTekstina") if results: REQUEST.RESPONSE.redirect("testid/"+testinimi+"/kasutajateTulemused") if showhide: #getattr(self.testid, testinimi).muudaAvatudTaitmiseks(REQUEST) #REQUEST.RESPONSE.redirect(self.find_URL_of_fle_root(REQUEST)+"/testid/"+testinimi+"/lubadeViited") REQUEST.RESPONSE.redirect("testid/"+testinimi+"/lubadeViited") if randomize: getattr(self.testid, testinimi).muudaKysimusteJuhuslikJarjekord() # return "Muudetud" REQUEST.RESPONSE.redirect(self.find_URL_of_fle_root(REQUEST)+"/testihaldus") security.declarePublic('kustuta_grupp') def kustuta_grupp(self, gnimi): "Kustutab kursusesisese grupi" self.subgroups._delObject(gnimi) return "kustutatud" security.declareProtected(perm_view, 'get_printable_name') # No additional comments. def get_printable_name(self): """Return name of the course.""" return self.__name security.declareProtected(perm_view, 'get_bg_colour_name') def get_bg_colour_name(self): """...""" return 'gr' # security.declareProtected(perm_view, 'get_name') security.declarePublic('get_name') # No additional comments. def get_name(self): """Get course name.""" return self.__name security.declareProtected(perm_view, 'get_organisation') # No additional comments. def get_organisation(self): """Get organisation name.""" return self.__organisation security.declareProtected(perm_view, 'get_description') # No additional comments. def get_description(self): """Get description.""" return self.__description security.declareProtected(perm_view,'render_description') def render_description(self): """Render description.""" return render( self.get_description(), legal_tags=normal_entry_tags_and_link) security.declareProtected(perm_view, 'get_methods') # No additional comments. def get_methods(self): """Get info on methods.""" return self.__methods security.declareProtected(perm_view,'render_methods') def render_methods(self): """Render methods.""" return render( self.get_methods(), legal_tags=normal_entry_tags_and_link) def get_courseID(self): """ get course id """ try: return self.__courseID except: return "" def set_courseID(self,courseID): """ set course id(the other one) """ self.__courseID = courseID def get_credits(self): """ get credits info """ try: return self.__credits except: return "" def set_credits(self,credits): """ set credits """ self.__credits = credits # security.declareProtected(perm_view, 'get_teachers') # No additional comments. security.declarePublic('get_teachers') def get_teachers(self): """Get teachers.""" retval = [] for (user, roles) in self.get_local_roles(): if 'Teacher' in roles: retval.append(user) return retval security.declareProtected(perm_view, 'get_start_dd') # No additional comments. def get_start_dd(self): """Return starting day.""" if self.__starting_date: return time.localtime(self.__starting_date)[2] else: return '' security.declareProtected(perm_view, 'get_start_mm') # No additional comments. def get_start_mm(self): """Return starting month.""" if self.__starting_date: return time.localtime(self.__starting_date)[1] else: return '' security.declareProtected(perm_view, 'get_start_yyyy') # No additional comments. def get_start_yyyy(self): """Return starting year.""" if self.__starting_date: return time.localtime(self.__starting_date)[0] else: return '' security.declareProtected(perm_view, 'get_end_dd') # No additional comments. def get_end_dd(self): """Return ending day.""" if self.__ending_date: return time.localtime(self.__ending_date)[2] else: return '' security.declareProtected(perm_view, 'get_end_mm') # No additional comments. def get_end_mm(self): """Return ending month.""" if self.__ending_date: return time.localtime(self.__ending_date)[1] else: return '' security.declareProtected(perm_view, 'get_end_yyyy') # No additional comments. def get_end_yyyy(self): """Return ending year.""" if self.__ending_date: return time.localtime(self.__ending_date)[0] else: return '' # security.declareProtected(perm_view, 'get_printable_starting_date') security.declarePublic('get_printable_starting_date') #FIX:security check # No additional comments. def get_printable_starting_date(self, REQUEST): """Get starting date.""" return time.strftime(translate(self,'short_date_format',target=self.giveLanguage(REQUEST)), time.localtime(self.__starting_date)) # security.declareProtected(perm_view, 'get_printable_ending_date') security.declarePublic('get_printable_ending_date') #FIX:security check # No additional comments. def get_printable_ending_date(self, REQUEST): """Get ending date.""" if self.__ending_date == 0: return '' return time.strftime(translate(self,'short_date_format',target=self.giveLanguage(REQUEST)), time.localtime(self.__ending_date)) security.declarePrivate('get_start_date') def get_start_date(self): return self.__starting_date security.declarePrivate('get_end_date') def get_end_date(self): return self.__ending_date security.declareProtected(perm_view, 'get_users') def get_users(self, REQUEST): """Return dict with 2 members of attendees as UserInfo objects. 'active_d' is the list of active members. 'others_d' is the rest .. [[UIObj'active1'], [UIObj'other1', UIObj'other2', ..]]""" rv = {'active_d':[], 'others_d': []} au = str(REQUEST.AUTHENTICATED_USER) for uname in [(u[0]) for u in self.get_local_roles()]: from Errors import FleError try: o = self.fle_users.get_user_info(uname) if uname == au or uname in self.active_memb_cache: rv['active_d'].append(o) else: rv['others_d'].append(o) except FleError: pass return rv security.declarePublic('get_n_users') def get_n_users(self): return len(self.get_all_users_id()) security.declareProtected(perm_view, 'get_all_users') def get_all_users(self): """Return a list of all users on course.""" rv = [] for uname in self.get_all_users_id(): try: rv.append(self.fle_users.get_user_info(uname)) except Exception: pass return rv def kasutajateKodutoodeArhiiv(self, REQUEST): "Arhiiv, kuhu paigutatakse kasutaja esitatud materjalid" import tempfile import zipfile failinimi=tempfile.mktemp() arhiiv=zipfile.ZipFile(failinimi,"w",zipfile.ZIP_DEFLATED) kasutajad=self.get_all_users() for x in kasutajad: kc=getattr(x.webtop, 'c'+self.id) for too in self.kodutood.objectValues(): if too.tyyp==1: #materjal if hasattr(kc, 'esitlused'): if hasattr(kc.esitlused, too.id): tookataloog=getattr(kc.esitlused, too.id) tookataloog.looArhiiv(REQUEST, arhiiv, x.id+'/') if too.tyyp==2: #grupp mitu=0 punkte=-1 for kg in x.kysiKursuseSisegrupid(self): if kg.id in too.grupid: esitluskaust=getattr(self.leiaGrupiKaust(kg.id), too.id) esitluskaust.looArhiiv(REQUEST, arhiiv, kg.id+'/') arhiiv.close() file = open(failinimi,"rb") export_data=file.read() file.close() import os os.remove(failinimi) REQUEST.RESPONSE.setHeader('Content-type','application/zip') REQUEST.RESPONSE.setHeader('Content-disposition','attachment; filename=tooarhiiv.zip') return export_data def kysiCSV(self, REQUEST): "Kasutaja salvestatud punktid" REQUEST.RESPONSE.setHeader('Content-disposition','attachment; filename=grades.csv') t="nimi" kasutajad=self.get_all_users() for too in self.kodutood.objectValues(): t+=","+too.id t+=",koond" for x in kasutajad: kc=getattr(x.webtop, 'c'+self.id) t+="\n"+x.get_id() for too in self.kodutood.objectValues(): t+="," if hasattr(kc, too.id): t+=str(getattr(kc, too.id)) t+="," if hasattr(kc, 'koondhinne'): t+=str(kc.koondhinne) return t def fotogaKasutajad(self): "kasutajad, kel on foto" m=[] for x in self.get_all_users(): if x.has_photo(): m.append(x) return m def fototaKasutajad(self): "kasutajad, kel pole fotot" m=[] for x in self.get_all_users(): if not x.has_photo(): m.append(x) return m security.declareProtected(perm_view, 'get_all_users_id') def get_all_users_id(self): """Return a list of all users on this course. Same thing as get_all_users, but this one returns a list of id's of UserInfo objects, not the UserInfo object reference.""" cl = [] for u in self.get_local_roles(): if 'Student' in u[1] or 'Teacher' in u[1]: cl.append(u[0]) return cl # return [u[0] for u in self.get_local_roles()] def kasutajad_sisegrupis(self, grupinimi,objektina=None): "Sisegrupi rahva loetelu" loetelu=[] for u in getattr(self.subgroups, grupinimi).get_local_roles(): if ('User' in u[1]): if objektina: loetelu.append(self.fle_users.get_user_info(u[0])) else: loetelu.append(u[0]) return loetelu def kasutajad_sisegrupis_objektina(self,grupinimi): """Return a list of all users on course.""" rv = [] grupplased=self.kasutajad_sisegrupis(grupinimi) for uname in self.kasutajad_sisegrupis(grupinimi): grupid = [] try: tekst = '' rv.append(self.fle_users.get_user_info(uname)) for sisegr in self.fle_users.get_user_info(uname).kysiKursuseSisegrupid(self): if grupinimi != sisegr.get_name(): grupid.append(sisegr.get_name()) if len(grupid) == 1: tekst += ' ('+grupid[0]+')' if len(grupid)>1: #tekst += ' (' for gname in grupid: if tekst: tekst += ', ' tekst += gname tekst = '( '+tekst tekst += ')' rv.append(tekst) except Exception: pass return rv def kasutajad_mitte_sisegrupis(self, grupinimi): "Nimed, kes on kursusel, kuid mitte grupis" kursuslased=self.get_all_users_id(); grupplased=self.kasutajad_sisegrupis(grupinimi) mittegrupplased=[] for u in kursuslased: tekst = '' grupid = [] if u not in grupplased: tekst = '' for sisegr in self.fle_users.get_user_info(u).kysiKursuseSisegrupid(self): if grupinimi != sisegr.get_name(): grupid.append(sisegr.get_name()) if len(grupid) == 1: tekst += ' (' + grupid[0] + ')' if len(grupid) >1: tekst += ' (' i = 0 for gnimi in grupid: if i != 0: tekst += ', ' tekst += gnimi i = i + 1 tekst += ')' mittegrupplased.append(u) mittegrupplased.append(tekst) return mittegrupplased def kasutajad_sisegruppidesse(self, grupinimi, REQUEST, sisse='', valja=''): "Tostab kasutajaid gruppi ja valja" if sisse: if type(sisse) is types.StringType: sisse=(sisse,) for x in sisse: self.lisa_sisegruppi(grupinimi, x) if valja: if type(valja) is types.StringType: valja=(valja,) for x in valja: self.eemalda_sisegrupist(grupinimi, x) REQUEST.RESPONSE.redirect("workshop_subgroup_show?grname=%s" % grupinimi) #XXX: security check! #security.declareProtected(perm_edit, 'workshop_subgroup_handler') def workshop_subgroup_handler(self,REQUEST,groupName='',delete='',participants='',eventmanage='',sendmessage='',confirmation='',cancel=''): """ workshop_subgroup form handler """ if not self.is_student(REQUEST) and not self.kas_opetaja(REQUEST): return "" if not groupName: return self.message_dialog_error( self, REQUEST, title="Error", message="no group selected", action="workshop_subgroup") if delete: if confirmation: self.kustuta_grupp(groupName) elif cancel: pass else: return self.message_dialog2(self,REQUEST, title="Confirmation", message="Are you sure you want to delete subgroup? There will be no undo!", option1_name="cancel", option1_value="Cancel", option2_value="Delete", option2_name="confirmation", extra_value_name='delete', extra_values = ('yes',), item_name='groupName', item_value=groupName, handler="workshop_subgroup_handler") return REQUEST.RESPONSE.redirect("workshop_subgroup") if participants: return REQUEST.RESPONSE.redirect("workshop_subgroup_show?grname="+groupName) return "show participants..." if eventmanage: return REQUEST.RESPONSE.redirect("subgroups/"+groupName+"/syndmused/event_list?userLocation=Tootuba") # return "Event management..." if sendmessage: curUser = self.jooksevKasutaja(REQUEST) REQUEST.RESPONSE.redirect(curUser.absolute_url()+"/kirjad/createMail?userLocation=Tootuba") kellele = '' for x in self.kasutajad_sisegrupis(groupName): if kellele: kellele+=',' kellele+=x REQUEST.SESSION.set('kellele',kellele) # FIX: delete session variable return curUser.kirjad.createMail() return "sending messages..." return "oioioi" security.declareProtected(perm_edit, 'kustuta_sisegrupid') # FIX: XXX REMOVE def kustuta_sisegrupid(self, REQUEST, grupinimi=None): "kustutab etteantud grupid" if grupinimi: if type(grupinimi) is types.StringType: grupinimi=(grupinimi,) for x in grupinimi: self.kustuta_grupp(x) REQUEST.RESPONSE.redirect("workshop_subgroup") security.declareProtected(perm_view, 'get_users_with_role') def get_users_with_role(self, role): """Return a list of participants who have a specified role.""" rv = [] for e in self.get_local_roles(): if role in e[1]: # try: rv.append(self.fle_users.get_user_info(e[0])) # except Exception: # pass return rv security.declareProtected(perm_edit, 'add_student') #The person is added with Student role access. # NOTE: This method is no longer needed, except in the test cases! def add_student(self, name): """Add person to the course.""" # Check that user exists... Raises exception if not. #XXX: is this really needed!? now commented out # self.fle_users.get_user_info(name) uinf = self.fle_users.get_user_info(name) uinf.user_courselist_cache.append(self.get_id()) uinf._p_changed = True self.set_roles(name, ('Student',)) security.declareProtected(perm_view, 'get_valid_roles') # No additional comments. def get_valid_roles(self): """Get the roles valid for persons added to the course.""" from CourseManager import course_level_roles valid_roles = list(course_level_roles) #valid_roles.append('Teacher') return valid_roles security.declareProtected(perm_manage, 'remove_person') def remove_person(self, person): """Remove person from the course.""" # Check that user exists... Raises exception if not. kasutaja=self.fle_users.get_user_info(person) try: kasutaja.user_courselist_cache.remove(self.get_id()) except: pass kasutaja._p_changed = True #We have to do it the hard way since set_jooksev_kursus turns me away kasutaja.jooksev_kursus=0 # We use the get_local_roles method, because we need to # see if the user has a role attached to this course object # specifically, and we don't want the roles in the acquisition # tree to interfere. if len(get_local_roles(self,person))==0: raise FleError, ("User "+person+" does not belong to this course.") self.__unset_roles((person,)) # Note: person _must_ be a sequence! def __unset_roles(self, persons): """Unset roles of one user.""" self.manage_delLocalRoles(persons) security.declareProtected(perm_view, 'has_role') # No additional comments. def has_role(self, person, role): """Return whether the user is in the specified role.""" return role in get_roles(self,person) security.declareProtected(perm_view, 'get_teacher') def get_teacher(self): """Get the name of the teacher (creator of the course).""" for user,roles in self.get_local_roles(): if 'Teacher' in roles: return user raise 'Course has no teacher!' security.declareProtected(perm_edit, 'set_roles') # Note: roles _must_ be a sequence! # Called from CourseManager.add_users_form_handler def set_roles(self, person, roles): """Set roles of one person.""" self.__unset_roles(person) self.manage_setLocalRoles(person, roles) def lisa_sisegruppi(self, grupinimi, kasutajanimi): """ Lisab kasutaja gruppi """ rols = getattr(self.subgroups, grupinimi).get_local_roles_for_userid(kasutajanimi) if "User" not in rols: rols = rols +("User",) getattr(self.subgroups, grupinimi).manage_setLocalRoles(kasutajanimi, rols) return kasutajanimi + "grupis" def eemalda_sisegrupist(self, grupinimi, kasutajanimi): """ Eemaldab kasutaja grupist """ roles = getattr(self.subgroups, grupinimi).get_local_roles_for_userid(kasutajanimi) new_roles = () for x in roles: if x == 'User': continue new_roles += (x,) if not new_roles: getattr(self.subgroups, grupinimi).manage_delLocalRoles((kasutajanimi,)) else: getattr(self.subgroups, grupinimi).manage_setLocalRoles(kasutajanimi,new_roles) return kasutajanimi + "grupist" # FIXME: input_checks: tt_set_name not checked # FIXME: input_checks: two course contexts can have identical name. security.declareProtected(perm_add_lo, 'add_course_context') # Handler for add_course_context_form def add_course_context( self, my_name, description, tt_set_name, description_long, REQUEST, use_roleplay='', # New in ZPTIVA show_only_roleplay='', # Submit buttons. publish='', cancel='', ): """Add CourseContext object.""" if publish: error_fields = [] errors = [] my_name = my_name.strip() if not is_valid_title(my_name): error_fields.append(translate(self,'title of context',target=self.giveLanguage(REQUEST))) if my_name in [x[1] for x in self.get_course_context_names()]: errors.append(translate(self,"Name '%s' taken",target=self.giveLanguage(REQUEST)) % my_name) # Variables 'description' and 'description_long' are not checked # because render_description() and render_long_description() # methods in CourseContext filter out unwanted HTML tags. if len(error_fields) > 0 or len(errors) > 0: msg = ", ".join(errors) if len(error_fields) > 0: msg = msg + "
" + 'Invalid fields' + \ ": '" + "' , '".join(error_fields) + "'" return self.message_dialog_error( self, REQUEST, title='Invalid input', message=msg, action=apply( make_action, ['add_course_context_form'] + [(x, eval(x)) for x in ('my_name', 'description', 'tt_set_name', 'description_long')])) uname=str(REQUEST.AUTHENTICATED_USER) obj = CourseContext( self, my_name, description, description_long, tt_set_name, uname,) obj.public = 1 if (show_only_roleplay)==1: obj.__roleplay_only = 1 id = obj.get_id() self._setObject(id, obj) self.lisaSyndmus(REQUEST, 'konteksteLisatud') try: obj.changeOwnership(self.acl_users.getUser(uname).__of__(self.acl_users)) obj.manage_setLocalRoles(uname,('Owner',)) except: pass if REQUEST: pagename="" if use_roleplay: pagename="course_setup_roleplay_form" REQUEST.RESPONSE.redirect('%s/%s' % (str(id),pagename)) elif cancel: return REQUEST.RESPONSE.redirect(REQUEST.URL1) else: raise "add_course_context called without 'publish' or 'cancel'" security.declareProtected(perm_view, 'get_course_context_names') # No additional comments. def get_course_context_names(self): """Return a list of CourseContext names.""" retval = {} for e in self.get_children('CourseContext'): id = e.get_id() name = e.get_name() retval[id] = name return retval.items() #security.declareProtected(perm_view, 'get_n_notes') def get_n_notes(self): """Returns a sum of all notes in all contexts.""" count = 0 for cc in self.get_course_contexts(): count += cc.get_n_notes() return count security.declareProtected(perm_view, 'get_n_unread_notes') def get_n_unread_notes(self,uname): """Returns a sum of all unread notes in all contexts.""" count = 0 for cc in self.get_course_contexts(): count += cc.get_n_unread_notes(uname) return count security.declarePublic('update') # Parameters are received from the form (apparently). def update( self, name, description, organisation, methods, starting_date, ending_date, tekst, logo=None, staatus=0, cCat = 0, credits='', courseID='', ): """Edit course information.""" self.__name = name self.__description = description self.__organisation = organisation self.__methods = methods self.__starting_date = starting_date self.__ending_date = ending_date self.paneTekst(tekst) if logo: self.paneLogo(logo) self.paneStaatus(staatus) self.setCourseCategory(int(cCat)) self.set_credits(credits) self.set_courseID(courseID) security.declareProtected(perm_view, 'get_course_contexts') def get_course_contexts(self): """Return a list of all course contexts in this course.""" for abc in self.get_children('CourseContext'): if not hasattr(abc, 'public'): abc.public = 1 return self.get_children('CourseContext') security.declareProtected(perm_view, 'get_course_context_ids_in_order') def get_course_context_ids_in_order(self, id_list): """Return a list of ids of all course contexts in this course.""" return [o.get_id() for o in self.get_course_contexts_in_order(id_list)] security.declareProtected(perm_edit, 'delete_course_context') def context_form_handler(self,REQUEST,cc_id,staatus='', kustuta=''): """ delete or change status """ import types if type(cc_id) is types.StringType: cc_id = ((cc_id),) #if staatus and kustuta: # raise 'IVA error','oops, both buttons athe same time in Knowledge building form' for abc in cc_id: self.hide_show_course_context(abc) #if kustuta: # for abc in cc_id: # self.delete_course_context(abc) return REQUEST.RESPONSE.redirect(self.absolute_url()+'/course_html') security.declareProtected(perm_edit, 'delete_course_context') def delete_course_context(self,id): for c in self.get_children('CourseContext'): if c.get_id() == id: self._delObject(id) return security.declareProtected(perm_edit, 'hide_show_course_context') def hide_show_course_context(self,id): for c in self.get_children('CourseContext'): if c.get_id() == id: if c.public == 1: c.public = 0 else: c.public = 1 return # FIXME: See the random comment below, random is not # FIXME: probably the order that we really want. security.declareProtected(perm_view, 'get_course_contexts_in_order') def get_course_contexts_in_order(self, id_list): """Return a list of all course contexts in this course.""" contexts = {} for c in self.get_children('CourseContext'): contexts[c.get_id()] = c try: pass except: c.public = 1 retval = [] if id_list and id_list != ['']: if type(id_list) == types.StringType: id_list = (id_list, ) # Return courses contexts in a given order. for identifier in id_list: try: retval.append(contexts[identifier]) del contexts[identifier] except KeyError: # invalid id_list pass # If we still course contexts left (id_list is shorter # than the actual number of course_contexts), append # them to list in a random order. for key in contexts.keys(): retval.append(contexts[key]) return retval security.declarePublic('may_view_course') def may_view_course(self, REQUEST): """Return boolean depending on wether user may or may not view the course.""" from AccessControl.PermissionRole import rolesForPermissionOn return intersect_bool( get_roles(self,str(REQUEST.AUTHENTICATED_USER)), rolesForPermissionOn(perm_view,self)) security.declareProtected(perm_view, 'may_add_course_context') def may_add_course_context(self, person): """Return boolean depending on wether user may or may not add a course context to the course.""" from AccessControl.PermissionRole import rolesForPermissionOn return intersect_bool( get_roles(self,person), rolesForPermissionOn(perm_add_lo,self)) security.declareProtected(perm_view, 'may_edit_course') def may_edit_course(self, person): """Return boolean depending on whether person can edit the course or not.""" from AccessControl.PermissionRole import rolesForPermissionOn return intersect_bool( get_roles(self,person), rolesForPermissionOn(perm_edit,self)) security.declareProtected(perm_view, 'active_members') #FIXME: Why not "get_active_members" def active_members(self): """Return a list of names of users who are active.""" return self.active_memb_cache security.declareProtected(perm_view, 'has_group_folder') def has_group_folder(self): """Return whether course has a group folder or not.""" return len(self.objectIds('GroupFolder'))>0 def add_folder(self, my_name): from GroupFolder import GroupFolder from GroupFolderProxy import GroupFolderProxy new_id = 'gf' fol = GroupFolder(None,my_name) fol.id=new_id self._setObject(new_id,fol) fol=fol.__of__(self) # self.make_group_folder_proxies(self.get_all_users()) proxy = GroupFolderProxy(None, # any sense? self.get_name(), self.get_id()) self.jamming._setObject('0', proxy) return fol def make_group_folder_proxies(self, users): for user in users: # user.webtop.add_link(self.get_name()+" (Shared)",self.get_url_to_object(self.gf),1) user.webtop.add_group_folder_proxy(self.get_name(), self.get_id()) def remove_folder_link(self,users): gf = self.get_child('gf') for user in users: fol = user.webtop self.__recurse_remove_folder_link(fol, gf) def __recurse_remove_folder_link(self, folder, gf): for (_id, proxy_fol) in folder.objectItems('GroupFolderProxy'): if proxy_fol.is_proxy_for(gf): folder._delObject(_id) for fol in folder.objectValues('WebtopFolder'): self.__recurse_remove_folder_link(fol, gf) security.declareProtected(perm_edit, 'teacher_export') def teacher_export(self,REQUEST): """ teacher export """ self.iva_ims_export(REQUEST) security.declareProtected(perm_edit, 'iva_ims_export') def iva_ims_export(self, REQUEST=None, testinimi='',teacherExporting=1): """ Course or a quiz export. XML format. """ from ImportExportIMS import Kirjutus from ImportExportIMS import kirjutaYldM import tempfile, os failinimi = tempfile.mktemp() # self.fle_users.export_users(REQUEST,failinimi='ivaexport.zip',kursusega='jah',palju='self.fle_root().fle_users.get_users()') if testinimi: yld = kirjutaYldM() yld.kirjutaYldmanifest(self.get_id(),'QTI test','imsqti_xmlv1p1','','qti.xml') yld.lisaFaili(failinimi) k= Kirjutus(self.fle_root(), self.get_id()) #k.looKursuseFail() #k.exportQTI(failinimi,'') parent = k.looTestiFail() k.kirjutaTestid(parent,testinimi) k.kirjutaTestidZipi(failinimi,'') #k.pakiKursusFaili(failinimi) # k.pakiTulemusFaili(failinimi,testsonly="testsonly") else: yld = kirjutaYldM() yld.kirjutaYldmanifest(self.get_id(), self.get_description(),base=str(self.get_id())+"/") yld.lisaFaili(failinimi) k = Kirjutus(self.fle_root(), self.get_id()) k.looKursuseFail() k.kirjutavCal(self.syndmused,'kursus','GROUP') k.kirjutaWebtop(self.gf,tiitel='RAAMATURIIUL') for sisegr in self.subgroups.objectValues('GroupFolder'): k.kirjutaWebtop(sisegr,'SISEGRUPP:'+sisegr.get_name()) try: k.kirjutavCal(sisegr.syndmused,sisegr.get_name(),'GROUP') except: pass if not teacherExporting: k.kirjutaKasutajaWebtop(self.get_all_users()) k.kirjutaKasutajaSyndmus(self.get_all_users()) self.fle_users.export_users(REQUEST,failinimi=failinimi,kursusega=self.get_id(),palju='kursus.get_all_users()') k.kirjutaItem(k.organization, tiitel='KURSUSE KASUTAJAD',parameters='KURSUSE KASUTAJAD') k.kirjutaResource(k.resources, 'imsent_xmlv1p1','users.xml') k.exportQTI(failinimi,str(self.get_id())+"/",teacherExporting=teacherExporting) k.exportPajad(failinimi,str(self.get_id())+"/",startonly=teacherExporting) k.exportKodutood(self.kodutood,failinimi,str(self.get_id())+"/") k.pakiKursusFaili(failinimi) if REQUEST: file = open(failinimi,"rb") export_data=file.read() file.close() os.remove(failinimi) REQUEST.RESPONSE.setHeader('Content-disposition','attachment; filename=ivaexport.zip') REQUEST.RESPONSE.setHeader('content-type','application/zip') return export_data else: import os import shutil name='iva_'+re.sub('[^a-zA-Z0-9]', '_', self.get_name()) name2 = name number = 1 searched=0 print os.path.isfile(os.path.join(Globals.INSTANCE_HOME,'var',name+'.zip')) print os.path.join(Globals.INSTANCE_HOME,'var',name+'.zip') while os.path.isfile(os.path.join(Globals.INSTANCE_HOME,'var',name+'.zip')): number = number + 1 name = name2+'_ver'+str(number) searched=1 name += '.zip' shutil.move(failinimi,os.path.join(Globals.INSTANCE_HOME,'var',name)) return self.get_name() + ' - ' + os.path.join(Globals.INSTANCE_HOME,'var',name) def write_touchgraph_data(self,obj,type,children_types=None,extra_links=None): links = '' if children_types: links = ' '.join(obj.objectIds(children_types)) if extra_links: links = ' '.join((links,extra_links)) if not links: links=' ' return obj.get_id()+'\t'+\ type+"\t"+\ self.REQUEST.BASE0+self.get_url_to_object(obj)+'\t'+\ obj.get_name()+'\t'\ +links+'\t' # But should we protect it somehow? # The Java client would then need authentication def touchgraph_data(self): """This is a public method.""" data=self.write_touchgraph_data(self,"COURSE","CourseContext") for ctx in self.objectValues("CourseContext"): data=data+ctx.touchgraph_data() return data+"[END DATA]" def kysiSyndmusteKataloog(self): "Lisatakse kui pole" import Kalender if not hasattr(self, 'syndmused'): self._setObject('syndmused', Kalender.KalendriSyndmusteKataloog()) self.syndmused.id='syndmused' return self.syndmused def kysiTekst(self): "Kursuse uudis/moto. Vastab tyhja kui pole" if hasattr(self, 'teatetekst'): return self.teatetekst else: return "" def paneTekst(self, tekst): "Teksti lisamine" self.teatetekst=tekst return "Lisatud "+tekst def paneLogo(self, logo): "Logo lisamine" self.logo=logo def kysiLogo(self): "Pildi kahendandmed" # XXX:weird hack if hasattr(self, 'logo') and self.logo and self.logo.strip(): return self.logo return None def kysiLogoViide(self, REQUEST=None): "Logo link, kui on" if self.kysiLogo(): return "\"\"" return "" def paneAutomaatRegistreerumine(self, automaatRegistreerumine): "Tunnuse salvestus" self.automaatRegistreerumine=automaatRegistreerumine def kysiAutomaatRegistreerumine(self): "Väljastus, puudumise korral 0" if hasattr(self, 'automaatRegistreerumine'): return self.automaatRegistreerumine return 0 def paneStaatus(self, staatus): "staatuse salvestus" self.staatus=staatus def kysiStaatus(self): "Staatuse küsimine" if hasattr(self, 'staatus'): return self.staatus return 0 def kysiStaatusNimi(self, REQUEST): "Staatuse nimi" if hasattr(self,'staatus'): return self.kysiStaatuseTekst(int(self.kysiStaatus()), REQUEST) return 0 def kysiStaatuseValikud(self, REQUEST): "Valikud rippmenüüsse" tulemus="" for i in range(5): tulemus=tulemus+"\n" return tulemus def tootoaKylastus(self, REQUEST, ala): "Vastava alamtoa külastusaja sättimine" if not hasattr(self, 'tootoaKylastused'): self.tootoaKylastused={} if not self.tootoaKylastused.has_key(ala): self.tootoaKylastused[ala]={} self.tootoaKylastused[ala][REQUEST.AUTHENTICATED_USER.getUserName()]=time.time() self.tootoaKylastused=self.tootoaKylastused return self.tootoaKylastused def tootoaMuutus(self, ala): "Alamtoas toimunud muutus" if not hasattr(self, 'tootoaMuutused'): self.tootoaMuutused={} self.tootoaMuutused[ala]=time.time() self._p_changed = True return self.tootoaMuutused def viimaneTootoaMuutus(self, ala): "Muutuse lugemine" try: return self.tootoaMuutused[ala] except KeyError: return 0 def viimaneTootoaKylastus(self, REQUEST, ala): "Viimane külastusaeg vastaval inimesel selle ala peal" knimi=REQUEST.AUTHENTICATED_USER.getUserName() if hasattr(self, 'tootoaKylastused'): if self.tootoaKylastused.has_key(ala): if self.tootoaKylastused[ala].has_key(knimi): return self.tootoaKylastused[ala][knimi] return 0 def kasMuudetudParastTootoaKylastust(self, REQUEST, ala): "jah/ei" return str(self.viimaneTootoaKylastus(REQUEST, ala)>self.viimaneTootoaMuutus(ala))+"!!" security.declareProtected(perm_view, 'search_form_handler') def search_form_handler( self, REQUEST, cancel=None, # submit buttons submit=None, # get_name = None, get_content= None ): """Search form handler.""" if (submit) and ((get_name) or (get_content)): for s in 'get_name', 'get_content': REQUEST.set(s, REQUEST[s]) if REQUEST['get_author_name'] == '___anyone___': uname = str(self.REQUEST.AUTHENTICATED_USER) if len(self.fle_users.get_user_info(uname).user_courses()) > 0: REQUEST.set('get_author_name', self.courses.get_unames_on_my_courses(REQUEST)) else: REQUEST.set('get_author_name', uname) else: REQUEST.set('get_author_name', REQUEST['get_author_name']) return self.wt_search_results(self, REQUEST) elif cancel: REQUEST.RESPONSE.redirect('index_html') else: REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER']) security.declareProtected(perm_view,'getCourseCategory') def getCourseCategory(self): return self.course_category security.declarePrivate('setcourseCategory') def setCourseCategory(self, id): self.course_category = id self._p_changed = 1 def get_n_artefacts(self): """ number of artefacts on a course """ total = 0 for x in self.jamming.objectValues('JamSession'): total += x.get_n_artefacts() return total def total_n_unseen_jams(self,REQUEST): total = 0 for x in self.jamming.objectValues('JamSession'): total += x.get_n_unread_artefacts(REQUEST) return total def isCourseAlive(self): """ when was last input, new objects, artefacts? """ curtime = time.time() aeg = curtime-86400*30 #XXX: go away! if not hasattr(self, 'tootoaMuutused'): self.tootoaMuutused = {} if self.viimaneTootoaMuutus('teadmuspaja')aeg: aeg = self.viimaneTootoaMuutus('teadmuspaja') if self.viimaneTootoaMuutus('meediapaja')>aeg: aeg = self.viimaneTootoaMuutus('meediapaja') return aeg def lastModify_printable(self,REQUEST): """ returns printable last modification date """ return time.strftime(translate(self,'short_date_format',target=self.giveLanguage(REQUEST)),time.localtime(self.lastModify())) def lastActive(self): """ return last visit to course """ first = 1 for x in self.get_all_users(): if first: aeg = x.last_active(self.get_id()) first = 0 if x.last_active(self.get_id())>aeg: aeg = x.last_active(self.get_id()) return aeg def lastActive_printable(self,REQUEST): """ return last visit to course """ return time.strftime(translate(self,'short_date_format',target=self.giveLanguage(REQUEST)),time.localtime(self.lastActive())) Globals.default__class_init__(Course) # EOF