source: WAeUP_SRP/trunk/WAeUPTables.py @ 1703

Last change on this file since 1703 was 1702, checked in by joachim, 18 years ago

added reindexIndex for students_catalog

  • Property svn:keywords set to Id
File size: 21.9 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 1702 2007-04-24 13:52:06Z 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
[1700]27import urllib
[1620]28import DateTime,time
[780]29import csv,re
30import logging
31import Globals
32p_home = Globals.package_home(globals())
33i_home = Globals.INSTANCE_HOME
[1702]34from Products.AdvancedQuery import Eq, Between, Le,In
[780]35
[363]36from interfaces import IWAeUPTable
37
38class AttributeHolder(object):
39    pass
40
41def dict2ob(dict):
42    ob = AttributeHolder()
43    for key, value in dict.items():
44        setattr(ob, key, value)
45    return ob
46
[834]47
[1146]48class WAeUPTable(ZCatalog): ###(
[834]49
[363]50    implements(IWAeUPTable)
[780]51    security = ClassSecurityInfo()
[834]52
[1620]53    def refreshCatalog(self, clear=0, pghandler=None):
54        """ don't refresh for a normal table """
55
56        if self.REQUEST and self.REQUEST.RESPONSE:
57            self.REQUEST.RESPONSE.redirect(
58              URL1 +
59              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20refresh%20not%20implemented')
60
61    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
62        """ clears the whole enchilada """
63        #self._catalog.clear()
64
65        if REQUEST and RESPONSE:
66            RESPONSE.redirect(
67              URL1 +
68              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Clearing%20disabled')
69
[363]70    def addRecord(self, **data):
[502]71        # The uid is the same as "bed".
72        uid = data[self.key]
73        res = self.searchResults({"%s" % self.key : uid})
74        if len(res) > 0:
75            raise ValueError("More than one record with uid %s" % uid)
76        self.catalog_object(dict2ob(data), uid=uid)
77        return uid
[834]78
[363]79    def deleteRecord(self, uid):
80        self.uncatalog_object(uid)
[834]81
[502]82    def searchAndSetRecord(self, **data):
83        raise NotImplemented
84
85    def modifyRecord(self, **data):
86        #records = self.searchResults(uid=uid)
87        uid = data[self.key]
88        records = self.searchResults({"%s" % self.key : uid})
[363]89        if len(records) > 1:
90            # Can not happen, but anyway...
91            raise ValueError("More than one record with uid %s" % uid)
92        if len(records) == 0:
93            raise KeyError("No record for uid %s" % uid)
94        record = records[0]
95        record_data = {}
96        for field in self.schema() + self.indexes():
97            record_data[field] = getattr(record, field)
98        # Add the updated data:
99        record_data.update(data)
100        self.catalog_object(dict2ob(record_data), uid)
101
[1062]102    def reindexIndex(self, name, REQUEST,pghandler=None):
103        if isinstance(name, str):
104            name = (name,)
105        paths = self._catalog.uids.items()
106        i = 0
107        #import pdb;pdb.set_trace()
108        for p,rid in paths:
109            i += 1
110            metadata = self.getMetadataForRID(rid)
111            record_data = {}
112            for field in name:
113                record_data[field] = metadata.get(field)
114            uid = metadata.get(self.key)
115            self.catalog_object(dict2ob(record_data), uid, idxs=name,
116                                update_metadata=0)
[1082]117
[780]118    security.declareProtected(ModifyPortalContent,"exportAllRecords")
119    def exportAllRecords(self):
120        "export a WAeUPTable"
121        #import pdb;pdb.set_trace()
122        fields = [field for field in self.schema()]
123        format = ','.join(['"%%(%s)s"' % fn for fn in fields])
124        csv = []
125        csv.append(','.join(['"%s"' % fn for fn in fields]))
126        for uid in self._catalog.uids:
127            records = self.searchResults({"%s" % self.key : uid})
128            if len(records) > 1:
129                # Can not happen, but anyway...
130                raise ValueError("More than one record with uid %s" % uid)
131            if len(records) == 0:
132                raise KeyError("No record for uid %s" % uid)
133            rec = records[0]
134            csv.append(format % rec)
135        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
136        open("%s/import/%s-%s.csv" % (i_home,self.getId(),current),"w+").write('\n'.join(csv))
[834]137
[1146]138###)
[834]139
[1146]140class AccommodationTable(WAeUPTable): ###(
[834]141
[404]142    meta_type = 'WAeUP Accommodation Tool'
[502]143    name = "accommodation"
144    key = "bed"
[363]145    def __init__(self):
[404]146        WAeUPTable.__init__(self, 'portal_accommodation')
[363]147
[635]148    def searchAndReserveBed(self, student_id,bed_type):
149        records = self.searchResults({'student' : student_id})
150        if len(records) > 0:
[1293]151            return -1,"Student with Id %s already booked bed %s." % (student_id,records[0].bed)
[834]152
[673]153        records = [r for r in self.searchResults({'bed_type' : bed_type}) if not r.student]
[686]154        #import pdb;pdb.set_trace()
[635]155        if len(records) == 0:
[1306]156            return -2,"No bed available"
[635]157        rec = records[0]
158        self.modifyRecord(bed=rec.bed,student=student_id)
[1571]159        s_logger = logging.getLogger('WAeUPTables.AccommodationTable.searchAndReserveBed')
160        s_logger.info('%s reserved bed %s' % (student_id,rec.bed))
[635]161        return 1,rec.bed
[363]162
[834]163
[404]164InitializeClass(AccommodationTable)
[411]165
[1146]166###)
167
168class PinTable(WAeUPTable): ###(
[1030]169    from ZODB.POSException import ConflictError
[440]170    meta_type = 'WAeUP Pin Tool'
[502]171    name = "pins"
172    key = 'pin'
[440]173    def __init__(self):
174        WAeUPTable.__init__(self, 'portal_pins')
[1082]175
176
[710]177    def searchAndSetRecord(self, uid, student_id,prefix):
[502]178        #records = self.searchResults(uid=uid)
[710]179        records = self.searchResults(student = student_id)
[990]180        #import pdb;pdb.set_trace()
[710]181        if len(records) > 0:
182            for r in records:
[834]183                if r.pin != uid and r.prefix_batch.startswith(prefix):
[710]184                    return -2
[502]185        records = self.searchResults({"%s" % self.key : uid})
186        if len(records) > 1:
187            # Can not happen, but anyway...
188            raise ValueError("More than one record with uid %s" % uid)
189        if len(records) == 0:
190            return -1
191        record = records[0]
192        if record.student == "":
193            record_data = {}
194            for field in self.schema() + self.indexes():
195                record_data[field] = getattr(record, field)
196            # Add the updated data:
[635]197            record_data['student'] = student_id
[1030]198            try:
199                self.catalog_object(dict2ob(record_data), uid)
200                return 1
201            except ConflictError:
202                return 2
[990]203        if record.student.upper() != student_id.upper():
[502]204            return 0
[997]205        if record.student.upper() == student_id.upper():
[502]206            return 2
[997]207        return -3
[440]208
209InitializeClass(PinTable)
210
[1146]211###)
[966]212
[1146]213class PumeResultsTable(WAeUPTable): ###(
214
[966]215    meta_type = 'WAeUP PumeResults Tool'
216    name = "pumeresults"
217    key = "jamb_reg_no"
218    def __init__(self):
219        WAeUPTable.__init__(self, 'portal_pumeresults')
220
221
222InitializeClass(PumeResultsTable)
223
[1146]224###)
[971]225
[1146]226class StudentsCatalog(WAeUPTable): ###(
[1620]227    security = ClassSecurityInfo()
[1146]228
[971]229    meta_type = 'WAeUP Students Catalog'
230    name = "students_catalog"
231    key = "id"
[1700]232    affected_types = {   ###(
233                      'StudentApplication':
234                             ('jamb_reg_no',
235                              'entry_mode',
236                              'entry_session',
237                              ),
238                      'StudentClearance':
239                             ('matric_no',
240                              ),
241                         'StudentPersonal':
242                             ('name',
243                              'sex',
244                              'email',
245                              'phone',
246                              ),
247                         'StudentStudyCourse':
248                             ('course',
249                              'faculty',
250                              'department',
251                              'level',
252                              'study_mode',
253                              'session',
254                              'verdict',
255                              ),
256                         }
257    ###)
[1625]258
[971]259    def __init__(self):
260        WAeUPTable.__init__(self, 'students_catalog')
[1620]261        return
[1625]262
[1700]263    def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
264        """ clears the whole enchilada """
265        self._catalog.clear()
[971]266
[1700]267        if REQUEST and RESPONSE:
268            RESPONSE.redirect(
269              URL1 +
270              '/manage_catalogAdvanced?manage_tabs_message=Catalog%20Cleared')
[971]271
[1700]272    def manage_catalogReindex(self, REQUEST, RESPONSE, URL1): ###(
273        """ clear the catalog, then re-index everything """
274
275        elapse = time.time()
276        c_elapse = time.clock()
277
278        pgthreshold = self._getProgressThreshold()
279        handler = (pgthreshold > 0) and ZLogHandler(pgthreshold) or None
280        self.refreshCatalog(clear=1, pghandler=handler)
281
282        elapse = time.time() - elapse
283        c_elapse = time.clock() - c_elapse
284
285        RESPONSE.redirect(
286            URL1 +
287            '/manage_catalogAdvanced?manage_tabs_message=' +
288            urllib.quote('Catalog Updated \n'
289                         'Total time: %s\n'
290                         'Total CPU time: %s' % (`elapse`, `c_elapse`)))
291    ###)
292
293    def get_from_doc_department(self,doc): ###(
[1620]294        "return the students department"
[1700]295        if doc is None:
[1620]296            return None
[1700]297        certificate_res = self.portal_catalog(id = doc.study_course)
[1620]298        if len(certificate_res) != 1:
299            return None
300        return certificate_res[0].getPath().split('/')[-3]
301
[1700]302    def get_from_doc_faculty(self,doc):
303        "return the students faculty"
304        if doc is None:
[1620]305            return None
[1700]306        certificate_res = self.portal_catalog(id = doc.study_course)
307        if len(certificate_res) != 1:
308            return None
309        return certificate_res[0].getPath().split('/')[-4]
[1620]310
[1700]311    def get_from_doc_level(self,doc):
312        "return the students level"
313        if doc is None:
[1620]314            return None
[1700]315        return getattr(doc,'current_level',None)
[1620]316
[1700]317    def get_from_doc_study_mode(self,doc):
318        "return the students study_mode"
319        if doc is None:
[1620]320            return None
[1700]321        return getattr(doc,'current_study_mode',None)
[1625]322
[1700]323    def get_from_doc_entry_session(self,doc):
324        "return the students entry_session"
325        if doc is None:
[1620]326            return None
[1700]327        try:
328            digit = int(doc.jamb_reg_no[0])
329        except:
330            return "xx"
331        if digit < 8:
332            return "0%c" % doc.jamb_reg_no[0]
333        return "9%c" % doc.jamb_reg_no[0]
334
335    def get_from_doc_session(self,doc):
336        "return the students session"
337        if doc is None:
[1620]338            return None
[1700]339        return getattr(doc,'current_session',None)
[1620]340
[1700]341    def get_from_doc_course(self,doc):
[1620]342        "return the students study_course"
[1700]343        if doc is None:
[1620]344            return None
[1700]345        return getattr(doc,'study_course',None)
[1620]346
[1700]347    def get_from_doc_name(self,doc):
[1620]348        "return the students name from the personal"
[1700]349        if doc is None:
[1620]350            return None
351        return "%s %s %s" % (doc.firstname,doc.middlename,doc.lastname)
352
[1700]353    def get_from_doc_verdict(self,doc):
354        "return the students study_course"
355        if doc is None:
[1620]356            return None
[1700]357        return getattr(doc,'current_verdict',None)
[1702]358    ###)
[1620]359
[1702]360    def reindexIndex(self, name, REQUEST,pghandler=None): ###(
361        if isinstance(name, str):
362            name = (name,)
363        reindextypes = {}
364        reindex_special = []
365        #import pdb;pdb.set_trace()
366        for n in name:
367            if n in ("review_state","registered_courses"):
368                reindex_special.append(n)
369            else:
370                for pt in self.affected_types.keys():
371                    if n in self.affected_types[pt]:
372                        if reindextypes.has_key(pt):
373                            reindextypes[pt].append(n)
374                        else:
375                            reindextypes[pt]= [n]
376                        break
377        students = self.portal_catalog(portal_type="Student")
378        aq_portal = self.portal_catalog.evalAdvancedQuery
379        num_objects = len(students)
380        if pghandler:
381            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
382        noattr = set(('StudentClearance','StudentPersonal')) & set(reindextypes.keys())
383        for i in xrange(num_objects):
384            if pghandler: pghandler.report(i)
385            student_brain = students[i]
386            data = {}
387            modified = False
388            sid = data['id'] = student_brain.getId
389            if reindex_special and 'review_state' in reindex_special:
390                modified = True
391                data['review_state'] = student_brain.review_state
392            if reindextypes:
393                query = Eq('path',student_brain.getPath())
394                sub_brains = aq_portal(query)
395                modified = True
396                spath = student_brain.getPath()
397                if len(sub_brains) > 1:
398                    for sub_brain in sub_brains:
399                        if not sub_brain.portal_type in reindextypes.keys():
400                            continue
401                        doc = sub_brain.getObject().getContent()
402                        for field in self.affected_types[sub_brain.portal_type]:
403                            if hasattr(self,'get_from_doc_%s' % field):
404                                data[field] = getattr(self,'get_from_doc_%s' % field)(doc)
405                            else:
406                                data[field] = getattr(doc,field)
407                elif len(sub_brains) == 1 and noattr:
408                    import_res = self.returning_import(id = sid)
409                    if not import_res:
410                        continue
411                    import_record = import_res[0]
412                    data['matric_no'] = import_record.matric_no
413                    data['sex'] = import_record.Sex == 'F'
414                    data['name'] = "%s %s %s" % (import_record.Firstname,
415                                                 import_record.Middlename,
416                                                 import_record.Lastname)
417                    data['matric_no'] = import_record.Entryregno
418            if reindex_special and 'registered_courses' in reindex_special:
419                query = Eq('id','study_course') & Eq('path',student_brain.getPath())
420                brains = aq_portal(query)
421                while brains:
422                    study_course_path = brains[0].getPath()
423                    level_brains = self.portal_catalog(path = study_course_path,
424                                                       portal_type = "StudentStudyLevel")
425                    if not level_brains:
426                        break
427                    modified = True
428                    level_ids = [l.getId for l in level_brains]
429                    level_ids.sort()
430                    for l in level_brains:
431                        if l.getId == level_ids[-1]:
432                            level_path = l.getPath()
433                            break
434                    result_brains = self.portal_catalog(path = level_path,
435                                                        portal_type = "StudentCourseResult")
436                    course_ids = [cr.getId for cr in result_brains]
437                    courses = []
438                    for c in course_ids:
439                        if c.endswith('_co'):
440                            courses.append(c[:-3])
441                        else:
442                            courses.append(c)
443                    data['registered_courses'] = courses
444                    break
445            if modified:
446                self.modifyRecord(**data)
447        if pghandler: pghandler.finish()
448    ###)
[1620]449
450    def refreshCatalog(self, clear=0, pghandler=None): ###(
451        """ re-index everything we can find """
452        students_folder = self.portal_url.getPortalObject().campus.students
[1625]453
[1620]454        cat = self._catalog
455        paths = self._catalog.uids.items()
456        if clear:
457            paths = tuple(paths)
458            cat.clear()
[1700]459        students = self.portal_catalog(portal_type="Student")
460        num_objects = len(students)
[1620]461        if pghandler:
462            pghandler.init('Refreshing catalog: %s' % self.absolute_url(1), num_objects)
463        for i in xrange(num_objects):
464            if pghandler: pghandler.report(i)
[1700]465            student_brain = students[i]
466            spath = student_brain.getPath()
[1620]467            student_obj = student_brain.getObject()
468            data = {}
[1700]469            sid = data['id'] = student_brain.getId
470            data['review_state'] = student_brain.review_state
471            sub_brains = self.portal_catalog(path = spath)
472            if len(sub_brains) > 1:
473                for sub_brain in sub_brains:
474                    if not sub_brain.portal_type in self.affected_types.keys():
475                        continue
476                    doc = sub_brain.getObject().getContent()
477                    for field in self.affected_types[sub_brain.portal_type]:
478                        if hasattr(self,'get_from_doc_%s' % field):
479                            data[field] = getattr(self,'get_from_doc_%s' % field)(doc)
480                        else:
481                            data[field] = getattr(doc,field)
482            elif len(sub_brains) == 1:
483                #import pdb;pdb.set_trace()
484                import_res = self.returning_import(id = sid)
485                if not import_res:
[1620]486                    continue
[1700]487                import_record = import_res[0]
488                data['matric_no'] = import_record.matric_no
489                data['sex'] = import_record.Sex == 'F'
490                data['name'] = "%s %s %s" % (import_record.Firstname,
491                                             import_record.Middlename,
492                                             import_record.Lastname)
493                data['matric_no'] = import_record.Entryregno
494            study_course = getattr(student_obj,'study_course',None)
495            current_level = data.get('level',None)
496            data['registered_courses'] = []
497            if study_course and current_level and current_level in study_course.objectIds():
498                level_obj = getattr(study_course,current_level)
499                courses = []
500                for c in level_obj.objectIds():
501                    if c.endswith('_co'):
502                        courses.append(c[:-3])
503                    else:
504                        courses.append(c)
505                data['registered_courses'] = courses
506            self.addRecord(**data)
[1620]507        if pghandler: pghandler.finish()
508    ###)
509
510
[1700]511    security.declarePrivate('notify_event_listener') ###(
[1620]512    def notify_event_listener(self,event_type,object,infos):
513        "listen for events"
[1702]514        pt = getattr(object,'portal_type',None)
515        mt = getattr(object,'meta_type',None)
[1620]516        students_catalog = self.students_catalog
[1702]517        data = {}
518        if pt == 'Student' and\
519           mt == 'CPS Proxy Folder' and\
520           event_type.startswith('workflow'):
521            data['id'] = object.getId()
522            data['review_state'] = self.portal_workflow.getInfoFor(object,'review_state',None)
523            #from pdb import set_trace;set_trace()
524            students_catalog.modifyRecord(**data)
525            return
[1700]526        if pt not in self.affected_types.keys():
527            return
[1620]528        if not infos.has_key('rpath'):
529            return
[1700]530        rpl = infos['rpath'].split('/')
531        if pt == 'Student' and event_type == "sys_add_object":
532            student_id = object.id
533            try:
534                self.addRecord(id = student_id)
535            except ValueError:
536                pass
537            return
538        elif pt == 'CourseResult' and mt == 'CPS Proxy Folder':
[1620]539            from pdb import set_trace;set_trace()
[1700]540           
541        if event_type not in ('sys_modify_object'):
[1702]542            from pdb import set_trace;set_trace()
[1700]543            return
544        if mt == 'CPS Proxy Folder':
545            return
546        for field in self.affected_types[pt]:
547            if hasattr(self,'get_from_doc_%s' % field):
548                data[field] = getattr(self,'get_from_doc_%s' % field)(object)
549            else:
550                data[field] = getattr(object,field)
551        data['id'] = rpl[2]
552        students_catalog.modifyRecord(**data)
553    ###)
[1620]554
[1625]555
[971]556InitializeClass(StudentsCatalog)
557
[1146]558###)
559
560class CoursesCatalog(WAeUPTable): ###(
561
562    meta_type = 'WAeUP Courses Catalog'
563    name = "students_catalog"
564    key = "code"
565    def __init__(self):
566        WAeUPTable.__init__(self, 'courses_catalog')
567
568
569InitializeClass(CoursesCatalog)
[1151]570###)
[1146]571
[1625]572class OnlinePaymentsImport(WAeUPTable): ###(
[1620]573
574    meta_type = 'WAeUP Online Payment Transactions'
[1625]575    name = "online_payments_import"
[1620]576    key = "order_id"
577    def __init__(self):
578        WAeUPTable.__init__(self, self.name)
579
580
581InitializeClass(CoursesCatalog)
582###)
583
[1151]584class ReturningImport(WAeUPTable): ###(
[1146]585
[1151]586    meta_type = 'Returning Import Table'
587    name = "returning_import"
[1146]588    key = "matric_no"
589    def __init__(self):
[1151]590        WAeUPTable.__init__(self, 'returning_import')
[1146]591
592
[1151]593InitializeClass(ReturningImport)
594###)
[1146]595
596class ResultsImport(WAeUPTable): ###(
597
598    meta_type = 'Results Import Table'
599    name = "results_import"
600    key = "key"
601    def __init__(self):
602        WAeUPTable.__init__(self, 'results_import')
603
604
605InitializeClass(ResultsImport)
606
607###)
608
609class PaymentsCatalog(WAeUPTable): ###(
610
611    meta_type = 'WAeUP Payments Catalog'
612    name = "students_catalog"
613    key = "id"
614    def __init__(self):
615        WAeUPTable.__init__(self, 'payments_catalog')
616
617
618InitializeClass(PaymentsCatalog)
619
620###)
621
[414]622# BBB:
623AccomodationTable = AccommodationTable
Note: See TracBrowser for help on using the repository browser.