source: WAeUP_SRP/base/WAeUPTool.py @ 2578

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

Uebergabe an Joachim, darf noch nicht ausgecheckt werden

  • Property svn:keywords set to Id
File size: 74.5 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 2576 2007-11-08 07:55:07Z 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 not self.isStaff():
349            mtool = self.portal_membership
350            member = mtool.getAuthenticatedMember()
351            logger = logging.getLogger('WAeUPTool.getCredential')
352            logger.info('%s tried to access password of %s' % (member,student_id))
353            return None
354        if student_entry is None:
355            return None
356        return getattr(student_entry,"password","not set")
357    ###)
358
359    security.declarePublic('checkPassword') ###(
360    def checkPassword(self,student_id,password):
361        "return a student password"
362        student_entry = getattr(self.portal_directories.students,student_id,None)
363        if student_entry is None:
364            return False
365        return getattr(student_entry,"password","not set") == password
366    ###)
367
368    security.declareProtected(ModifyPortalContent,'editPassword') ###(
369    def editPassword(self,student_id,password):
370        "edit a student password"
371        student_entry = getattr(self.portal_directories.students,student_id,None)
372        if student_entry is None:
373            return
374        setattr(student_entry,'password',password)
375    ###)
376
377    security.declareProtected(ModifyPortalContent,'doCommit') ###(
378    def doCommit(self,logger=None):
379        "commit some transactions"
380        transaction.commit()
381    ###)
382
383    security.declarePublic('loadStudentFoto') ###(
384    def loadStudentFoto(self,student,filename,folder):
385        "return a student passport picture"
386        #import pdb;pdb.set_trace()
387        picture ="%s/import/%s/%s" % (i_home,folder,filename)
388        student_id = student.getId()
389        images_dir = os.path.join("%s" % images_base,student_id)
390        if not os.path.exists(images_dir):
391            os.mkdir(images_dir)
392        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
393        for extension in ('.jpg','.JPG'):
394            fullname = "%(picture)s%(extension)s" % vars()
395            if os.path.exists(fullname):
396                copy2(fullname,image_name)
397                return "successfully copied passport picture"
398        return "passport picture not found: %s.jpg or .JPG" % picture
399    ###)
400
401    def old____loadStudentFoto(self,student,filename,folder): ###(
402        "return a student passport picture"
403        app = student.application
404        app_doc = app.getContent()
405        #clear = student.clearance
406        #clear_doc = clear.getContent()
407        #matric_no = clear_doc.matric_no.upper()
408        picture1 ="%s/import/%s/%s.jpg" % (i_home,folder,filename)
409        picture2 ="%s/import/%s/%s.JPG" % (i_home,folder,filename)
410        #import pdb;pdb.set_trace()
411        if os.path.exists(picture1):
412            file = open(picture1)
413        elif os.path.exists(picture2):
414            file = open(picture2)
415        else:
416            return "passport picture not found %s" % picture1
417        reopened = False
418        if self.portal_workflow.getInfoFor(app,'review_state',None) !='opened':
419            self.portal_workflow.doActionFor(app,'open')
420            reopened = True
421        outfile = file.read()
422        app_doc.manage_addFile('passport',
423                               file=outfile,
424                               title="%s.jpg" % filename)
425        if reopened:
426            self.portal_workflow.doActionFor(app,'close')
427        return "successfully loaded passport picture"
428    ###)
429
430    security.declareProtected(ModifyPortalContent,'createOne') ###(
431    def createOne(self,students_folder,student_brain,letter,commit=False):
432        sid = self.waeup_tool.generateStudentId(letter)
433        students_folder.invokeFactory('Student', sid)
434        student = getattr(students_folder,sid)
435        self.portal_workflow.doActionFor(student,'return')
436        student.manage_setLocalRoles(sid, ['Owner',])
437        matric_no = student_brain.matric_no
438        jamb_reg_no = student_brain.Entryregno
439        self.students_catalog.addRecord(id = sid,
440                                           matric_no = matric_no,
441                                           jamb_reg_no = jamb_reg_no,
442                                           sex = student_brain.Sex == "F",
443                                           name = "%s %s %s" % (student_brain.Firstname,
444                                                                student_brain.Middlename,
445                                                                student_brain.Lastname)
446                                        )
447        if commit:
448            transaction.commit()
449        return sid,jamb_reg_no
450    ###)
451
452    security.declareProtected(ModifyPortalContent,'addStudent') ###(
453    def addStudent(self,dict):
454        students_folder = self.portal_url.getPortalObject().campus.students
455        sid = self.waeup_tool.generateStudentId('?')
456        students_folder.invokeFactory('Student', sid)
457        student_obj = getattr(students_folder,sid)
458        f2t = self.student_field2types
459        #from pdb import set_trace; set_trace()
460        d = {}
461        #d['jamb_sex']  = 'M'
462        #if dict.get('sex'):
463        #    d['jamb_sex']  = 'F'
464
465        entry_session = dict.get('entry_session')
466        if entry_session == self.getSessionId()[0]:
467            wfaction = 'admit'
468            wft = 'wf_transition_admit'
469            password = None
470        else:
471            wfaction = 'return'
472            wft = 'wf_transition_return'
473            password = self.generatePassword()
474            self.makeStudentMember(sid,password)
475
476        for pt in f2t.keys():
477            student_obj.invokeFactory(pt,f2t[pt]['id'])
478            sub_obj = getattr(student_obj,f2t[pt]['id'])
479            sub_doc = sub_obj.getContent()
480            #self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
481            d['Title'] = f2t[pt]['title']
482            for field in f2t[pt]['fields']:
483                d[field] = dict.get(field,'')
484            sub_doc.edit(mapping = d)
485            new_state = f2t[pt][wft]
486            if new_state != "remain":
487                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
488        self.portal_workflow.doActionFor(student_obj,wfaction)
489        student_obj.manage_setLocalRoles(sid, ['Owner',])
490        return sid,password
491    ###)
492
493    security.declarePublic('getCertificateBrain') ###(
494    def getCertificateBrain(self,cert_id):
495        "do it"
496        res = ZCatalog.searchResults(self.portal_catalog_real,
497                                {'portal_type':"Certificate",
498                                      'id': cert_id})
499        if res:
500            return res[0]
501        return None
502    ###)
503
504    security.declareProtected(ModifyPortalContent,'get_csv_filenames') ###(
505    def get_csv_filenames(self):
506        "do it"
507        files = [file for file in os.listdir("%s/import/" % (i_home))
508                 if file.endswith('.csv') and file.find('imported') == -1]
509        return files
510    ###)
511
512    security.declarePublic('findStudentByMatricelNo') ###(
513    def findStudentByMatricelNo(self,matric_no):
514        "do it"
515        res = ZCatalog.searchResults(self.portal_catalog_real,
516                                {'portal_type':"StudentClearance",
517                                 'SearchableText': matric_no})
518        if res:
519            return res[0]
520        return None
521    ###)
522
523    security.declarePublic('makeStudentMember') ###(
524    def makeStudentMember(self,sid,password='uNsEt'):
525        """make the student a member"""
526        membership = self.portal_membership
527        membership.addMember(sid,
528                             password ,
529                             roles=('Member',
530                                     'Student',
531                                     ),
532                             domains='',
533                             properties = {'memberareaCreationFlag': False,
534                                           'homeless': True},)
535        member = membership.getMemberById(sid)
536        self.portal_registration.afterAdd(member, sid, password, None)
537        #self.manage_setLocalRoles(sid, ['Owner',])
538    ###)
539
540    security.declareProtected(View,'makeStudentData') ###(
541    def makeStudentData(self,student_id,email=None,phone_nr=None):
542        "create Datastructure for a returning Student"
543        #import pdb;pdb.set_trace()
544        logger = logging.getLogger('WAeUPTool.makeStudentData')
545        students_folder = self.portal_url.getPortalObject().campus.students
546        #res = self.students_catalog(id=student_id)
547        #if res:
548        #    st = res[0]
549        #res = self.returning_import(matric_no = st.matric_no)
550        res = self.returning_import(id = student_id)
551        if res:
552            student = res[0]
553        else:
554            logger.info('Id %s not found in returning_import' % student_id)
555            return
556        logger.info('%s creates data structure' % student_id)
557        s_results = self.results_import(matric_no = student.matric_no)
558        if s_results:
559            lnr = self.getLevelFromResultsCosCode(s_results)
560            level = "%d00" % lnr
561            verdict,eligible = self.getVerdict(s_results[0].Verdict)
562            #if eligible:
563            #    level = "%d00" % (lnr + 1)
564        else:
565            logger.info('matric_no %s not found in results_import' % student.matric_no)
566            level = 0
567            verdict = 'N/A'
568        #student should not be allowed to perform this transition
569        #wftool = self.portal_workflow
570        #wftool.doActionFor(student,'return')
571        certcode_org = student.Coursemajorcode
572        certcode = makeCertificateCode(certcode_org)
573        certificate_brain = self.getCertificateBrain(certcode)
574        if not certificate_brain:
575            em = 'Certificate %s org-code %s not found\n' % (certcode, certcode_org)
576            logger.info(em)
577        matric_no = student.matric_no
578        sid = student_id
579        student_obj = getattr(students_folder,sid)
580        student_obj.invokeFactory('StudentApplication','application')
581        application = student_obj.application
582        self.portal_workflow.doActionFor(application,'open',dest_container=application)
583        da = {'Title': 'Application Data'}
584        student_obj.invokeFactory('StudentPersonal','personal')
585        da['jamb_reg_no'] = student.Entryregno
586        em = self.getEntryMode(student.Entryregno)
587        da['entry_mode'] = em
588        personal = student_obj.personal
589        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
590        dp = {'Title': 'Personal Data'}
591        student_obj.invokeFactory('StudentClearance','clearance')
592        clearance = student_obj.clearance
593        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
594        dc = {'Title': 'Clearance/Eligibility Record'}
595        dc['matric_no'] = matric_no
596        state = student.State
597        lga = student.LGA
598        if state and lga:
599            lga =  state + ' / ' + lga
600        else:
601            lga = "None"
602        da['jamb_lga'] = dc['lga'] = lga
603        da['app_email'] = dp['email'] = email
604        da['app_mobile'] = dp['phone'] = phone_nr
605        dp['firstname'] = student.Firstname
606        dp['middlename'] = student.Middlename
607        dp['lastname'] = student.Lastname
608        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
609        da['jamb_sex'] = student.Sex
610        dp['sex'] = student.Sex == 'F'
611        dp['perm_address'] = student.Permanent_Address
612        application.getContent().edit(mapping=da)
613        self.portal_workflow.doActionFor(application,'close',dest_container=application)
614        personal.getContent().edit(mapping=dp)
615        clearance.getContent().edit(mapping=dc)
616        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
617        #
618        # Study Course
619        #
620        student_obj.invokeFactory('StudentStudyCourse','study_course')
621        studycourse = student_obj.study_course
622        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
623        dsc = {}
624        dsc['study_course'] = certcode
625        dsc['current_level'] = level
626        dsc['current_verdict'] = verdict
627        dsc['current_mode'] = em
628        dsc['current_session'] = '05'
629        studycourse.getContent().edit(mapping=dsc)
630        #
631        # Level
632        #
633##        l = getattr(studycourse,level,None)
634##        if l is None:
635##            studycourse.invokeFactory('StudentStudyLevel', level)
636##            l = getattr(studycourse, level)
637##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
638##            l.getContent().edit(mapping={'Title': "Level %s" % level})
639###)
640
641    security.declareProtected(ModifyPortalContent,'admitOneStudent') ###(
642    def admitOneStudent(self,brain,entry_session,pin_password):
643        "create Datastructure for an admitted Student"
644        #import pdb;pdb.set_trace()
645        students_folder = self.portal_url.getPortalObject().campus.students
646        logger = logging.getLogger('WAeUPTool.admitStudent')
647        if brain.status != "admitted":
648            logger.info('status of %s is %s' % (brain.reg_no,brain.status))
649            return
650        pin_parts = brain.pin.split('-')
651        if len(pin_parts) != 3:
652            logger.info('invalid pin %s for %s' % (brain.pin,brain.reg_no))
653            return
654        student_id = self.generateStudentId('?')
655        students_folder.invokeFactory('Student', student_id)
656        student_object = getattr(students_folder,student_id)
657        if pin_password:
658            password = pin_parts[2]
659            self.makeStudentMember(student_id,password = password)
660        else:
661            self.makeStudentMember(student_id)
662        student_object.manage_setLocalRoles(student_id, ['Owner',])
663        #logger.info("creating %s reg_no %s" % (student_id,brain.reg_no))
664        #
665        # application
666        #
667        student_object.invokeFactory('StudentApplication','application')
668        application = student_object.application
669        #self.portal_workflow.doActionFor(application,'open',dest_container=application)
670        da = {'Title': 'Application Data'}
671        da['jamb_reg_no'] = brain.reg_no
672
673        sex = 'M'
674        if brain.sex:
675            sex = 'F'
676        da['jamb_sex'] = sex
677        #da['app_ac_pin'] = brain.pin
678        #if brain.lga:
679        #    state_lga = brain.lga.split('_')
680        #    da['state_lga'] = state_lga[0]
681        #    da['jamb_lga'] = state_lga[-1]
682        da['state_lga'] = brain.jamb_lga
683        da['jamb_lga'] = brain.jamb_state
684        da['jamb_score'] = brain.aggregate
685        da['app_email'] = brain.email
686        da['app_mobile'] = brain.phone
687        if brain.entry_mode:
688            da['entry_mode'] = brain.entry_mode
689        elif brain.screening_type == 'pume':
690            da['entry_mode'] = 'ume_ft'
691        elif brain.screening_type == 'pde':
692            da['entry_mode'] = 'de_ft'
693        else:
694            da['entry_mode'] = brain.screening_type
695        da['entry_session'] = entry_session
696        da['jamb_lastname'] = brain.lastname
697        da['jamb_middlename'] = brain.middlenames   # different field names!
698        da['firstname'] = brain.firstname
699        da['screening_application_date'] = brain.application_date
700        da['date_of_birth'] = brain.date_of_birth
701        da['jamb_first_cos'] = brain.course1
702        da['jamb_second_cos'] = brain.course2
703        da['course3'] = brain.course3
704        da['screening_type'] = brain.screening_type
705        da['screening_score'] = brain.screening_score
706        da['screening_date'] = brain.screening_date
707        da['hq_type'] = brain.hq_type
708        da['hq_grade'] = brain.hq_grade
709        da['aos'] = brain.aos
710
711        application.getContent().edit(mapping=da)
712        #self.portal_workflow.doActionFor(application,'close',dest_container=application)
713        #
714        # personal
715        #
716        student_object.invokeFactory('StudentPersonal','personal')
717        personal = student_object.personal
718        #self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
719        dp = {'Title': 'Personal Data'}
720        dp['sex'] = brain.sex
721        dp['email'] = brain.email
722        dp['phone'] = brain.phone
723        dp['lastname'] = brain.lastname
724        dp['middlename'] = brain.middlenames   # different field names!
725        dp['firstname'] = brain.firstname
726        personal.getContent().edit(mapping=dp)
727        #
728        # clearance
729        #
730        student_object.invokeFactory('StudentClearance','clearance')
731        clearance = student_object.clearance
732        #self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
733        dc = {'Title': 'Clearance/Eligibility Record'}
734        dc['lga'] = brain.lga
735        clearance.getContent().edit(mapping=dc)
736        #self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
737        #
738        # study Course
739        #
740        student_object.invokeFactory('StudentStudyCourse','study_course')
741        studycourse = student_object.study_course
742        #self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
743        dsc = {}
744        dsc['study_course'] = brain.course_admitted
745        dsc['current_verdict'] = ''
746        dsc['current_mode'] = da['entry_mode']
747        if da['entry_mode'].startswith('de'):
748            dsc['current_level'] = '200'
749        else:
750            dsc['current_level'] = '100'
751        dsc['current_session'] = entry_session
752        studycourse.getContent().edit(mapping=dsc)
753        #
754        # payments folder
755        student_object.invokeFactory('PaymentsFolder','payments')
756        payments = getattr(student_object,'payments')
757        dpay = {}
758        dpay['Title'] = 'Payments'
759        payments.getContent().edit(mapping=dpay)
760        self.portal_workflow.doActionFor(payments,'open')
761        return student_id
762    ###)
763
764    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
765    def makeStudentLevel(self,student_id):
766        "create the StudyLevel for a returning Student"
767        #import pdb;pdb.set_trace()
768        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
769        students_folder = self.portal_url.getPortalObject().campus.students
770        res = self.students_catalog(id=student_id)
771        if res:
772            st = res[0]
773        course = st.course
774        matric_no = st.matric_no
775        level = st.level
776        res = self.results_import(matric_no = matric_no)
777        if res:
778            results = res
779        logger.info('%s creating Level %s' % (student_id,level))
780        #
781        # Level
782        #
783        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
784        studycourse = getattr(student_obj,"study_course",None)
785        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
786        l = getattr(studycourse,level,None)
787        if l is None:
788            studycourse.invokeFactory('StudentStudyLevel', level)
789            l = getattr(studycourse, level)
790            self.portal_workflow.doActionFor(l,'open',dest_container=l)
791            l.getContent().edit(mapping={'Title': "Level %s" % level})
792        ###)
793
794    security.declarePublic('getHallInfo') ###(
795    def getHallInfo(self,bed):
796        """return Hall Info"""
797        info = {}
798        hall,block,room,letter = bed.split('_')
799        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
800        if res and len(res) == 1:
801            hall_brain = res[0]
802            hall_doc = hall_brain.getObject().getContent()
803        else:
804            return info
805        info['hall_title'] = hall_brain.Title
806        info['maintenance_code'] = hall_doc.maintenance_code
807        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
808        batch_doc = None
809        for brain in res:
810            if brain.id.startswith(info['maintenance_code']):
811                batch_doc = brain.getObject().getContent()
812                break
813        if batch_doc is None:
814            info['maintenance_fee'] = None
815        else:
816            info['maintenance_fee'] = batch_doc.cost
817        return info
818    ###)
819
820    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
821    def removePictureFolder(self,student_id):
822        """remove picture_folder by renaming it"""
823        path = 'images'
824        picture_path = os.path.join(i_home,path,student_id)
825        if not os.path.exists(picture_path):
826            return False
827        os.rename(picture_path,picture_path + "_removed")
828        return True
829    ###)
830
831    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
832    def restorePictureFolder(self,student_id):
833        """restore picture_folder by renaming it"""
834        path = 'images'
835        picture_path = os.path.join(i_home,path,student_id)
836        if not os.path.exists(picture_path + "_removed"):
837            return False
838        os.rename(picture_path + "_removed",picture_path)
839        return True
840    ###)
841
842    security.declarePublic('picturesExist') ###(
843    def picturesExist(self, ids,student_id=None):
844        """check if pictures exist in the filesystem"""
845        if student_id is None:
846            student_id = self.getStudentId()
847        if student_id is None:
848            return False
849        picture_path = os.path.join(images_base,student_id)
850        if not os.path.exists(picture_path):
851            return False
852        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
853        return set(ids).issubset(set(pictures))
854    ###)
855
856    security.declarePublic('picturesList') ###(
857    def picturesList(self):
858        """check if pictures exist in the filesystem"""
859        path = 'images'
860        student_id = self.getStudentId()
861        picture_path = os.path.join(i_home,path,student_id)
862        if not os.path.exists(picture_path):
863            return []
864        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
865    ###)
866
867    security.declarePublic('showFsPicture') ###(
868    def showFsPicture(self,path):
869        """return a picture from the filesystem"""
870        picture_path = os.path.join(i_home,path)
871        response = self.REQUEST.RESPONSE
872        #import pdb;pdb.set_trace()
873        registry = getToolByName(self, 'mimetypes_registry')
874        mimetype = str(registry.lookupExtension(path.lower()) or
875                    registry.lookupExtension('file.bin'))
876        if os.path.exists(picture_path):
877            response.setHeader('Content-type',mimetype)
878            return open(picture_path).read()
879        picture_path = os.path.join(i_home,'import',path)
880        if os.path.exists(picture_path):
881            return open(picture_path).read()
882    ###)
883
884    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
885    def deleteAllCourses(self,department="All"):
886        ''' delete the courses'''
887        pm = self.portal_membership
888        member = pm.getAuthenticatedMember()
889
890        if str(member) not in ("henrik","joachim"):
891            return "not possible"
892        if department == "All":
893            res = self.portal_catalog({'meta_type': 'Department'})
894        if len(res) < 1:
895            return "No Departments found"
896
897        deleted = []
898        for dep in res:
899            cf = dep.getObject().courses
900            if cf:
901                cf.manage_delObjects(ids=cf.objectIds())
902                deleted.append("deleted Courses in %s" % dep.getId)
903        return "\r".join(deleted)
904    ###)
905
906    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
907    def getLogfileLines(self,filename="event.log",numlines=20):
908        """Get last NUMLINES lines of logfile FILENAME.
909
910        Return last lines' of a file in the instances logfile directory as
911        a list. The number of returned lines equals `numlines' or less. If
912        less than `numlines' lines are available, the whole file ist
913        returned. If the file can not be opened or some other error
914        occurs, empty list is returend.
915        """
916        result = []
917        lines_hit = 0
918
919        # We only handle files in instances' log directory...
920        logpath = os.path.join(i_home, "log")
921        filename = str(os.path.abspath( os.path.join( logpath, filename )))
922        if not filename.startswith( logpath ):
923            # Attempt to access file outside log-dir...
924            return []
925
926        try:
927            fd = file( filename, "rb" )
928        except IOError:
929            return []
930        if not fd:
931            return []
932
933        if os.linesep == None:
934            linesep = '\n'
935        else:
936            linesep = os.linesep
937
938        # Try to find 'numlines' times a lineseparator, searching from end
939        # and moving to the beginning of file...
940        fd.seek( 0, 2) # Move to end of file...
941        while lines_hit < numlines:
942            if fd.read(1) == linesep[-1]: # This moves filedescriptor
943                                          # one step forward...
944                lines_hit += 1
945            try:
946                fd.seek( -2, 1) # Go two bytes back from current pos...
947            except IOError:
948                # We cannot go back two bytes. Maybe the file is too small...
949                break
950        fd.seek(2,1)
951
952        # Read all lines from current position...
953        result = fd.readlines()
954        # Remove line endings...
955        result = [x.strip() for x in result]
956        fd.close()
957        return result
958    ###)
959
960    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
961    def getCallbacksFromLog(self,filename):
962        """fix Online Payment Transactions from Z2.log entries"""
963        import transaction
964        import random
965        from cgi import parse_qs
966        from urlparse import urlparse
967        #from pdb import set_trace
968        wftool = self.portal_workflow
969        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
970        students_folder = self.portal_url.getPortalObject().campus.students
971        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
972        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
973        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
974        data = re.compile(s)
975        start = True
976        tr_count = 1
977        total = 0
978        #name = 'pume_results'
979        #name = 'epaymentsuccessful_z2log2'
980        name = filename
981        no_import = []
982        imported = []
983        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
984        try:
985            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
986        except:
987            logger.error('Error reading %s' % name)
988            return
989        tas = []
990        for line in transactions:
991            dict = {}
992            items = data.search(line)
993            dict['idict'] = idict = items.groupdict()
994            #print idict
995            #from pdb import set_trace;set_trace()
996            urlparsed = urlparse(idict['get'][4:])
997            #print urlparsed
998            path = urlparsed[2].split('/')
999            dict['student_id'] = student_id = path[8]
1000            dict['payment_id'] = payment_id = path[10]
1001            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
1002            tas.append(dict)
1003            tr_count += 1
1004        return tas
1005    ###)
1006
1007    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
1008    def importOnlinePaymentTransactions(self):
1009        """load Online Payment Transactions from CSV values"""
1010        import transaction
1011        import random
1012        #from pdb import set_trace
1013        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1014        opt = self.online_payments_import
1015        students_folder = self.portal_url.getPortalObject().campus.students
1016        start = True
1017        tr_count = 1
1018        total = 0
1019        #name = 'pume_results'
1020        name = 'OnlineTransactions'
1021        no_import = []
1022        imported = []
1023        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
1024        try:
1025            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
1026        except:
1027            logger.error('Error reading %s.csv' % name)
1028            return
1029        for pay_transaction in transactions:
1030            if start:
1031                start = False
1032                logger.info('Start loading from %s.csv' % name)
1033                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
1034                no_import.append('%s,"Error"' % s)
1035                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
1036                format_error = format + ',"%(Error)s"'
1037            data = {}
1038
1039            # format of the first file sent by Tayo
1040            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
1041            #data['student_id'] = student_id = pay_transaction['Payer ID']
1042            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1043            #data['response_code'] = response_code = pay_transaction['Resp Code']
1044            #data['amount'] = amount = pay_transaction['Amount']
1045
1046            # format of the second file sent by Tayo
1047            #data['datetime'] = date = 0
1048            #data['student_id'] = student_id = pay_transaction['Payer ID']
1049            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1050            #data['response_code'] = response_code = '00'
1051            #data['amount'] = amount = pay_transaction['Amount']
1052
1053            # format of the third file sent by Kehinde
1054            data['datetime'] = date = 0
1055            data['student_id'] = student_id = pay_transaction['customer_id']
1056            data['order_id'] = order_id = pay_transaction['merchant_reference']
1057            data['response_code'] = response_code = '00'
1058            data['amount'] = amount = pay_transaction['Amount']
1059
1060            dup = False
1061            if response_code == "12":
1062                continue
1063            try:
1064                opt.addRecord(**data)
1065            except ValueError:
1066                dup = True
1067            #from pdb import set_trace;set_trace()
1068            if dup:
1069                if response_code == "00":
1070                    try:
1071                        opt.modifyRecord(**data)
1072                    except:
1073                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
1074                        continue
1075                else:
1076                    pay_transaction['Error'] = "Duplicate order_id"
1077                    no_import.append( format_error % pay_transaction)
1078                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
1079                    continue
1080            tr_count += 1
1081            if tr_count > 1000:
1082                if len(no_import) > 0:
1083                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1084                             '\n'.join(no_import) + '\n')
1085                    no_import = []
1086                em = '%d transactions committed\n' % (tr_count)
1087                transaction.commit()
1088                regs = []
1089                logger.info(em)
1090                total += tr_count
1091                tr_count = 0
1092        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1093                                                '\n'.join(no_import))
1094        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
1095    ###)
1096
1097    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
1098    def mass_create_faculty(self,mapping):
1099        "create a faculty"
1100        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
1101        academics_folder = self.portal_url.getPortalObject().campus.academics
1102        fid = mapping['code']
1103        if getattr(academics_folder,fid,None) is not None:
1104            return '', "Faculty with ID: %s exists" % fid
1105        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
1106        try:
1107            academics_folder.invokeFactory('Faculty', fid)
1108        except BadRequest,E:
1109            return '', "%s" % E
1110        f = getattr(academics_folder,fid,None)
1111        f.getContent().edit(mapping=mapping)
1112        return fid,''
1113    ###)
1114
1115    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
1116    def mass_edit_faculty(self,mapping):
1117        "edit a faculty"
1118        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
1119        academics_folder = self.portal_url.getPortalObject().campus.academics
1120        fid = mapping['code']
1121        f = getattr(academics_folder,fid,None)
1122        if f is None:
1123            return '', "Faculty with ID: %s does not exist" % fid
1124        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
1125        f.getContent().edit(mapping=mapping)
1126        return fid,''
1127    ###)
1128
1129    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
1130    def mass_create_department(self,mapping):
1131        "create a department in the correct faculty"
1132        logger = logging.getLogger('WAeUPTool.mass_create_department')
1133        fid = mapping['faculty_code']
1134        if getattr(self,'_v_faculties',None) is None:
1135            res = self.portal_catalog(portal_type = "Faculty")
1136            self._v_faculties = {}
1137            for f in res:
1138                self._v_faculties[f.getId] = f.getObject()
1139        f = self._v_faculties.get(fid,None)
1140        if f is None:
1141            return '', "No Faculty with ID: %s" % fid
1142        else:
1143            did = mapping.get('code')
1144            d = getattr(f,did,None)
1145            if d is None or d.portal_type == "Faculty":
1146                logger.info('Creating Department %(code)s, %(title)s' % mapping)
1147                try:
1148                    f.invokeFactory('Department', did)
1149                except BadRequest,E:
1150                    return '', "%s" % E
1151                d = getattr(f,did)
1152                d.invokeFactory('CoursesFolder','courses')
1153                courses = getattr(d,'courses')
1154                dict = {'Title': 'Courses'}
1155                courses.getContent().edit(mapping=dict)
1156                d.invokeFactory('CertificatesFolder','certificates')
1157                certificates = getattr(d,'certificates')
1158                dict = {'Title': 'Certificates'}
1159                certificates.getContent().edit(mapping=dict)
1160            d.getContent().edit(mapping=mapping)
1161        return did,''
1162    ###)
1163
1164    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
1165    def mass_edit_department(self,mapping):
1166        "create a department in the correct faculty"
1167        logger = logging.getLogger('WAeUPTool.mass_create_department')
1168        academics_folder = self.portal_url.getPortalObject().campus.academics
1169        fid = mapping['faculty_code']
1170        did = mapping.get('code')
1171        try:
1172            d = getattr(getattr(academics_folder,fid),did,None)
1173        except KeyError:
1174            return '', "Department %s or Faculty %s wrong" % (did,fid)
1175        else:
1176            if d is None or d.portal_type == "Faculty":
1177                logger.info('Editing Department %(code)s, %(title)s' % mapping)
1178            d.getContent().edit(mapping=mapping)
1179        return did,''
1180    ###)
1181
1182    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1183    def mass_create_course(self,mapping):
1184        #import pdb;pdb.set_trace()
1185        if getattr(self,'_v_course_list',None) is None:
1186            self._v_course_list = []
1187        if getattr(self,'_v_departments',None) is None:
1188            res = self.portal_catalog(portal_type = "Department")
1189            self._v_department_courses = {}
1190            for d in res:
1191                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
1192        did = mapping['department_code']
1193        d = self._v_department_courses.get(did,None)
1194        if d is None:
1195            return '', "No Department with ID: %s" % did
1196        course_id = mapping.get('code')
1197        if course_id in self._v_course_list:
1198            return '', "Duplicate Course ID: %s" % did
1199        c = getattr(d,course_id,None)
1200        if c is not None:
1201            return '', "Duplicate Course ID: %s" % did
1202        try:
1203            d.invokeFactory('Course', course_id)
1204        except BadRequest,E:
1205            return '', "%s" % E
1206        self._v_course_list.append(course_id)
1207        c = getattr(d,course_id)
1208        c.getContent().edit(mapping=mapping)
1209        return course_id,''
1210    ###)
1211
1212    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1213    def mass_edit_course(self,mapping):
1214        #import pdb;pdb.set_trace()
1215        course_id = mapping.get('code')
1216        res = self.portal_catalog(id=course_id)
1217        if not res:
1218            return '', "No Course with ID: %s" % course_id
1219        c = res[0].getObject()
1220        c.getContent().edit(mapping=mapping)
1221        return course_id,''
1222    ###)
1223
1224    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1225    def mass_create_certificate(self,mapping):
1226        if getattr(self,'_v_certificate_list',None) is None:
1227            self._v_certificate_list = []
1228        if getattr(self,'_v_department_certificates',None) is None:
1229            res = self.portal_catalog(portal_type = "Department")
1230            self._v_department_certificates = {}
1231            for d in res:
1232                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
1233        did = mapping['department_code']
1234        d = self._v_department_certificates.get(did,None)
1235        if d is None:
1236            return '', "No Department with ID: %s" % did
1237        certificate_id = mapping.get('code')
1238        if certificate_id in self._v_certificate_list:
1239            return '', "Duplicate Certificate ID: %s" % did
1240        c = getattr(d,certificate_id,None)
1241        if c is not None:
1242            return '', "Duplicate Certificate ID: %s" % did
1243        try:
1244            d.invokeFactory('Certificate', certificate_id)
1245        except BadRequest,E:
1246            return '', "%s" % E
1247        self._v_certificate_list.append(certificate_id)
1248        c = getattr(d,certificate_id)
1249        c.getContent().edit(mapping=mapping)
1250        return certificate_id,''
1251    ###)
1252
1253    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1254    def mass_edit_certificate(self,mapping):
1255        #import pdb;pdb.set_trace()
1256        certificate_id = mapping.get('code')
1257        res = self.portal_catalog(id=certificate_id)
1258        if not res:
1259            return '', "No Certificate with ID: %s" % did
1260        c = res[0].getObject()
1261        c.getContent().edit(mapping=mapping)
1262        return certificate_id,''
1263    ###)
1264
1265    security.declareProtected(ModifyPortalContent,'mass_create_application') ###(
1266    def mass_create_application(self,mapping):
1267        #import pdb;pdb.set_trace()
1268        reg_no = mapping.get('reg_no')
1269        try:
1270            self.applicants_catalog.addRecord(**mapping)
1271        except ValueError:
1272            return '', "applicant record with reg_no %s already exists" % reg_no
1273        return reg_no,''
1274    ###)
1275
1276    security.declareProtected(ModifyPortalContent,'mass_edit_application') ###(
1277    def mass_edit_application(self,mapping):
1278        #import pdb;pdb.set_trace()
1279        reg_no = mapping.get('reg_no')
1280        try:
1281            self.applicants_catalog.modifyRecord(**mapping)
1282        except KeyError:
1283            return '', "applicant record with reg_no %s does not exist" % reg_no
1284        return reg_no,''
1285    ###)
1286
1287    security.declareProtected(ModifyPortalContent,'mass_create_course_result') ###(
1288    def mass_create_course_result(self,mapping):
1289        #import pdb;pdb.set_trace()
1290        if getattr(self,'_v_courses',None) is None:
1291            res = self.courses_catalog()
1292            self._v_courses = {}
1293            for brain in res:
1294                self._v_courses[brain.code] = brain
1295        course_id = mapping.get('code')
1296        if course_id not in self._v_courses.keys():
1297            return '', "No course with ID: %s" % did
1298        id_key = ''
1299        for id_key in ('student_id','matric_no'):
1300            id_field = mapping.get(id_key,None)
1301            if id_field is not None:
1302                student_id = id_field
1303                break
1304        query = Eq(id_key,id_field)
1305        res = self.students_catalog.evalAdvancedQuery(query)
1306        if not res:
1307            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1308        if id_field != "student_id":
1309            mapping['student_id'] = res[0].id
1310        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % mapping
1311        for k in ('semester',):
1312            mapping[k] = getattr(self._v_courses[course_id],k)
1313        try:
1314            self.course_results.addRecord(**mapping)
1315        except ValueError:
1316            return '', "course result already exists: %s" % key
1317        return key,''
1318    ###)
1319
1320    security.declareProtected(ModifyPortalContent,'mass_edit_course_result') ###(
1321    def mass_edit_course_result(self,mapping):
1322        #import pdb;pdb.set_trace()
1323        # if getattr(self,'_v_courses',None) is None:
1324        #     res = self.courses_catalog()
1325        #     self._v_courses = {}
1326        #     for brain in res:
1327        #         self._v_courses[brain.code] = brain
1328        # course_id = mapping.get('code')
1329        # if course_id not in self._v_courses.keys():
1330        #     return '', "No course with ID: %s" % did
1331        id_key = ''
1332        for id_key in ('student_id','matric_no'):
1333            id_field = mapping.get(id_key,None)
1334            if id_field is not None:
1335                student_id = id_field
1336                break
1337        query = Eq(id_key,id_field)
1338        res = self.students_catalog.evalAdvancedQuery(query)
1339        if not res:
1340            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1341        if id_field != "student_id":
1342            mapping['student_id'] = res[0].id
1343        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % mapping
1344        # for k in ('semester',):
1345        #     mapping[k] = getattr(self._v_courses[course_id],k)
1346        try:
1347            self.course_results.modifyRecord(**mapping)
1348        except KeyError:
1349            return '', "No course result to edit: %s" % key
1350        return key,''
1351    ###)
1352
1353    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1354    def mass_create_certificate_course(self,mapping):
1355        if getattr(self,'_v_courses',None) is None:
1356            res = self.courses_catalog()
1357            self._v_courses= [course.code for course in res]
1358        if getattr(self,'_v_ceritficates',None) is None:
1359            res = self.portal_catalog(portal_type = "Certificate")
1360            self._v_certificates = {}
1361            for cert in res:
1362                self._v_certificates[cert.getId] = cert.getObject()
1363        certificate_course_id = mapping.get('code')
1364        if certificate_course_id not in self._v_courses:
1365            return '', "No Course with ID: %s" % certificate_course_id
1366        cert_id = mapping['certificate_code']
1367        cert = self._v_certificates.get(cert_id,None)
1368        if cert is None:
1369            return '', "No Certificate with ID: %s" % cert_id
1370        level_id = mapping.get('level')
1371        level = getattr(cert,level_id,None)
1372        if level is None:
1373            cert.invokeFactory('StudyLevel', level_id)
1374            level = getattr(cert,level_id,None)
1375        elif hasattr(level,certificate_course_id):
1376            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1377            (certificate_course_id,cert_id,level_id)
1378        level.invokeFactory('CertificateCourse', certificate_course_id)
1379        c = getattr(level,certificate_course_id)
1380        c.getContent().edit(mapping=mapping)
1381        return certificate_course_id,''
1382    ###)
1383
1384    field2types_student = {   ###(
1385                      'StudentApplication':
1386                          {'id': 'application',
1387                           'title': 'Application Data',
1388                           'wf_transition_return': 'close',
1389                           'wf_transition_admit': 'remain',
1390                           'fields':
1391                             ('jamb_reg_no',
1392                              'entry_mode',
1393                              'entry_session',
1394                              'jamb_score',
1395                              'app_email',
1396                              'jamb_age',
1397                              'jamb_state',
1398                              'jamb_lga',
1399                              )
1400                              },
1401                      #'StudentPume':
1402                      #    {'id': 'pume',
1403                      #     'title': 'Pume Data',
1404                      #     'wf_transition_return': 'close',
1405                      #     'wf_transition_admit': 'close',
1406                      #     'fields':
1407                      #       ('pume_score',
1408                      #        )
1409                      #        },
1410                      'StudentClearance':
1411                          {'id': 'clearance',
1412                           'title': 'Clearance/Eligibility Record',
1413                           'wf_transition_return': 'close',
1414                           'wf_transition_admit': 'remain',
1415                           'fields':
1416                             ('matric_no',
1417                              'nationality',
1418                              'lga',
1419                              'birthday',
1420                              )
1421                              },
1422                         'StudentPersonal':
1423                          {'id': 'personal',
1424                           'title': 'Personal Data',
1425                           'wf_transition_return': 'open',
1426                           'wf_transition_admit': 'remain',
1427                           'fields':
1428                             ('firstname',
1429                              'middlename',
1430                              'lastname',
1431                              'sex',
1432                              'email',
1433                              'phone',
1434                              'perm_address',
1435                              )
1436                              },
1437                         'StudentStudyCourse':
1438                          {'id': 'study_course',
1439                           'title': 'Study Course',
1440                           'wf_transition_return': 'open',
1441                           'wf_transition_admit': 'remain',
1442                           'fields':
1443                             ('study_course',
1444                              'current_level',
1445                              'current_session',
1446                              'current_mode',
1447                              'current_verdict',
1448                              'previous_verdict',
1449                              )
1450                              },
1451
1452                         'PaymentsFolder':
1453                          {'id': 'payments',
1454                           'title': 'Payments',
1455                           'wf_transition_return': 'open',
1456                           'wf_transition_admit': 'open',
1457                           'fields':
1458                             ()
1459                              },
1460                         }
1461    ###)
1462
1463    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1464    def mass_create_student(self,mapping):
1465        "create a students record due import"
1466        logger = logging.getLogger('WAeUPTool.mass_create_student')
1467        students_folder = self.portal_url.getPortalObject().campus.students
1468        jamb_reg_no = mapping.get('jamb_reg_no',None)
1469        if jamb_reg_no:
1470            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1471            if res:
1472                return '',"jamb_reg_no exists"
1473        matric_no = mapping.get('matric_no',None)
1474        if matric_no:
1475            res = self.students_catalog(matric_no = matric_no)
1476            if res:
1477                return '',"matric_no exists"
1478        sid = self.waeup_tool.generateStudentId('?')
1479        students_folder.invokeFactory('Student', sid)
1480        student_obj = getattr(students_folder,sid)
1481        f2t = self.field2types_student
1482        d = {}
1483        transition = mapping.get('reg_transition','admit')
1484        if transition not in ('admit','return'):
1485            return '',"no valid transition provided"
1486        for pt in f2t.keys():
1487            student_obj.invokeFactory(pt,f2t[pt]['id'])
1488            sub_obj = getattr(student_obj,f2t[pt]['id'])
1489            sub_doc = sub_obj.getContent()
1490            d['Title'] = f2t[pt]['title']
1491            for field in f2t[pt]['fields']:
1492                d[field] = mapping.get(field,'')
1493
1494            if pt == "StudentApplication":
1495                d['jamb_sex']  = 'M'
1496                if mapping.get('sex'):
1497                    d['jamb_sex']  = 'F'
1498                d['jamb_firstname'] = mapping.get('firstname',None)
1499                d['jamb_middlename'] = mapping.get('middlename',None)
1500                d['jamb_lastname'] = mapping.get('lastname',None)
1501
1502            # if pt == "StudyCourse":
1503            #     for von,zu in (('entry_mode','current_mode'),
1504            #                    ('entry_session','current_session')):
1505            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1506            #             d[zu] = mapping[von]
1507            sub_doc.edit(mapping = d)
1508
1509            #import pdb;pdb.set_trace()
1510            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
1511            if new_state != "remain":
1512                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1513        self.portal_workflow.doActionFor(student_obj,transition)
1514        student_obj.manage_setLocalRoles(sid, ['Owner',])
1515        return sid,''
1516    ###)
1517
1518    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1519    def mass_edit_student(self,mapping):
1520        "edit a students record due import"
1521        logger = logging.getLogger('WAeUPTool.mass_edit_student')
1522        students_folder = self.portal_url.getPortalObject().campus.students
1523        sid = mapping.get('id',None)
1524        jamb_reg_no = mapping.get('jamb_reg_no',None)
1525        matric_no = mapping.get('matric_no',None)
1526        editable_keys = mapping.keys()
1527        if sid:
1528            res = self.students_catalog(id = sid)
1529            if not res:
1530                return '',"no student with id %s" % sid
1531            if matric_no and res[0].matric_no and\
1532              matric_no != res[0].matric_no:
1533                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1534            if jamb_reg_no and res[0].jamb_reg_no and\
1535              jamb_reg_no != res[0].jamb_reg_no:
1536                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
1537        elif jamb_reg_no:
1538            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1539            if not res:
1540                return '',"no student with jamb_reg_no %s" % jamb_reg_no
1541            editable_keys.remove('jamb_reg_no')
1542        elif matric_no:
1543            res = self.students_catalog(matric_no = matric_no)
1544            if not res:
1545                return '',"no student with matric_no %s" % matric_no
1546            editable_keys.remove('matric_no')
1547
1548        ## included only to change wf state from admitted to returning
1549        #if res[0].review_state not in ('admitted','objection_raised'):
1550        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1551        ## end inclusion
1552
1553        sid = res[0].id
1554        student_obj = getattr(students_folder,sid)
1555        f2t = self.field2types_student
1556        d = {}
1557        #import pdb;pdb.set_trace()
1558        any_change = False
1559        for pt in f2t.keys():
1560            if pt == "student_application":
1561                d['jamb_sex']  = 'M'
1562                if mapping.get('sex'):
1563                    d['jamb_sex']  = 'F'
1564            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
1565            if intersect:
1566                sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1567                if sub_obj is None:
1568                    try:
1569                        student_obj.invokeFactory(pt,f2t[pt]['id'])
1570                    except:
1571                        continue
1572                    sub_obj = getattr(student_obj,f2t[pt]['id'])
1573                    d['Title'] = f2t[pt]['title']
1574                sub_doc = sub_obj.getContent()
1575                for field in intersect:
1576                    changed = False
1577                    if getattr(sub_doc,field,None) != mapping.get(field,''):
1578                        any_change = True
1579                        changed = True
1580                        d[field] = mapping.get(field,'')
1581                    if changed:
1582                        sub_doc.edit(mapping = d)
1583
1584
1585        ## included only to change wf state from admitted to returning
1586        #    if res[0].review_state in ('admitted','objection_raised'):
1587        #        new_state = f2t[pt]['wf_transition_return']
1588        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1589        #        if sub_obj and new_state != "remain":
1590        #            try:
1591        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1592        #            except:
1593        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1594        #                pass
1595        #if res[0].review_state in ('admitted','objection_raised'):
1596        #    wfaction = 'return'
1597        #    try:
1598        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1599        #        logger.info('%s, wf state changed' % sid)
1600        #        any_change = True
1601        #    except:
1602        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1603        #        pass
1604        ## end inclusion
1605
1606
1607        if any_change:
1608            return sid,''
1609        else:
1610            return sid,'not modified'
1611    ###)
1612
1613    security.declareProtected(ModifyPortalContent,"importData")###(
1614    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
1615        """load data from CSV values"""
1616        import transaction
1617        import random
1618
1619        pm = self.portal_membership
1620        member = pm.getAuthenticatedMember()
1621
1622        logger = logging.getLogger('WAeUPTool.importData')
1623        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1624        students_folder = self.portal_url.getPortalObject().campus.students
1625        start = True
1626        tr_count = 0
1627        total_imported = 0
1628        total_not_imported = 0
1629        total = 0
1630        iname = "import_%s" % name
1631        if iname == 'import_application':
1632            commit_after = 2000
1633        else:
1634            commit_after = 100
1635        stool = getToolByName(self, 'portal_schemas')
1636        ltool = getToolByName(self, 'portal_layouts')
1637        schema = stool._getOb(iname)
1638        if schema is None:
1639            em = 'No such schema %s' % iname
1640            logger.error('No such schema %s' % iname)
1641            return em
1642        layout = ltool._getOb(iname)
1643        if layout is None:
1644            em = 'No such layout %s' % iname
1645            logger.error(em)
1646            return em
1647        validators = {}
1648        for widget in layout.keys():
1649            validators[widget] = layout[widget].validate
1650        #import pdb;pdb.set_trace()
1651        mode = "create"
1652        if edit:
1653            mode = "edit"
1654        importer_name = "mass_%(mode)s_%(name)s" % vars()
1655        importer = getattr(self, '%s' % importer_name,None)
1656        if importer is None:
1657            em = 'No importer function %s' % importer_name
1658            logger.error(em)
1659            return em
1660        not_imported = []
1661        imported = []
1662        try:
1663            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
1664        except:
1665            em = 'Error reading %s.csv' % filename
1666            logger.error(em)
1667            return em
1668        for item in items:
1669            if start:
1670                start = False
1671                adapters = [MappingStorageAdapter(schema, item)]
1672                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
1673                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
1674                import_keys = [k for k in attrs if not k.startswith('ignore')]
1675                diff2schema = set(import_keys).difference(set(schema.keys()))
1676                diff2layout = set(import_keys).difference(set(layout.keys()))
1677                if diff2schema:
1678                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
1679                    return em
1680                if mode == "create":
1681                    required_keys = [layout.getIdUnprefixed(id)
1682                                     for id,widget in layout.objectItems()
1683                                     if widget.is_required]
1684                    if not set(required_keys).issubset(set(import_keys)):
1685                        diff2import = set(required_keys).difference(set(import_keys))
1686                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
1687                        return em
1688                s = ','.join(['"%s"' % fn for fn in import_keys])
1689                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
1690                s = '"id",' + s
1691                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
1692                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
1693                format_error = format + ',"%(Error)s"'
1694                format = '"%(id)s",'+ format
1695
1696            dm = DataModel(item, adapters,context=self)
1697            ds = DataStructure(data=item,datamodel=dm)
1698            error_string = ""
1699            total += 1
1700            for k in import_keys:
1701                if not validators[k](ds,mode=mode):
1702                    error_string += " %s : %s" % (k,
1703                                                  self.translation_service(ds.getError(k),
1704                                                                           ds.getErrorMapping(k)))
1705            if not error_string:
1706                temp_item = item.copy()
1707                temp_item.update(dm)
1708                temp_item['id'],error = importer(temp_item)
1709                if error:
1710                    error_string += error
1711                else:
1712                    item = temp_item
1713            if error_string:
1714                item['Error'] = error_string
1715                not_imported.append(format_error % item)
1716                total_not_imported += 1
1717            else:
1718                em = format % item
1719                imported.append(em)
1720                tr_count += 1
1721                total_imported += 1
1722                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
1723
1724            if total and not total % commit_after:
1725                transaction.commit()
1726                if len(not_imported) > 0:
1727                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1728                             '\n'.join(not_imported) + '\n')
1729                    not_imported = []
1730                if len(imported) > 0:
1731                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1732                             '\n'.join(imported) + '\n')
1733                    imported = []
1734                em = '%d transactions committed\n' % (tr_count)
1735                regs = []
1736                logger.info(em)
1737                tr_count = 0
1738                #if total > 100:
1739                #    return
1740        if len(imported) > 0:
1741            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1742                                                '\n'.join(imported))
1743        if len(not_imported) > 0:
1744            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1745                                                '\n'.join(not_imported))
1746        em = "Finished: %d imported, %d not imported (of total %d)" % (total_imported,total_not_imported,total)
1747        logger.info(em)
1748        return em
1749    ###)
1750
1751    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
1752    def moveImagesToFS(self,student_id="O738726"):
1753        "move the images to the filesystem"
1754        images_dir = os.path.join("%s" % images_base,student_id)
1755        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1756        stool = getToolByName(self, 'portal_schemas')
1757        schemas = ['student_application',
1758                   'student_clearance',
1759                   ]
1760        created = False
1761        for schema_id in schemas:
1762            schema = stool._getOb(schema_id)
1763            object = getattr(student_folder,schema_id[len('student_'):],None)
1764            if object is None:
1765                continue
1766            doc = object.getContent()
1767            for key in schema.keys():
1768                if schema[key].meta_type != "CPS Image Field":
1769                    continue
1770                #import pdb;pdb.set_trace()
1771                image = getattr(doc,key,None)
1772                if not image or not hasattr(image,"data"):
1773                    continue
1774                if not created:
1775                    if not os.path.exists(images_dir):
1776                        os.mkdir(images_dir)
1777                    created = True
1778                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
1779                open(filename,"wb").write(str(image.data))
1780    ###)
1781
1782    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
1783    def movePassportToFS(self,student_id="O738726"):
1784        "move the passports to the filesystem"
1785        images_dir = os.path.join("%s" % i_home,'passports')
1786        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1787        stool = getToolByName(self, 'portal_schemas')
1788        schemas = ['student_application',
1789                   #'student_clearance',
1790                   ]
1791        created = False
1792        for schema_id in schemas:
1793            schema = stool._getOb(schema_id)
1794            object = getattr(student_folder,schema_id[len('student_'):],None)
1795            if object is None:
1796                continue
1797            doc = object.getContent()
1798            for key in schema.keys():
1799                if schema[key].meta_type != "CPS Image Field":
1800                    continue
1801                #import pdb;pdb.set_trace()
1802                image = getattr(doc,key)
1803                if not hasattr(image,"data"):
1804                    continue
1805                if not created:
1806                    if not os.path.exists(images_dir):
1807                        os.mkdir(images_dir)
1808                    created = True
1809                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
1810                open(filename,"wb").write(str(image.data))
1811    ###)
1812
1813InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.