source: WAeUP_SRP/base/WAeUPTool.py @ 2425

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

use waeup_tool.picturesExist for passport check

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