source: WAeUP_SRP/base/WAeUPTables.py @ 2628

Last change on this file since 2628 was 2627, checked in by Henrik Bettermann, 17 years ago

dump aos text not the key

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