source: WAeUP_SRP/trunk/WAeUPTables.py @ 2188

Last change on this file since 2188 was 2185, checked in by joachim, 17 years ago

ignore empty lga, state fields, headings can now start with spaces

  • Property svn:keywords set to Id
File size: 57.2 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 2185 2007-09-07 12:15:45Z 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
27from Products.CMFCore.utils import getToolByName
28from Products.CMFCore.CatalogTool import CatalogTool
29from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
30from Products.CPSSchemas.DataStructure import DataStructure
31from Products.CPSSchemas.DataModel import DataModel
32from Products.AdvancedQuery import Eq, Between, Le,In
33import urllib
34import DateTime,time
35import csv,re
36import logging
37import Globals
38p_home = Globals.package_home(globals())
39i_home = Globals.INSTANCE_HOME
40
41ADDING_SHEDULED = "adding_sheduled"
42OBJECT_CREATED = "object_created"
43
44from interfaces import IWAeUPTable
45
46class AttributeHolder(object):
47    pass
48
49def dict2ob(dict):
50    ob = AttributeHolder()
51    for key, value in dict.items():
52        setattr(ob, key, value)
53    return ob
54
55class WAeUPTable(ZCatalog): ###(
56
57    implements(IWAeUPTable)
58    security = ClassSecurityInfo()
59    meta_type = None
60
61    def __init__(self,name=None):
62        if name ==  None:
63            name = self.name
64        ZCatalog.__init__(self,name)
65
66    def refreshCatalog(self, clear=0, pghandler=None): ###(
67        """ don't refresh for a normal table """
68
69        if self.REQUEST and self.REQUEST.RESPONSE:
70            self.REQUEST.RESPONSE.redirect(
71              URL1 +
72              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20refresh%20not%20implemented')
73
74###)
75
76    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None): ###(
77        """ clears the whole enchilada """
78
79        #if REQUEST and RESPONSE:
80        #    RESPONSE.redirect(
81        #      URL1 +
82        #      '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Clearing%20disabled')
83
84        self._catalog.clear()
85        if REQUEST and RESPONSE:
86            RESPONSE.redirect(
87              URL1 +
88              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20cleared')
89
90###)
91
92    def addRecord(self, **data): ###(
93        # The uid is the same as "bed".
94        uid = data[self.key]
95        res = self.searchResults({"%s" % self.key : uid})
96        if len(res) > 0:
97            raise ValueError("More than one record with uid %s" % uid)
98        self.catalog_object(dict2ob(data), uid=uid)
99        return uid
100
101###)
102
103    def deleteRecord(self, uid):
104        self.uncatalog_object(uid)
105
106    def searchAndSetRecord(self, **data):
107        raise NotImplemented
108
109    def modifyRecord(self, record=None, **data): ###(
110        #records = self.searchResults(uid=uid)
111        uid = data[self.key]
112        if record is None:
113            records = self.searchResults({"%s" % self.key : uid})
114            if len(records) > 1:
115                # Can not happen, but anyway...
116                raise ValueError("More than one record with uid %s" % uid)
117            if len(records) == 0:
118                raise KeyError("No record for uid %s" % uid)
119            record = records[0]
120        record_data = {}
121        for field in self.schema() + self.indexes():
122            record_data[field] = getattr(record, field)
123        # Add the updated data:
124        record_data.update(data)
125        self.catalog_object(dict2ob(record_data), uid)
126
127###)
128
129    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
130        if isinstance(name, str):
131            name =  (name,)
132        paths = self._catalog.uids.items()
133        i = 0
134        #import pdb;pdb.set_trace()
135        for p,rid in paths:
136            i += 1
137            metadata = self.getMetadataForRID(rid)
138            record_data = {}
139            for field in name:
140                record_data[field] = metadata.get(field)
141            uid = metadata.get(self.key)
142            self.catalog_object(dict2ob(record_data), uid, idxs=name,
143                                update_metadata=0)
144
145###)
146
147    security.declareProtected(ModifyPortalContent,"exportAllRecords") ###(
148    def exportAllRecords(self):
149        "export a WAeUPTable"
150        #import pdb;pdb.set_trace()
151        fields = [field for field in self.schema()]
152        format = ','.join(['"%%(%s)s"' % fn for fn in fields])
153        csv = []
154        csv.append(','.join(['"%s"' % fn for fn in fields]))
155        for uid in self._catalog.uids:
156            records = self.searchResults({"%s" % self.key : uid})
157            if len(records) > 1:
158                # Can not happen, but anyway...
159                raise ValueError("More than one record with uid %s" % uid)
160            if len(records) == 0:
161                raise KeyError("No record for uid %s" % uid)
162            rec = records[0]
163            csv.append(format % rec)
164        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
165        open("%s/import/%s-%s.csv" % (i_home,self.getId(),current),"w+").write('\n'.join(csv))
166
167###)
168
169    security.declarePrivate("_import_old") ###(
170    def _import_old(self,filename,schema,layout, mode,logger):
171        "import data from csv"
172        import transaction
173        import random
174        pm = self.portal_membership
175        member = pm.getAuthenticatedMember()
176        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
177        import_fn = "%s/import/%s.csv" % (i_home,filename)
178        imported_fn = "%s/import/%s_imported%s.csv" % (i_home,filename,current)
179        not_imported_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
180        start = True
181        tr_count = 1
182        total_imported = 0
183        total_not_imported = 0
184        total = 0
185        iname =  "%s" % filename
186        not_imported = []
187        imported = []
188        valid_records = []
189        invalid_records = []
190        d = {}
191        d['mode'] = mode
192        d['imported'] = total_imported
193        d['not_imported'] = total_not_imported
194        d['valid_records'] = valid_records
195        d['invalid_records'] = invalid_records
196        d['import_fn'] = import_fn
197        d['imported_fn'] = imported_fn
198        d['not_imported_fn'] = not_imported_fn
199        if schema is None:
200            em = 'No schema specified'
201            logger.error(em)
202            return d
203        if layout is None:
204            em = 'No layout specified'
205            logger.error(em)
206            return d
207        validators = {}
208        for widget in layout.keys():
209            try:
210                validators[widget] = layout[widget].validate
211            except AttributeError:
212                logger.info('%s has no validate attribute' % widget)
213                return d
214        # if mode == 'edit':
215        #     importer = self.importEdit
216        # elif mode == 'add':
217        #     importer = self.importAdd
218        # else:
219        #     importer = None
220        try:
221            items = csv.DictReader(open(import_fn,"rb"),
222                                   dialect="excel",
223                                   skipinitialspace=True)
224        except:
225            em = 'Error reading %s.csv' % filename
226            logger.error(em)
227            return d
228        #import pdb;pdb.set_trace()
229        for item in items:
230            if start:
231                start = False
232                logger.info('%s starts import from %s.csv' % (member,filename))
233                #import_keys = [k for k in item.keys() if not k.startswith('ignore')]
234                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb"),
235                                   dialect="excel",
236                                   skipinitialspace=True).next()
237                import_keys = [k for k in attrs if not (k.startswith('ignore') or k.isupper())]
238                diff2schema = set(import_keys).difference(set(schema.keys()))
239                diff2layout = set(import_keys).difference(set(layout.keys()))
240                if diff2layout:
241                    em = "not ignorable key(s) %s found in heading" % diff2layout
242                    logger.info(em)
243                    return d
244                s = ','.join(['"%s"' % fn for fn in import_keys])
245                open(not_imported_fn,"a").write(s + ',"Error"'+ '\n')
246                #s = '"id",' + s
247                open(imported_fn,"a").write(s + '\n')
248                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
249                format_error = format + ',"%(Error)s"'
250                #format = '"%(id)s",'+ format
251                adapters = [MappingStorageAdapter(schema, item)]
252            dm = DataModel(item, adapters,context=self)
253            ds = DataStructure(data=item,datamodel=dm)
254            error_string = ""
255            for k in import_keys:
256                if not validators[k](ds,mode=mode):
257                    error_string += " %s : %s" % (k,ds.getError(k))
258            # if not error_string and importer:
259            #     item.update(dm)
260            #     item['id'],error = importer(item)
261            #     if error:
262            #         error_string += error
263            if error_string:
264                item['Error'] = error_string
265                invalid_records.append(dm)
266                not_imported.append(format_error % item)
267                total_not_imported += 1
268            else:
269                em = format % item
270                valid_records.append(dm)
271                imported.append(em)
272                #logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
273                tr_count += 1
274                total_imported += 1
275            total += 1
276        if len(imported) > 0:
277            open(imported_fn,"a").write('\n'.join(imported))
278        if len(not_imported) > 0:
279            open(not_imported_fn,"a").write('\n'.join(not_imported))
280        #em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
281        d['imported'] = total_imported
282        d['not_imported'] = total_not_imported
283        d['valid_records'] = valid_records
284        d['invalid_records'] = invalid_records
285        d['imported_fn'] = imported_fn
286        d['not_imported_fn'] = not_imported_fn
287        #logger.info(em)
288        return d
289    ###)
290
291    security.declarePrivate("_import") ###(
292    def _import_new(self,csv_items,schema, layout, mode,logger):
293        "import data from csv.Dictreader Instance"
294        start = True
295        tr_count = 1
296        total_imported = 0
297        total_not_imported = 0
298        total = 0
299        iname =  "%s" % filename
300        not_imported = []
301        valid_records = []
302        invalid_records = []
303        duplicate_records = []
304        d = {}
305        d['mode'] = mode
306        d['valid_records'] = valid_records
307        d['invalid_records'] = invalid_records
308        d['invalid_records'] = duplicate_records
309        # d['import_fn'] = import_fn
310        # d['imported_fn'] = imported_fn
311        # d['not_imported_fn'] = not_imported_fn
312        validators = {}
313        for widget in layout.keys():
314            try:
315                validators[widget] = layout[widget].validate
316            except AttributeError:
317                logger.info('%s has no validate attribute' % widget)
318                return d
319        for item in csv_items:
320            if start:
321                start = False
322                logger.info('%s starts import from %s.csv' % (member,filename))
323                #import_keys = [k for k in item.keys() if not k.startswith('ignore')]
324                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
325                import_keys = [k for k in attrs if not (k.startswith('ignore') or k.isupper())]
326                diff2schema = set(import_keys).difference(set(schema.keys()))
327                diff2layout = set(import_keys).difference(set(layout.keys()))
328                if diff2layout:
329                    em = "not ignorable key(s) %s found in heading" % diff2layout
330                    logger.info(em)
331                    return d
332                # s = ','.join(['"%s"' % fn for fn in import_keys])
333                # open(not_imported_fn,"a").write(s + ',"Error"'+ '\n')
334                # #s = '"id",' + s
335                # open(imported_fn,"a").write(s + '\n')
336                # format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
337                # format_error = format + ',"%(Error)s"'
338                # #format = '"%(id)s",'+ format
339                adapters = [MappingStorageAdapter(schema, item)]
340            dm = DataModel(item, adapters,context=self)
341            ds = DataStructure(data=item,datamodel=dm)
342            error_string = ""
343            for k in import_keys:
344                if not validators[k](ds,mode=mode):
345                    error_string += " %s : %s" % (k,ds.getError(k))
346            if error_string:
347                item['Error'] = error_string
348                #invalid_records.append(dm)
349                invalid_records.append(item)
350                total_not_imported += 1
351            else:
352                em = format % item
353                valid_records.append(dm)
354                #logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
355                tr_count += 1
356                total_imported += 1
357            total += 1
358        # if len(imported) > 0:
359        #     open(imported_fn,"a").write('\n'.join(imported))
360        # if len(not_imported) > 0:
361        #     open(not_imported_fn,"a").write('\n'.join(not_imported))
362        #em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
363        d['imported'] = total_imported
364        d['not_imported'] = total_not_imported
365        d['valid_records'] = valid_records
366        d['invalid_records'] = invalid_records
367        return d
368    ###)
369
370###)
371
372class AccommodationTable(WAeUPTable): ###(
373
374    meta_type = 'WAeUP Accommodation Tool'
375    name = "portal_accommodation"
376    key = "bed"
377    def __init__(self,name=None):
378        if name ==  None:
379            name = self.name
380        WAeUPTable.__init__(self, name)
381
382    def searchAndReserveBed(self, student_id,bed_type):
383        records = self.searchResults({'student' : student_id})
384        if len(records) > 0:
385            return -1,"Student with Id %s already booked bed %s." % (student_id,records[0].bed)
386
387        records = [r for r in self.searchResults({'bed_type' : bed_type}) if not r.student]
388        #import pdb;pdb.set_trace()
389        if len(records) == 0:
390            return -2,"No bed available"
391        rec = records[0]
392        self.modifyRecord(bed=rec.bed,student=student_id)
393        s_logger = logging.getLogger('WAeUPTables.AccommodationTable.searchAndReserveBed')
394        s_logger.info('%s reserved bed %s' % (student_id,rec.bed))
395        return 1,rec.bed
396
397
398InitializeClass(AccommodationTable)
399
400###)
401
402class PinTable(WAeUPTable): ###(
403    from ZODB.POSException import ConflictError
404    meta_type = 'WAeUP Pin Tool'
405    name = "portal_pins"
406    key = 'pin'
407    def __init__(self,name=None):
408        if name ==  None:
409            name = self.name
410        WAeUPTable.__init__(self, name)
411
412
413    def searchAndSetRecord(self, uid, student_id,prefix):
414       
415        # The following line must be activated after resetting the
416        # the portal_pins table. This is to avoid duplicate entries
417        # and disable duplicate payments.
418       
419        #student_id = student_id.upper()
420
421        records = self.searchResults(student = student_id)
422        if len(records) > 0 and prefix in ('CLR','APP'):
423            for r in records:
424                if r.pin != uid and r.prefix_batch.startswith(prefix):
425                    return -2
426        records = self.searchResults({"%s" % self.key : uid})
427        if len(records) > 1:
428            # Can not happen, but anyway...
429            raise ValueError("More than one record with uid %s" % uid)
430        if len(records) == 0:
431            return -1
432        record = records[0]
433        if record.student == "":
434            record_data = {}
435            for field in self.schema() + self.indexes():
436                record_data[field] = getattr(record, field)
437            # Add the updated data:
438            record_data['student'] = student_id
439            try:
440                self.catalog_object(dict2ob(record_data), uid)
441                return 1
442            except ConflictError:
443                return 2
444        if record.student.upper() != student_id.upper():
445            return 0
446        if record.student.upper() == student_id.upper():
447            return 2
448        return -3
449
450InitializeClass(PinTable)
451
452###)
453
454class PumeResultsTable(WAeUPTable): ###(
455
456    meta_type = 'WAeUP PumeResults Tool'
457    name = "portal_pumeresults"
458    key = "jamb_reg_no"
459    def __init__(self,name=None):
460        if name ==  None:
461            name = self.name
462        WAeUPTable.__init__(self, name)
463
464
465InitializeClass(PumeResultsTable)
466
467###)
468
469class ApplicantsCatalog(WAeUPTable): ###(
470
471    meta_type = 'WAeUP Applicants Catalog'
472    name = "applicants_catalog"
473    key = "reg_no"
474    security = ClassSecurityInfo()
475
476    def __init__(self,name=None):
477        if name ==  None:
478            name = self.name
479        WAeUPTable.__init__(self, name)
480
481    security.declareProtected(ModifyPortalContent,"new_importCSV")###(
482    def new_importCSV(self,filename="JAMB_data",
483                  schema_id="application",
484                  layout_id="application_import",
485                  mode='add'):
486        """ import JAMB data """
487        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
488        pm = self.portal_membership
489        member = pm.getAuthenticatedMember()
490        logger = logging.getLogger('WAeUPTables.ApplicantsCatalog.importCSV')
491        lock_fn = "%s/import/%s_import_lock" % (i_home,filename)
492        import_fn = "%s/import/%s.csv" % (i_home,filename)
493        if mode not in ('add','edit'):
494            logger.info("invalid mode: %s" % mode)
495        if os.path.exists(lock_fn):
496            logger.info("import of %(import_fn)s already in progress" % vars())
497            return
498        lock_file = open(lock_fn,"w")
499        lock_file.write("%(current)s \n" % vars())
500        lock_file.close()
501        invalid_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
502        duplicate_fn = "%s/import/%s_not_imported%s.csv" % (i_home,filename,current)
503        stool = getToolByName(self, 'portal_schemas')
504        ltool = getToolByName(self, 'portal_layouts')
505        schema = stool._getOb(schema_id)
506        if schema is None:
507            em = 'No such schema %s' % schema_id
508            logger.error(em)
509            return
510        for postfix in ('_import',''):
511            layout_name = "%(layout_id)s%(postfix)s" % vars()
512            if hasattr(ltool,layout_name):
513                break
514        layout = ltool._getOb(layout_name)
515        if layout is None:
516            em = 'No such layout %s' % layout_id
517            logger.error(em)
518            return
519        try:
520            csv_file = csv.DictReader(open(import_fn,"rb"))
521        except:
522            em = 'Error reading %s.csv' % filename
523            logger.error(em)
524            return
525        d = self._import_new(csv_items,schema,layout,mode,logger)
526        imported = []
527        edited = []
528        duplicates = []
529        not_found = []
530        if len(d['valid_records']) > 0:
531            for record in d['valid_records']:
532                #import pdb;pdb.set_trace()
533                if mode == "add":
534                    try:
535                        self.addRecord(**dict(record.items()))
536                        imported.append(**dict(record.items()))
537                        logger.info("added %s" % record.items())
538                    except ValueError:
539                        dupplicate.append(**dict(record.items()))
540                        logger.info("duplicate %s" % record.items())
541                elif mode == "edit":
542                    try:
543                        self.modifyRecord(**dict(record.items()))
544                        edited.append(**dict(record.items()))
545                        logger.info("edited %s" % record.items())
546                    except KeyError:
547                        not_found.append(**dict(record.items()))
548                        logger.info("not found %s" % record.items())
549        invalid = d['invalid_records']
550        for itype in ("imported","edited","not_found","duplicate","invalid"):
551            outlist = locals[itype]
552            if len(outlist):
553                d = {}
554                for k in outlist[0].keys():
555                    d[k] = k
556                outlist[0] = d
557                outfile = open("file_name_%s" % itype,'w')
558                csv.DictWriter(outfile,outlist[0].keys()).writerows(outlist)
559                logger.info("wrote %(itype)s records to %(, written to %(not_imported_fn)s" % d)
560###)
561
562    security.declareProtected(ModifyPortalContent,"importCSV")###(
563    def importCSV(self,filename="JAMB_data",
564                  schema_id="application",
565                  layout_id="application",
566                  mode='add'):
567        """ import JAMB data """
568        stool = getToolByName(self, 'portal_schemas')
569        ltool = getToolByName(self, 'portal_layouts')
570        schema = stool._getOb(schema_id)
571        if schema is None:
572            em = 'No such schema %s' % schema_id
573            logger.error(em)
574            return
575        layout = ltool._getOb(layout_id)
576        if layout is None:
577            em = 'No such layout %s' % layout_id
578            logger.error(em)
579            return
580        logger = logging.getLogger('WAeUPTables.ApplicantsCatalog.importCSV')
581        d = self._import_old(filename,schema,layout,mode,logger)
582        if len(d['valid_records']) > 0:
583            for record in d['valid_records']:
584                #import pdb;pdb.set_trace()
585                if mode == "add":
586                    self.addRecord(**dict(record.items()))
587                    logger.info("added %s" % record.items())
588                elif mode == "edit":
589                    self.modifyRecord(**dict(record.items()))
590                    logger.info("edited %s" % record.items())
591                else:
592                    logger.info("invalid mode: %s" % mode)
593        logger.info("%(mode)sed %(imported)d records, invalid written to %(not_imported_fn)s" % d)
594###)
595
596InitializeClass(ApplicantsCatalog)
597
598###)
599
600class StudentsCatalog(WAeUPTable): ###(
601    security = ClassSecurityInfo()
602
603    meta_type = 'WAeUP Students Catalog'
604    name = "students_catalog"
605    key = "id"
606    affected_types = {   ###(
607                      'StudentApplication':
608                      {'id': 'application',
609                       'fields':
610                       ('jamb_reg_no',
611                        'entry_mode',
612                        #'entry_level',
613                        'entry_session',
614                       )
615                      },
616                      'StudentClearance':
617                      {'id': 'clearance',
618                       'fields':
619                       ('matric_no',
620                        'lga',
621                       )
622                      },
623                      'StudentPersonal':
624                      {'id': 'personal',
625                       'fields':
626                       ('name',
627                        'sex',
628                        'perm_address',
629                        'email',
630                        'phone',
631                       )
632                      },
633                      'StudentStudyCourse':
634                      {'id': 'study_course',
635                       'fields':
636                       ('course', # study_course
637                        'faculty', # from certificate
638                        'department', # from certificate
639                        'end_level', # from certificate
640                        'level', # current_level
641                        'mode',  # current_mode
642                        'session', # current_session
643                        'verdict', # current_verdict
644                       )
645                      },
646                     }
647    ###)
648
649    def __init__(self,name=None):
650        if name ==  None:
651            name = self.name
652        WAeUPTable.__init__(self, name)
653        return
654
655    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
656        """ clears the whole enchilada """
657        self._catalog.clear()
658
659        if REQUEST and RESPONSE:
660            RESPONSE.redirect(
661              URL1 +
662              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
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 fill_certificates_dict(self): ###(
686        "return certificate data in  dict"
687        certificates_brains = self.portal_catalog(portal_type ='Certificate')
688        d = {}
689        for cb in certificates_brains:
690            certificate_doc = cb.getObject().getContent()
691            cb_path = cb.getPath().split('/')
692            ld = {}
693            ld['faculty'] = cb_path[-4]
694            ld['department'] = cb_path[-3]
695            ld['end_level'] = getattr(certificate_doc,'end_level','999')
696            d[cb.getId] = ld
697        return d
698    ###)
699
700    def get_from_doc_department(self,doc,cached_data={}): ###(
701        "return the students department"
702        if doc is None:
703            return None
704        if cached_data.has_key(doc.study_course):
705            return cached_data[doc.study_course]['department']
706        certificate_res = self.portal_catalog(id = doc.study_course)
707        if len(certificate_res) != 1:
708            return None
709        return certificate_res[0].getPath().split('/')[-3]
710
711    def get_from_doc_faculty(self,doc,cached_data={}):
712        "return the students faculty"
713        if doc is None:
714            return None
715        if cached_data.has_key(doc.study_course):
716            return cached_data[doc.study_course]['faculty']
717        certificate_res = self.portal_catalog(id = doc.study_course)
718        if len(certificate_res) != 1:
719            return None
720        return certificate_res[0].getPath().split('/')[-4]
721
722    def get_from_doc_end_level(self,doc,cached_data={}):
723        "return the students end_level"
724        if doc is None:
725            return None
726        if cached_data.has_key(doc.study_course):
727            return cached_data[doc.study_course]['end_level']
728        certificate_res = self.portal_catalog(id = doc.study_course)
729        if len(certificate_res) != 1:
730            return None
731        return getattr(certificate_res[0].getObject().getContent(),'end_level','unknown')
732
733    def get_from_doc_level(self,doc,cached_data={}):
734        "return the students level"
735        if doc is None:
736            return None
737        return getattr(doc,'current_level',None)
738
739    def get_from_doc_mode(self,doc,cached_data={}):
740        "return the students mode"
741        if doc is None:
742            return None
743        cm = getattr(doc,'current_mode',None)
744        return cm
745
746
747    def get_from_doc_session(self,doc,cached_data={}):
748        "return the students current_session"
749        if doc is None:
750            return None
751        return getattr(doc,'current_session',None)
752
753    def get_from_doc_entry_session(self,doc,cached_data={}):
754        "return the students entry_session"
755        if doc is None:
756            return None
757        es = getattr(doc,'entry_session',None)
758        if es is not None and len(es) == 2:
759            return es
760        try:
761            digit = int(doc.jamb_reg_no[0])
762        except:
763            return "-1"
764        if digit < 8:
765            return "0%c" % doc.jamb_reg_no[0]
766        return "9%c" % doc.jamb_reg_no[0]
767
768    def get_from_doc_course(self,doc,cached_data={}):
769        "return the students study_course"
770        if doc is None:
771            return None
772        return getattr(doc,'study_course',None)
773
774    def get_from_doc_name(self,doc,cached_data={}):
775        "return the students name from the personal"
776        if doc is None:
777            return None
778        return "%s %s %s" % (doc.firstname,doc.middlename,doc.lastname)
779
780    def get_from_doc_verdict(self,doc,cached_data={}):
781        "return the students study_course"
782        if doc is None:
783            return None
784        return getattr(doc,'current_verdict',None)
785    ###)
786
787    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
788        if isinstance(name, str):
789            name = (name,)
790        reindextypes = {}
791        reindex_special = []
792        for n in name:
793            if n in ("review_state","registered_courses"):
794                reindex_special.append(n)
795            else:
796                for pt in self.affected_types.keys():
797                    if n in self.affected_types[pt]['fields']:
798                        if reindextypes.has_key(pt):
799                            reindextypes[pt].append(n)
800                        else:
801                            reindextypes[pt]= [n]
802                        break
803        cached_data = {}
804        if set(name).intersection(set(('faculty','department','end_level'))):
805            cached_data = self.fill_certificates_dict()
806        students = self.portal_catalog(portal_type="Student")
807        if hasattr(self,'portal_catalog_real'):
808            aq_portal = self.portal_catalog_real.evalAdvancedQuery
809        else:
810            aq_portal = self.portal_catalog.evalAdvancedQuery
811        num_objects = len(students)
812        if pghandler:
813            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
814        noattr = set(('StudentClearance','StudentPersonal')) & set(reindextypes.keys())
815        #import pdb;pdb.set_trace()
816        for i in xrange(num_objects):
817            if pghandler: pghandler.report(i)
818            student_brain = students[i]
819            student_object = student_brain.getObject()
820            # query = Eq('path',student_brain.getPath())
821            # sub_brains_list = aq_portal(query)
822            # sub_brains = {}
823            # for sub_brain in sub_brains_list:
824            #     sub_brains[sub_brain.portal_type] = sub_brain
825            # student_path = student_brain.getPath()
826            data = {}
827            modified = False
828            sid = data['id'] = student_brain.getId
829            if reindex_special and 'review_state' in reindex_special:
830                modified = True
831                data['review_state'] = student_brain.review_state
832            sub_objects = False
833            for pt in reindextypes.keys():
834                modified = True
835                try:
836                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
837                    #doc = sub_brains[pt].getObject().getContent()
838                    # path = "%s/%s" % (student_path,self.affected_types[pt]['id'])
839                    # doc = self.unrestrictedTraverse(path).getContent()
840                    sub_objects = True
841                except:
842                    continue
843                for field in set(name).intersection(self.affected_types[pt]['fields']):
844                    if hasattr(self,'get_from_doc_%s' % field):
845                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
846                                                                              cached_data=cached_data)
847                    else:
848                        data[field] = getattr(doc,field)
849            if not sub_objects and noattr:
850                import_res = self.returning_import(id = sid)
851                if not import_res:
852                    continue
853                import_record = import_res[0]
854                data['matric_no'] = import_record.matric_no
855                data['sex'] = import_record.Sex == 'F'
856                data['name'] = "%s %s %s" % (import_record.Firstname,
857                                             import_record.Middlename,
858                                             import_record.Lastname)
859                data['jamb_reg_no'] = import_record.Entryregno
860            if reindex_special and 'registered_courses' in reindex_special:
861                try:
862                    study_course = getattr(student_object,"study_course")
863                    level_ids = study_course.objectIds()
864                except:
865                    continue
866                if not level_ids:
867                    continue
868                modified = True
869                level_ids.sort()
870                course_ids = getattr(study_course,level_ids[-1]).objectIds()
871                courses = []
872                for c in course_ids:
873                    if c.endswith('_co'):
874                        courses.append(c[:-3])
875                    else:
876                        courses.append(c)
877                data['registered_courses'] = courses
878            if modified:
879                self.modifyRecord(**data)
880        if pghandler: pghandler.finish()
881    ###)
882
883    def refreshCatalog(self, clear=0, pghandler=None): ###(
884        """ re-index everything we can find """
885        students_folder = self.portal_url.getPortalObject().campus.students
886        if clear:
887            self._catalog.clear()
888        students = self.portal_catalog(portal_type="Student")
889        num_objects = len(students)
890        cached_data = self.fill_certificates_dict()
891        if pghandler:
892            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
893        for i in xrange(num_objects):
894            if pghandler: pghandler.report(i)
895            student_brain = students[i]
896            spath = student_brain.getPath()
897            student_object = student_brain.getObject()
898            data = {}
899            sid = data['id'] = student_brain.getId
900            data['review_state'] = student_brain.review_state
901            sub_objects = False
902            for pt in self.affected_types.keys():
903                modified = True
904                try:
905                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
906                    sub_objects = True
907                except:
908                    #from pdb import set_trace;set_trace()
909                    continue
910                for field in self.affected_types[pt]['fields']:
911                    if hasattr(self,'get_from_doc_%s' % field):
912                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
913                                                                              cached_data=cached_data)
914                    else:
915                        data[field] = getattr(doc,field,None)
916            if not sub_objects:
917                import_res = self.returning_import(id = sid)
918                if not import_res:
919                    continue
920                import_record = import_res[0]
921                data['matric_no'] = import_record.matric_no
922                data['sex'] = import_record.Sex == 'F'
923                data['name'] = "%s %s %s" % (import_record.Firstname,
924                                             import_record.Middlename,
925                                             import_record.Lastname)
926                data['jamb_reg_no'] = import_record.Entryregno
927            else:
928                study_course = getattr(student_object,'study_course',None)
929                current_level = data.get('level',None)
930                data['registered_courses'] = []
931                if study_course and current_level and current_level in study_course.objectIds():
932                    level_obj = getattr(study_course,current_level)
933                    courses = []
934                    for c in level_obj.objectIds():
935                        if c.endswith('_co'):
936                            courses.append(c[:-3])
937                        else:
938                            courses.append(c)
939                    data['registered_courses'] = courses
940            self.addRecord(**data)
941        if pghandler: pghandler.finish()
942    ###)
943
944    security.declarePrivate('notify_event_listener') ###(
945    def notify_event_listener(self,event_type,object,infos):
946        "listen for events"
947        if not infos.has_key('rpath'):
948            return
949        pt = getattr(object,'portal_type',None)
950        mt = getattr(object,'meta_type',None)
951        students_catalog = self
952        data = {}
953        if pt == 'Student' and\
954           mt == 'CPS Proxy Folder' and\
955           event_type.startswith('workflow'):
956            data['id'] = object.getId()
957            data['review_state'] = self.portal_workflow.getInfoFor(object,'review_state',None)
958            students_catalog.modifyRecord(**data)
959            return
960        rpl = infos['rpath'].split('/')
961        if pt == 'Student' and mt == 'CPS Proxy Folder'\
962           and event_type == "sys_add_object":
963            student_id = object.id
964            try:
965                self.addRecord(id = student_id)
966            except ValueError:
967                pass
968            return
969        elif pt == 'StudentCourseResult' and mt == 'CPS Proxy Folder':
970            if event_type not in ("sys_add_object","sys_del_object"):
971                return
972            level_session = getattr(object.aq_parent.getContent(),'session','unknown')
973            if level_session not in (self.getSessionId()[-2:],'2006/2007'):
974                return
975            course_id = object.getId()
976            if course_id.endswith('_co'):
977                course_id = course_id[:-3]
978            student_id = object.absolute_url_path().split('/')[-4]
979            res = students_catalog(id = student_id)
980            if not res:
981                return
982            student_rec = res[0]
983            registered_courses = getattr(student_rec,'registered_courses',None)
984            if not registered_courses:
985                registered_courses = []
986            #import pdb;pdb.set_trace()
987            if event_type == "sys_add_object":
988                if course_id not in registered_courses:
989                    registered_courses.append(course_id)
990                else:
991                    return
992            elif registered_courses and event_type == "sys_del_object":
993                removed = False
994                while course_id in registered_courses:
995                    removed = True
996                    registered_courses.remove(course_id)
997                if not removed:
998                    return
999            data['id'] = student_id
1000            data['registered_courses'] = registered_courses
1001            self.modifyRecord(record = student_rec, **data)
1002            return
1003        if pt not in self.affected_types.keys():
1004            return
1005        if event_type not in ('sys_modify_object'):
1006            return
1007        if mt == 'CPS Proxy Folder':
1008            return
1009        for field in self.affected_types[pt]['fields']:
1010            if hasattr(self,'get_from_doc_%s' % field):
1011                data[field] = getattr(self,'get_from_doc_%s' % field)(object)
1012            else:
1013                data[field] = getattr(object,field)
1014        data['id'] = rpl[2]
1015        self.modifyRecord(**data)
1016    ###)
1017
1018
1019InitializeClass(StudentsCatalog)
1020
1021###)
1022
1023class CoursesCatalog(WAeUPTable): ###(
1024    security = ClassSecurityInfo()
1025
1026    meta_type = 'WAeUP Courses Catalog'
1027    name =  "courses_catalog"
1028    key = "code"
1029    def __init__(self,name=None):
1030        if name ==  None:
1031            name =  self.name
1032        WAeUPTable.__init__(self, name)
1033
1034    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
1035        """ clear the catalog, then re-index everything """
1036
1037        elapse = time.time()
1038        c_elapse = time.clock()
1039
1040        pgthreshold = self._getProgressThreshold()
1041        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
1042        self.refreshCatalog(clear=1, pghandler=handler)
1043
1044        elapse = time.time() - elapse
1045        c_elapse = time.clock() - c_elapse
1046
1047        RESPONSE.redirect(
1048            URL1 +
1049            '/manage_catalogAdvanced?manage_tabs_message=' +
1050            urllib.quote('Catalog Updated \n'
1051                         'Total time: %s\n'
1052                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
1053    ###)
1054
1055    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
1056        if isinstance(name, str):
1057            name = (name,)
1058        courses = self.portal_catalog(portal_type="Course")
1059        num_objects = len(courses)
1060        if pghandler:
1061            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1062        for i in xrange(num_objects):
1063            if pghandler: pghandler.report(i)
1064            course_brain = courses[i]
1065            course_object = course_brain.getObject()
1066            pl = course_brain.getPath().split('/')
1067            data = {}
1068            cid = data[self.key] = course_brain.getId
1069            data['faculty'] = pl[-4]
1070            data['department'] = pl[-3]
1071            doc = course_object.getContent()
1072            for field in name:
1073                if field not in (self.key,'faculty','department'):
1074                    data[field] = getattr(doc,field)
1075            self.modifyRecord(**data)
1076        if pghandler: pghandler.finish()
1077    ###)
1078
1079    def refreshCatalog(self, clear=0, pghandler=None): ###(
1080        """ re-index everything we can find """
1081        if clear:
1082            self._catalog.clear()
1083        courses = self.portal_catalog(portal_type="Course")
1084        num_objects = len(courses)
1085        if pghandler:
1086            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1087        #from pdb import set_trace;set_trace()
1088        for i in xrange(num_objects):
1089            if pghandler: pghandler.report(i)
1090            course_brain = courses[i]
1091            course_doc = course_brain.getObject().getContent()
1092            pl = course_brain.getPath().split('/')
1093            data = {}
1094            for field in self.schema():
1095                data[field] = getattr(course_doc,field,None)
1096            data[self.key] = course_brain.getId
1097            ai = pl.index('academics')
1098            data['faculty'] = pl[ai +1]
1099            data['department'] = pl[ai +2]
1100            if clear:
1101                self.addRecord(**data)
1102            else:
1103                self.modifyRecord(**data)
1104        if pghandler: pghandler.finish()
1105    ###)
1106
1107    security.declarePrivate('notify_event_listener') ###(
1108    def notify_event_listener(self,event_type,object,infos):
1109        "listen for events"
1110        if not infos.has_key('rpath'):
1111            return
1112        pt = getattr(object,'portal_type',None)
1113        mt = getattr(object,'meta_type',None)
1114        if pt != 'Course':
1115            return
1116        data = {}
1117        rpl = infos['rpath'].split('/')
1118        if event_type not in ("sys_add_object","sys_modify_object","sys_del_object"):
1119            return
1120        course_id = object.getId()
1121        data[self.key] = course_id
1122        if event_type == "sys_add_object" and mt == 'CPS Proxy Folder':
1123            try:
1124                self.addRecord(**data)
1125            except ValueError:
1126                return
1127            course_id = object.getId()
1128            doc = object.getContent()
1129            if doc is None:
1130                return
1131            for field in self.schema():
1132                data[field] = getattr(doc,field,None)
1133            data[self.key] = course_id
1134            ai = rpl.index('academics')
1135            data['faculty'] = rpl[ai +1]
1136            data['department'] = rpl[ai +2]
1137            self.modifyRecord(**data)
1138            return
1139        if event_type == "sys_del_object":
1140            self.deleteRecord(course_id)
1141            return
1142        if event_type == "sys_modify_object" and mt == 'Course':
1143            #from pdb import set_trace;set_trace()
1144            for field in self.schema():
1145                data[field] = getattr(object,field,None)
1146            course_id = object.aq_parent.getId()
1147            data[self.key] = course_id
1148            ai = rpl.index('academics')
1149            data['faculty'] = rpl[ai +1]
1150            data['department'] = rpl[ai +2]
1151            self.modifyRecord(**data)
1152    ###)
1153
1154
1155InitializeClass(CoursesCatalog)
1156###)
1157
1158class CourseResults(WAeUPTable): ###(
1159    security = ClassSecurityInfo()
1160
1161    meta_type = 'WAeUP Results Catalog'
1162    name = "course_results"
1163    key = "key" #student_id + level + course_id
1164    def __init__(self,name=None):
1165        if name ==  None:
1166            name = self.name
1167        WAeUPTable.__init__(self, name)
1168        self._queue = []
1169
1170    def addRecord(self, **data): ###(
1171        """add one record"""
1172
1173        uid = key = "%(student_id)s|%(level_id)s|%(course_id)s" % data
1174        if key in self._queue:
1175            return uid
1176        data['queue_status'] = ADDING_SHEDULED
1177        data['%s' % self.key] = uid
1178        res = self.searchResults({"%s" % self.key : uid})
1179        if len(res) > 0:
1180            raise ValueError("More than one record with uid %s" % uid)
1181        self.catalog_object(dict2ob(data), uid=uid)
1182        if not hasattr(self,'_queue'):
1183            self._queue = []
1184        self._queue.append(key)
1185        self._p_changed = 1
1186        return uid
1187    ###)
1188
1189    # def _p_resolveConflict(self, oldstate, committed, newstate):
1190    #     # Apply the changes made in going from old to newstate to
1191    #     # committed
1192
1193    #     # Note that in the case of undo, the olddata is the data for
1194    #     # the transaction being undone and newdata is the data for the
1195    #     # transaction previous to the undone transaction.
1196
1197    #     # Find the conflict policy on the new state to make sure changes
1198    #     # to it will be applied
1199
1200    #     # Committed is always the currently committed data.
1201    #     import pdb;pdb.set_trace()
1202    #     oldstate_data  =  oldstate['_queue']
1203    #     committed_data = committed['_queue']
1204    #     newstate_data  =  newstate['_queue']
1205
1206    #     # Merge newstate changes into committed
1207    #     for uid, new in newstate_data.items():
1208
1209    #         # Decide if this is a change
1210    #         old = oldstate_data.get(uid)
1211    #         current = committed_data.get(uid)
1212
1213
1214    def addMultipleRecords(self, records): ###(
1215        """add many records"""
1216        added_keys = []
1217        for data in records:
1218            uid = key = "%(student_id)s|%(level_id)s|%(course_id)s" % data
1219            added_keys.append(key)
1220            if key in self._queue:
1221                return uid
1222            data['queue_status'] = ADDING_SHEDULED
1223            data['%s' % self.key] = uid
1224            res = self.searchResults({"%s" % self.key : uid})
1225            if len(res) > 0:
1226                raise ValueError("More than one record with uid %s" % uid)
1227            self.catalog_object(dict2ob(data), uid=uid)
1228        if not hasattr(self,'_queue'):
1229            self._queue = added_keys
1230        self._queue.extend(added_keys)
1231        self._p_changed = 1
1232        return uid
1233    ###)
1234
1235    def deleteRecord(self, uid): ###(
1236        self.uncatalog_object(uid)
1237        if uid in self._queue:
1238            self._queue.remove(uid)
1239    ###)
1240
1241    def updateCourseResults(self,student_id,level_id,portal_catalog_results,course_results): ###(
1242        # query = Eq('path',"%s/campus/students/%s/study_course/%s" %
1243        #            (self.portal_url.getPortalPath(),
1244        #             student_id,
1245        #             level_id)) &\
1246        #             Eq('portal_type', "StudentCourseResult")
1247        # level_results = self.portal_catalog_real.evalAdvancedQuery(query)
1248        # level_results = [r for r in course_results
1249        #                  if level_id in r.relative_path.split('/')]
1250        course_results_ids = [cr.getId for cr in course_results]
1251        for r in portal_catalog_results:
1252            if r.getId in course_results_ids:
1253                continue
1254            course_result_doc = r.getObject().getContent()
1255            data = {}
1256            course_id = r.getId
1257            for field in self.schema():
1258                data[field] = getattr(course_result_doc,field,'')
1259            data['key'] = key = "%(student_id)s|%(level_id)s|%(course_id)s" % vars()
1260            data['student_id'] = student_id
1261            data['level_id'] = level_id
1262            data['queue_status'] = OBJECT_CREATED
1263            data['code'] = course_id
1264            self.catalog_object(dict2ob(data), uid=key)
1265        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1266        return self.course_results.evalAdvancedQuery(query)
1267    ###)
1268
1269    def getCourses(self,student_id,level_id): ###(
1270        level_path = "%s/campus/students/%s/study_course/%s" % (self.portal_url.getPortalPath(),
1271                                                                student_id,
1272                                                                level_id)
1273        # portal_catalog_query = Eq('path',level_path) &\
1274        #                        Eq('portal_type', "StudentCourseResult")
1275        # portal_catalog_results = self.portal_catalog_real.evalAdvancedQuery(portal_catalog_query)
1276        portal_catalog_results = self.portal_catalog(path = level_path,
1277                                                     portal_type = "StudentCourseResult")
1278        query = Eq('student_id',student_id) & Eq('level_id', level_id)
1279        course_results = self.course_results.evalAdvancedQuery(query)
1280        if len(course_results) != len(portal_catalog_results):
1281            course_results = self.updateCourseResults(student_id,
1282                                                      level_id,
1283                                                      portal_catalog_results,
1284                                                      course_results)
1285        carry_overs = []
1286        normal = []
1287        credits = 0
1288        for brain in course_results:
1289            d = {}
1290            credits += int(brain.credits)
1291            for field in self.schema():
1292                d[field] = getattr(brain,field,'')
1293            d['sheduled'] = brain.queue_status == ADDING_SHEDULED
1294            d['coe'] = 'Elective'
1295            if brain.core_or_elective:
1296                d['coe'] = 'Core'
1297            id = code = d['id'] = brain.code
1298            is_carry_over = False
1299            if code.endswith('_co'):
1300                is_carry_over = True
1301                code = code[:-3]
1302            d['code'] = code
1303            d['title'] = self.courses_catalog.evalAdvancedQuery(Eq('code',code))[0].title
1304            if is_carry_over:
1305                d['coe'] = 'Core'
1306                carry_overs.append(d)
1307            else:
1308                normal.append(d)
1309        normal.sort(cmp=lambda x,y: cmp(x['semester'], y['semester']))
1310        carry_overs.sort(cmp=lambda x,y: cmp(x['semester'], y['semester']))
1311        return credits,carry_overs,normal
1312    ###)
1313
1314    def addObject(self,record): ###(
1315        key = record.key
1316        student_id,level_id,course_id = key.split('|')
1317        level = getattr(getattr(self.portal_url.getPortalObject().campus.students,student_id).study_course,level_id)
1318        cr_id = level.invokeFactory('StudentCourseResult', course_id)
1319        course_result = getattr(level,cr_id)
1320        self.portal_workflow.doActionFor(course_result,'open')
1321        d = {}
1322        for field in self.schema():
1323            d[field] = getattr(record,field,'')
1324        course_result.getContent().edit(mapping=d)
1325    ###)
1326
1327    security.declareProtected(ModifyPortalContent,"process_queue") ###(
1328    def process_queue(self,limit=None):
1329        """adds objects and removes them from the queue.
1330        If limit is specified, at most (limit) events are removed.
1331        """
1332        if not hasattr(self,'_queue'):
1333            return 0
1334        queue= self._queue
1335        if not limit or len(queue) <= limit:
1336            keys = self._queue[:]
1337        else:
1338            keys = queue[:limit]
1339        if not keys:
1340            records = self.evalAdvancedQuery(Eq('queue_status',ADDING_SHEDULED))
1341        else:
1342            records = self.evalAdvancedQuery(In("%s" % self.key,keys))
1343        for record in records:
1344            if record.queue_status == OBJECT_CREATED:
1345                continue
1346            self.addObject(record)
1347            data = {}
1348            data['key'] = record.key
1349            data['queue_status'] = OBJECT_CREATED
1350            self.modifyRecord(**data)
1351        count = 0
1352        for key in keys:
1353            count +=1
1354            if key in self._queue:
1355                self._queue.remove(key)
1356        self._p_changed = 1
1357        return count,len(self._queue)
1358    ###)
1359
1360    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None): ###(
1361        """ clears the whole enchilada """
1362        self._catalog.clear()
1363
1364        if REQUEST and RESPONSE:
1365            RESPONSE.redirect(
1366              URL1 +
1367              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
1368    ###)
1369
1370    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
1371        """ clear the catalog, then re-index everything """
1372
1373        elapse = time.time()
1374        c_elapse = time.clock()
1375
1376        pgthreshold = self._getProgressThreshold()
1377        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
1378        self.refreshCatalog(clear=1, pghandler=handler)
1379
1380        elapse = time.time() - elapse
1381        c_elapse = time.clock() - c_elapse
1382
1383        RESPONSE.redirect(
1384            URL1 +
1385            '/manage_catalogAdvanced?manage_tabs_message=' +
1386            urllib.quote('Catalog Updated \n'
1387                         'Total time: %s\n'
1388                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
1389    ###)
1390
1391    def refreshCatalog(self, clear=1, pghandler=None): ###(
1392        """ re-index everything we can find """
1393        students_folder = self.portal_url.getPortalObject().campus.students
1394        if clear:
1395            self._catalog.clear()
1396        course_results = self.portal_catalog(portal_type="StudentCourseResult")
1397        num_objects = len(course_results)
1398        if pghandler:
1399            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
1400        #import pdb;pdb.set_trace()
1401        for i in xrange(num_objects):
1402            if pghandler:
1403                pghandler.report(i)
1404            course_result_brain = course_results[i]
1405            path_list = course_result_brain.getPath().split('/')
1406            course_result_doc = course_result_brain.getObject().getContent()
1407            data = {}
1408            level_id = path_list[-2]
1409            course_id = path_list[-1]
1410            student_id = path_list[-4]
1411            for field in self.schema():
1412                data[field] = getattr(course_result_doc,field,'')
1413            data['key'] = key = "%(student_id)s|%(level_id)s|%(course_id)s" % vars()
1414            data['student_id'] = student_id
1415            data['level_id'] = level_id
1416            data['queue_status'] = OBJECT_CREATED
1417            self.catalog_object(dict2ob(data), uid=key)
1418        if pghandler: pghandler.finish()
1419    ###)
1420
1421    security.declarePrivate('notify_event_listener') ###(
1422    def notify_event_listener(self,event_type,object,infos):
1423        "listen for events"
1424        if not infos.has_key('rpath'):
1425            return
1426        pt = getattr(object,'portal_type',None)
1427        mt = getattr(object,'meta_type',None)
1428        data = {}
1429        rpl = infos['rpath'].split('/')
1430        if mt == 'CPS Proxy Folder':
1431            return
1432        if pt == 'StudentCourseResult' and event_type == "sys_modify_object":
1433            data["%s" % self.key] = uid = "%s|%s|%s" % (rpl[-5],rpl[-3],rpl[-2])
1434            records = self.searchResults({"%s" % self.key : uid})
1435            if len(records) > 1:
1436                # Can not happen, but anyway...
1437                raise ValueError("More than one record with uid %s" % uid)
1438            if len(records) == 0:
1439                raise KeyError("No record for uid %s" % uid)
1440            record = records[0]
1441            for field in ('core_or_elective','score'):
1442                value = getattr(object,field,None)
1443                data[field] = value
1444            try:
1445                self.modifyRecord(record,**data)
1446            except KeyError:
1447                pass
1448        if pt == 'StudentStudyLevel' and event_type == "sys_del_object":
1449            #import pdb;pdb.set_trace()
1450            student_id = rpl[-3]
1451            level_id = rpl[-1]
1452            res = self.searchResults(student_id = student_id,
1453                                     level_id = level_id)
1454            for cr in res:
1455                self.deleteRecord(cr.key)
1456    ###)
1457
1458InitializeClass(CourseResults)
1459###)
1460
1461class OnlinePaymentsImport(WAeUPTable): ###(
1462
1463    meta_type = 'WAeUP Online Payment Transactions'
1464    name = "online_payments_import"
1465    key = "order_id"
1466    def __init__(self,name=None):
1467        if name ==  None:
1468            name = self.name
1469        WAeUPTable.__init__(self, name)
1470
1471
1472InitializeClass(OnlinePaymentsImport)
1473###)
1474
1475class ReturningImport(WAeUPTable): ###(
1476
1477    meta_type = 'Returning Import Table'
1478    name = "returning_import"
1479    key = "matric_no"
1480    def __init__(self,name=None):
1481        if name ==  None:
1482            name = self.name
1483        WAeUPTable.__init__(self, name)
1484
1485
1486InitializeClass(ReturningImport)
1487###)
1488
1489class ResultsImport(WAeUPTable): ###(
1490
1491    meta_type = 'Results Import Table'
1492    name = "results_import"
1493    key = "key"
1494    def __init__(self,name=None):
1495        if name ==  None:
1496            name = self.name
1497        WAeUPTable.__init__(self, name)
1498
1499
1500InitializeClass(ResultsImport)
1501
1502###)
1503
1504class PaymentsCatalog(WAeUPTable): ###(
1505
1506    meta_type = 'WAeUP Payments Catalog'
1507    name = "students_catalog"
1508    key = "id"
1509    def __init__(self,name=None):
1510        if name ==  None:
1511            name = self.name
1512        WAeUPTable.__init__(self, name)
1513
1514
1515InitializeClass(PaymentsCatalog)
1516
1517###)
1518
1519# BBB:
1520AccomodationTable = AccommodationTable
Note: See TracBrowser for help on using the repository browser.