source: WAeUP_SRP/base/WAeUPTool.py @ 2413

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

modified loadstudentFoto to copy file

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