source: WAeUP_SRP/trunk/Students.py @ 425

Last change on this file since 425 was 423, checked in by joachim, 18 years ago

addopted studentimport to new schemas,

  • Property svn:keywords set to Id
File size: 22.3 KB
RevLine 
[57]1#-*- mode: python; mode: fold -*-
[200]2# $Id: Students.py 423 2006-08-25 17:19:21Z joachim $
[45]3from Globals import InitializeClass
4from AccessControl import ClassSecurityInfo
[164]5from AccessControl.SecurityManagement import newSecurityManager
[45]6
[47]7from Products.CMFCore.utils import UniqueObject, getToolByName
[45]8from Products.CMFCore.permissions import View
9from Products.CMFCore.permissions import ModifyPortalContent
[154]10from Products.CPSCore.CPSBase import CPSBase_adder, CPSBaseFolder
11#from Products.CPSCore.CPSBase import CPSBaseDocument as BaseDocument
12from Products.CPSDocument.CPSDocument import CPSDocument
13from Products.CPSCore.CPSBase import CPSBaseBTreeFolder as BaseBTreeFolder
[164]14from Products.CPSCore.CPSMembershipTool import CPSUnrestrictedUser
[361]15from Products.WAeUP_SRP.Academics import makeCertificateCode
[362]16import logging
17import csv,re
18import Globals
19p_home = Globals.package_home(globals())
20i_home = Globals.INSTANCE_HOME
[398]21MAX_TRANS = 1000
[154]22
[422]23def generateStudentId():
24    import random
[423]25    r = random
26    return "%c%d" % (r.choice('ABCDEFGHKLMNPQRSTUVWXY'),r.randint(99999,1000000))
[422]27   
28   
29
[361]30class StudentsFolder(CPSDocument): ###(
31    """
32    WAeUP container for the various WAeUP containers data
33    """
[362]34    meta_type = 'StudentsFolder'
[361]35    portal_type = meta_type
36    security = ClassSecurityInfo()
[154]37
[361]38    security.declareProtected(ModifyPortalContent,"loadFullTimeStudentsFromCSV")###(
39    def loadFullTimeStudentsFromCSV(self):
40        """load Fulltime Studentdata from CSV values"""
41        #return
[398]42        import transaction
43        tr_count = 0
[361]44        name = 'short_full_time'
45        no_import = False
[395]46        if not no_import:
47            no_import = open("%s/import/%s_not_imported.csv" % (i_home,name),"w")
48            no_import.write('"MatricNo","EntryRegNo","CurrentSession","StudentLevel","fullname","FirstName","MiddleName","Lastname","FormerSurname","Sex","Nationality","State","LGA","PermanentAddress","PermanentAddressCity","CampusAddress","PhoneNumber","Emailaddress","Mode","CourseMajor","Faculty","Dept"\n')
[361]49        logger = logging.getLogger('%s_import' % name)
50        logger.info('Start loading from %s.csv' % name)
51        students_folder = self.portal_catalog({'meta_type': 'StudentsFolder'})[-1].getObject()
52        try:
53            students = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
54        except:
55            logger.error('Error reading %s.csv' % name)
56            return
[422]57        l = self.portal_catalog({'meta_type': "StudentClearance",})
58        matrics = []
[361]59        for s in l:
[422]60            matrics.append(s.getObject().getContent().matric_no)
[423]61        print matrics
[361]62        l = self.portal_catalog({'meta_type': "Certificate"})
63        certs = {}
64        for c in l:
[362]65            certs[c.id] = c.getObject()
[361]66        for student in students:
[393]67            logger.info('processing "%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
[361]68            sid = student.get('MatricNo')
[396]69            if sid == "":
70                em = 'Empty MatricNo\n'
71                logger.info(em)
72                no_import.write(em)
73                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
74                continue
[361]75            certcode = makeCertificateCode(student.get('CourseMajor'))
76            if certcode not in certs.keys():
[393]77                em = 'Certificate with ID %s %s not found\n' % (certcode, student.get('CourseMajor'))
[361]78                logger.info(em)
[393]79                no_import.write(em)
80                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
[361]81                continue
[395]82            level = student.get('StudentLevel')
83            try:
84                int(level)
85            except:
86                em = 'Student with ID %(MatricNo)s StudentLevel is empty\n' % student
87                logger.info(em)
88                no_import.write(em)
89                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
90                continue
[422]91            matric_no = student.get('MatricNo')
92            if matric_no not in matrics:
93                matrics.append(matric_no)
94                sid = generateStudentId()
[361]95                #self.log('Creating Faculty %(id)s = %(Title)s' % faculty)
[422]96                logger.info('Creating Student with ID %(sid)s Matric_no %(matric_no)s ' % vars())
[361]97                students_folder.invokeFactory('Student', sid)
98                s = getattr(self,sid)
99                s.invokeFactory('StudentPersonal','personal')
[362]100                sp = s.personal
[361]101                d = {'Title': 'Personal Data'}
[422]102                s.invokeFactory('StudentClearance','clearance')
103                sc = s.personal
104                dc = {'Title': 'Clearance Data'}
105                dc['matric_no'] = matric_no
106                dc['jamb_reg_no'] = student.get('EntryRegNo')
107                dc['lga'] = student.get('LGA')
108                dc['nationality'] = student.get('Nationality')
109                dc['email'] = student.get('Emailaddress')
[361]110                d['firstname'] = student.get('FirstName')
111                d['middlename'] = student.get('MiddleName')
[362]112                d['lastname'] = student.get('Lastname')
[361]113                d['former_surname'] = student.get('FormerSurname')
[362]114                d['sex'] = student.get('Sex') == 'F'
[422]115                d['for_state'] = student.get('State')
116                d['for_lga'] = student.get('LGA')
117                d['perm_address'] = student.get('PermanentAddress')
118                d['perm_city'] = student.get('PermanentAddressCity')
[361]119                d['campus_address'] = student.get('CampusAddress')
120                d['phone'] = student.get('PhoneNumber')
[362]121                sp.getContent().edit(mapping=d)
[422]122                sc.getContent().edit(mapping=dc)
[362]123                #
124                # Study Course
125                #
126                s.invokeFactory('StudentStudyCourse','study_course')
127                sc = s.study_course
128                d = {}
[422]129                #d['matricel_no'] = student.get('MatricNo')
130                #d['entry_reg_no'] = student.get('EntryRegNo')
131                #d['faculty'] = student.get('Faculty')
132                #d['department'] = student.get('Dept')
[362]133                d['course_major'] = certcode
134                css = student.get('CurrentSession') or '2004-2005'
135                cs = int(css.split('-')[0]) - 2000
136                cl = int(student.get('StudentLevel'))/100
137                d['entry_session'] = "200%s" % (cs - cl)
138                sc.getContent().edit(mapping=d)
[364]139                #
140                # Level
141                #
142                l = getattr(sc,level,None)
143                if l is None:
144                    #self.log('Creating Department %(DeptCode)s = %(Description)s' % dep)
145                    logger.info('Creating Level %(StudentLevel)s for %(fullname)s' % student)
146                    sc.invokeFactory('StudyLevel', level)
147                    l = getattr(sc, level)
148                    certificate = certs[certcode]
149                    cert_level = getattr(certificate,level,None)
150                    if cert_level is None:
151                        logger.info('Level %(level)s not in %(certcode)s' % vars())
152                    l.getContent().edit(mapping={'Title': "Level %s" % level})
153                    l.invokeFactory('Semester','first')
154                    l.invokeFactory('Semester','second')
155                    first_s = getattr(l,'first')
156                    first_s.getContent().edit(mapping={'Title': 'First Semester'})
157                    second_s = getattr(l,'second')
158                    second_s.getContent().edit(mapping={'Title': 'Second Semester'})
[361]159            else:
[393]160                em = 'Student with ID %(MatricNo)s %(fullname)s already exists\n' % student
[361]161                logger.info(em)
[393]162                no_import.write(em)
163                no_import.write('"%(MatricNo)s","%(EntryRegNo)s","%(CurrentSession)s","%(StudentLevel)s","%(fullname)s","%(FirstName)s","%(MiddleName)s","%(Lastname)s","%(FormerSurname)s","%(Sex)s","%(Nationality)s","%(State)s","%(LGA)s","%(PermanentAddress)s","%(PermanentAddressCity)s","%(CampusAddress)s","%(PhoneNumber)s","%(Emailaddress)s","%(Mode)s","%(CourseMajor)s","%(Faculty)s","%(Dept)s"\n' % student)
[398]164            if tr_count > MAX_TRANS:
[422]165                transaction.commit()
166                em = 'Transaction commited\n' % student
[398]167                logger.info(em)
168                tr_count = 0
169            tr_count += 1
[423]170        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
[393]171        return self.students.academics_contents()
[361]172    ###)
[382]173
[398]174    security.declareProtected(ModifyPortalContent,"loadFullTimeStudentsResultsFromCSV") ###(
[396]175    def loadFullTimeStudentsResultsFromCSV(self):
176        """load Fulltime Studentdata from CSV values"""
177        #return
[398]178        import transaction
179        tr_count = 0
180        name = 'short_full_time_results_2004_2005'
[396]181        no_import = False
182        if not no_import:
183            no_import = open("%s/import/%s_not_imported.csv" % (i_home,name),"w")
184            no_import.write('"Matnumber","CosCode","Ansbook","CosStuatus","Session","Mat_Cos","Score","CarryLevel","Grade","Weight","Semster","Verdict","Level","id","GPA"\n')
185        logger = logging.getLogger('%s_import' % name)
186        logger.info('Start loading from %s.csv' % name)
187        students_folder = self.portal_catalog({'meta_type': 'StudentsFolder'})[-1].getObject()
188        try:
189            results = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
190        except:
191            logger.error('Error reading %s.csv' % name)
192            return
193        l = self.portal_catalog({'meta_type': "Student"})
194        students = {}
195        for s in l:
196            students[s.id] = s.getObject()
[398]197        l = self.portal_catalog({'meta_type': "Course"})
198        courses = {}
199        for c in l:
200            courses[c.id] = c.getObject()
[396]201        for result in results:
202            sid = result.get('Matnumber')
203            if sid not in students.keys():               
[398]204                em = 'Student with ID %(Matnumber)s not found\n' % result
[396]205                logger.info(em)
206                no_import.write(em)
[398]207                no_import.write('"%(Matnumber)s","%(CosCode)s","%(Ansbook)s","%(CosStuatus)s","%(Session)s","%(Mat_Cos)s","%(Score)s","%(CarryLevel)s","%(Grade)s","%(Weight)s","%(Semster)s","%(Verdict)s","%(Level)s","%(id)s","%(GPA)s"\n' % result)
[396]208                continue
[398]209            course = result.get('CosCode')
210            if course not in courses.keys():
211                em = 'Course with ID %(CosCode)s not found\n' % result
[396]212                logger.info(em)
213                no_import.write(em)
[398]214                no_import.write('"%(Matnumber)s","%(CosCode)s","%(Ansbook)s","%(CosStuatus)s","%(Session)s","%(Mat_Cos)s","%(Score)s","%(CarryLevel)s","%(Grade)s","%(Weight)s","%(Semster)s","%(Verdict)s","%(Level)s","%(id)s","%(GPA)s"\n' % result)
[396]215                continue
[398]216            level = result.get('Level')
[396]217            try:
218                int(level)
219            except:
[398]220                em = 'Result for result with ID %(Matnumber)s Course %(CosCode)s Level is empty\n' % result
[396]221                logger.info(em)
222                no_import.write(em)
[398]223                no_import.write('"%(Matnumber)s","%(CosCode)s","%(Ansbook)s","%(CosStuatus)s","%(Session)s","%(Mat_Cos)s","%(Score)s","%(CarryLevel)s","%(Grade)s","%(Weight)s","%(Semster)s","%(Verdict)s","%(Level)s","%(id)s","%(GPA)s"\n' % result)
[396]224                continue
225            sf = students.get(sid)
226            sc = getattr(sf,'study_course')
227            l = getattr(sc,level,None)
228            if l is None:
229                #self.log('Creating Department %(DeptCode)s = %(Description)s' % dep)
[398]230                logger.info('Creating Level %(Level)s for %(Matnumber)s' % result)
[396]231                sc.invokeFactory('StudyLevel', level)
232                l = getattr(sc, level)
233                l.getContent().edit(mapping={'Title': "Level %s" % level})
234                l.invokeFactory('Semester','first')
235                l.invokeFactory('Semester','second')
236                first_s = getattr(l,'first')
237                first_s.getContent().edit(mapping={'Title': 'First Semester'})
238                second_s = getattr(l,'second')
239                second_s.getContent().edit(mapping={'Title': 'Second Semester'})
[398]240            snr = result.get('Semester')
[396]241            semester = getattr(l,'first')
[398]242            if snr == "2":
[396]243                semester = getattr(l,'second')
[398]244            logger.info('Creating CourseTicket %(CourseTicket)s in Level %(Level)s for %(Matnumber)s' % result)
245            semester.invokeFactory('CourseTicket',course)
246            ct = getattr(semester,course)
247            d = {}
248            d['ansbook'] = result.get('Ansbook')
249            d['status'] = result.get('CosStuatus')
250            d['score'] = result.get('Score')
251            d['carry_level'] = result.get('CarryLevel')
252            d['grade'] = result.get('Grade')
253            d['weight'] = result.get('Weight')
254            d['verdict'] = result.get('Verdict')
255            d['import_id'] = result.get('id')
256            gpa = result.get('GPA').replace(',','.')
257            d['gpa'] = float(gpa)
258            ct.getContent().edit(mapping = d)
259            if tr_count > MAX_TRANS:
260                transaction.commit()
261                tr_count = 0
262            tr_count += 1
263        return self.students.academics_contents()
[396]264           
[398]265###)
[396]266
[398]267           
[364]268    security.declareProtected(View,"Title")
269    def Title(self):
270        """compose title"""
[382]271        return "Student Section"
[361]272
273InitializeClass(StudentsFolder)
274
275def addStudentsFolder(container, id, REQUEST=None, **kw):
276    """Add a Student."""
277    ob = StudentsFolder(id, **kw)
278    return CPSBase_adder(container, ob, REQUEST=REQUEST)
279###)
280
[57]281class Student(CPSDocument): ###(
282    """
[154]283    WAeUP Student container for the various student data
[57]284    """
285    meta_type = 'Student'
286    portal_type = meta_type
287    security = ClassSecurityInfo()
[154]288
[152]289    security.declareProtected(View,"Title")
290    def Title(self):
291        """compose title"""
[153]292        reg_nr = self.getId()[1:]
[362]293        data = getattr(self,'personal',None)
[152]294        if data is None:
[362]295            data = getattr(self,'jamb',None)
[152]296        if data:
297            content = data.getContent()
298            return "%s %s" % (content.firstname,content.lastname)
299        return self.title
[154]300
301    def Description(self):
302        """compose description"""
[170]303        data = getattr(self,'PERSONAL',None)
304        if data is None:
[191]305            return "none"
[154]306        if data:
[191]307            content = data.getContent()
308            return "%s" % (content.description)
[154]309        return self.description
310
[164]311    security.declareProtected(View,"setScratchCardData")
312    def setScratchCardData(self,ident,ds):
313        """set this data """
314        dict = {'%s_sc_pin' % ident : ds.get('sc_pin'),
315                '%s_sc_id' % ident : ds.get('sc_id'),
316                '%s_sc_value' % ident : ds.get('sc_value'),
[166]317                '%s_date' % ident : ds.get('sc_date'),
[164]318                }
[170]319
[173]320        old_user = self.portal_membership.getAuthenticatedMember()
[166]321        if self.portal_membership.isAnonymousUser():
322            tmp_user = CPSUnrestrictedUser('s%(jamb_id)s' % ds, '',
[164]323                                       ['StudentManager'], '')
[166]324            tmp_user = tmp_user.__of__(self.acl_users)
325            newSecurityManager(None, tmp_user)
326        #print str(dict)
[164]327        self.edit(mapping=dict)
[173]328        newSecurityManager(None, old_user)
[164]329
330    security.declareProtected(View,"memberIsOwner")
331    def memberIsOwner(self):
332        """is the current user the owner"""
333        member = self.portal_membership.getAuthenticatedMember()
334        #print member, self.getId(),self.aq_parent.getId()
335        if self.aq_parent.getId() == str(member):
336            return True
337        return False
338
[166]339    security.declareProtected(View,"accommodationIsBooked")
340    def accommodationIsBooked(self):
341        """is the accommodation booked"""
342        if self.accommodation_sc_pin != '':
343            return True
344        return False
345
346    security.declareProtected(View,"accommodationIsPayed")
347    def accommodationIsPayed(self):
348        """is the accommodation payed"""
[168]349        if self.hostel_fee_sc_pin != '':
[166]350            return True
351        return False
352
353    security.declareProtected(View,"isRegisteredForCurrentLevel")
354    def isRegisteredForCurrentLevel(self):
355        """is the student registered for the current level"""
356        for l in  self.aq_parent.objectValues():
357            if l.portal_type == 'StudyLevel':
358                return True
359        return False
360
[57]361InitializeClass(Student)
362
363def addStudent(container, id, REQUEST=None, **kw):
364    """Add a Student."""
365    ob = Student(id, **kw)
366    return CPSBase_adder(container, ob, REQUEST=REQUEST)
367
368###)
[91]369
[89]370class StudentPersonal(CPSDocument): ###(
371    """
[154]372    WAeUP Student container for the various student data
[89]373    """
374    meta_type = 'StudentPersonal'
375    portal_type = meta_type
376    security = ClassSecurityInfo()
[152]377
378    security.declareProtected(View,"Title")
379    def Title(self):
380        """compose title"""
381        content = self.getContent()
[364]382        #return "Personal Data for %s %s" % (content.firstname,content.lastname)
383        return "Personal Data"
[152]384
[154]385
[89]386InitializeClass(StudentPersonal)
387
388def addStudentPersonal(container, id, REQUEST=None, **kw):
389    """Add a Students personal data."""
390    ob = StudentPersonal(id, **kw)
391    return CPSBase_adder(container, ob, REQUEST=REQUEST)
392
393###)
394
[423]395class StudentClearance(CPSDocument): ###(
396    """
397    WAeUP Student container for the various student data
398    """
399    meta_type = 'StudentClearance'
400    portal_type = meta_type
401    security = ClassSecurityInfo()
402
403    security.declareProtected(View,"Title")
404    def Title(self):
405        """compose title"""
406        content = self.getContent()
407        #return "Clearance Data for %s %s" % (content.firstname,content.lastname)
408        return "Clearance Data"
409
410
411InitializeClass(StudentClearance)
412
413def addStudentClearance(container, id, REQUEST=None, **kw):
414    """Add a Students personal data."""
415    ob = StudentClearance(id, **kw)
416    return CPSBase_adder(container, ob, REQUEST=REQUEST)
417
418###)
419
[362]420class StudentStudyCourse(CPSDocument): ###(
421    """
422    WAeUP Student container for the various student data
423    """
424    meta_type = 'StudentStudyCourse'
425    portal_type = meta_type
426    security = ClassSecurityInfo()
427
[364]428    security.declareProtected(View,"Title")
429    def Title(self):
430        """compose title"""
431        content = self.getContent()
[382]432        return "Course Major"
[362]433
434
435InitializeClass(StudentStudyCourse)
436
437def addStudentStudyCourse(container, id, REQUEST=None, **kw):
438    """Add a Students personal data."""
439    ob = StudentStudyCourse(id, **kw)
440    return CPSBase_adder(container, ob, REQUEST=REQUEST)
441
442###)
443
[423]444class StudentAdmission(CPSDocument): ###(
[179]445    """
446    WAeUP Student container for the various student data
447    """
[423]448    meta_type = 'StudentAdmission'
[179]449    portal_type = meta_type
450    security = ClassSecurityInfo()
451
[181]452    security.declareProtected(View,"Title")
453    def Title(self):
454        """compose title"""
[423]455        return "Admission Data"
[179]456
[181]457
[423]458InitializeClass(StudentAdmission)
[179]459
[423]460def addStudentAdmission(container, id, REQUEST=None, **kw):
[179]461    """Add a Students eligibility data."""
[423]462    ob = StudentAdmission(id, **kw)
[179]463    return CPSBase_adder(container, ob, REQUEST=REQUEST)
464
465###)
[181]466
[166]467class StudentDocuments(CPSDocument): ###(
468    """
469    WAeUP Student container for the various student data
470    """
471    meta_type = 'StudentDocuments'
472    portal_type = meta_type
473    security = ClassSecurityInfo()
474
475    security.declareProtected(View,"Title")
476    def Title(self):
477        """compose title"""
478        content = self.getContent()
479        return "Scanned Documents"
480
481
482InitializeClass(StudentDocuments)
483
484def addStudentDocuments(container, id, REQUEST=None, **kw):
485    """Add a Students documents"""
486    ob = StudentDocuments(id, **kw)
487    return CPSBase_adder(container, ob, REQUEST=REQUEST)
488
489###)
490
[89]491class Jamb(CPSDocument): ###(
492    """
493    WAeUP Jamb containing the courses and students
494    """
495    meta_type = 'Jamb'
496    portal_type = meta_type
497    security = ClassSecurityInfo()
[154]498
[152]499    security.declareProtected(View,"Title")
500    def Title(self):
501        """compose title"""
502        content = self.getContent()
503        return "JAMB Data for %s %s" % (content.firstname,content.lastname)
504
505    security.declareProtected(View,"setOwnership")
506    def setOwnership(self,member_id):
507        """set ownership"""
508        pm = getattr(self,'portal_membership')
509        member = pm.getMemberById(member_id)
510        self.changeOwnership(member)
511
[89]512InitializeClass(Jamb)
513
514def addJamb(container, id, REQUEST=None, **kw):
515    """Add a Jamb."""
516    ob = Jamb(id, **kw)
517    return CPSBase_adder(container, ob, REQUEST=REQUEST)
518
[139]519###)
520
521class StudyLevel(CPSDocument): ###(
522    """
523    WAeUP StudyLevel containing the courses and students
524    """
525    meta_type = 'StudyLevel'
526    portal_type = meta_type
527    security = ClassSecurityInfo()
[154]528
[139]529InitializeClass(StudyLevel)
530
531def addStudyLevel(container, id, REQUEST=None, **kw):
532    """Add a StudyLevel."""
533    ob = StudyLevel(id, **kw)
534    return CPSBase_adder(container, ob, REQUEST=REQUEST)
535
536###)
537
538class Semester(CPSDocument): ###(
539    """
540    WAeUP Semester containing the courses and students
541    """
542    meta_type = 'Semester'
543    portal_type = meta_type
544    security = ClassSecurityInfo()
[154]545
[139]546InitializeClass(Semester)
547
548def addSemester(container, id, REQUEST=None, **kw):
549    """Add a Semester."""
550    ob = Semester(id, **kw)
551    return CPSBase_adder(container, ob, REQUEST=REQUEST)
[200]552
[139]553###)
554
Note: See TracBrowser for help on using the repository browser.