source: WAeUP_SRP/trunk/WAeUPTables.py @ 2089

Last change on this file since 2089 was 2084, checked in by joachim, 17 years ago

add course_results catalog

  • Property svn:keywords set to Id
File size: 37.7 KB
Line 
1#-*- mode: python; mode: fold -*-
2# (C) Copyright 2005 AixtraWare <http://aixtraware.de>
3# Author: Joachim Schmitz <js@aixtraware.de>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 2 as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17# 02111-1307, USA.
18#
19# $Id: WAeUPTables.py 2084 2007-08-03 05:58:51Z joachim $
20
21from zope.interface import implements
22from Globals import InitializeClass
23from Products.ZCatalog.ZCatalog import ZCatalog
24from Products.ZCatalog.ProgressHandler import ZLogHandler
25from AccessControl import ClassSecurityInfo
26from Products.CMFCore.permissions import ModifyPortalContent
27import urllib
28import DateTime,time
29import csv,re
30import logging
31import Globals
32p_home = Globals.package_home(globals())
33i_home = Globals.INSTANCE_HOME
34from Products.CMFCore.CatalogTool import CatalogTool
35from Products.AdvancedQuery import Eq, Between, Le,In
36
37ADDING_SHEDULED = "adding_sheduled"
38OBJECT_CREATED = "object_created"
39
40from interfaces import IWAeUPTable
41
42class AttributeHolder(object):
43    pass
44
45def dict2ob(dict):
46    ob = AttributeHolder()
47    for key, value in dict.items():
48        setattr(ob, key, value)
49    return ob
50
51class WAeUPTable(ZCatalog): ###(
52
53    implements(IWAeUPTable)
54    security = ClassSecurityInfo()
55
56    def refreshCatalog(self, clear=0, pghandler=None):
57        """ don't refresh for a normal table """
58
59        if self.REQUEST and self.REQUEST.RESPONSE:
60            self.REQUEST.RESPONSE.redirect(
61              URL1 +
62              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20refresh%20not%20implemented')
63
64    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
65        """ clears the whole enchilada """
66
67        #if REQUEST and RESPONSE:
68        #    RESPONSE.redirect(
69        #      URL1 +
70        #      '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Clearing%20disabled')
71
72        self._catalog.clear()
73        if REQUEST and RESPONSE:
74            RESPONSE.redirect(
75              URL1 +
76              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20cleared')
77
78    def addRecord(self, **data):
79        # The uid is the same as "bed".
80        uid = data[self.key]
81        res = self.searchResults({"%s" % self.key : uid})
82        if len(res) > 0:
83            raise ValueError("More than one record with uid %s" % uid)
84        self.catalog_object(dict2ob(data), uid=uid)
85        return uid
86
87    def deleteRecord(self, uid):
88        self.uncatalog_object(uid)
89
90    def searchAndSetRecord(self, **data):
91        raise NotImplemented
92
93    def modifyRecord(self, record=None, **data):
94        #records = self.searchResults(uid=uid)
95        uid = data[self.key]
96        if record is None:
97            records = self.searchResults({"%s" % self.key : uid})
98            if len(records) > 1:
99                # Can not happen, but anyway...
100                raise ValueError("More than one record with uid %s" % uid)
101            if len(records) == 0:
102                raise KeyError("No record for uid %s" % uid)
103            record = records[0]
104        record_data = {}
105        for field in self.schema() + self.indexes():
106            record_data[field] = getattr(record, field)
107        # Add the updated data:
108        record_data.update(data)
109        self.catalog_object(dict2ob(record_data), uid)
110
111    def reindexIndex(self, name, REQUEST,pghandler=None):
112        if isinstance(name, str):
113            name = (name,)
114        paths = self._catalog.uids.items()
115        i = 0
116        #import pdb;pdb.set_trace()
117        for p,rid in paths:
118            i += 1
119            metadata = self.getMetadataForRID(rid)
120            record_data = {}
121            for field in name:
122                record_data[field] = metadata.get(field)
123            uid = metadata.get(self.key)
124            self.catalog_object(dict2ob(record_data), uid, idxs=name,
125                                update_metadata=0)
126
127    security.declareProtected(ModifyPortalContent,"exportAllRecords")
128    def exportAllRecords(self):
129        "export a WAeUPTable"
130        #import pdb;pdb.set_trace()
131        fields = [field for field in self.schema()]
132        format = ','.join(['"%%(%s)s"' % fn for fn in fields])
133        csv = []
134        csv.append(','.join(['"%s"' % fn for fn in fields]))
135        for uid in self._catalog.uids:
136            records = self.searchResults({"%s" % self.key : uid})
137            if len(records) > 1:
138                # Can not happen, but anyway...
139                raise ValueError("More than one record with uid %s" % uid)
140            if len(records) == 0:
141                raise KeyError("No record for uid %s" % uid)
142            rec = records[0]
143            csv.append(format % rec)
144        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
145        open("%s/import/%s-%s.csv" % (i_home,self.getId(),current),"w+").write('\n'.join(csv))
146    ###)
147
148class AccommodationTable(WAeUPTable): ###(
149
150    meta_type = 'WAeUP Accommodation Tool'
151    name = "accommodation"
152    key = "bed"
153    def __init__(self):
154        WAeUPTable.__init__(self, 'portal_accommodation')
155
156    def searchAndReserveBed(self, student_id,bed_type):
157        records = self.searchResults({'student' : student_id})
158        if len(records) > 0:
159            return -1,"Student with Id %s already booked bed %s." % (student_id,records[0].bed)
160
161        records = [r for r in self.searchResults({'bed_type' : bed_type}) if not r.student]
162        #import pdb;pdb.set_trace()
163        if len(records) == 0:
164            return -2,"No bed available"
165        rec = records[0]
166        self.modifyRecord(bed=rec.bed,student=student_id)
167        s_logger = logging.getLogger('WAeUPTables.AccommodationTable.searchAndReserveBed')
168        s_logger.info('%s reserved bed %s' % (student_id,rec.bed))
169        return 1,rec.bed
170
171
172InitializeClass(AccommodationTable)
173
174###)
175
176class PinTable(WAeUPTable): ###(
177    from ZODB.POSException import ConflictError
178    meta_type = 'WAeUP Pin Tool'
179    name = "pins"
180    key = 'pin'
181    def __init__(self):
182        WAeUPTable.__init__(self, 'portal_pins')
183
184
185    def searchAndSetRecord(self, uid, student_id,prefix):
186        #records = self.searchResults(uid=uid)
187        records = self.searchResults(student = student_id)
188        #import pdb;pdb.set_trace()
189        if len(records) > 0 and prefix in ('CLR','APP'):
190            for r in records:
191                if r.pin != uid and r.prefix_batch.startswith(prefix):
192                    return -2
193        records = self.searchResults({"%s" % self.key : uid})
194        if len(records) > 1:
195            # Can not happen, but anyway...
196            raise ValueError("More than one record with uid %s" % uid)
197        if len(records) == 0:
198            return -1
199        record = records[0]
200        if record.student == "":
201            record_data = {}
202            for field in self.schema() + self.indexes():
203                record_data[field] = getattr(record, field)
204            # Add the updated data:
205            record_data['student'] = student_id
206            try:
207                self.catalog_object(dict2ob(record_data), uid)
208                return 1
209            except ConflictError:
210                return 2
211        if record.student.upper() != student_id.upper():
212            return 0
213        if record.student.upper() == student_id.upper():
214            return 2
215        return -3
216
217InitializeClass(PinTable)
218
219###)
220
221class PumeResultsTable(WAeUPTable): ###(
222
223    meta_type = 'WAeUP PumeResults Tool'
224    name = "pumeresults"
225    key = "jamb_reg_no"
226    def __init__(self):
227        WAeUPTable.__init__(self, 'portal_pumeresults')
228
229
230InitializeClass(PumeResultsTable)
231
232###)
233
234class StudentsCatalog(WAeUPTable): ###(
235    security = ClassSecurityInfo()
236
237    meta_type = 'WAeUP Students Catalog'
238    name = "students_catalog"
239    key = "id"
240    affected_types = {   ###(
241                      'StudentApplication':
242                      {'id': 'application',
243                       'fields':
244                       ('jamb_reg_no',
245                        'entry_mode',
246                        #'entry_level',
247                        'entry_session',
248                       )
249                      },
250                      'StudentClearance':
251                      {'id': 'clearance',
252                       'fields':
253                       ('matric_no',
254                        'lga',
255                       )
256                      },
257                      'StudentPersonal':
258                      {'id': 'personal',
259                       'fields':
260                       ('name',
261                        'sex',
262                        'perm_address',
263                        'email',
264                        'phone',
265                       )
266                      },
267                      'StudentStudyCourse':
268                      {'id': 'study_course',
269                       'fields':
270                       ('course', # study_course
271                        'faculty', # from certificate
272                        'department', # from certificate
273                        'end_level', # from certificate
274                        'level', # current_level
275                        'mode',  # current_mode
276                        'session', # current_session
277                        'verdict', # current_verdict
278                       )
279                      },
280                     }
281    ###)
282
283    def __init__(self):
284        WAeUPTable.__init__(self, 'students_catalog')
285        return
286
287    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
288        """ clears the whole enchilada """
289        self._catalog.clear()
290
291        if REQUEST and RESPONSE:
292            RESPONSE.redirect(
293              URL1 +
294              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
295
296    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
297        """ clear the catalog, then re-index everything """
298
299        elapse = time.time()
300        c_elapse = time.clock()
301
302        pgthreshold = self._getProgressThreshold()
303        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
304        self.refreshCatalog(clear=1, pghandler=handler)
305
306        elapse = time.time() - elapse
307        c_elapse = time.clock() - c_elapse
308
309        RESPONSE.redirect(
310            URL1 +
311            '/manage_catalogAdvanced?manage_tabs_message=' +
312            urllib.quote('Catalog Updated \n'
313                         'Total time: %s\n'
314                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
315    ###)
316
317    def fill_certificates_dict(self): ###(
318        "return certificate data in  dict"
319        certificates_brains = self.portal_catalog(portal_type ='Certificate')
320        d = {}
321        for cb in certificates_brains:
322            certificate_doc = cb.getObject().getContent()
323            cb_path = cb.getPath().split('/')
324            ld = {}
325            ld['faculty'] = cb_path[-4]
326            ld['department'] = cb_path[-3]
327            ld['end_level'] = getattr(certificate_doc,'end_level','999')
328            d[cb.getId] = ld
329        return d
330    ###)
331
332    def get_from_doc_department(self,doc,cached_data={}): ###(
333        "return the students department"
334        if doc is None:
335            return None
336        if cached_data.has_key(doc.study_course):
337            return cached_data[doc.study_course]['department']
338        certificate_res = self.portal_catalog(id = doc.study_course)
339        if len(certificate_res) != 1:
340            return None
341        return certificate_res[0].getPath().split('/')[-3]
342
343    def get_from_doc_faculty(self,doc,cached_data={}):
344        "return the students faculty"
345        if doc is None:
346            return None
347        if cached_data.has_key(doc.study_course):
348            return cached_data[doc.study_course]['faculty']
349        certificate_res = self.portal_catalog(id = doc.study_course)
350        if len(certificate_res) != 1:
351            return None
352        return certificate_res[0].getPath().split('/')[-4]
353
354    def get_from_doc_end_level(self,doc,cached_data={}):
355        "return the students end_level"
356        if doc is None:
357            return None
358        if cached_data.has_key(doc.study_course):
359            return cached_data[doc.study_course]['end_level']
360        certificate_res = self.portal_catalog(id = doc.study_course)
361        if len(certificate_res) != 1:
362            return None
363        return getattr(certificate_res[0].getObject().getContent(),'end_level','unknown')
364
365    def get_from_doc_level(self,doc,cached_data={}):
366        "return the students level"
367        if doc is None:
368            return None
369        return getattr(doc,'current_level',None)
370
371    def get_from_doc_mode(self,doc,cached_data={}):
372        "return the students mode"
373        if doc is None:
374            return None
375        cm = getattr(doc,'current_mode',None)
376        return cm
377
378
379    def get_from_doc_session(self,doc,cached_data={}):
380        "return the students current_session"
381        if doc is None:
382            return None
383        return getattr(doc,'current_session',None)
384
385    def get_from_doc_entry_session(self,doc,cached_data={}):
386        "return the students entry_session"
387        if doc is None:
388            return None
389        es = getattr(doc,'entry_session',None)
390        if es is not None and len(es) == 2:
391            return es
392        try:
393            digit = int(doc.jamb_reg_no[0])
394        except:
395            return "-1"
396        if digit < 8:
397            return "0%c" % doc.jamb_reg_no[0]
398        return "9%c" % doc.jamb_reg_no[0]
399
400    def get_from_doc_course(self,doc,cached_data={}):
401        "return the students study_course"
402        if doc is None:
403            return None
404        return getattr(doc,'study_course',None)
405
406    def get_from_doc_name(self,doc,cached_data={}):
407        "return the students name from the personal"
408        if doc is None:
409            return None
410        return "%s %s %s" % (doc.firstname,doc.middlename,doc.lastname)
411
412    def get_from_doc_verdict(self,doc,cached_data={}):
413        "return the students study_course"
414        if doc is None:
415            return None
416        return getattr(doc,'current_verdict',None)
417    ###)
418
419    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
420        if isinstance(name, str):
421            name = (name,)
422        reindextypes = {}
423        reindex_special = []
424        for n in name:
425            if n in ("review_state","registered_courses"):
426                reindex_special.append(n)
427            else:
428                for pt in self.affected_types.keys():
429                    if n in self.affected_types[pt]['fields']:
430                        if reindextypes.has_key(pt):
431                            reindextypes[pt].append(n)
432                        else:
433                            reindextypes[pt]= [n]
434                        break
435        cached_data = {}
436        if set(name).intersection(set(('faculty','department','end_level'))):
437            cached_data = self.fill_certificates_dict()
438        students = self.portal_catalog(portal_type="Student")
439        if hasattr(self,'portal_catalog_real'):
440            aq_portal = self.portal_catalog_real.evalAdvancedQuery
441        else:
442            aq_portal = self.portal_catalog.evalAdvancedQuery
443        num_objects = len(students)
444        if pghandler:
445            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
446        noattr = set(('StudentClearance','StudentPersonal')) & set(reindextypes.keys())
447        #import pdb;pdb.set_trace()
448        for i in xrange(num_objects):
449            if pghandler: pghandler.report(i)
450            student_brain = students[i]
451            student_object = student_brain.getObject()
452            # query = Eq('path',student_brain.getPath())
453            # sub_brains_list = aq_portal(query)
454            # sub_brains = {}
455            # for sub_brain in sub_brains_list:
456            #     sub_brains[sub_brain.portal_type] = sub_brain
457            # student_path = student_brain.getPath()
458            data = {}
459            modified = False
460            sid = data['id'] = student_brain.getId
461            if reindex_special and 'review_state' in reindex_special:
462                modified = True
463                data['review_state'] = student_brain.review_state
464            sub_objects = False
465            for pt in reindextypes.keys():
466                modified = True
467                try:
468                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
469                    #doc = sub_brains[pt].getObject().getContent()
470                    # path = "%s/%s" % (student_path,self.affected_types[pt]['id'])
471                    # doc = self.unrestrictedTraverse(path).getContent()
472                    sub_objects = True
473                except:
474                    continue
475                for field in set(name).intersection(self.affected_types[pt]['fields']):
476                    if hasattr(self,'get_from_doc_%s' % field):
477                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
478                                                                              cached_data=cached_data)
479                    else:
480                        data[field] = getattr(doc,field)
481            if not sub_objects and noattr:
482                import_res = self.returning_import(id = sid)
483                if not import_res:
484                    continue
485                import_record = import_res[0]
486                data['matric_no'] = import_record.matric_no
487                data['sex'] = import_record.Sex == 'F'
488                data['name'] = "%s %s %s" % (import_record.Firstname,
489                                             import_record.Middlename,
490                                             import_record.Lastname)
491                data['jamb_reg_no'] = import_record.Entryregno
492            if reindex_special and 'registered_courses' in reindex_special:
493                try:
494                    study_course = getattr(student_object,"study_course")
495                    level_ids = study_course.objectIds()
496                except:
497                    continue
498                if not level_ids:
499                    continue
500                modified = True
501                level_ids.sort()
502                course_ids = getattr(study_course,level_ids[-1]).objectIds()
503                courses = []
504                for c in course_ids:
505                    if c.endswith('_co'):
506                        courses.append(c[:-3])
507                    else:
508                        courses.append(c)
509                data['registered_courses'] = courses
510            if modified:
511                self.modifyRecord(**data)
512        if pghandler: pghandler.finish()
513    ###)
514
515    def refreshCatalog(self, clear=0, pghandler=None): ###(
516        """ re-index everything we can find """
517        students_folder = self.portal_url.getPortalObject().campus.students
518        if clear:
519            self._catalog.clear()
520        students = self.portal_catalog(portal_type="Student")
521        num_objects = len(students)
522        cached_data = self.fill_certificates_dict()
523        if pghandler:
524            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
525        for i in xrange(num_objects):
526            if pghandler: pghandler.report(i)
527            student_brain = students[i]
528            spath = student_brain.getPath()
529            student_object = student_brain.getObject()
530            data = {}
531            sid = data['id'] = student_brain.getId
532            data['review_state'] = student_brain.review_state
533            sub_objects = False
534            for pt in self.affected_types.keys():
535                modified = True
536                try:
537                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
538                    sub_objects = True
539                except:
540                    #from pdb import set_trace;set_trace()
541                    continue
542                for field in self.affected_types[pt]['fields']:
543                    if hasattr(self,'get_from_doc_%s' % field):
544                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
545                                                                              cached_data=cached_data)
546                    else:
547                        data[field] = getattr(doc,field,None)
548            if not sub_objects:
549                import_res = self.returning_import(id = sid)
550                if not import_res:
551                    continue
552                import_record = import_res[0]
553                data['matric_no'] = import_record.matric_no
554                data['sex'] = import_record.Sex == 'F'
555                data['name'] = "%s %s %s" % (import_record.Firstname,
556                                             import_record.Middlename,
557                                             import_record.Lastname)
558                data['jamb_reg_no'] = import_record.Entryregno
559            else:
560                study_course = getattr(student_object,'study_course',None)
561                current_level = data.get('level',None)
562                data['registered_courses'] = []
563                if study_course and current_level and current_level in study_course.objectIds():
564                    level_obj = getattr(study_course,current_level)
565                    courses = []
566                    for c in level_obj.objectIds():
567                        if c.endswith('_co'):
568                            courses.append(c[:-3])
569                        else:
570                            courses.append(c)
571                    data['registered_courses'] = courses
572            self.addRecord(**data)
573        if pghandler: pghandler.finish()
574    ###)
575
576    security.declarePrivate('notify_event_listener') ###(
577    def notify_event_listener(self,event_type,object,infos):
578        "listen for events"
579        if not infos.has_key('rpath'):
580            return
581        pt = getattr(object,'portal_type',None)
582        mt = getattr(object,'meta_type',None)
583        students_catalog = self
584        data = {}
585        if pt == 'Student' and\
586           mt == 'CPS Proxy Folder' and\
587           event_type.startswith('workflow'):
588            data['id'] = object.getId()
589            data['review_state'] = self.portal_workflow.getInfoFor(object,'review_state',None)
590            students_catalog.modifyRecord(**data)
591            return
592        rpl = infos['rpath'].split('/')
593        if pt == 'Student' and mt == 'CPS Proxy Folder'\
594           and event_type == "sys_add_object":
595            student_id = object.id
596            try:
597                self.addRecord(id = student_id)
598            except ValueError:
599                pass
600            return
601        elif pt == 'StudentCourseResult' and mt == 'CPS Proxy Folder':
602            if event_type not in ("sys_add_object","sys_del_object"):
603                return
604            level_session = getattr(object.aq_parent.getContent(),'session','unknown')
605            if level_session not in (self.getSessionId()[-2:],'2006/2007'):
606                return
607            course_id = object.getId()
608            if course_id.endswith('_co'):
609                course_id = course_id[:-3]
610            student_id = object.absolute_url_path().split('/')[-4]
611            res = students_catalog(id = student_id)
612            if not res:
613                return
614            student_rec = res[0]
615            registered_courses = getattr(student_rec,'registered_courses',None)
616            if not registered_courses:
617                registered_courses = []
618            #import pdb;pdb.set_trace()
619            if event_type == "sys_add_object":
620                if course_id not in registered_courses:
621                    registered_courses.append(course_id)
622                else:
623                    return
624            elif registered_courses and event_type == "sys_del_object":
625                removed = False
626                while course_id in registered_courses:
627                    removed = True
628                    registered_courses.remove(course_id)
629                if not removed:
630                    return
631            data['id'] = student_id
632            data['registered_courses'] = registered_courses
633            self.modifyRecord(record = student_rec, **data)
634            return
635        if pt not in self.affected_types.keys():
636            return
637        if event_type not in ('sys_modify_object'):
638            return
639        if mt == 'CPS Proxy Folder':
640            return
641        for field in self.affected_types[pt]['fields']:
642            if hasattr(self,'get_from_doc_%s' % field):
643                data[field] = getattr(self,'get_from_doc_%s' % field)(object)
644            else:
645                data[field] = getattr(object,field)
646        data['id'] = rpl[2]
647        self.modifyRecord(**data)
648    ###)
649
650
651InitializeClass(StudentsCatalog)
652
653###)
654
655class CoursesCatalog(WAeUPTable): ###(
656    security = ClassSecurityInfo()
657
658    meta_type = 'WAeUP Courses Catalog'
659    name = "courses_catalog"
660    key = "code"
661    def __init__(self):
662        WAeUPTable.__init__(self, 'courses_catalog')
663
664    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
665        """ clear the catalog, then re-index everything """
666
667        elapse = time.time()
668        c_elapse = time.clock()
669
670        pgthreshold = self._getProgressThreshold()
671        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
672        self.refreshCatalog(clear=1, pghandler=handler)
673
674        elapse = time.time() - elapse
675        c_elapse = time.clock() - c_elapse
676
677        RESPONSE.redirect(
678            URL1 +
679            '/manage_catalogAdvanced?manage_tabs_message=' +
680            urllib.quote('Catalog Updated \n'
681                         'Total time: %s\n'
682                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
683    ###)
684
685    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
686        if isinstance(name, str):
687            name = (name,)
688        courses = self.portal_catalog(portal_type="Course")
689        num_objects = len(courses)
690        if pghandler:
691            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
692        for i in xrange(num_objects):
693            if pghandler: pghandler.report(i)
694            course_brain = courses[i]
695            course_object = course_brain.getObject()
696            pl = course_brain.getPath().split('/')
697            data = {}
698            cid = data[self.key] = course_brain.getId
699            data['faculty'] = pl[-4]
700            data['department'] = pl[-3]
701            doc = course_object.getContent()
702            for field in name:
703                if field not in (self.key,'faculty','department'):
704                    data[field] = getattr(doc,field)
705            self.modifyRecord(**data)
706        if pghandler: pghandler.finish()
707    ###)
708
709    def refreshCatalog(self, clear=0, pghandler=None): ###(
710        """ re-index everything we can find """
711        if clear:
712            self._catalog.clear()
713        courses = self.portal_catalog(portal_type="Course")
714        num_objects = len(courses)
715        if pghandler:
716            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
717        #from pdb import set_trace;set_trace()
718        for i in xrange(num_objects):
719            if pghandler: pghandler.report(i)
720            course_brain = courses[i]
721            course_doc = course_brain.getObject().getContent()
722            pl = course_brain.getPath().split('/')
723            data = {}
724            for field in self.schema():
725                data[field] = getattr(course_doc,field,None)
726            data[self.key] = course_brain.getId
727            ai = pl.index('academics')
728            data['faculty'] = pl[ai +1]
729            data['department'] = pl[ai +2]
730            if clear:
731                self.addRecord(**data)
732            else:
733                self.modifyRecord(**data)
734        if pghandler: pghandler.finish()
735    ###)
736
737    security.declarePrivate('notify_event_listener') ###(
738    def notify_event_listener(self,event_type,object,infos):
739        "listen for events"
740        if not infos.has_key('rpath'):
741            return
742        pt = getattr(object,'portal_type',None)
743        mt = getattr(object,'meta_type',None)
744        if pt != 'Course':
745            return
746        data = {}
747        rpl = infos['rpath'].split('/')
748        if event_type not in ("sys_add_object","sys_modify_object","sys_del_object"):
749            return
750        course_id = object.getId()
751        data[self.key] = course_id
752        if event_type == "sys_add_object" and mt == 'CPS Proxy Folder':
753            try:
754                self.addRecord(**data)
755            except ValueError:
756                return
757            course_id = object.getId()
758            doc = object.getContent()
759            if doc is None:
760                return
761            for field in self.schema():
762                data[field] = getattr(doc,field,None)
763            data[self.key] = course_id
764            ai = rpl.index('academics')
765            data['faculty'] = rpl[ai +1]
766            data['department'] = rpl[ai +2]
767            self.modifyRecord(**data)
768            return
769        if event_type == "sys_del_object":
770            self.deleteRecord(course_id)
771            return
772        if event_type == "sys_modify_object" and mt == 'Course':
773            #from pdb import set_trace;set_trace()
774            for field in self.schema():
775                data[field] = getattr(object,field,None)
776            course_id = object.aq_parent.getId()
777            data[self.key] = course_id
778            ai = rpl.index('academics')
779            data['faculty'] = rpl[ai +1]
780            data['department'] = rpl[ai +2]
781            self.modifyRecord(**data)
782    ###)
783
784
785InitializeClass(CoursesCatalog)
786###)
787
788class CourseResults(WAeUPTable): ###(
789    security = ClassSecurityInfo()
790
791    meta_type = 'WAeUP Results Catalog'
792    name = "course_results"
793    key = "key" #student_id + level + course_id
794    def __init__(self):
795        WAeUPTable.__init__(self, 'course_results')
796        self._queue = []
797       
798    def addRecord(self, **data): ###(
799        # The uid is the same as "bed".
800        uid = key = "%(student_id)s|%(level_id)s|%(course_id)s" % data
801        if key in self._queue:
802            return uid
803        data['queue_status'] = ADDING_SHEDULED
804        data['%s' % self.key] = uid
805        res = self.searchResults({"%s" % self.key : uid})
806        if len(res) > 0:
807            raise ValueError("More than one record with uid %s" % uid)
808        self.catalog_object(dict2ob(data), uid=uid)
809        if not hasattr(self,'_queue'):
810            self._queue = []
811        self._queue.append(key)
812        self._p_changed = 1
813        return uid
814    ###)
815
816    def deleteRecord(self, uid): ###(
817        self.uncatalog_object(uid)
818        if uid in self._queue:
819            self._queue.remove(uid)
820    ###)
821
822    def getCourses(self,student_id,level_id): ###(
823        query = Eq('student_id',student_id) & Eq('level_id', level_id)
824        carry_overs = []
825        normal = []
826        credits = 0
827        for brain in self.course_results.evalAdvancedQuery(query):
828            d = {}
829            credits += int(brain.credits)
830            for field in self.schema():
831                d[field] = getattr(brain,field,'')
832            d['sheduled'] = brain.queue_status == ADDING_SHEDULED
833            d['coe'] = 'Elective'
834            if brain.core_or_elective:
835                d['coe'] = 'Core'
836            d['title'] = self.courses_catalog.evalAdvancedQuery(Eq('code',brain.code))[0].title
837            if brain.code.endswith('_co'):
838                carry_overs.append(d)
839            else:
840                normal.append(d)
841        normal.sort(cmp=lambda x,y: cmp(x['semester'], y['semester']))
842        carry_overs.sort(cmp=lambda x,y: cmp(x['semester'], y['semester']))
843        return credits,carry_overs,normal
844    ###)
845
846    def addObject(self,record): ###(
847        key = record.key
848        student_id,level_id,course_id = key.split('|')
849        level = getattr(getattr(self.portal_url.getPortalObject().campus.students,student_id).study_course,level_id)
850        cr_id = level.invokeFactory('StudentCourseResult', course_id)
851        course_result = getattr(level,cr_id)
852        self.portal_workflow.doActionFor(course_result,'open')
853        d = {}
854        for field in self.schema():
855            d[field] = getattr(record,field,'')
856        course_result.getContent().edit(mapping=d)
857    ###)
858       
859    security.declareProtected(ModifyPortalContent,"process_queue") ###(
860    def process_queue(self,limit=None):
861        """adds objects and removes them from the queue.
862        If limit is specified, at most (limit) events are removed.
863        """
864        if not hasattr(self,'_queue'):
865            return 0
866        queue= self._queue
867        if not limit or len(queue) <= limit:
868            keys = self._queue[:]
869        else:
870            keys = queue[:limit]
871        if not keys:
872            records = self.evalAdvancedQuery(Eq('queue_status',ADDING_SHEDULED))
873        else:
874            records = self.evalAdvancedQuery(In("%s" % self.key,keys))
875        for record in records:
876            if record.queue_status == OBJECT_CREATED:
877                continue
878            self.addObject(record)
879            data = {}
880            data['key'] = record.key
881            data['queue_status'] = OBJECT_CREATED
882            self.modifyRecord(**data)
883        count = 0
884        for key in keys:
885            count +=1
886            if key in self._queue:
887                self._queue.remove(key)
888        self._p_changed = 1
889        return count,len(self._queue)
890    ###)
891
892    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None): ###(
893        """ clears the whole enchilada """
894        self._catalog.clear()
895
896        if REQUEST and RESPONSE:
897            RESPONSE.redirect(
898              URL1 +
899              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
900    ###)
901
902    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
903        """ clear the catalog, then re-index everything """
904
905        elapse = time.time()
906        c_elapse = time.clock()
907
908        pgthreshold = self._getProgressThreshold()
909        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
910        self.refreshCatalog(clear=1, pghandler=handler)
911
912        elapse = time.time() - elapse
913        c_elapse = time.clock() - c_elapse
914
915        RESPONSE.redirect(
916            URL1 +
917            '/manage_catalogAdvanced?manage_tabs_message=' +
918            urllib.quote('Catalog Updated \n'
919                         'Total time: %s\n'
920                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
921    ###)
922
923    def refreshCatalog(self, clear=1, pghandler=None): ###(
924        """ re-index everything we can find """
925        students_folder = self.portal_url.getPortalObject().campus.students
926        if clear:
927            self._catalog.clear()
928        course_results = self.portal_catalog(portal_type="StudentCourseResult")
929        num_objects = len(course_results)
930        if pghandler:
931            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
932        #import pdb;pdb.set_trace()
933        for i in xrange(num_objects):
934            if pghandler:
935                pghandler.report(i)
936            course_result_brain = course_results[i]
937            path_list = course_result_brain.getPath().split('/')
938            course_result_object = course_result_brain.getObject()
939            course_result_doc = course_result_object.getContent()
940            data = {}
941            level_id = path_list[-2]
942            course_id = path_list[-1]
943            student_id = path_list[-4]
944            for field in self.schema():
945                data[field] = getattr(course_result_doc,field,'')
946            data['key'] = key = "%(student_id)s|%(level_id)s|%(course_id)s" % vars()
947            data['student_id'] = student_id
948            data['level_id'] = level_id
949            data['queue_status'] = OBJECT_CREATED
950            self.catalog_object(dict2ob(data), uid=key)
951        if pghandler: pghandler.finish()
952    ###)
953
954    security.declarePrivate('notify_event_listener') ###(
955    def notify_event_listener(self,event_type,object,infos):
956        "listen for events"
957        if not infos.has_key('rpath'):
958            return
959        pt = getattr(object,'portal_type',None)
960        mt = getattr(object,'meta_type',None)
961        data = {}
962        rpl = infos['rpath'].split('/')
963        if mt == 'CPS Proxy Folder':
964            return
965        if pt == 'StudentCourseResult' and event_type == "sys_modify_object":
966            data["%s" % self.key] = uid = "%s|%s|%s" % (rpl[-5],rpl[-3],rpl[-2])
967            records = self.searchResults({"%s" % self.key : uid})
968            if len(records) > 1:
969                # Can not happen, but anyway...
970                raise ValueError("More than one record with uid %s" % uid)
971            if len(records) == 0:
972                raise KeyError("No record for uid %s" % uid)
973            record = records[0]
974            #import pdb;pdb.set_trace()
975            for field in ('core_or_elective','score'):
976                value = getattr(object,field,None)
977                data[field] = value
978            self.modifyRecord(record,**data)
979    ###)
980
981InitializeClass(CourseResults)
982###)
983
984class OnlinePaymentsImport(WAeUPTable): ###(
985
986    meta_type = 'WAeUP Online Payment Transactions'
987    name = "online_payments_import"
988    key = "order_id"
989    def __init__(self):
990        WAeUPTable.__init__(self, self.name)
991
992
993InitializeClass(OnlinePaymentsImport)
994###)
995
996class ReturningImport(WAeUPTable): ###(
997
998    meta_type = 'Returning Import Table'
999    name = "returning_import"
1000    key = "matric_no"
1001    def __init__(self):
1002        WAeUPTable.__init__(self, 'returning_import')
1003
1004
1005InitializeClass(ReturningImport)
1006###)
1007
1008class ResultsImport(WAeUPTable): ###(
1009
1010    meta_type = 'Results Import Table'
1011    name = "results_import"
1012    key = "key"
1013    def __init__(self):
1014        WAeUPTable.__init__(self, 'results_import')
1015
1016
1017InitializeClass(ResultsImport)
1018
1019###)
1020
1021class PaymentsCatalog(WAeUPTable): ###(
1022
1023    meta_type = 'WAeUP Payments Catalog'
1024    name = "students_catalog"
1025    key = "id"
1026    def __init__(self):
1027        WAeUPTable.__init__(self, 'payments_catalog')
1028
1029
1030InitializeClass(PaymentsCatalog)
1031
1032###)
1033
1034# BBB:
1035AccomodationTable = AccommodationTable
Note: See TracBrowser for help on using the repository browser.