source: WAeUP_SRP/base/WAeUPTool.py @ 2579

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

Ziwschenversion

Ich arbeite noch an layout_application_edit.pt

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