source: WAeUP_SRP/base/WAeUPTool.py @ 2587

Last change on this file since 2587 was 2580, checked in by joachim, 17 years ago

copy passport foto

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