source: WAeUP_SRP/trunk/Students.py @ 428

Last change on this file since 428 was 427, checked in by Henrik Bettermann, 18 years ago

types modified and FT student import changed

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