source: WAeUP_SRP/trunk/WAeUPTables.py @ 2186

Last change on this file since 2186 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
RevLine 
[966]1#-*- mode: python; mode: fold -*-
[363]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
[1620]24from Products.ZCatalog.ProgressHandler import ZLogHandler
[780]25from AccessControl import ClassSecurityInfo
26from Products.CMFCore.permissions import ModifyPortalContent
[2094]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
[1700]33import urllib
[1620]34import DateTime,time
[780]35import csv,re
36import logging
37import Globals
38p_home = Globals.package_home(globals())
39i_home = Globals.INSTANCE_HOME
40
[2084]41ADDING_SHEDULED = "adding_sheduled"
42OBJECT_CREATED = "object_created"
43
[363]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
[1146]55class WAeUPTable(ZCatalog): ###(
[834]56
[363]57    implements(IWAeUPTable)
[780]58    security = ClassSecurityInfo()
[2094]59    meta_type = None
[2099]60
[2094]61    def __init__(self,name=None):
62        if name ==  None:
63            name = self.name
64        ZCatalog.__init__(self,name)
[2099]65
[2094]66    def refreshCatalog(self, clear=0, pghandler=None): ###(
[1620]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
[2094]74###)
75
76    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None): ###(
[1620]77        """ clears the whole enchilada """
[1986]78
[1916]79        #if REQUEST and RESPONSE:
80        #    RESPONSE.redirect(
81        #      URL1 +
82        #      '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Clearing%20disabled')
[1620]83
[1916]84        self._catalog.clear()
[1620]85        if REQUEST and RESPONSE:
86            RESPONSE.redirect(
87              URL1 +
[1916]88              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20cleared')
[1620]89
[2094]90###)
91
92    def addRecord(self, **data): ###(
[502]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
[834]100
[2094]101###)
102
[363]103    def deleteRecord(self, uid):
104        self.uncatalog_object(uid)
[834]105
[502]106    def searchAndSetRecord(self, **data):
107        raise NotImplemented
108
[2094]109    def modifyRecord(self, record=None, **data): ###(
[502]110        #records = self.searchResults(uid=uid)
111        uid = data[self.key]
[2069]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]
[363]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
[2094]127###)
128
129    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
[1062]130        if isinstance(name, str):
[2094]131            name =  (name,)
[1062]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)
[1082]144
[2094]145###)
146
147    security.declareProtected(ModifyPortalContent,"exportAllRecords") ###(
[780]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))
[2094]166
167###)
168
[2185]169    security.declarePrivate("_import_old") ###(
170    def _import_old(self,filename,schema,layout, mode,logger):
[2094]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
[2112]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
[2094]199        if schema is None:
200            em = 'No schema specified'
201            logger.error(em)
[2112]202            return d
[2094]203        if layout is None:
204            em = 'No layout specified'
205            logger.error(em)
[2112]206            return d
[2094]207        validators = {}
208        for widget in layout.keys():
[2112]209            try:
210                validators[widget] = layout[widget].validate
211            except AttributeError:
212                logger.info('%s has no validate attribute' % widget)
213                return d
[2094]214        # if mode == 'edit':
215        #     importer = self.importEdit
216        # elif mode == 'add':
217        #     importer = self.importAdd
218        # else:
219        #     importer = None
220        try:
[2185]221            items = csv.DictReader(open(import_fn,"rb"),
222                                   dialect="excel",
223                                   skipinitialspace=True)
[2094]224        except:
225            em = 'Error reading %s.csv' % filename
226            logger.error(em)
227            return d
[2185]228        #import pdb;pdb.set_trace()
[2094]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')]
[2185]234                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb"),
235                                   dialect="excel",
236                                   skipinitialspace=True).next()
[2094]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
[1935]289    ###)
[2185]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
[2094]370###)
[834]371
[1146]372class AccommodationTable(WAeUPTable): ###(
[834]373
[404]374    meta_type = 'WAeUP Accommodation Tool'
[2094]375    name = "portal_accommodation"
[502]376    key = "bed"
[2094]377    def __init__(self,name=None):
378        if name ==  None:
379            name = self.name
380        WAeUPTable.__init__(self, name)
[363]381
[635]382    def searchAndReserveBed(self, student_id,bed_type):
383        records = self.searchResults({'student' : student_id})
384        if len(records) > 0:
[1293]385            return -1,"Student with Id %s already booked bed %s." % (student_id,records[0].bed)
[834]386
[673]387        records = [r for r in self.searchResults({'bed_type' : bed_type}) if not r.student]
[686]388        #import pdb;pdb.set_trace()
[635]389        if len(records) == 0:
[1306]390            return -2,"No bed available"
[635]391        rec = records[0]
392        self.modifyRecord(bed=rec.bed,student=student_id)
[1571]393        s_logger = logging.getLogger('WAeUPTables.AccommodationTable.searchAndReserveBed')
394        s_logger.info('%s reserved bed %s' % (student_id,rec.bed))
[635]395        return 1,rec.bed
[363]396
[834]397
[404]398InitializeClass(AccommodationTable)
[411]399
[1146]400###)
401
402class PinTable(WAeUPTable): ###(
[1030]403    from ZODB.POSException import ConflictError
[440]404    meta_type = 'WAeUP Pin Tool'
[2094]405    name = "portal_pins"
[502]406    key = 'pin'
[2094]407    def __init__(self,name=None):
408        if name ==  None:
409            name = self.name
410        WAeUPTable.__init__(self, name)
[1082]411
412
[710]413    def searchAndSetRecord(self, uid, student_id,prefix):
[2184]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
[710]421        records = self.searchResults(student = student_id)
[1776]422        if len(records) > 0 and prefix in ('CLR','APP'):
[710]423            for r in records:
[834]424                if r.pin != uid and r.prefix_batch.startswith(prefix):
[710]425                    return -2
[502]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:
[635]438            record_data['student'] = student_id
[1030]439            try:
440                self.catalog_object(dict2ob(record_data), uid)
441                return 1
442            except ConflictError:
443                return 2
[990]444        if record.student.upper() != student_id.upper():
[502]445            return 0
[997]446        if record.student.upper() == student_id.upper():
[502]447            return 2
[997]448        return -3
[440]449
450InitializeClass(PinTable)
451
[1146]452###)
[966]453
[1146]454class PumeResultsTable(WAeUPTable): ###(
455
[966]456    meta_type = 'WAeUP PumeResults Tool'
[2094]457    name = "portal_pumeresults"
[966]458    key = "jamb_reg_no"
[2094]459    def __init__(self,name=None):
460        if name ==  None:
461            name = self.name
462        WAeUPTable.__init__(self, name)
[966]463
464
465InitializeClass(PumeResultsTable)
466
[1146]467###)
[971]468
[2094]469class ApplicantsCatalog(WAeUPTable): ###(
470
[2113]471    meta_type = 'WAeUP Applicants Catalog'
[2094]472    name = "applicants_catalog"
473    key = "reg_no"
474    security = ClassSecurityInfo()
[2099]475
[2094]476    def __init__(self,name=None):
477        if name ==  None:
478            name = self.name
479        WAeUPTable.__init__(self, name)
480
[2185]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
[2094]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
[2099]580        logger = logging.getLogger('WAeUPTables.ApplicantsCatalog.importCSV')
[2185]581        d = self._import_old(filename,schema,layout,mode,logger)
[2094]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
[1146]600class StudentsCatalog(WAeUPTable): ###(
[1620]601    security = ClassSecurityInfo()
[1146]602
[971]603    meta_type = 'WAeUP Students Catalog'
604    name = "students_catalog"
605    key = "id"
[1700]606    affected_types = {   ###(
[1749]607                      'StudentApplication':
[2069]608                      {'id': 'application',
609                       'fields':
610                       ('jamb_reg_no',
611                        'entry_mode',
612                        #'entry_level',
613                        'entry_session',
614                       )
615                      },
[1700]616                      'StudentClearance':
[2069]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                     }
[1700]647    ###)
[1625]648
[2094]649    def __init__(self,name=None):
650        if name ==  None:
651            name = self.name
652        WAeUPTable.__init__(self, name)
[1620]653        return
[1625]654
[1700]655    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
656        """ clears the whole enchilada """
657        self._catalog.clear()
[971]658
[1700]659        if REQUEST and RESPONSE:
660            RESPONSE.redirect(
661              URL1 +
662              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
[971]663
[1700]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
[2084]685    def fill_certificates_dict(self): ###(
[2078]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
[2084]698    ###)
699
[2078]700    def get_from_doc_department(self,doc,cached_data={}): ###(
[1620]701        "return the students department"
[1700]702        if doc is None:
[1620]703            return None
[2078]704        if cached_data.has_key(doc.study_course):
705            return cached_data[doc.study_course]['department']
[1700]706        certificate_res = self.portal_catalog(id = doc.study_course)
[1620]707        if len(certificate_res) != 1:
708            return None
709        return certificate_res[0].getPath().split('/')[-3]
710
[2078]711    def get_from_doc_faculty(self,doc,cached_data={}):
[1700]712        "return the students faculty"
713        if doc is None:
[1620]714            return None
[2078]715        if cached_data.has_key(doc.study_course):
716            return cached_data[doc.study_course]['faculty']
[1700]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]
[1620]721
[2099]722    def get_from_doc_end_level(self,doc,cached_data={}):
[2069]723        "return the students end_level"
724        if doc is None:
725            return None
[2078]726        if cached_data.has_key(doc.study_course):
727            return cached_data[doc.study_course]['end_level']
[2069]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
[2078]733    def get_from_doc_level(self,doc,cached_data={}):
[1700]734        "return the students level"
735        if doc is None:
[1620]736            return None
[1700]737        return getattr(doc,'current_level',None)
[1620]738
[2078]739    def get_from_doc_mode(self,doc,cached_data={}):
[1705]740        "return the students mode"
[1700]741        if doc is None:
[1620]742            return None
[1705]743        cm = getattr(doc,'current_mode',None)
744        return cm
[1625]745
[1749]746
[2078]747    def get_from_doc_session(self,doc,cached_data={}):
[1705]748        "return the students current_session"
749        if doc is None:
750            return None
751        return getattr(doc,'current_session',None)
752
[2078]753    def get_from_doc_entry_session(self,doc,cached_data={}):
[1700]754        "return the students entry_session"
755        if doc is None:
[1620]756            return None
[1705]757        es = getattr(doc,'entry_session',None)
[1729]758        if es is not None and len(es) == 2:
[1705]759            return es
[1700]760        try:
761            digit = int(doc.jamb_reg_no[0])
762        except:
[1986]763            return "-1"
[1700]764        if digit < 8:
765            return "0%c" % doc.jamb_reg_no[0]
766        return "9%c" % doc.jamb_reg_no[0]
767
[2078]768    def get_from_doc_course(self,doc,cached_data={}):
[1620]769        "return the students study_course"
[1700]770        if doc is None:
[1620]771            return None
[1700]772        return getattr(doc,'study_course',None)
[1620]773
[2078]774    def get_from_doc_name(self,doc,cached_data={}):
[1620]775        "return the students name from the personal"
[1700]776        if doc is None:
[1620]777            return None
778        return "%s %s %s" % (doc.firstname,doc.middlename,doc.lastname)
779
[2078]780    def get_from_doc_verdict(self,doc,cached_data={}):
[1700]781        "return the students study_course"
782        if doc is None:
[1620]783            return None
[1700]784        return getattr(doc,'current_verdict',None)
[1702]785    ###)
[1620]786
[1702]787    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
788        if isinstance(name, str):
789            name = (name,)
[1749]790        reindextypes = {}
[1702]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():
[1707]797                    if n in self.affected_types[pt]['fields']:
[1702]798                        if reindextypes.has_key(pt):
799                            reindextypes[pt].append(n)
800                        else:
801                            reindextypes[pt]= [n]
802                        break
[2078]803        cached_data = {}
804        if set(name).intersection(set(('faculty','department','end_level'))):
805            cached_data = self.fill_certificates_dict()
[1702]806        students = self.portal_catalog(portal_type="Student")
[1954]807        if hasattr(self,'portal_catalog_real'):
808            aq_portal = self.portal_catalog_real.evalAdvancedQuery
809        else:
810            aq_portal = self.portal_catalog.evalAdvancedQuery
[1702]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())
[2084]815        #import pdb;pdb.set_trace()
[1702]816        for i in xrange(num_objects):
817            if pghandler: pghandler.report(i)
818            student_brain = students[i]
[1707]819            student_object = student_brain.getObject()
[2084]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()
[1702]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
[1707]832            sub_objects = False
833            for pt in reindextypes.keys():
[1702]834                modified = True
[1707]835                try:
836                    doc = getattr(student_object,self.affected_types[pt]['id']).getContent()
[2084]837                    #doc = sub_brains[pt].getObject().getContent()
838                    # path = "%s/%s" % (student_path,self.affected_types[pt]['id'])
839                    # doc = self.unrestrictedTraverse(path).getContent()
[1707]840                    sub_objects = True
841                except:
842                    continue
[2084]843                for field in set(name).intersection(self.affected_types[pt]['fields']):
[1707]844                    if hasattr(self,'get_from_doc_%s' % field):
[2078]845                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
846                                                                              cached_data=cached_data)
[1707]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)
[1815]859                data['jamb_reg_no'] = import_record.Entryregno
[1702]860            if reindex_special and 'registered_courses' in reindex_special:
[1954]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
[1702]878            if modified:
879                self.modifyRecord(**data)
880        if pghandler: pghandler.finish()
881    ###)
[1620]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:
[1724]887            self._catalog.clear()
[1700]888        students = self.portal_catalog(portal_type="Student")
889        num_objects = len(students)
[2078]890        cached_data = self.fill_certificates_dict()
[1620]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)
[1700]895            student_brain = students[i]
896            spath = student_brain.getPath()
[1727]897            student_object = student_brain.getObject()
[1620]898            data = {}
[1700]899            sid = data['id'] = student_brain.getId
900            data['review_state'] = student_brain.review_state
[1707]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:
[1727]908                    #from pdb import set_trace;set_trace()
[1707]909                    continue
910                for field in self.affected_types[pt]['fields']:
911                    if hasattr(self,'get_from_doc_%s' % field):
[2078]912                        data[field] = getattr(self,'get_from_doc_%s' % field)(doc,
913                                                                              cached_data=cached_data)
[1707]914                    else:
[1727]915                        data[field] = getattr(doc,field,None)
916            if not sub_objects:
[1700]917                import_res = self.returning_import(id = sid)
918                if not import_res:
[1620]919                    continue
[1700]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)
[1815]926                data['jamb_reg_no'] = import_record.Entryregno
[1727]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)
[1749]933                    courses = []
[1727]934                    for c in level_obj.objectIds():
935                        if c.endswith('_co'):
936                            courses.append(c[:-3])
937                        else:
938                            courses.append(c)
[1749]939                    data['registered_courses'] = courses
[1700]940            self.addRecord(**data)
[1620]941        if pghandler: pghandler.finish()
942    ###)
943
[1700]944    security.declarePrivate('notify_event_listener') ###(
[1620]945    def notify_event_listener(self,event_type,object,infos):
946        "listen for events"
[1716]947        if not infos.has_key('rpath'):
948            return
[1702]949        pt = getattr(object,'portal_type',None)
950        mt = getattr(object,'meta_type',None)
[1954]951        students_catalog = self
[1702]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
[1700]960        rpl = infos['rpath'].split('/')
[1731]961        if pt == 'Student' and mt == 'CPS Proxy Folder'\
962           and event_type == "sys_add_object":
[1700]963            student_id = object.id
964            try:
965                self.addRecord(id = student_id)
966            except ValueError:
967                pass
968            return
[1716]969        elif pt == 'StudentCourseResult' and mt == 'CPS Proxy Folder':
970            if event_type not in ("sys_add_object","sys_del_object"):
971                return
[2033]972            level_session = getattr(object.aq_parent.getContent(),'session','unknown')
973            if level_session not in (self.getSessionId()[-2:],'2006/2007'):
974                return
[1716]975            course_id = object.getId()
[1954]976            if course_id.endswith('_co'):
977                course_id = course_id[:-3]
[1716]978            student_id = object.absolute_url_path().split('/')[-4]
[1954]979            res = students_catalog(id = student_id)
[1716]980            if not res:
981                return
982            student_rec = res[0]
[2039]983            registered_courses = getattr(student_rec,'registered_courses',None)
984            if not registered_courses:
[1967]985                registered_courses = []
[2039]986            #import pdb;pdb.set_trace()
[1971]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
[2039]992            elif registered_courses and event_type == "sys_del_object":
993                removed = False
[1954]994                while course_id in registered_courses:
[2039]995                    removed = True
[1954]996                    registered_courses.remove(course_id)
[2039]997                if not removed:
998                    return
[1716]999            data['id'] = student_id
1000            data['registered_courses'] = registered_courses
[2069]1001            self.modifyRecord(record = student_rec, **data)
[1971]1002            return
[1716]1003        if pt not in self.affected_types.keys():
[1700]1004            return
[1716]1005        if event_type not in ('sys_modify_object'):
1006            return
[1700]1007        if mt == 'CPS Proxy Folder':
1008            return
[1716]1009        for field in self.affected_types[pt]['fields']:
[1700]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]
[1716]1015        self.modifyRecord(**data)
[1700]1016    ###)
[1620]1017
[1625]1018
[971]1019InitializeClass(StudentsCatalog)
1020
[1146]1021###)
1022
1023class CoursesCatalog(WAeUPTable): ###(
[1716]1024    security = ClassSecurityInfo()
[1146]1025
1026    meta_type = 'WAeUP Courses Catalog'
[2094]1027    name =  "courses_catalog"
[1146]1028    key = "code"
[2094]1029    def __init__(self,name=None):
1030        if name ==  None:
1031            name =  self.name
1032        WAeUPTable.__init__(self, name)
[1146]1033
[1716]1034    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
1035        """ clear the catalog, then re-index everything """
[1146]1036
[1716]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 """
[1724]1081        if clear:
1082            self._catalog.clear()
[1716]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)
[1724]1087        #from pdb import set_trace;set_trace()
[1716]1088        for i in xrange(num_objects):
1089            if pghandler: pghandler.report(i)
1090            course_brain = courses[i]
[1724]1091            course_doc = course_brain.getObject().getContent()
[1716]1092            pl = course_brain.getPath().split('/')
1093            data = {}
[1724]1094            for field in self.schema():
[1749]1095                data[field] = getattr(course_doc,field,None)
[1716]1096            data[self.key] = course_brain.getId
[1724]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)
[1716]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
[1724]1122        if event_type == "sys_add_object" and mt == 'CPS Proxy Folder':
[1716]1123            try:
1124                self.addRecord(**data)
1125            except ValueError:
[1724]1126                return
1127            course_id = object.getId()
1128            doc = object.getContent()
1129            if doc is None:
1130                return
1131            for field in self.schema():
[1749]1132                data[field] = getattr(doc,field,None)
[1724]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
[1716]1139        if event_type == "sys_del_object":
1140            self.deleteRecord(course_id)
[1724]1141            return
[1716]1142        if event_type == "sys_modify_object" and mt == 'Course':
[1724]1143            #from pdb import set_trace;set_trace()
[1716]1144            for field in self.schema():
[1749]1145                data[field] = getattr(object,field,None)
[1716]1146            course_id = object.aq_parent.getId()
1147            data[self.key] = course_id
[1724]1148            ai = rpl.index('academics')
1149            data['faculty'] = rpl[ai +1]
1150            data['department'] = rpl[ai +2]
[1716]1151            self.modifyRecord(**data)
1152    ###)
1153
1154
[1146]1155InitializeClass(CoursesCatalog)
[1151]1156###)
[1146]1157
[2084]1158class CourseResults(WAeUPTable): ###(
[2069]1159    security = ClassSecurityInfo()
1160
1161    meta_type = 'WAeUP Results Catalog'
1162    name = "course_results"
[2084]1163    key = "key" #student_id + level + course_id
[2094]1164    def __init__(self,name=None):
1165        if name ==  None:
1166            name = self.name
1167        WAeUPTable.__init__(self, name)
[2084]1168        self._queue = []
[2099]1169
[2084]1170    def addRecord(self, **data): ###(
[2094]1171        """add one record"""
[2099]1172
[2084]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    ###)
[2099]1188
[2094]1189    # def _p_resolveConflict(self, oldstate, committed, newstate):
1190    #     # Apply the changes made in going from old to newstate to
1191    #     # committed
[2099]1192
[2094]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.
[2069]1196
[2094]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
[2084]1235    def deleteRecord(self, uid): ###(
1236        self.uncatalog_object(uid)
1237        if uid in self._queue:
1238            self._queue.remove(uid)
1239    ###)
1240
[2094]1241    def updateCourseResults(self,student_id,level_id,portal_catalog_results,course_results): ###(
[2099]1242        # query = Eq('path',"%s/campus/students/%s/study_course/%s" %
[2094]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)
[2099]1248        # level_results = [r for r in course_results
[2094]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()
[2099]1260            data['student_id'] = student_id
1261            data['level_id'] = level_id
[2094]1262            data['queue_status'] = OBJECT_CREATED
[2099]1263            data['code'] = course_id
[2094]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
[2084]1269    def getCourses(self,student_id,level_id): ###(
[2094]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")
[2084]1278        query = Eq('student_id',student_id) & Eq('level_id', level_id)
[2094]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)
[2084]1285        carry_overs = []
1286        normal = []
[2099]1287        credits = 0
[2094]1288        for brain in course_results:
[2084]1289            d = {}
[2099]1290            credits += int(brain.credits)
[2084]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'
[2094]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'
[2084]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    ###)
[2099]1326
[2084]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
[2069]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
[2084]1378        self.refreshCatalog(clear=1, pghandler=handler)
[2069]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
[2084]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):
[2099]1402            if pghandler:
[2084]1403                pghandler.report(i)
1404            course_result_brain = course_results[i]
1405            path_list = course_result_brain.getPath().split('/')
[2094]1406            course_result_doc = course_result_brain.getObject().getContent()
[2084]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()
[2099]1414            data['student_id'] = student_id
1415            data['level_id'] = level_id
[2084]1416            data['queue_status'] = OBJECT_CREATED
1417            self.catalog_object(dict2ob(data), uid=key)
1418        if pghandler: pghandler.finish()
1419    ###)
[2069]1420
[2084]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
[2094]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)
[2084]1456    ###)
1457
1458InitializeClass(CourseResults)
[2069]1459###)
1460
[1625]1461class OnlinePaymentsImport(WAeUPTable): ###(
[1620]1462
1463    meta_type = 'WAeUP Online Payment Transactions'
[1625]1464    name = "online_payments_import"
[1620]1465    key = "order_id"
[2094]1466    def __init__(self,name=None):
1467        if name ==  None:
1468            name = self.name
1469        WAeUPTable.__init__(self, name)
[1620]1470
1471
[2069]1472InitializeClass(OnlinePaymentsImport)
[1620]1473###)
1474
[1151]1475class ReturningImport(WAeUPTable): ###(
[1146]1476
[1151]1477    meta_type = 'Returning Import Table'
1478    name = "returning_import"
[1146]1479    key = "matric_no"
[2094]1480    def __init__(self,name=None):
1481        if name ==  None:
1482            name = self.name
1483        WAeUPTable.__init__(self, name)
[1146]1484
1485
[1151]1486InitializeClass(ReturningImport)
1487###)
[1146]1488
1489class ResultsImport(WAeUPTable): ###(
1490
1491    meta_type = 'Results Import Table'
1492    name = "results_import"
1493    key = "key"
[2094]1494    def __init__(self,name=None):
1495        if name ==  None:
1496            name = self.name
1497        WAeUPTable.__init__(self, name)
[1146]1498
1499
1500InitializeClass(ResultsImport)
1501
1502###)
1503
1504class PaymentsCatalog(WAeUPTable): ###(
1505
1506    meta_type = 'WAeUP Payments Catalog'
1507    name = "students_catalog"
1508    key = "id"
[2094]1509    def __init__(self,name=None):
1510        if name ==  None:
1511            name = self.name
1512        WAeUPTable.__init__(self, name)
[1146]1513
1514
1515InitializeClass(PaymentsCatalog)
1516
1517###)
1518
[414]1519# BBB:
1520AccomodationTable = AccommodationTable
Note: See TracBrowser for help on using the repository browser.