source: WAeUP_SRP/base/WAeUPTool.py @ 2458

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

rebuild getNextInfo.py completely
fetch session from portal properties.xml
change all scripts using getSessionId
remove StudentCourseResult? relevant code from event services
make pay_by_sc.py and interswitch_cb.py work (rebuild both)

  • Property svn:keywords set to Id
File size: 65.3 KB
Line 
1#-*- mode: python; mode: fold -*-
2# (C) Copyright 2005 The WAeUP group  <http://www.waeup.org>
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: WAeUPTool.py 2454 2007-10-27 21:53:04Z henrik $
20"""The WAeUP Tool Box.
21"""
22
23from AccessControl import ClassSecurityInfo
24from Acquisition import aq_inner
25from Acquisition import aq_parent
26from Globals import DTMLFile
27from Globals import InitializeClass
28from OFS.SimpleItem import SimpleItem
29from zExceptions import BadRequest
30
31from Products.CMFCore.utils import getToolByName
32from Products.CPSSchemas.DataStructure import DataStructure
33from Products.CPSSchemas.DataModel import DataModel
34from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
35from Products.CMFCore.ActionProviderBase import ActionProviderBase
36from Products.CMFCore.permissions import View
37from Products.ZCatalog.ZCatalog import ZCatalog
38from Products.CMFCore.permissions import ModifyPortalContent
39from Products.CMFCore.permissions import ManagePortal
40from Products.CMFCore.utils import UniqueObject
41from Products.CMFCore.URLTool import URLTool
42from Products.CMFCore.utils import getToolByName
43from Students import makeCertificateCode
44from Globals import package_home,INSTANCE_HOME
45import DateTime,time
46import logging
47import transaction
48import csv,re,os,sys
49from shutil import copy2
50from Products.AdvancedQuery import Eq, Between, Le,In
51
52p_home = package_home(globals())
53i_home = INSTANCE_HOME
54images_base = os.path.join(i_home,"images")
55
56
57def getObject(object,name):
58    if object.hasObject(name):
59        return getattr(object,name)
60    return None
61
62class WAeUPTool(UniqueObject, SimpleItem, ActionProviderBase):
63    """WAeUP tool"""
64
65    id = 'waeup_tool'
66    meta_type = 'WAeUP Tool'
67    _actions = ()
68    security = ClassSecurityInfo()
69    security.declareObjectProtected(View)
70    manage_options = ( ActionProviderBase.manage_options
71                     + SimpleItem.manage_options
72                     )
73
74    def rwrite(self,s): ###(
75        response = self.REQUEST.RESPONSE
76        response.setHeader('Content-type','text/html; charset=ISO-8859-15')
77        response.write("%s<br />\r\n" % s)
78    ###)
79
80    def sleep(self,secs): ###(
81        "sleep"
82        import time
83        time.sleep(secs)
84        return
85
86###)
87
88    security.declareProtected(ModifyPortalContent,'openLog') ###(
89    def openLog(self,name):
90        """open a log file"""
91        version = 1
92        path = "%s/log/%s_%d.log" % (i_home,name,version)
93        while os.path.exists(path):
94            version += 1
95            path = "%s/log/%s_%d.log" % (i_home,name,version)
96        log = open(path,"w")
97        return log
98    ###)
99
100    security.declareProtected(ModifyPortalContent,'bypassQueueCatalog') ###(
101    def bypassQueueCatalog(self,enable=True):
102        """bypass the QueueCatalog by setting all indexes to process imediate,
103        if enable is True (default) the old settings are restored
104        """
105
106    ###)
107
108    security.declareProtected(ModifyPortalContent,'measureOaT') ###(
109    def measureOaT(self,method="a",probe="1000",nr_pts="1"):
110        """measure Object access Time"""
111        import random
112        if hasattr(self,'portal_catalog_real'):
113            aq_portal = self.portal_catalog_real.evalAdvancedQuery
114        else:
115            aq_portal = self.portal_catalog.evalAdvancedQuery
116        nr_pts = int(nr_pts)
117        probe = int(probe)
118        intervall = probe/10
119        objects = ("application","clearance","personal")
120        portal_types = ("StudentApplication","StudentClearance","StudentPersonal")
121        #i = random.randrange(num_objects)
122        count = 0
123        found = 0
124        not_found = 0
125        t_found = 0
126        t_not_found = 0
127        time_found = time_not_found = 0.0
128        t_time_found = t_time_not_found = 0.0
129        accessed = []
130        t_min = 1000
131        t_max = 0
132        #import pdb;pdb.set_trace()
133        students = self.portal_catalog(portal_type="Student")
134        num_students = len(students)
135        if method == "d":
136            query = Eq('path','/uniben/campus/students') & In('portal_type',portal_types[:nr_pts])
137            res = aq_portal(query)
138            brains = {}
139            for r in res:
140                sid = r.relative_path.split('/')[-2]
141                if brains.has_key(sid):
142                    brains[sid][r.portal_type] = r
143                else:
144                    brains[sid] = {r.portal_type : r}
145            brains_list = brains.keys()
146            num_objects = len(brains_list)
147        else:
148            num_objects = num_students
149        print "="*40
150        print "method: %s probes: %d nr_pts: %d num_objects: %d" % (method,
151                                                                        probe,
152                                                                        nr_pts,
153                                                                        num_objects)
154        print "nr found/not time found/not min/max"
155        elapse = time.time()
156        i_elapse = time.time()
157        c_elapse = time.clock()
158        for c in range(1,probe + 1):
159            i = random.randrange(num_objects)
160            if method in ('a','b','c'):
161                student_brain = students[i]
162            elif method == "d":
163                #import pdb;pdb.set_trace()
164                student_brain = brains[brains_list[i]]
165            if method == "c":
166                query = Eq('path',student_brain.getPath()) & In('portal_type',portal_types[:nr_pts])
167                res = aq_portal(query)
168                this_portal_types = [r.portal_type for r in res]
169            for i in range(nr_pts):
170                oid = objects[i]
171                if method == "a":
172                    try:
173                        student_path = student_brain.getPath()
174                        path = "%s/%s" % (student_path,oid)
175                        doc = self.unrestrictedTraverse(path).getContent()
176                        found += 1
177                        i_time = time.time() - i_elapse
178                        time_found += i_time
179                    except:
180                        not_found += 1
181                        i_time = time.time() - i_elapse
182                        time_not_found += i_time
183                        pass
184                elif method == "b":
185                    try:
186                        student_object = student_brain.getObject()
187                        doc = getattr(student_object,oid).getContent()
188                        found += 1
189                        i_time = time.time() - i_elapse
190                        time_found += i_time
191                    except:
192                        i_time = time.time() - i_elapse
193                        time_not_found += i_time
194                        not_found += 1
195                        pass
196                elif method == "c":
197                    if portal_types[i] in this_portal_types:
198                        found += 1
199                        doc = res[this_portal_types.index(portal_types[i])].getObject().getContent()
200                        i_time = time.time() - i_elapse
201                        time_found += i_time
202                    else:
203                        not_found += 1
204                        i_time = time.time() - i_elapse
205                        time_not_found += i_time
206                elif method == "d":
207                    if student_brain.has_key(portal_types[i]):
208                        found += 1
209                        doc = student_brain[portal_types[i]].getObject().getContent()
210                        i_time = time.time() - i_elapse
211                        time_found += i_time
212                    else:
213                        not_found += 1
214                        i_time = time.time() - i_elapse
215                        time_not_found += i_time
216                i_elapse = time.time()
217            if c and (c % intervall == 0):
218                #i_time = time.time() - i_elapse
219                t_per = 0.0
220                if found:
221                    t_per = time_found/found
222                if t_per > t_max:
223                    t_max = t_per
224                if t_per > 0.0 and t_per < t_min:
225                    t_min = t_per
226                itf = 0.0
227                if found:
228                    itf = time_found/found
229                itnf = 0.0
230                if not_found :
231                    itnf = time_not_found / not_found
232                interval_time = time_found + time_not_found
233                s = "%(c)d: %(found)d/%(not_found)d " % vars()
234                s += "%(interval_time)6.2f %(itf)6.4f/%(itnf)6.4f " % vars()
235                s += "%(t_min)6.4f/%(t_max)6.4f" %  vars()
236                print s
237                t_found += found
238                t_not_found += not_found
239                t_time_found += time_found
240                t_time_not_found += time_not_found
241                time_found = time_not_found = 0.0
242                found = not_found = 0
243        # t_found += found
244        # t_not_found += not_found
245        elapse = time.time() - elapse
246        itf = 0.0
247        if t_found:
248            itf = t_time_found/t_found
249        itnf = 0.0
250        if t_not_found:
251            itnf = t_time_not_found / t_not_found
252        #c_elapse = time.clock() - c_elapse
253        s = "%(probe)d: %(t_found)d/%(t_not_found)d " % vars()
254        s += "%(elapse)6.2f %(itf)6.4f/%(itnf)6.4f " % vars()
255        s += "%(t_min)6.4f/%(t_max)6.4f" %  vars()
256        print "-"*40
257        print s
258        rel_found = float(t_found)/probe
259        rel_not_found = float(t_not_found)/probe
260        estimated_total_time = num_objects*(rel_found*itf + rel_not_found*itnf)
261        print estimated_total_time
262    ###)
263
264    security.declareProtected(ModifyPortalContent,'writeLog') ###(
265    def writeLog(self,logfile,s):
266        """write to the log file"""
267        logfile.write(s)
268
269###)
270
271    def generateStudentId(self,letter): ###(
272        import random
273        r = random
274        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
275        if letter == '?':
276            letter= r.choice('ABCDEFGHKLMNPQRSTUVWXY')
277        sid = "%c%d" % (letter,r.randint(99999,1000000))
278        students = self.portal_url.getPortalObject().campus.students
279##        while hasattr(students, sid):
280##            sid = "%c%d" % (letter,r.randint(99999,1000000))
281        while self.students_catalog(id = sid):
282            sid = "%c%d" % (letter,r.randint(99999,1000000))
283        return sid
284    ###)
285
286    def generatePassword(self,s=None): ###(
287        import random
288        r = random
289        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
290        if s is None:
291            s = 'abcdefghklmnpqrstuvwxy23456789'
292        pw = ''
293        while len(pw) < 6:
294            pw += r.choice(s)
295        return pw
296    ###)
297
298    security.declareProtected(ManagePortal, 'removeDeletedDocIds') ###(
299    def removeDeletedDocIds(self, max=1000):
300        """
301        remove deleted docids from repository commit after max
302        """
303        logger = logging.getLogger('WAeUPTool.removeDeletedDocIds')
304        repository = getToolByName(self, 'portal_repository')
305        pxtool = getToolByName(self, 'portal_proxies')
306        pxtool_infos = pxtool.getRevisionsUsed()
307
308        nb_revs = 0
309        docids_d = {} # all docids
310        unused_docids_d = {} # all docids that are unused
311        ids_unused_revs_docids = [] # ids for revs of unused docids
312        ids_unused_revs = [] # ids for unused revs
313        total = 0
314        idlist = repository.objectIds()
315        for id in idlist:
316            docid, rev = repository._splitId(id)
317            if docid is None:
318                logger.info("invalid doc_id %s" % docid)
319                continue
320            nb_revs += 1
321            docids_d[docid] = None
322            if not pxtool_infos.has_key(docid):
323                unused_docids_d[docid] = None
324                ids_unused_revs_docids.append(id)
325                ids_unused_revs.append(id)
326            elif not pxtool_infos[docid].has_key(rev):
327                ids_unused_revs.append(id)
328            if len(ids_unused_revs) >= max:
329                repository.manage_delObjects(ids_unused_revs)
330                #import pdb;pdb.set_trace()
331                transaction.commit()
332                total += max
333                logger.info('removed %d total %d unused docids ' % (max,total))
334        anz = len(ids_unused_revs)
335        if anz > 0:
336            repository.manage_delObjects(ids_unused_revs)
337            transaction.commit()
338            total += anz
339            logger.info('finished removing %d unused docids ' % (total))
340
341
342###)
343
344    security.declareProtected(View,'getCredential') ###(
345    def getCredential(self,student_id):
346        "return a student password"
347        student_entry = getattr(self.portal_directories.students,student_id,None)
348        if student_entry is None:
349            return None
350        return getattr(student_entry,"password","not set")
351    ###)
352
353    security.declarePublic('checkPassword') ###(
354    def checkPassword(self,student_id,password):
355        "return a student password"
356        student_entry = getattr(self.portal_directories.students,student_id,None)
357        if student_entry is None:
358            return False
359        return getattr(student_entry,"password","not set") == password
360    ###)
361
362    security.declarePublic('editPassword') ###(
363    def editPassword(self,student_id,password):
364        "edit a student password"
365        student_entry = getattr(self.portal_directories.students,student_id,None)
366        if student_entry is None:
367            return
368        setattr(student_entry,'password',password)
369    ###)
370
371    security.declareProtected(View,'doCommit') ###(
372    def doCommit(self,logger=None):
373        "commit some transactions"
374        transaction.commit()
375    ###)
376
377    security.declarePublic('loadStudentFoto') ###(
378    def loadStudentFoto(self,student,filename,folder):
379        "return a student passport picture"
380        #import pdb;pdb.set_trace()
381        picture ="%s/import/%s/%s" % (i_home,folder,filename)
382        student_id = student.getId()
383        images_dir = os.path.join("%s" % images_base,student_id)
384        if not os.path.exists(images_dir):
385            os.mkdir(images_dir)
386        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
387        for extension in ('.jpg','.JPG'):
388            fullname = "%(picture)s%(extension)s" % vars()
389            if os.path.exists(fullname):
390                copy2(fullname,image_name)
391                return "successfully copied passport picture"
392        return "passport picture not found %s.(jpg,.JPG)" % picture
393    ###)
394
395    def old____loadStudentFoto(self,student,filename,folder): ###(
396        "return a student passport picture"
397        app = student.application
398        app_doc = app.getContent()
399        #clear = student.clearance
400        #clear_doc = clear.getContent()
401        #matric_no = clear_doc.matric_no.upper()
402        picture1 ="%s/import/%s/%s.jpg" % (i_home,folder,filename)
403        picture2 ="%s/import/%s/%s.JPG" % (i_home,folder,filename)
404        #import pdb;pdb.set_trace()
405        if os.path.exists(picture1):
406            file = open(picture1)
407        elif os.path.exists(picture2):
408            file = open(picture2)
409        else:
410            return "passport picture not found %s" % picture1
411        reopened = False
412        if self.portal_workflow.getInfoFor(app,'review_state',None) !='opened':
413            self.portal_workflow.doActionFor(app,'open')
414            reopened = True
415        outfile = file.read()
416        app_doc.manage_addFile('passport',
417                               file=outfile,
418                               title="%s.jpg" % filename)
419        if reopened:
420            self.portal_workflow.doActionFor(app,'close')
421        return "successfully loaded passport picture"
422    ###)
423
424    security.declareProtected(ModifyPortalContent,'createOne') ###(
425    def createOne(self,students_folder,student_brain,letter,commit=False):
426        sid = self.waeup_tool.generateStudentId(letter)
427        students_folder.invokeFactory('Student', sid)
428        student = getattr(students_folder,sid)
429        self.portal_workflow.doActionFor(student,'return')
430        student.manage_setLocalRoles(sid, ['Owner',])
431        matric_no = student_brain.matric_no
432        jamb_reg_no = student_brain.Entryregno
433        self.students_catalog.addRecord(id = sid,
434                                           matric_no = matric_no,
435                                           jamb_reg_no = jamb_reg_no,
436                                           sex = student_brain.Sex == "F",
437                                           name = "%s %s %s" % (student_brain.Firstname,
438                                                                student_brain.Middlename,
439                                                                student_brain.Lastname)
440                                        )
441        if commit:
442            transaction.commit()
443        return sid,jamb_reg_no
444    ###)
445
446    security.declareProtected(ModifyPortalContent,'addStudent') ###(
447    def addStudent(self,dict):
448        students_folder = self.portal_url.getPortalObject().campus.students
449        sid = self.waeup_tool.generateStudentId('?')
450        students_folder.invokeFactory('Student', sid)
451        student_obj = getattr(students_folder,sid)
452        f2t = self.student_field2types
453        #from pdb import set_trace; set_trace()
454        d = {}
455        #d['jamb_sex']  = 'M'
456        #if dict.get('sex'):
457        #    d['jamb_sex']  = 'F'
458
459        entry_session = dict.get('entry_session')
460        if entry_session == self.getSessionId()[0]:
461            wfaction = 'admit'
462            wft = 'wf_transition_admit'
463            password = None
464        else:
465            wfaction = 'return'
466            wft = 'wf_transition_return'
467            password = self.generatePassword()
468            self.makeStudentMember(sid,password)
469
470        for pt in f2t.keys():
471            student_obj.invokeFactory(pt,f2t[pt]['id'])
472            sub_obj = getattr(student_obj,f2t[pt]['id'])
473            sub_doc = sub_obj.getContent()
474            #self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
475            d['Title'] = f2t[pt]['title']
476            for field in f2t[pt]['fields']:
477                d[field] = dict.get(field,'')
478            sub_doc.edit(mapping = d)
479            new_state = f2t[pt][wft]
480            if new_state != "remain":
481                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
482        self.portal_workflow.doActionFor(student_obj,wfaction)
483        student_obj.manage_setLocalRoles(sid, ['Owner',])
484        return sid,password
485    ###)
486
487    security.declarePublic('getCertificateBrain') ###(
488    def getCertificateBrain(self,cert_id):
489        "do it"
490        res = ZCatalog.searchResults(self.portal_catalog_real,
491                                {'portal_type':"Certificate",
492                                      'id': cert_id})
493        if res:
494            return res[0]
495        return None
496    ###)
497
498    security.declareProtected(ModifyPortalContent,'get_csv_filenames') ###(
499    def get_csv_filenames(self):
500        "do it"
501        files = [file for file in os.listdir("%s/import/" % (i_home))
502                 if file.endswith('.csv') and file.find('imported') == -1]
503        return files
504    ###)
505
506    security.declarePublic('findStudentByMatricelNo') ###(
507    def findStudentByMatricelNo(self,matric_no):
508        "do it"
509        res = ZCatalog.searchResults(self.portal_catalog_real,
510                                {'portal_type':"StudentClearance",
511                                 'SearchableText': matric_no})
512        if res:
513            return res[0]
514        return None
515    ###)
516
517    security.declarePublic('makeStudentMember') ###(
518    def makeStudentMember(self,sid,password='uNsEt'):
519        """make the student a member"""
520        membership = self.portal_membership
521        membership.addMember(sid,
522                             password ,
523                             roles=('Member',
524                                     'Student',
525                                     ),
526                             domains='',
527                             properties = {'memberareaCreationFlag': False,
528                                           'homeless': True},)
529        member = membership.getMemberById(sid)
530        self.portal_registration.afterAdd(member, sid, password, None)
531        #self.manage_setLocalRoles(sid, ['Owner',])
532    ###)
533
534    security.declarePublic('makeStudentData') ###(
535    def makeStudentData(self,student_id,email=None,phone_nr=None):
536        "create Datastructure for a returning Student"
537        #import pdb;pdb.set_trace()
538        logger = logging.getLogger('WAeUPTool.makeStudentData')
539        students_folder = self.portal_url.getPortalObject().campus.students
540        #res = self.students_catalog(id=student_id)
541        #if res:
542        #    st = res[0]
543        #res = self.returning_import(matric_no = st.matric_no)
544        res = self.returning_import(id = student_id)
545        if res:
546            student = res[0]
547        else:
548            logger.info('Id %s not found in returning_import' % student_id)
549            return
550        logger.info('%s creates data structure' % student_id)
551        s_results = self.results_import(matric_no = student.matric_no)
552        if s_results:
553            lnr = self.getLevelFromResultsCosCode(s_results)
554            level = "%d00" % lnr
555            verdict,eligible = self.getVerdict(s_results[0].Verdict)
556            #if eligible:
557            #    level = "%d00" % (lnr + 1)
558        else:
559            logger.info('matric_no %s not found in results_import' % student.matric_no)
560            level = 0
561            verdict = 'N/A'
562        #student should not be allowed to perform this transition
563        #wftool = self.portal_workflow
564        #wftool.doActionFor(student,'return')
565        certcode_org = student.Coursemajorcode
566        certcode = makeCertificateCode(certcode_org)
567        certificate_brain = self.getCertificateBrain(certcode)
568        if not certificate_brain:
569            em = 'Certificate %s org-code %s not found\n' % (certcode, certcode_org)
570            logger.info(em)
571        matric_no = student.matric_no
572        sid = student_id
573        student_obj = getattr(students_folder,sid)
574        student_obj.invokeFactory('StudentApplication','application')
575        application = student_obj.application
576        self.portal_workflow.doActionFor(application,'open',dest_container=application)
577        da = {'Title': 'Application Data'}
578        student_obj.invokeFactory('StudentPersonal','personal')
579        da['jamb_reg_no'] = student.Entryregno
580        em = self.getEntryMode(student.Entryregno)
581        da['entry_mode'] = em
582        personal = student_obj.personal
583        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
584        dp = {'Title': 'Personal Data'}
585        student_obj.invokeFactory('StudentClearance','clearance')
586        clearance = student_obj.clearance
587        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
588        dc = {'Title': 'Clearance/Eligibility Record'}
589        dc['matric_no'] = matric_no
590        state = student.State
591        lga = student.LGA
592        if state and lga:
593            lga =  state + ' / ' + lga
594        else:
595            lga = "None"
596        da['jamb_lga'] = dc['lga'] = lga
597        da['app_email'] = dp['email'] = email
598        da['app_mobile'] = dp['phone'] = phone_nr
599        dp['firstname'] = student.Firstname
600        dp['middlename'] = student.Middlename
601        dp['lastname'] = student.Lastname
602        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
603        da['jamb_sex'] = student.Sex
604        dp['sex'] = student.Sex == 'F'
605        dp['perm_address'] = student.Permanent_Address
606        application.getContent().edit(mapping=da)
607        self.portal_workflow.doActionFor(application,'close',dest_container=application)
608        personal.getContent().edit(mapping=dp)
609        clearance.getContent().edit(mapping=dc)
610        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
611        #
612        # Study Course
613        #
614        student_obj.invokeFactory('StudentStudyCourse','study_course')
615        studycourse = student_obj.study_course
616        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
617        dsc = {}
618        dsc['study_course'] = certcode
619        dsc['current_level'] = level
620        dsc['current_verdict'] = verdict
621        dsc['current_mode'] = em
622        dsc['current_session'] = '06'
623        studycourse.getContent().edit(mapping=dsc)
624        #
625        # Level
626        #
627##        l = getattr(studycourse,level,None)
628##        if l is None:
629##            studycourse.invokeFactory('StudentStudyLevel', level)
630##            l = getattr(studycourse, level)
631##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
632##            l.getContent().edit(mapping={'Title': "Level %s" % level})
633###)
634
635    security.declarePublic('makeStudentLevel') ###(
636    def makeStudentLevel(self,student_id):
637        "create the StudyLevel for a returning Student"
638        #import pdb;pdb.set_trace()
639        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
640        students_folder = self.portal_url.getPortalObject().campus.students
641        res = self.students_catalog(id=student_id)
642        if res:
643            st = res[0]
644        course = st.course
645        matric_no = st.matric_no
646        level = st.level
647        res = self.results_import(matric_no = matric_no)
648        if res:
649            results = res
650        logger.info('%s creating Level %s' % (student_id,level))
651        #
652        # Level
653        #
654        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
655        studycourse = getattr(student_obj,"study_course",None)
656        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
657        l = getattr(studycourse,level,None)
658        if l is None:
659            studycourse.invokeFactory('StudentStudyLevel', level)
660            l = getattr(studycourse, level)
661            self.portal_workflow.doActionFor(l,'open',dest_container=l)
662            l.getContent().edit(mapping={'Title': "Level %s" % level})
663        ###)
664
665    security.declarePublic('getHallInfo') ###(
666    def getHallInfo(self,bed):
667        """return Hall Info"""
668        info = {}
669        hall,block,room,letter = bed.split('_')
670        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
671        if res and len(res) == 1:
672            hall_brain = res[0]
673            hall_doc = hall_brain.getObject().getContent()
674        else:
675            return info
676        info['hall_title'] = hall_brain.Title
677        info['maintenance_code'] = hall_doc.maintenance_code
678        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
679        batch_doc = None
680        for brain in res:
681            if brain.id.startswith(info['maintenance_code']):
682                batch_doc = brain.getObject().getContent()
683                break
684        if batch_doc is None:
685            info['maintenance_fee'] = None
686        else:
687            info['maintenance_fee'] = batch_doc.cost
688        return info
689    ###)
690
691    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
692    def removePictureFolder(self,student_id):
693        """remove picture_folder by renaming it"""
694        path = 'images'
695        picture_path = os.path.join(i_home,path,student_id)
696        if not os.path.exists(picture_path):
697            return False
698        os.rename(picture_path,picture_path + "_removed")
699        return True
700    ###)
701
702    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
703    def restorePictureFolder(self,student_id):
704        """restore picture_folder by renaming it"""
705        path = 'images'
706        picture_path = os.path.join(i_home,path,student_id)
707        if not os.path.exists(picture_path + "_removed"):
708            return False
709        os.rename(picture_path + "_removed",picture_path)
710        return True
711    ###)
712
713    security.declarePublic('picturesExist') ###(
714    def picturesExist(self, ids,student_id=None):
715        """check if pictures exist in the filesystem"""
716        if student_id is None:
717            student_id = self.getStudentId()
718        if student_id is None:
719            return False
720        picture_path = os.path.join(images_base,student_id)
721        if not os.path.exists(picture_path):
722            return False
723        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
724        return set(ids).issubset(set(pictures))
725    ###)
726
727    security.declarePublic('picturesList') ###(
728    def picturesList(self):
729        """check if pictures exist in the filesystem"""
730        path = 'images'
731        student_id = self.getStudentId()
732        picture_path = os.path.join(i_home,path,student_id)
733        if not os.path.exists(picture_path):
734            return []
735        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
736    ###)
737
738    security.declarePublic('showFsPicture') ###(
739    def showFsPicture(self,path):
740        """return a picture from the filesystem"""
741        picture_path = os.path.join(i_home,path)
742        response = self.REQUEST.RESPONSE
743        #import pdb;pdb.set_trace()
744        registry = getToolByName(self, 'mimetypes_registry')
745        mimetype = str(registry.lookupExtension(path.lower()) or
746                    registry.lookupExtension('file.bin'))
747        if os.path.exists(picture_path):
748            response.setHeader('Content-type',mimetype)
749            return open(picture_path).read()
750        picture_path = os.path.join(i_home,'import',path)
751        if os.path.exists(picture_path):
752            return open(picture_path).read()
753    ###)
754
755    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
756    def deleteAllCourses(self,department="All"):
757        ''' delete the courses'''
758        pm = self.portal_membership
759        member = pm.getAuthenticatedMember()
760
761        if str(member) not in ("henrik","joachim"):
762            return "not possible"
763        if department == "All":
764            res = self.portal_catalog({'meta_type': 'Department'})
765        if len(res) < 1:
766            return "No Departments found"
767
768        deleted = []
769        for dep in res:
770            cf = dep.getObject().courses
771            if cf:
772                cf.manage_delObjects(ids=cf.objectIds())
773                deleted.append("deleted Courses in %s" % dep.getId)
774        return "\r".join(deleted)
775    ###)
776
777    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
778    def getLogfileLines(self,filename="event.log",numlines=20):
779        """Get last NUMLINES lines of logfile FILENAME.
780
781        Return last lines' of a file in the instances logfile directory as
782        a list. The number of returned lines equals `numlines' or less. If
783        less than `numlines' lines are available, the whole file ist
784        returned. If the file can not be opened or some other error
785        occurs, empty list is returend.
786        """
787        result = []
788        lines_hit = 0
789
790        # We only handle files in instances' log directory...
791        logpath = os.path.join(i_home, "log")
792        filename = str(os.path.abspath( os.path.join( logpath, filename )))
793        if not filename.startswith( logpath ):
794            # Attempt to access file outside log-dir...
795            return []
796
797        try:
798            fd = file( filename, "rb" )
799        except IOError:
800            return []
801        if not fd:
802            return []
803
804        if os.linesep == None:
805            linesep = '\n'
806        else:
807            linesep = os.linesep
808
809        # Try to find 'numlines' times a lineseparator, searching from end
810        # and moving to the beginning of file...
811        fd.seek( 0, 2) # Move to end of file...
812        while lines_hit < numlines:
813            if fd.read(1) == linesep[-1]: # This moves filedescriptor
814                                          # one step forward...
815                lines_hit += 1
816            try:
817                fd.seek( -2, 1) # Go two bytes back from current pos...
818            except IOError:
819                # We cannot go back two bytes. Maybe the file is too small...
820                break
821        fd.seek(2,1)
822
823        # Read all lines from current position...
824        result = fd.readlines()
825        # Remove line endings...
826        result = [x.strip() for x in result]
827        fd.close()
828        return result
829    ###)
830
831    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
832    def getCallbacksFromLog(self,filename):
833        """fix Online Payment Transactions from Z2.log entries"""
834        import transaction
835        import random
836        from cgi import parse_qs
837        from urlparse import urlparse
838        #from pdb import set_trace
839        wftool = self.portal_workflow
840        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
841        students_folder = self.portal_url.getPortalObject().campus.students
842        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
843        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
844        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
845        data = re.compile(s)
846        start = True
847        tr_count = 1
848        total = 0
849        #name = 'pume_results'
850        #name = 'epaymentsuccessful_z2log2'
851        name = filename
852        no_import = []
853        imported = []
854        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
855        try:
856            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
857        except:
858            logger.error('Error reading %s' % name)
859            return
860        tas = []
861        for line in transactions:
862            dict = {}
863            items = data.search(line)
864            dict['idict'] = idict = items.groupdict()
865            #print idict
866            #from pdb import set_trace;set_trace()
867            urlparsed = urlparse(idict['get'][4:])
868            #print urlparsed
869            path = urlparsed[2].split('/')
870            dict['student_id'] = student_id = path[8]
871            dict['payment_id'] = payment_id = path[10]
872            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
873            tas.append(dict)
874            tr_count += 1
875        return tas
876    ###)
877
878    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
879    def importOnlinePaymentTransactions(self):
880        """load Online Payment Transactions from CSV values"""
881        import transaction
882        import random
883        #from pdb import set_trace
884        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
885        opt = self.online_payments_import
886        students_folder = self.portal_url.getPortalObject().campus.students
887        start = True
888        tr_count = 1
889        total = 0
890        #name = 'pume_results'
891        name = 'OnlineTransactions'
892        no_import = []
893        imported = []
894        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
895        try:
896            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
897        except:
898            logger.error('Error reading %s.csv' % name)
899            return
900        for pay_transaction in transactions:
901            if start:
902                start = False
903                logger.info('Start loading from %s.csv' % name)
904                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
905                no_import.append('%s,"Error"' % s)
906                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
907                format_error = format + ',"%(Error)s"'
908            data = {}
909
910            # format of the first file sent by Tayo
911            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
912            #data['student_id'] = student_id = pay_transaction['Payer ID']
913            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
914            #data['response_code'] = response_code = pay_transaction['Resp Code']
915            #data['amount'] = amount = pay_transaction['Amount']
916
917            # format of the second file sent by Tayo
918            #data['datetime'] = date = 0
919            #data['student_id'] = student_id = pay_transaction['Payer ID']
920            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
921            #data['response_code'] = response_code = '00'
922            #data['amount'] = amount = pay_transaction['Amount']
923
924            # format of the third file sent by Kehinde
925            data['datetime'] = date = 0
926            data['student_id'] = student_id = pay_transaction['customer_id']
927            data['order_id'] = order_id = pay_transaction['merchant_reference']
928            data['response_code'] = response_code = '00'
929            data['amount'] = amount = pay_transaction['Amount']
930
931            dup = False
932            if response_code == "12":
933                continue
934            try:
935                opt.addRecord(**data)
936            except ValueError:
937                dup = True
938            #from pdb import set_trace;set_trace()
939            if dup:
940                if response_code == "00":
941                    try:
942                        opt.modifyRecord(**data)
943                    except:
944                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
945                        continue
946                else:
947                    pay_transaction['Error'] = "Duplicate order_id"
948                    no_import.append( format_error % pay_transaction)
949                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
950                    continue
951            tr_count += 1
952            if tr_count > 1000:
953                if len(no_import) > 0:
954                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
955                             '\n'.join(no_import) + '\n')
956                    no_import = []
957                em = '%d transactions committed\n' % (tr_count)
958                transaction.commit()
959                regs = []
960                logger.info(em)
961                total += tr_count
962                tr_count = 0
963        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
964                                                '\n'.join(no_import))
965        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
966    ###)
967
968    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
969    def mass_create_faculty(self,mapping):
970        "create a faculty"
971        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
972        academics_folder = self.portal_url.getPortalObject().campus.academics
973        fid = mapping['code']
974        if getattr(academics_folder,fid,None) is not None:
975            return '', "Faculty with ID: %s exists" % fid
976        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
977        try:
978            academics_folder.invokeFactory('Faculty', fid)
979        except BadRequest,E:
980            return '', "%s" % E
981        f = getattr(academics_folder,fid,None)
982        f.getContent().edit(mapping=mapping)
983        return fid,''
984    ###)
985
986    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
987    def mass_edit_faculty(self,mapping):
988        "edit a faculty"
989        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
990        academics_folder = self.portal_url.getPortalObject().campus.academics
991        fid = mapping['code']
992        f = getattr(academics_folder,fid,None)
993        if f is None:
994            return '', "Faculty with ID: %s does not exist" % fid
995        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
996        f.getContent().edit(mapping=mapping)
997        return fid,''
998    ###)
999
1000    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
1001    def mass_create_department(self,mapping):
1002        "create a department in the correct faculty"
1003        logger = logging.getLogger('WAeUPTool.mass_create_department')
1004        fid = mapping['faculty_code']
1005        if getattr(self,'_v_faculties',None) is None:
1006            res = self.portal_catalog(portal_type = "Faculty")
1007            self._v_faculties = {}
1008            for f in res:
1009                self._v_faculties[f.getId] = f.getObject()
1010        f = self._v_faculties.get(fid,None)
1011        if f is None:
1012            return '', "No Faculty with ID: %s" % fid
1013        else:
1014            did = mapping.get('code')
1015            d = getattr(f,did,None)
1016            if d is None or d.portal_type == "Faculty":
1017                logger.info('Creating Department %(code)s, %(title)s' % mapping)
1018                try:
1019                    f.invokeFactory('Department', did)
1020                except BadRequest,E:
1021                    return '', "%s" % E
1022                d = getattr(f,did)
1023                d.invokeFactory('CoursesFolder','courses')
1024                courses = getattr(d,'courses')
1025                dict = {'Title': 'Courses'}
1026                courses.getContent().edit(mapping=dict)
1027                d.invokeFactory('CertificatesFolder','certificates')
1028                certificates = getattr(d,'certificates')
1029                dict = {'Title': 'Certificates'}
1030                certificates.getContent().edit(mapping=dict)
1031            d.getContent().edit(mapping=mapping)
1032        return did,''
1033    ###)
1034
1035    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
1036    def mass_edit_department(self,mapping):
1037        "create a department in the correct faculty"
1038        logger = logging.getLogger('WAeUPTool.mass_create_department')
1039        academics_folder = self.portal_url.getPortalObject().campus.academics
1040        fid = mapping['faculty_code']
1041        did = mapping.get('code')
1042        try:
1043            d = getattr(getattr(academics_folder,fid),did,None)
1044        except KeyError:
1045            return '', "Department %s or Faculty %s wrong" % (did,fid)
1046        else:
1047            if d is None or d.portal_type == "Faculty":
1048                logger.info('Editing Department %(code)s, %(title)s' % mapping)
1049            d.getContent().edit(mapping=mapping)
1050        return did,''
1051    ###)
1052
1053    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1054    def mass_create_course(self,mapping):
1055        #import pdb;pdb.set_trace()
1056        if getattr(self,'_v_course_list',None) is None:
1057            self._v_course_list = []
1058        if getattr(self,'_v_departments',None) is None:
1059            res = self.portal_catalog(portal_type = "Department")
1060            self._v_department_courses = {}
1061            for d in res:
1062                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
1063        did = mapping['department_code']
1064        d = self._v_department_courses.get(did,None)
1065        if d is None:
1066            return '', "No Department with ID: %s" % did
1067        course_id = mapping.get('code')
1068        if course_id in self._v_course_list:
1069            return '', "Duplicate Course ID: %s" % did
1070        c = getattr(d,course_id,None)
1071        if c is not None:
1072            return '', "Duplicate Course ID: %s" % did
1073        try:
1074            d.invokeFactory('Course', course_id)
1075        except BadRequest,E:
1076            return '', "%s" % E
1077        self._v_course_list.append(course_id)
1078        c = getattr(d,course_id)
1079        c.getContent().edit(mapping=mapping)
1080        return course_id,''
1081    ###)
1082
1083    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1084    def mass_edit_course(self,mapping):
1085        #import pdb;pdb.set_trace()
1086        course_id = mapping.get('code')
1087        res = self.portal_catalog(id=course_id)
1088        if not res:
1089            return '', "No Course with ID: %s" % course_id
1090        c = res[0].getObject()
1091        c.getContent().edit(mapping=mapping)
1092        return course_id,''
1093    ###)
1094
1095    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1096    def mass_create_certificate(self,mapping):
1097        if getattr(self,'_v_certificate_list',None) is None:
1098            self._v_certificate_list = []
1099        if getattr(self,'_v_department_certificates',None) is None:
1100            res = self.portal_catalog(portal_type = "Department")
1101            self._v_department_certificates = {}
1102            for d in res:
1103                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
1104        did = mapping['department_code']
1105        d = self._v_department_certificates.get(did,None)
1106        if d is None:
1107            return '', "No Department with ID: %s" % did
1108        certificate_id = mapping.get('code')
1109        if certificate_id in self._v_certificate_list:
1110            return '', "Duplicate Certificate ID: %s" % did
1111        c = getattr(d,certificate_id,None)
1112        if c is not None:
1113            return '', "Duplicate Certificate ID: %s" % did
1114        try:
1115            d.invokeFactory('Certificate', certificate_id)
1116        except BadRequest,E:
1117            return '', "%s" % E
1118        self._v_certificate_list.append(certificate_id)
1119        c = getattr(d,certificate_id)
1120        c.getContent().edit(mapping=mapping)
1121        return certificate_id,''
1122    ###)
1123
1124    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1125    def mass_edit_certificate(self,mapping):
1126        #import pdb;pdb.set_trace()
1127        certificate_id = mapping.get('code')
1128        res = self.portal_catalog(id=certificate_id)
1129        if not res:
1130            return '', "No Certificate with ID: %s" % did
1131        c = res[0].getObject()
1132        c.getContent().edit(mapping=mapping)
1133        return certificate_id,''
1134    ###)
1135
1136    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1137    def mass_create_certificate_course(self,mapping):
1138        if getattr(self,'_v_courses',None) is None:
1139            res = self.courses_catalog()
1140            self._v_courses= [course.code for course in res]
1141        if getattr(self,'_v_ceritficates',None) is None:
1142            res = self.portal_catalog(portal_type = "Certificate")
1143            self._v_certificates = {}
1144            for cert in res:
1145                self._v_certificates[cert.getId] = cert.getObject()
1146        certificate_course_id = mapping.get('code')
1147        if certificate_course_id not in self._v_courses:
1148            return '', "No Course with ID: %s" % certificate_course_id
1149        cert_id = mapping['certificate_code']
1150        cert = self._v_certificates.get(cert_id,None)
1151        if cert is None:
1152            return '', "No Certificate with ID: %s" % cert_id
1153        level_id = mapping.get('level')
1154        level = getattr(cert,level_id,None)
1155        if level is None:
1156            cert.invokeFactory('StudyLevel', level_id)
1157            level = getattr(cert,level_id,None)
1158        elif hasattr(level,certificate_course_id):
1159            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1160            (certificate_course_id,cert_id,level_id)
1161        level.invokeFactory('CertificateCourse', certificate_course_id)
1162        c = getattr(level,certificate_course_id)
1163        c.getContent().edit(mapping=mapping)
1164        return certificate_course_id,''
1165    ###)
1166
1167    field2types_student = {   ###(
1168                      'StudentApplication':
1169                          {'id': 'application',
1170                           'title': 'Application Data',
1171                           'wf_transition_return': 'close',
1172                           'wf_transition_admit': 'remain',
1173                           'fields':
1174                             ('jamb_reg_no',
1175                              'entry_mode',
1176                              'entry_session',
1177                              'jamb_score',
1178                              'app_email',
1179                              'jamb_age',
1180                              'jamb_state',
1181                              'jamb_lga',
1182                              )
1183                              },
1184                      #'StudentPume':
1185                      #    {'id': 'pume',
1186                      #     'title': 'Pume Data',
1187                      #     'wf_transition_return': 'close',
1188                      #     'wf_transition_admit': 'close',
1189                      #     'fields':
1190                      #       ('pume_score',
1191                      #        )
1192                      #        },
1193                      'StudentClearance':
1194                          {'id': 'clearance',
1195                           'title': 'Clearance/Eligibility Record',
1196                           'wf_transition_return': 'close',
1197                           'wf_transition_admit': 'remain',
1198                           'fields':
1199                             ('matric_no',
1200                              'nationality',
1201                              'lga',
1202                              'birthday',
1203                              )
1204                              },
1205                         'StudentPersonal':
1206                          {'id': 'personal',
1207                           'title': 'Personal Data',
1208                           'wf_transition_return': 'open',
1209                           'wf_transition_admit': 'remain',
1210                           'fields':
1211                             ('firstname',
1212                              'middlename',
1213                              'lastname',
1214                              'sex',
1215                              'email',
1216                              'phone',
1217                              'perm_address',
1218                              )
1219                              },
1220                         'StudentStudyCourse':
1221                          {'id': 'study_course',
1222                           'title': 'Study Course',
1223                           'wf_transition_return': 'open',
1224                           'wf_transition_admit': 'remain',
1225                           'fields':
1226                             ('study_course',
1227                              'current_level',
1228                              'current_session',
1229                              'current_mode',
1230                              'current_verdict',
1231                              )
1232                              },
1233
1234                         'PaymentsFolder':
1235                          {'id': 'payments',
1236                           'title': 'Payments',
1237                           'wf_transition_return': 'open',
1238                           'wf_transition_admit': 'open',
1239                           'fields':
1240                             ()
1241                              },
1242                         }
1243    ###)
1244
1245    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1246    def mass_create_student(self,mapping):
1247        "create a students record due import"
1248        logger = logging.getLogger('WAeUPTool.mass_create_student')
1249        students_folder = self.portal_url.getPortalObject().campus.students
1250        jamb_reg_no = mapping.get('jamb_reg_no',None)
1251        if jamb_reg_no:
1252            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1253            if res:
1254                return '',"jamb_reg_no exists"
1255        matric_no = mapping.get('matric_no',None)
1256        if matric_no:
1257            res = self.students_catalog(matric_no = matric_no)
1258            if res:
1259                return '',"matric_no exists"
1260        sid = self.waeup_tool.generateStudentId('?')
1261        students_folder.invokeFactory('Student', sid)
1262        student_obj = getattr(students_folder,sid)
1263        f2t = self.field2types_student
1264        d = {}
1265        transition = mapping.get('reg_transition','admit')
1266        if transition not in ('admit','return'):
1267            return '',"no valid transition provided"
1268        for pt in f2t.keys():
1269            student_obj.invokeFactory(pt,f2t[pt]['id'])
1270            sub_obj = getattr(student_obj,f2t[pt]['id'])
1271            sub_doc = sub_obj.getContent()
1272            d['Title'] = f2t[pt]['title']
1273            for field in f2t[pt]['fields']:
1274                d[field] = mapping.get(field,'')
1275
1276            if pt == "StudentApplication":
1277                d['jamb_sex']  = 'M'
1278                if mapping.get('sex'):
1279                    d['jamb_sex']  = 'F'
1280                d['jamb_firstname'] = mapping.get('firstname',None)
1281                d['jamb_middlename'] = mapping.get('middlename',None)
1282                d['jamb_lastname'] = mapping.get('lastname',None)
1283
1284            # if pt == "StudyCourse":
1285            #     for von,zu in (('entry_mode','current_mode'),
1286            #                    ('entry_session','current_session')):
1287            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1288            #             d[zu] = mapping[von]
1289            sub_doc.edit(mapping = d)
1290
1291            #import pdb;pdb.set_trace()
1292            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
1293            if new_state != "remain":
1294                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1295        self.portal_workflow.doActionFor(student_obj,transition)
1296        student_obj.manage_setLocalRoles(sid, ['Owner',])
1297        return sid,''
1298    ###)
1299
1300    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1301    def mass_edit_student(self,mapping):
1302        "edit a students record due import"
1303        logger = logging.getLogger('WAeUPTool.mass_edit_student')
1304        students_folder = self.portal_url.getPortalObject().campus.students
1305        sid = mapping.get('id',None)
1306        jamb_reg_no = mapping.get('jamb_reg_no',None)
1307        matric_no = mapping.get('matric_no',None)
1308        editable_keys = mapping.keys()
1309        if sid:
1310            res = self.students_catalog(id = sid)
1311            if not res:
1312                return '',"no student with id %s" % sid
1313            if matric_no and res[0].matric_no and\
1314              matric_no != res[0].matric_no:
1315                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1316            if jamb_reg_no and res[0].jamb_reg_no and\
1317              jamb_reg_no != res[0].jamb_reg_no:
1318                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
1319        elif jamb_reg_no:
1320            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1321            if not res:
1322                return '',"no student with jamb_reg_no %s" % jamb_reg_no
1323            editable_keys.remove('jamb_reg_no')
1324        elif matric_no:
1325            res = self.students_catalog(matric_no = matric_no)
1326            if not res:
1327                return '',"no student with matric_no %s" % matric_no
1328            editable_keys.remove('matric_no')
1329
1330        ## included only to change wf state from admitted to returning
1331        #if res[0].review_state not in ('admitted','objection_raised'):
1332        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1333        ## end inclusion
1334
1335        sid = res[0].id
1336        student_obj = getattr(students_folder,sid)
1337        f2t = self.field2types_student
1338        d = {}
1339        #import pdb;pdb.set_trace()
1340        any_change = False
1341        for pt in f2t.keys():
1342            if pt == "student_application":
1343                d['jamb_sex']  = 'M'
1344                if mapping.get('sex'):
1345                    d['jamb_sex']  = 'F'
1346            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
1347            if intersect:
1348                sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1349                if sub_obj is None:
1350                    try:
1351                        student_obj.invokeFactory(pt,f2t[pt]['id'])
1352                    except:
1353                        continue
1354                    sub_obj = getattr(student_obj,f2t[pt]['id'])
1355                    d['Title'] = f2t[pt]['title']
1356                sub_doc = sub_obj.getContent()
1357                for field in intersect:
1358                    changed = False
1359                    if getattr(sub_doc,field) != mapping.get(field,''):
1360                        any_change = True
1361                        changed = True
1362                        d[field] = mapping.get(field,'')
1363                    if changed:
1364                        sub_doc.edit(mapping = d)
1365
1366
1367        ## included only to change wf state from admitted to returning
1368        #    if res[0].review_state in ('admitted','objection_raised'):
1369        #        new_state = f2t[pt]['wf_transition_return']
1370        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1371        #        if sub_obj and new_state != "remain":
1372        #            try:
1373        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1374        #            except:
1375        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1376        #                pass
1377        #if res[0].review_state in ('admitted','objection_raised'):
1378        #    wfaction = 'return'
1379        #    try:
1380        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1381        #        logger.info('%s, wf state changed' % sid)
1382        #        any_change = True
1383        #    except:
1384        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1385        #        pass
1386        ## end inclusion
1387
1388
1389        if any_change:
1390            return sid,''
1391        else:
1392            return sid,'not modified'
1393    ###)
1394
1395    security.declareProtected(ModifyPortalContent,"importData")###(
1396    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
1397        """load data from CSV values"""
1398        import transaction
1399        import random
1400
1401        pm = self.portal_membership
1402        member = pm.getAuthenticatedMember()
1403
1404        logger = logging.getLogger('WAeUPTool.importData')
1405        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1406        students_folder = self.portal_url.getPortalObject().campus.students
1407        start = True
1408        tr_count = 1
1409        total_imported = 0
1410        total_not_imported = 0
1411        total = 0
1412        iname = "import_%s" % name
1413        stool = getToolByName(self, 'portal_schemas')
1414        ltool = getToolByName(self, 'portal_layouts')
1415        schema = stool._getOb(iname)
1416        if schema is None:
1417            em = 'No such schema %s' % iname
1418            logger.error('No such schema %s' % iname)
1419            return em
1420        layout = ltool._getOb(iname)
1421        if layout is None:
1422            em = 'No such layout %s' % iname
1423            logger.error(em)
1424            return em
1425        validators = {}
1426        for widget in layout.keys():
1427            validators[widget] = layout[widget].validate
1428        #import pdb;pdb.set_trace()
1429        mode = "create"
1430        if edit:
1431            mode = "edit"
1432        importer_name = "mass_%(mode)s_%(name)s" % vars()
1433        importer = getattr(self, '%s' % importer_name,None)
1434        if importer is None:
1435            em = 'No importer function %s' % importer_name
1436            logger.error(em)
1437            return em
1438        not_imported = []
1439        imported = []
1440        try:
1441            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
1442        except:
1443            em = 'Error reading %s.csv' % filename
1444            logger.error(em)
1445            return em
1446        for item in items:
1447            if start:
1448                start = False
1449                adapters = [MappingStorageAdapter(schema, item)]
1450                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
1451                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
1452                import_keys = [k for k in attrs if not k.startswith('ignore')]
1453                diff2schema = set(import_keys).difference(set(schema.keys()))
1454                diff2layout = set(import_keys).difference(set(layout.keys()))
1455                if diff2schema:
1456                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
1457                    return em
1458                if mode == "create":
1459                    required_keys = [layout.getIdUnprefixed(id)
1460                                     for id,widget in layout.objectItems()
1461                                     if widget.is_required]
1462                    #import pdb;pdb.set_trace()
1463                    if not set(required_keys).issubset(set(import_keys)):
1464                        diff2import = set(required_keys).difference(set(import_keys))
1465                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
1466                        return em
1467                s = ','.join(['"%s"' % fn for fn in import_keys])
1468                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
1469                s = '"id",' + s
1470                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
1471                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
1472                format_error = format + ',"%(Error)s"'
1473                format = '"%(id)s",'+ format
1474
1475            dm = DataModel(item, adapters,context=self)
1476            ds = DataStructure(data=item,datamodel=dm)
1477            error_string = ""
1478            for k in import_keys:
1479                if not validators[k](ds,mode=mode):
1480                    error_string += " %s : %s" % (k,
1481                                                  self.translation_service(ds.getError(k),
1482                                                                           ds.getErrorMapping(k)))
1483            if not error_string:
1484                temp_item = item.copy()
1485                temp_item.update(dm)
1486                temp_item['id'],error = importer(temp_item)
1487                if error:
1488                    error_string += error
1489                else:
1490                    item = temp_item
1491            if error_string:
1492                item['Error'] = error_string
1493                not_imported.append(format_error % item)
1494                total_not_imported += 1
1495            else:
1496                em = format % item
1497                imported.append(em)
1498                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
1499                tr_count += 1
1500                total_imported += 1
1501            total += 1
1502            if total and not total % 100:
1503                transaction.commit()
1504                if len(not_imported) > 0:
1505                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1506                             '\n'.join(not_imported) + '\n')
1507                    not_imported = []
1508                if len(imported) > 0:
1509                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1510                             '\n'.join(imported) + '\n')
1511                    imported = []
1512                em = '%d transactions committed\n' % (tr_count)
1513                regs = []
1514                logger.info(em)
1515                tr_count = 0
1516        if len(imported) > 0:
1517            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1518                                                '\n'.join(imported))
1519        if len(not_imported) > 0:
1520            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1521                                                '\n'.join(not_imported))
1522        em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
1523        return em
1524    ###)
1525
1526    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
1527    def moveImagesToFS(self,student_id="O738726"):
1528        "move the images to the filesystem"
1529        images_dir = os.path.join("%s" % images_base,student_id)
1530        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1531        stool = getToolByName(self, 'portal_schemas')
1532        schemas = ['student_application',
1533                   'student_clearance',
1534                   ]
1535        created = False
1536        for schema_id in schemas:
1537            schema = stool._getOb(schema_id)
1538            object = getattr(student_folder,schema_id[len('student_'):],None)
1539            if object is None:
1540                continue
1541            doc = object.getContent()
1542            for key in schema.keys():
1543                if schema[key].meta_type != "CPS Image Field":
1544                    continue
1545                #import pdb;pdb.set_trace()
1546                image = getattr(doc,key,None)
1547                if not image or not hasattr(image,"data"):
1548                    continue
1549                if not created:
1550                    if not os.path.exists(images_dir):
1551                        os.mkdir(images_dir)
1552                    created = True
1553                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
1554                open(filename,"wb").write(str(image.data))
1555
1556    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
1557    def movePassportToFS(self,student_id="O738726"):
1558        "move the passports to the filesystem"
1559        images_dir = os.path.join("%s" % i_home,'passports')
1560        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1561        stool = getToolByName(self, 'portal_schemas')
1562        schemas = ['student_application',
1563                   #'student_clearance',
1564                   ]
1565        created = False
1566        for schema_id in schemas:
1567            schema = stool._getOb(schema_id)
1568            object = getattr(student_folder,schema_id[len('student_'):],None)
1569            if object is None:
1570                continue
1571            doc = object.getContent()
1572            for key in schema.keys():
1573                if schema[key].meta_type != "CPS Image Field":
1574                    continue
1575                #import pdb;pdb.set_trace()
1576                image = getattr(doc,key)
1577                if not hasattr(image,"data"):
1578                    continue
1579                if not created:
1580                    if not os.path.exists(images_dir):
1581                        os.mkdir(images_dir)
1582                    created = True
1583                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
1584                open(filename,"wb").write(str(image.data))
1585
1586InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.