source: WAeUP_SRP/trunk/WAeUPTables.py @ 1700

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

students_catalog reindexing implemented.

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