source: WAeUP_SRP/base/WAeUPTool.py @ 2954

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

set entry_mode and current_mode for pce and prence students

  • Property svn:keywords set to Id
File size: 84.4 KB
Line 
1#-*- mode: python; mode: fold -*-
2# (C) Copyright 2005 The WAeUP group  <http://www.waeup.org>
3# Author: Joachim Schmitz (js@aixtraware.de)
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 2 as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17# 02111-1307, USA.
18#
19# $Id: WAeUPTool.py 2950 2007-12-18 06:55:30Z henrik $
20"""The WAeUP Tool Box.
21"""
22
23from AccessControl import ClassSecurityInfo
24from Acquisition import aq_inner
25from Acquisition import aq_parent
26from Globals import DTMLFile
27from Globals import InitializeClass
28from OFS.SimpleItem import SimpleItem
29from zExceptions import BadRequest
30
31from Products.CMFCore.utils import getToolByName
32from Products.CPSSchemas.DataStructure import DataStructure
33from Products.CPSSchemas.DataModel import DataModel
34from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
35from Products.CMFCore.ActionProviderBase import ActionProviderBase
36from Products.CMFCore.permissions import View
37from Products.ZCatalog.ZCatalog import ZCatalog
38from Products.CMFCore.permissions import ModifyPortalContent
39from Products.CMFCore.permissions import ManagePortal
40from Products.CMFCore.utils import UniqueObject
41from Products.CMFCore.URLTool import URLTool
42from Products.CMFCore.utils import getToolByName
43from Students import makeCertificateCode
44from Globals import package_home,INSTANCE_HOME
45import DateTime,time
46import logging
47import transaction
48import csv,re,os,sys
49from shutil import copy2
50from Products.AdvancedQuery import Eq, Between, Le,In
51
52p_home = package_home(globals())
53i_home = INSTANCE_HOME
54images_base = os.path.join(i_home,"images")
55
56def getImagesDir(student_id):
57    return os.path.join("%s" % images_base,student_id[0],student_id)
58
59def getObject(object,name):
60    if object.hasObject(name):
61        return getattr(object,name)
62    return None
63
64class WAeUPTool(UniqueObject, SimpleItem, ActionProviderBase):
65    """WAeUP tool"""
66
67    id = 'waeup_tool'
68    meta_type = 'WAeUP Tool'
69    _actions = ()
70    security = ClassSecurityInfo()
71    security.declareObjectProtected(View)
72    manage_options = ( ActionProviderBase.manage_options
73                     + SimpleItem.manage_options
74                     )
75
76    def rwrite(self,s): ###(
77        response = self.REQUEST.RESPONSE
78        response.setHeader('Content-type','text/html; charset=ISO-8859-15')
79        response.write("%s<br />\r\n" % s)
80    ###)
81
82    def addtodict(self,d,key,item): ###(
83        d[key].append(item)
84        return d[key]
85    ###)
86
87    def sleep(self,secs): ###(
88        "sleep"
89        import time
90        time.sleep(secs)
91        return
92
93###)
94
95    security.declareProtected(View,'updateRoleMappingsFor') ###(
96    def updateRoleMappingsFor(self,wf_definition,ob):
97        "do so for public"
98        wf_def = getattr(self.portal_workflow,wf_definition)
99        wf_def.updateRoleMappingsFor(ob)
100    ###)
101
102    security.declareProtected(ModifyPortalContent,'openLog') ###(
103    def openLog(self,name):
104        """open a log file"""
105        version = 1
106        path = "%s/log/%s_%d.log" % (i_home,name,version)
107        while os.path.exists(path):
108            version += 1
109            path = "%s/log/%s_%d.log" % (i_home,name,version)
110        log = open(path,"w")
111        return log
112    ###)
113
114    security.declareProtected(ModifyPortalContent,'bypassQueueCatalog') ###(
115    def bypassQueueCatalog(self,enable=True):
116        """bypass the QueueCatalog by setting all indexes to process imediate,
117        if enable is True (default) the old settings are restored
118        """
119
120    ###)
121
122    security.declareProtected(ModifyPortalContent,'measureOaT') ###(
123    def measureOaT(self,method="a",probe="1000",nr_pts="1"):
124        """measure Object access Time"""
125        import random
126        if hasattr(self,'portal_catalog_real'):
127            aq_portal = self.portal_catalog_real.evalAdvancedQuery
128        else:
129            aq_portal = self.portal_catalog.evalAdvancedQuery
130        nr_pts = int(nr_pts)
131        probe = int(probe)
132        intervall = probe/10
133        objects = ("application","clearance","personal")
134        portal_types = ("StudentApplication","StudentClearance","StudentPersonal")
135        #i = random.randrange(num_objects)
136        count = 0
137        found = 0
138        not_found = 0
139        t_found = 0
140        t_not_found = 0
141        time_found = time_not_found = 0.0
142        t_time_found = t_time_not_found = 0.0
143        accessed = []
144        t_min = 1000
145        t_max = 0
146        #import pdb;pdb.set_trace()
147        students = self.portal_catalog(portal_type="Student")
148        num_students = len(students)
149        if method == "d":
150            query = Eq('path','/uniben/campus/students') & In('portal_type',portal_types[:nr_pts])
151            res = aq_portal(query)
152            brains = {}
153            for r in res:
154                sid = r.relative_path.split('/')[-2]
155                if brains.has_key(sid):
156                    brains[sid][r.portal_type] = r
157                else:
158                    brains[sid] = {r.portal_type : r}
159            brains_list = brains.keys()
160            num_objects = len(brains_list)
161        else:
162            num_objects = num_students
163        print "="*40
164        print "method: %s probes: %d nr_pts: %d num_objects: %d" % (method,
165                                                                        probe,
166                                                                        nr_pts,
167                                                                        num_objects)
168        print "nr found/not time found/not min/max"
169        elapse = time.time()
170        i_elapse = time.time()
171        c_elapse = time.clock()
172        for c in range(1,probe + 1):
173            i = random.randrange(num_objects)
174            if method in ('a','b','c'):
175                student_brain = students[i]
176            elif method == "d":
177                #import pdb;pdb.set_trace()
178                student_brain = brains[brains_list[i]]
179            if method == "c":
180                query = Eq('path',student_brain.getPath()) & In('portal_type',portal_types[:nr_pts])
181                res = aq_portal(query)
182                this_portal_types = [r.portal_type for r in res]
183            for i in range(nr_pts):
184                oid = objects[i]
185                if method == "a":
186                    try:
187                        student_path = student_brain.getPath()
188                        path = "%s/%s" % (student_path,oid)
189                        doc = self.unrestrictedTraverse(path).getContent()
190                        found += 1
191                        i_time = time.time() - i_elapse
192                        time_found += i_time
193                    except:
194                        not_found += 1
195                        i_time = time.time() - i_elapse
196                        time_not_found += i_time
197                        pass
198                elif method == "b":
199                    try:
200                        student_object = student_brain.getObject()
201                        doc = getattr(student_object,oid).getContent()
202                        found += 1
203                        i_time = time.time() - i_elapse
204                        time_found += i_time
205                    except:
206                        i_time = time.time() - i_elapse
207                        time_not_found += i_time
208                        not_found += 1
209                        pass
210                elif method == "c":
211                    if portal_types[i] in this_portal_types:
212                        found += 1
213                        doc = res[this_portal_types.index(portal_types[i])].getObject().getContent()
214                        i_time = time.time() - i_elapse
215                        time_found += i_time
216                    else:
217                        not_found += 1
218                        i_time = time.time() - i_elapse
219                        time_not_found += i_time
220                elif method == "d":
221                    if student_brain.has_key(portal_types[i]):
222                        found += 1
223                        doc = student_brain[portal_types[i]].getObject().getContent()
224                        i_time = time.time() - i_elapse
225                        time_found += i_time
226                    else:
227                        not_found += 1
228                        i_time = time.time() - i_elapse
229                        time_not_found += i_time
230                i_elapse = time.time()
231            if c and (c % intervall == 0):
232                #i_time = time.time() - i_elapse
233                t_per = 0.0
234                if found:
235                    t_per = time_found/found
236                if t_per > t_max:
237                    t_max = t_per
238                if t_per > 0.0 and t_per < t_min:
239                    t_min = t_per
240                itf = 0.0
241                if found:
242                    itf = time_found/found
243                itnf = 0.0
244                if not_found :
245                    itnf = time_not_found / not_found
246                interval_time = time_found + time_not_found
247                s = "%(c)d: %(found)d/%(not_found)d " % vars()
248                s += "%(interval_time)6.2f %(itf)6.4f/%(itnf)6.4f " % vars()
249                s += "%(t_min)6.4f/%(t_max)6.4f" %  vars()
250                print s
251                t_found += found
252                t_not_found += not_found
253                t_time_found += time_found
254                t_time_not_found += time_not_found
255                time_found = time_not_found = 0.0
256                found = not_found = 0
257        # t_found += found
258        # t_not_found += not_found
259        elapse = time.time() - elapse
260        itf = 0.0
261        if t_found:
262            itf = t_time_found/t_found
263        itnf = 0.0
264        if t_not_found:
265            itnf = t_time_not_found / t_not_found
266        #c_elapse = time.clock() - c_elapse
267        s = "%(probe)d: %(t_found)d/%(t_not_found)d " % vars()
268        s += "%(elapse)6.2f %(itf)6.4f/%(itnf)6.4f " % vars()
269        s += "%(t_min)6.4f/%(t_max)6.4f" %  vars()
270        print "-"*40
271        print s
272        rel_found = float(t_found)/probe
273        rel_not_found = float(t_not_found)/probe
274        estimated_total_time = num_objects*(rel_found*itf + rel_not_found*itnf)
275        print estimated_total_time
276    ###)
277
278    security.declareProtected(ModifyPortalContent,'writeLog') ###(
279    def writeLog(self,logfile,s):
280        """write to the log file"""
281        logfile.write(s)
282
283###)
284
285    def generateStudentId(self,letter): ###(
286        import random
287        r = random
288        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
289        if letter == '?':
290            letter= r.choice('ABCDEFGHKLMNPQRSTUVWXY')
291        sid = "%c%d" % (letter,r.randint(99999,1000000))
292        students = self.portal_url.getPortalObject().campus.students
293##        while hasattr(students, sid):
294##            sid = "%c%d" % (letter,r.randint(99999,1000000))
295        while self.students_catalog(id = sid):
296            sid = "%c%d" % (letter,r.randint(99999,1000000))
297        return sid
298    ###)
299
300    def generatePassword(self,s=None): ###(
301        import random
302        r = random
303        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
304        if s is None:
305            s = 'abcdefghklmnpqrstuvwxy23456789'
306        pw = ''
307        while len(pw) < 6:
308            pw += r.choice(s)
309        return pw
310    ###)
311
312    security.declareProtected(ModifyPortalContent, 'dumpSchoolfeePayments') ###(
313    def dumpSchoolfeePayments(self):
314        "dump paid schoolfees"
315        mtool = self.portal_membership
316        member = mtool.getAuthenticatedMember()
317        logger = logging.getLogger('WAeUPTool.dumpSchoolfees')
318        aq_student = self.students_catalog.evalAdvancedQuery
319        query = In('review_state',('schoolfee_paid',
320                                   'courses_registered',
321                                   'courses_validated',
322                                   ))
323        res = aq_student(query)
324        #import pdb;pdb.set_trace()
325        l = []
326        logger.info("start for %d" % len(res))
327        count = 1
328        log_after = 100
329        for student in res:
330            if not count % log_after:
331                logger.info("processed %d total %d" % (log_after,count))
332            count += 1
333            fee_dict =self.getSchoolFee(student)
334            fulltime = student.mode.endswith('_ft')
335            d = {}
336            d['student_id'] = student.id
337            d['name'] = student.name
338            d['amount'] = fee_dict.get(new_returning)
339            l += d,
340        csv_name = self.dumpListToCSV(l,'payments')
341        logger.info('%s dumped payments to %s' % (member,export_file))
342    ###)
343
344    security.declarePublic('dumpListToCSV') ###(
345    def dumpListToCSV(self,l,filename,fields=None):
346        """dump a list of dicts to a CSV file"""
347        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
348        export_file = "%s/export/%s_%s.csv" % (i_home,filename,current,)
349        if fields is None:
350            fields = l[0].keys()
351        headline = ','.join(fields)
352        out = open(export_file,"wb")
353        out.write(headline +'\n')
354        out.close()
355        out = open(export_file,"a")
356        csv_writer = csv.DictWriter(out,fields,)
357        csv_writer.writerows(l)
358        return export_file
359    ###)
360
361    security.declareProtected(ManagePortal, 'listMembers') ###(
362    def listMembers(self):
363        "list all members"
364        mtool = self.portal_membership
365        member = mtool.getAuthenticatedMember()
366        logger = logging.getLogger('WAeUPTool.listMembers')
367        if str(member) not in ('admin','joachim'):
368            logger.info('%s tried to list members' % (member))
369            return None
370        members = self.portal_directories.members
371        all = members.listEntryIdsAndTitles()
372        l = []
373        for user_id,name in all:
374            d = {}
375            d['user_id'] = user_id
376            d['name'] = name
377            d['pw'] = getattr(getattr(members,user_id),'password')
378            d['email'] = getattr(getattr(members,user_id),'email')
379            d['groups'] = " ".join(getattr(getattr(members,user_id),'groups'))
380            d['roles'] = " ".join(getattr(getattr(members,user_id),'roles'))
381            l += d,
382        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
383        export_file = "%s/export/member_list_%s.csv" % (i_home,current,)
384        logger.info('%s dumped memberlist to %s' % (member,export_file))
385        fields = l[0].keys()
386        headline = ','.join(fields)
387        out = open(export_file,"wb")
388        out.write(headline +'\n')
389        out.close()
390        out = open(export_file,"a")
391        csv_writer = csv.DictWriter(out,fields,)
392        csv_writer.writerows(l)
393    ###)
394
395    security.declareProtected(ManagePortal, 'removeDeletedDocIds') ###(
396    def removeDeletedDocIds(self, max=1000):
397        """
398        remove deleted docids from repository commit after max
399        """
400        logger = logging.getLogger('WAeUPTool.removeDeletedDocIds')
401        repository = getToolByName(self, 'portal_repository')
402        pxtool = getToolByName(self, 'portal_proxies')
403        logger.info('start')
404        pxtool_infos = pxtool.getRevisionsUsed()
405        logger.info('found  %d used revisions ' % (len(pxtool_infos)))
406
407        nb_revs = 0
408        docids_d = {} # all docids
409        unused_docids_d = {} # all docids that are unused
410        ids_unused_revs_docids = [] # ids for revs of unused docids
411        unused_ids = [] # ids for unused revs
412        total = 0
413        idlist = repository.objectIds()
414        to_delete = 0
415        found = False
416        for id in idlist:
417            docid, rev = repository._splitId(id)
418            if docid is None:
419                logger.info("invalid doc_id %s" % docid)
420                continue
421            nb_revs += 1
422            if not pxtool_infos.has_key(docid):
423                found = True
424                to_delete += 1
425                unused_ids.append(id)
426            elif not pxtool_infos[docid].has_key(rev):
427                found = True
428                to_delete += 1
429                unused_ids.append(id)
430            if found and not to_delete % max:
431                found = False
432                #import pdb;pdb.set_trace()
433                repository.manage_delObjects(unused_ids)
434                transaction.commit()
435                logger.info('removed %d total %d unused docids ' % (max,to_delete))
436        else:
437            if unused_ids:
438                repository.manage_delObjects(unused_ids)
439                transaction.commit()
440        logger.info('finished removing %d unused docids ' % (to_delete))
441
442
443###)
444
445    security.declareProtected(View,'getCredential') ###(
446    def getCredential(self,student_id):
447        student_entry = getattr(self.portal_directories.students,student_id,None)
448        if not self.isStaff():
449            mtool = self.portal_membership
450            member = mtool.getAuthenticatedMember()
451            logger = logging.getLogger('WAeUPTool.getCredential')
452            logger.info('%s tried to access password of %s' % (member,student_id))
453            return None
454        if student_entry is None:
455            return None
456        return getattr(student_entry,"password","not set")
457    ###)
458
459    security.declarePublic('checkPassword') ###(
460    def checkPassword(self,student_id,password):
461        student_entry = getattr(self.portal_directories.students,student_id,None)
462        if student_entry is None:
463            return False
464        return getattr(student_entry,"password","not set") == password
465    ###)
466
467    security.declarePublic('checkGenericPassword') ###(
468    def checkGenericPassword(self,member_id):
469        member_entry = getattr(self.portal_directories.members,member_id,None)
470        if member_entry is None:
471            return False
472        ltool = getToolByName(self, 'portal_layouts')
473        unsecure_words = ltool._getOb('members')['w__password'].check_words
474        password = getattr(member_entry,"password","not set")
475        is_unsecure = password in unsecure_words
476        if is_unsecure:
477            logger = logging.getLogger('WAeUPTool.checkGenericPassword')
478            logger.info('Member %s tried to log in with unsecure password %s' %(member_id,password))
479        return is_unsecure
480    ###)
481
482    security.declareProtected(ModifyPortalContent,'editPassword') ###(
483    def editPassword(self,student_id,password):
484        "edit a student password"
485        student_entry = getattr(self.portal_directories.students,student_id,None)
486        if student_entry is None:
487            return
488        setattr(student_entry,'password',password)
489    ###)
490
491    security.declareProtected(ModifyPortalContent,'doCommit') ###(
492    def doCommit(self,logger=None):
493        "commit some transactions"
494        transaction.commit()
495    ###)
496
497    security.declarePublic('loadStudentFoto') ###(
498    def loadStudentFoto(self,student,filename,folder):
499        "return a student passport picture"
500        #import pdb;pdb.set_trace()
501        picture ="%s/import/%s/%s" % (i_home,folder,filename)
502        student_id = student.getId()
503        images_dir = getImagesDir(student_id)
504        if not os.path.exists(images_dir):
505            os.mkdir(images_dir)
506        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
507        for extension in ('.jpg','.JPG'):
508            fullname = "%(picture)s%(extension)s" % vars()
509            if os.path.exists(fullname):
510                copy2(fullname,image_name)
511                return "successfully copied passport picture"
512        return "passport picture not found: %s.jpg or .JPG" % picture
513    ###)
514
515    def old____loadStudentFoto(self,student,filename,folder): ###(
516        "return a student passport picture"
517        app = student.application
518        app_doc = app.getContent()
519        #clear = student.clearance
520        #clear_doc = clear.getContent()
521        #matric_no = clear_doc.matric_no.upper()
522        picture1 ="%s/import/%s/%s.jpg" % (i_home,folder,filename)
523        picture2 ="%s/import/%s/%s.JPG" % (i_home,folder,filename)
524        #import pdb;pdb.set_trace()
525        if os.path.exists(picture1):
526            file = open(picture1)
527        elif os.path.exists(picture2):
528            file = open(picture2)
529        else:
530            return "passport picture not found %s" % picture1
531        reopened = False
532        if self.portal_workflow.getInfoFor(app,'review_state',None) !='opened':
533            self.portal_workflow.doActionFor(app,'open')
534            reopened = True
535        outfile = file.read()
536        app_doc.manage_addFile('passport',
537                               file=outfile,
538                               title="%s.jpg" % filename)
539        if reopened:
540            self.portal_workflow.doActionFor(app,'close')
541        return "successfully loaded passport picture"
542    ###)
543
544    security.declareProtected(ModifyPortalContent,'createOne') ###(
545    def createOne(self,students_folder,student_brain,letter,commit=False):
546        sid = self.waeup_tool.generateStudentId(letter)
547        students_folder.invokeFactory('Student', sid)
548        student = getattr(students_folder,sid)
549        self.portal_workflow.doActionFor(student,'return')
550        student.manage_setLocalRoles(sid, ['Owner',])
551        matric_no = student_brain.matric_no
552        jamb_reg_no = student_brain.Entryregno
553        self.students_catalog.addRecord(id = sid,
554                                           matric_no = matric_no,
555                                           jamb_reg_no = jamb_reg_no,
556                                           sex = student_brain.Sex == "F",
557                                           name = "%s %s %s" % (student_brain.Firstname,
558                                                                student_brain.Middlename,
559                                                                student_brain.Lastname)
560                                        )
561        if commit:
562            transaction.commit()
563        return sid,jamb_reg_no
564    ###)
565
566    security.declareProtected(ModifyPortalContent,'addStudent') ###(
567    def addStudent(self,dict):
568        students_folder = self.portal_url.getPortalObject().campus.students
569        sid = self.waeup_tool.generateStudentId('?')
570        students_folder.invokeFactory('Student', sid)
571        student_obj = getattr(students_folder,sid)
572        f2t = self.student_field2types
573        #from pdb import set_trace; set_trace()
574        d = {}
575        #d['jamb_sex']  = 'M'
576        #if dict.get('sex'):
577        #    d['jamb_sex']  = 'F'
578
579        entry_session = dict.get('entry_session')
580        if entry_session == self.getSessionId()[0]:
581            wfaction = 'admit'
582            wft = 'wf_transition_admit'
583            password = None
584        else:
585            wfaction = 'return'
586            wft = 'wf_transition_return'
587            password = self.generatePassword()
588            self.makeStudentMember(sid,password)
589
590        for pt in f2t.keys():
591            student_obj.invokeFactory(pt,f2t[pt]['id'])
592            sub_obj = getattr(student_obj,f2t[pt]['id'])
593            sub_doc = sub_obj.getContent()
594            #self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
595            d['Title'] = f2t[pt]['title']
596            for field in f2t[pt]['fields']:
597                d[field] = dict.get(field,'')
598            sub_doc.edit(mapping = d)
599            new_state = f2t[pt][wft]
600            if new_state != "remain":
601                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
602        self.portal_workflow.doActionFor(student_obj,wfaction)
603        student_obj.manage_setLocalRoles(sid, ['Owner',])
604        return sid,password
605    ###)
606
607    security.declarePublic('getCertificateBrain') ###(
608    def getCertificateBrain(self,cert_id):
609        "do it"
610        res = ZCatalog.searchResults(self.portal_catalog_real,
611                                {'portal_type':"Certificate",
612                                      'id': cert_id})
613        if res:
614            return res[0]
615        return None
616    ###)
617
618    security.declareProtected(ModifyPortalContent,'get_csv_filenames') ###(
619    def get_csv_filenames(self):
620        "do it"
621        files = [file for file in os.listdir("%s/import/" % (i_home))
622                 if file.endswith('.csv') and file.find('imported') == -1]
623        return files
624    ###)
625
626    security.declarePublic('findStudentByMatricelNo') ###(
627    def findStudentByMatricelNo(self,matric_no):
628        "do it"
629        res = ZCatalog.searchResults(self.portal_catalog_real,
630                                {'portal_type':"StudentClearance",
631                                 'SearchableText': matric_no})
632        if res:
633            return res[0]
634        return None
635    ###)
636
637    security.declarePublic('makeStudentMember') ###(
638    def makeStudentMember(self,sid,password='uNsEt'):
639        """make the student a member"""
640        membership = self.portal_membership
641        membership.addMember(sid,
642                             password ,
643                             roles=('Member',
644                                     'Student',
645                                     ),
646                             domains='',
647                             properties = {'memberareaCreationFlag': False,
648                                           'homeless': True},)
649        member = membership.getMemberById(sid)
650        self.portal_registration.afterAdd(member, sid, password, None)
651        #self.manage_setLocalRoles(sid, ['Owner',])
652    ###)
653
654    security.declareProtected(View,'makeStudentData') ###(
655    def makeStudentData(self,student_id,email=None,phone_nr=None):
656        "create Datastructure for a returning Student"
657        #import pdb;pdb.set_trace()
658        logger = logging.getLogger('WAeUPTool.makeStudentData')
659        students_folder = self.portal_url.getPortalObject().campus.students
660        #res = self.students_catalog(id=student_id)
661        #if res:
662        #    st = res[0]
663        #res = self.returning_import(matric_no = st.matric_no)
664        res = self.returning_import(id = student_id)
665        if res:
666            student = res[0]
667        else:
668            logger.info('Id %s not found in returning_import' % student_id)
669            return
670        logger.info('%s creates data structure' % student_id)
671        s_results = self.results_import(matric_no = student.matric_no)
672        if s_results:
673            lnr = self.getLevelFromResultsCosCode(s_results)
674            level = "%d00" % lnr
675            verdict,eligible = self.getVerdict(s_results[0].Verdict)
676            #if eligible:
677            #    level = "%d00" % (lnr + 1)
678        else:
679            logger.info('matric_no %s not found in results_import' % student.matric_no)
680            level = ''
681            verdict = ''
682        #student should not be allowed to perform this transition
683        #wftool = self.portal_workflow
684        #wftool.doActionFor(student,'return')
685        certcode_org = student.Coursemajorcode
686        certcode = makeCertificateCode(certcode_org)
687        certificate_brain = self.getCertificateBrain(certcode)
688        if not certificate_brain:
689            em = 'Certificate %s org-code %s not found\n' % (certcode, certcode_org)
690            logger.info(em)
691        matric_no = student.matric_no
692        sid = student_id
693        student_obj = getattr(students_folder,sid)
694        student_obj.invokeFactory('StudentApplication','application')
695        application = student_obj.application
696        self.portal_workflow.doActionFor(application,'open',dest_container=application)
697        da = {'Title': 'Application Data'}
698        student_obj.invokeFactory('StudentPersonal','personal')
699        da['jamb_reg_no'] = student.Entryregno
700        em = self.getEntryMode(student.Entryregno)
701        da['entry_mode'] = em
702        personal = student_obj.personal
703        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
704        dp = {'Title': 'Personal Data'}
705        student_obj.invokeFactory('StudentClearance','clearance')
706        clearance = student_obj.clearance
707        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
708        dc = {'Title': 'Clearance/Eligibility Record'}
709        dc['matric_no'] = matric_no
710        state = student.State
711        lga = student.LGA
712        if state and lga:
713            lga =  state + ' / ' + lga
714        else:
715            lga = "None"
716        da['jamb_lga'] = dc['lga'] = lga
717        da['app_email'] = dp['email'] = email
718        da['app_mobile'] = dp['phone'] = phone_nr
719        dp['firstname'] = student.Firstname
720        dp['middlename'] = student.Middlename
721        dp['lastname'] = student.Lastname
722        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
723        da['jamb_sex'] = student.Sex
724        dp['sex'] = student.Sex == 'F'
725        dp['perm_address'] = student.Permanent_Address
726        application.getContent().edit(mapping=da)
727        self.portal_workflow.doActionFor(application,'close',dest_container=application)
728        personal.getContent().edit(mapping=dp)
729        clearance.getContent().edit(mapping=dc)
730        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
731        #
732        # Study Course
733        #
734        student_obj.invokeFactory('StudentStudyCourse','study_course')
735        studycourse = student_obj.study_course
736        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
737        dsc = {}
738        dsc['study_course'] = certcode
739        dsc['current_level'] = level
740        dsc['current_verdict'] = verdict
741        dsc['current_mode'] = em
742        dsc['current_session'] = '05'
743        studycourse.getContent().edit(mapping=dsc)
744        #
745        # Level
746        #
747##        l = getattr(studycourse,level,None)
748##        if l is None:
749##            studycourse.invokeFactory('StudentStudyLevel', level)
750##            l = getattr(studycourse, level)
751##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
752##            l.getContent().edit(mapping={'Title': "Level %s" % level})
753###)
754
755    security.declareProtected(ModifyPortalContent,'admitOneStudent') ###(
756    def admitOneStudent(self,brain,entry_session,pin_password):
757        "create Datastructure for an admitted Student"
758        #import pdb;pdb.set_trace()
759        if not hasattr(self,"_v_certificates"):
760            self._v_certificates = [entry[0] for entry in self.getCertificatesVoc()]
761        students_folder = self.portal_url.getPortalObject().campus.students
762        logger = logging.getLogger('WAeUPTool.admitOneStudent')
763        if brain.status != "admitted":
764            logger.info('status of %s is %s' % (brain.reg_no,brain.status))
765            return
766        pin_parts = brain.pin.split('-')
767        if pin_parts and len(pin_parts) != 3:
768            logger.info('invalid pin %s for %s' % (brain.pin,brain.reg_no))
769            return
770        if brain.course_admitted not in self._v_certificates:
771            logger.info('certificate %s not found for %s' % (brain.course_admitted,brain.reg_no))
772            return
773        student_id = self.generateStudentId('?')
774        students_folder.invokeFactory('Student', student_id)
775        student_object = getattr(students_folder,student_id)
776        if pin_password:
777            password = pin_parts[2]
778            self.makeStudentMember(student_id,password = password)
779        student_object.manage_setLocalRoles(student_id, ['Owner',])
780        #logger.info("creating %s reg_no %s" % (student_id,brain.reg_no))
781        #
782        # application
783        #
784        student_object.invokeFactory('StudentApplication','application')
785        application = student_object.application
786        #self.portal_workflow.doActionFor(application,'open',dest_container=application)
787        da = {'Title': 'Application Data'}
788        da['jamb_reg_no'] = brain.reg_no
789
790        sex = 'M'
791        if brain.sex:
792            sex = 'F'
793        da['jamb_sex'] = sex
794        da['jamb_age'] = brain.jamb_age
795        #da['app_ac_pin'] = brain.pin
796        da['jamb_lga'] = brain.jamb_lga
797        da['jamb_state'] = brain.jamb_state
798        da['jamb_score'] = brain.aggregate
799        da['app_email'] = brain.email
800        da['app_mobile'] = brain.phone
801        if brain.entry_mode:
802            da['entry_mode'] = brain.entry_mode
803        elif brain.screening_type == 'pume':
804            da['entry_mode'] = 'ume_ft'
805        elif brain.screening_type == 'pde':
806            da['entry_mode'] = 'de_ft'
807        elif brain.screening_type == 'pce':
808            da['entry_mode'] = 'pce'       
809        elif brain.screening_type == 'prence':
810            da['entry_mode'] = 'prence'                     
811        else:
812            da['entry_mode'] = ''
813        da['entry_session'] = entry_session
814        da['jamb_lastname'] = brain.lastname
815        da['jamb_middlename'] = brain.middlenames   # different field names!
816        da['jamb_firstname'] = brain.firstname
817        da['screening_application_date'] = brain.application_date
818        da['date_of_birth'] = brain.date_of_birth
819        da['jamb_first_cos'] = brain.course1
820        da['jamb_second_cos'] = brain.course2
821        da['course3'] = brain.course3
822        da['screening_type'] = brain.screening_type
823        da['screening_score'] = brain.screening_score
824        da['screening_date'] = brain.screening_date
825        da['hq_type'] = brain.hq_type
826        da['hq_grade'] = brain.hq_grade
827        da['aos'] = brain.aos
828
829        application.getContent().edit(mapping=da)
830        #self.portal_workflow.doActionFor(application,'close',dest_container=application)
831        #
832        # personal
833        #
834        student_object.invokeFactory('StudentPersonal','personal')
835        personal = student_object.personal
836        #self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
837        dp = {'Title': 'Personal Data'}
838        dp['sex'] = brain.sex
839        dp['email'] = brain.email
840        dp['phone'] = brain.phone
841        dp['lastname'] = brain.lastname
842        dp['middlename'] = brain.middlenames   # different field names!
843        dp['firstname'] = brain.firstname
844        personal.getContent().edit(mapping=dp)
845        #
846        # clearance
847        #
848        student_object.invokeFactory('StudentClearance','clearance')
849        clearance = student_object.clearance
850        #self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
851        dc = {'Title': 'Clearance/Eligibility Record'}
852        dc['lga'] = brain.lga
853        dc['birthday'] = brain.date_of_birth
854        clearance.getContent().edit(mapping=dc)
855        #self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
856        #
857        # study Course
858        #
859        student_object.invokeFactory('StudentStudyCourse','study_course')
860        studycourse = student_object.study_course
861        #self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
862        dsc = {}
863        dsc['study_course'] = brain.course_admitted
864        dsc['current_verdict'] = ''
865        dsc['current_mode'] = da['entry_mode']
866        if da['entry_mode'].startswith('de'):
867            dsc['current_level'] = '200'
868        else:
869            dsc['current_level'] = '100'
870        dsc['current_session'] = entry_session
871        studycourse.getContent().edit(mapping=dsc)
872        #
873        # payments folder
874        student_object.invokeFactory('PaymentsFolder','payments')
875        payments = getattr(student_object,'payments')
876        dpay = {}
877        dpay['Title'] = 'Payments'
878        payments.getContent().edit(mapping=dpay)
879        self.portal_workflow.doActionFor(payments,'open')
880        #
881        # passport foto
882        app_picture ="%s/import/images/%s/%s_passport.jpg" % (i_home,
883                                                              brain.screening_type,
884                                                              brain.reg_no)
885        images_dir = getImagesDir(student_id)
886        #images_dir = os.path.join("%s" % images_base,student_id)
887        letter_dir,student_dir = os.path.split(images_dir)
888        if not os.path.exists(letter_dir):
889            os.mkdir(letter_dir)
890        if not os.path.exists(images_dir):
891            os.mkdir(images_dir)
892        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
893        if os.path.exists(app_picture):
894            copy2(app_picture,image_name)
895        else:
896            logger.info('passport of %s/%s not found: %s' % (student_id,
897                                                             brain.reg_no,
898                                                             app_picture))
899
900        return student_id
901    ###)
902
903    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
904    def makeStudentLevel(self,student_id):
905        "create the StudyLevel for a returning Student"
906        #import pdb;pdb.set_trace()
907        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
908        students_folder = self.portal_url.getPortalObject().campus.students
909        res = self.students_catalog(id=student_id)
910        if res:
911            st = res[0]
912        course = st.course
913        matric_no = st.matric_no
914        level = st.level
915        res = self.results_import(matric_no = matric_no)
916        if res:
917            results = res
918        logger.info('%s creating Level %s' % (student_id,level))
919        #
920        # Level
921        #
922        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
923        studycourse = getattr(student_obj,"study_course",None)
924        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
925        l = getattr(studycourse,level,None)
926        if l is None:
927            studycourse.invokeFactory('StudentStudyLevel', level)
928            l = getattr(studycourse, level)
929            self.portal_workflow.doActionFor(l,'open',dest_container=l)
930            l.getContent().edit(mapping={'Title': "Level %s" % level})
931        ###)
932
933    security.declarePublic('getHallInfo') ###(
934    def getHallInfo(self,bed):
935        """return Hall Info"""
936        info = {}
937        hall,block,room,letter = bed.split('_')
938        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
939        if res and len(res) == 1:
940            hall_brain = res[0]
941            hall_doc = hall_brain.getObject().getContent()
942        else:
943            return info
944        info['hall_title'] = hall_brain.Title
945        info['maintenance_code'] = hall_doc.maintenance_code
946        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
947        batch_doc = None
948        for brain in res:
949            if brain.id.startswith(info['maintenance_code']):
950                batch_doc = brain.getObject().getContent()
951                break
952        if batch_doc is None:
953            info['maintenance_fee'] = ''
954        else:
955            info['maintenance_fee'] = batch_doc.cost
956        return info
957    ###)
958
959    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
960    def removePictureFolder(self,student_id):
961        """remove picture_folder by renaming it"""
962        path = 'images'
963        picture_path = os.path.join(i_home,path,student_id)
964        if not os.path.exists(picture_path):
965            return False
966        os.rename(picture_path,picture_path + "_removed")
967        return True
968    ###)
969
970    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
971    def restorePictureFolder(self,student_id):
972        """restore picture_folder by renaming it"""
973        path = 'images'
974        picture_path = os.path.join(i_home,path,student_id)
975        if not os.path.exists(picture_path + "_removed"):
976            return False
977        os.rename(picture_path + "_removed",picture_path)
978        return True
979    ###)
980
981    security.declarePublic('picturesExist') ###(
982    def picturesExist(self, ids,student_id=None):
983        """check if pictures exist in the filesystem"""
984        if student_id is None:
985            student_id = self.getStudentId()
986        if student_id is None:
987            return False
988        picture_path = getImagesDir(student_id)
989        #picture_path = os.path.join(images_base,student_id)
990        if not os.path.exists(picture_path):
991            return False
992        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
993        return set(ids).issubset(set(pictures))
994    ###)
995
996    security.declarePublic('picturesList') ###(
997    def picturesList(self):
998        """check if pictures exist in the filesystem"""
999        path = 'images'
1000        student_id = self.getStudentId()
1001        #picture_path = os.path.join(i_home,path,student_id)
1002        picture_path = getImagesDir(student_id)
1003        if not os.path.exists(picture_path):
1004            return []
1005        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1006    ###)
1007
1008    security.declarePublic('showFsPicture') ###(
1009    def showFsPicture(self,path):
1010        """return a picture from the filesystem"""
1011        #picture_path = os.path.join(i_home,path)
1012        picture_path = os.path.join(images_base,path)
1013        response = self.REQUEST.RESPONSE
1014        #import pdb;pdb.set_trace()
1015        registry = getToolByName(self, 'mimetypes_registry')
1016        mimetype = str(registry.lookupExtension(path.lower()) or
1017                    registry.lookupExtension('file.bin'))
1018        if os.path.exists(picture_path):
1019            response.setHeader('Content-type',mimetype)
1020            return open(picture_path).read()
1021        picture_path = os.path.join(i_home,'import',path)
1022        if os.path.exists(picture_path):
1023            return open(picture_path).read()
1024    ###)
1025
1026    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
1027    def deleteAllCourses(self,department="All"):
1028        ''' delete the courses'''
1029        pm = self.portal_membership
1030        member = pm.getAuthenticatedMember()
1031
1032        if str(member) not in ("henrik","joachim"):
1033            return "not possible"
1034        if department == "All":
1035            res = self.portal_catalog({'meta_type': 'Department'})
1036        if len(res) < 1:
1037            return "No Departments found"
1038
1039        deleted = []
1040        for dep in res:
1041            cf = dep.getObject().courses
1042            if cf:
1043                cf.manage_delObjects(ids=cf.objectIds())
1044                deleted.append("deleted Courses in %s" % dep.getId)
1045        return "\r".join(deleted)
1046    ###)
1047
1048    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
1049    def getLogfileLines(self,filename="event.log",numlines=20):
1050        """Get last NUMLINES lines of logfile FILENAME.
1051
1052        Return last lines' of a file in the instances logfile directory as
1053        a list. The number of returned lines equals `numlines' or less. If
1054        less than `numlines' lines are available, the whole file ist
1055        returned. If the file can not be opened or some other error
1056        occurs, empty list is returend.
1057        """
1058        result = []
1059        lines_hit = 0
1060
1061        # We only handle files in instances' log directory...
1062        logpath = os.path.join(i_home, "log")
1063        filename = str(os.path.abspath( os.path.join( logpath, filename )))
1064        if not filename.startswith( logpath ):
1065            # Attempt to access file outside log-dir...
1066            return []
1067
1068        try:
1069            fd = file( filename, "rb" )
1070        except IOError:
1071            return []
1072        if not fd:
1073            return []
1074
1075        if os.linesep == None:
1076            linesep = '\n'
1077        else:
1078            linesep = os.linesep
1079
1080        # Try to find 'numlines' times a lineseparator, searching from end
1081        # and moving to the beginning of file...
1082        fd.seek( 0, 2) # Move to end of file...
1083        while lines_hit < numlines:
1084            if fd.read(1) == linesep[-1]: # This moves filedescriptor
1085                                          # one step forward...
1086                lines_hit += 1
1087            try:
1088                fd.seek( -2, 1) # Go two bytes back from current pos...
1089            except IOError:
1090                # We cannot go back two bytes. Maybe the file is too small...
1091                break
1092        fd.seek(2,1)
1093
1094        # Read all lines from current position...
1095        result = fd.readlines()
1096        # Remove line endings...
1097        result = [x.strip() for x in result]
1098        fd.close()
1099        return result
1100    ###)
1101
1102    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
1103    def getCallbacksFromLog(self,filename):
1104        """fix Online Payment Transactions from Z2.log entries"""
1105        import transaction
1106        import random
1107        from cgi import parse_qs
1108        from urlparse import urlparse
1109        #from pdb import set_trace
1110        wftool = self.portal_workflow
1111        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1112        students_folder = self.portal_url.getPortalObject().campus.students
1113        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
1114        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
1115        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
1116        data = re.compile(s)
1117        start = True
1118        tr_count = 1
1119        total = 0
1120        #name = 'pume_results'
1121        #name = 'epaymentsuccessful_z2log2'
1122        name = filename
1123        no_import = []
1124        imported = []
1125        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
1126        try:
1127            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
1128        except:
1129            logger.error('Error reading %s' % name)
1130            return
1131        tas = []
1132        for line in transactions:
1133            dict = {}
1134            items = data.search(line)
1135            dict['idict'] = idict = items.groupdict()
1136            #print idict
1137            #from pdb import set_trace;set_trace()
1138            urlparsed = urlparse(idict['get'][4:])
1139            #print urlparsed
1140            path = urlparsed[2].split('/')
1141            dict['student_id'] = student_id = path[8]
1142            dict['payment_id'] = payment_id = path[10]
1143            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
1144            tas.append(dict)
1145            tr_count += 1
1146        return tas
1147    ###)
1148
1149    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
1150    def importOnlinePaymentTransactions(self):
1151        """load Online Payment Transactions from CSV values"""
1152        import transaction
1153        import random
1154        #from pdb import set_trace
1155        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1156        opt = self.online_payments_import
1157        students_folder = self.portal_url.getPortalObject().campus.students
1158        start = True
1159        tr_count = 1
1160        total = 0
1161        #name = 'pume_results'
1162        name = 'OnlineTransactions'
1163        no_import = []
1164        imported = []
1165        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
1166        try:
1167            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
1168        except:
1169            logger.error('Error reading %s.csv' % name)
1170            return
1171        for pay_transaction in transactions:
1172            if start:
1173                start = False
1174                logger.info('Start loading from %s.csv' % name)
1175                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
1176                no_import.append('%s,"Error"' % s)
1177                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
1178                format_error = format + ',"%(Error)s"'
1179            data = {}
1180
1181            # format of the first file sent by Tayo
1182            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
1183            #data['student_id'] = student_id = pay_transaction['Payer ID']
1184            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1185            #data['response_code'] = response_code = pay_transaction['Resp Code']
1186            #data['amount'] = amount = pay_transaction['Amount']
1187
1188            # format of the second file sent by Tayo
1189            #data['datetime'] = date = 0
1190            #data['student_id'] = student_id = pay_transaction['Payer ID']
1191            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1192            #data['response_code'] = response_code = '00'
1193            #data['amount'] = amount = pay_transaction['Amount']
1194
1195            # format of the third file sent by Kehinde
1196            data['datetime'] = date = 0
1197            data['student_id'] = student_id = pay_transaction['customer_id']
1198            data['order_id'] = order_id = pay_transaction['merchant_reference']
1199            data['response_code'] = response_code = '00'
1200            data['amount'] = amount = pay_transaction['Amount']
1201
1202            dup = False
1203            if response_code == "12":
1204                continue
1205            try:
1206                opt.addRecord(**data)
1207            except ValueError:
1208                dup = True
1209            #from pdb import set_trace;set_trace()
1210            if dup:
1211                if response_code == "00":
1212                    try:
1213                        opt.modifyRecord(**data)
1214                    except:
1215                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
1216                        continue
1217                else:
1218                    pay_transaction['Error'] = "Duplicate order_id"
1219                    no_import.append( format_error % pay_transaction)
1220                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
1221                    continue
1222            tr_count += 1
1223            if tr_count > 1000:
1224                if len(no_import) > 0:
1225                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1226                             '\n'.join(no_import) + '\n')
1227                    no_import = []
1228                em = '%d transactions committed\n' % (tr_count)
1229                transaction.commit()
1230                regs = []
1231                logger.info(em)
1232                total += tr_count
1233                tr_count = 0
1234        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1235                                                '\n'.join(no_import))
1236        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
1237    ###)
1238
1239    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
1240    def mass_create_faculty(self,mapping):
1241        "create a faculty"
1242        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
1243        academics_folder = self.portal_url.getPortalObject().campus.academics
1244        fid = mapping['code']
1245        if getattr(academics_folder,fid,None) is not None:
1246            return '', "Faculty with ID: %s exists" % fid
1247        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
1248        try:
1249            academics_folder.invokeFactory('Faculty', fid)
1250        except BadRequest,E:
1251            return '', "%s" % E
1252        f = getattr(academics_folder,fid,None)
1253        f.getContent().edit(mapping=mapping)
1254        return fid,''
1255    ###)
1256
1257    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
1258    def mass_edit_faculty(self,mapping):
1259        "edit a faculty"
1260        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
1261        academics_folder = self.portal_url.getPortalObject().campus.academics
1262        fid = mapping['code']
1263        f = getattr(academics_folder,fid,None)
1264        if f is None:
1265            return '', "Faculty with ID: %s does not exist" % fid
1266        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
1267        f.getContent().edit(mapping=mapping)
1268        return fid,''
1269    ###)
1270
1271    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
1272    def mass_create_department(self,mapping):
1273        "create a department in the correct faculty"
1274        logger = logging.getLogger('WAeUPTool.mass_create_department')
1275        fid = mapping['faculty_code']
1276        if getattr(self,'_v_faculties',None) is None:
1277            res = self.portal_catalog(portal_type = "Faculty")
1278            self._v_faculties = {}
1279            for f in res:
1280                self._v_faculties[f.getId] = f.getObject()
1281        f = self._v_faculties.get(fid,None)
1282        if f is None:
1283            return '', "No Faculty with ID: %s" % fid
1284        else:
1285            did = mapping.get('code')
1286            d = getattr(f,did,None)
1287            if d is None or d.portal_type == "Faculty":
1288                logger.info('Creating Department %(code)s, %(title)s' % mapping)
1289                try:
1290                    f.invokeFactory('Department', did)
1291                except BadRequest,E:
1292                    return '', "%s" % E
1293                d = getattr(f,did)
1294                d.invokeFactory('CoursesFolder','courses')
1295                courses = getattr(d,'courses')
1296                dict = {'Title': 'Courses'}
1297                courses.getContent().edit(mapping=dict)
1298                d.invokeFactory('CertificatesFolder','certificates')
1299                certificates = getattr(d,'certificates')
1300                dict = {'Title': 'Certificates'}
1301                certificates.getContent().edit(mapping=dict)
1302            d.getContent().edit(mapping=mapping)
1303        return did,''
1304    ###)
1305
1306    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
1307    def mass_edit_department(self,mapping):
1308        "create a department in the correct faculty"
1309        logger = logging.getLogger('WAeUPTool.mass_create_department')
1310        academics_folder = self.portal_url.getPortalObject().campus.academics
1311        fid = mapping['faculty_code']
1312        did = mapping.get('code')
1313        try:
1314            d = getattr(getattr(academics_folder,fid),did,None)
1315        except KeyError:
1316            return '', "Department %s or Faculty %s wrong" % (did,fid)
1317        else:
1318            if d is None or d.portal_type == "Faculty":
1319                logger.info('Editing Department %(code)s, %(title)s' % mapping)
1320            d.getContent().edit(mapping=mapping)
1321        return did,''
1322    ###)
1323
1324    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1325    def mass_create_course(self,mapping):
1326        #import pdb;pdb.set_trace()
1327        if getattr(self,'_v_course_list',None) is None:
1328            self._v_course_list = []
1329        if getattr(self,'_v_departments',None) is None:
1330            res = self.portal_catalog(portal_type = "Department")
1331            self._v_department_courses = {}
1332            for d in res:
1333                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
1334        did = mapping['department_code']
1335        d = self._v_department_courses.get(did,None)
1336        if d is None:
1337            return '', "No Department with ID: %s" % did
1338        course_id = mapping.get('code')
1339        if course_id in self._v_course_list:
1340            return '', "Duplicate Course ID: %s" % did
1341        c = getattr(d,course_id,None)
1342        if c is not None:
1343            return '', "Duplicate Course ID: %s" % did
1344        try:
1345            d.invokeFactory('Course', course_id)
1346        except BadRequest,E:
1347            return '', "%s" % E
1348        self._v_course_list.append(course_id)
1349        c = getattr(d,course_id)
1350        c.getContent().edit(mapping=mapping)
1351        return course_id,''
1352    ###)
1353
1354    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1355    def mass_edit_course(self,mapping):
1356        #import pdb;pdb.set_trace()
1357        course_id = mapping.get('code')
1358        res = self.portal_catalog(id=course_id)
1359        if not res:
1360            return '', "No Course with ID: %s" % course_id
1361        c = res[0].getObject()
1362        c.getContent().edit(mapping=mapping)
1363        return course_id,''
1364    ###)
1365
1366    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1367    def mass_create_certificate(self,mapping):
1368        if getattr(self,'_v_certificate_list',None) is None:
1369            self._v_certificate_list = []
1370        if getattr(self,'_v_department_certificates',None) is None:
1371            res = self.portal_catalog(portal_type = "Department")
1372            self._v_department_certificates = {}
1373            for d in res:
1374                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
1375        did = mapping['department_code']
1376        d = self._v_department_certificates.get(did,None)
1377        if d is None:
1378            return '', "No Department with ID: %s" % did
1379        certificate_id = mapping.get('code')
1380        if certificate_id in self._v_certificate_list:
1381            return '', "Duplicate Certificate ID: %s" % did
1382        c = getattr(d,certificate_id,None)
1383        if c is not None:
1384            return '', "Duplicate Certificate ID: %s" % did
1385        try:
1386            d.invokeFactory('Certificate', certificate_id)
1387        except BadRequest,E:
1388            return '', "%s" % E
1389        self._v_certificate_list.append(certificate_id)
1390        c = getattr(d,certificate_id)
1391        c.getContent().edit(mapping=mapping)
1392        return certificate_id,''
1393    ###)
1394
1395    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1396    def mass_edit_certificate(self,mapping):
1397        #import pdb;pdb.set_trace()
1398        certificate_id = mapping.get('code')
1399        res = self.portal_catalog(id=certificate_id)
1400        if not res:
1401            return '', "No Certificate with ID: %s" % did
1402        c = res[0].getObject()
1403        c.getContent().edit(mapping=mapping)
1404        return certificate_id,''
1405    ###)
1406
1407    security.declareProtected(ModifyPortalContent,'mass_create_application') ###(
1408    def mass_create_application(self,mapping):
1409        #import pdb;pdb.set_trace()
1410        reg_no = mapping.get('reg_no')
1411        try:
1412            self.applicants_catalog.addRecord(**mapping)
1413        except ValueError:
1414            return '', "applicant record with reg_no %s already exists" % reg_no
1415        return reg_no,''
1416    ###)
1417
1418    security.declareProtected(ModifyPortalContent,'mass_edit_application') ###(
1419    def mass_edit_application(self,mapping):
1420        #import pdb;pdb.set_trace()
1421        reg_no = mapping.get('reg_no')
1422        status = mapping.get('status')
1423        res = self.applicants_catalog(reg_no = reg_no)
1424        if len(res):
1425            if res[0].status == 'created' and status != 'created':
1426                return '', "student object with id %s for %s already created, status cannot be changed" % (res[0].student_id, reg_no)
1427            elif status == 'created' and res[0].status != 'created':
1428                return '', "student object for %s has not yet been created, status cannot be set to 'created'" % (reg_no)
1429            else:
1430                self.applicants_catalog.modifyRecord(**mapping)
1431                return reg_no,''
1432        else:
1433            return '', "applicant record with reg_no %s does not exist" % reg_no
1434
1435    ###)
1436
1437    security.declareProtected(ModifyPortalContent,'mass_create_course_result') ###(
1438    def mass_create_course_result(self,mapping):
1439        #import pdb;pdb.set_trace()
1440        students_folder = self.portal_url.getPortalObject().campus.students
1441        if getattr(self,'_v_courses',None) is None:
1442            res = self.courses_catalog()
1443            self._v_courses = {}
1444            for brain in res:
1445                self._v_courses[brain.code] = brain
1446        if getattr(self,'_v_level_created',None) is None:
1447            self._v_level_created = []
1448        course_id = mapping.get('code')
1449        if course_id not in self._v_courses.keys():
1450            return '', "No course with ID: %s" % course_id
1451        id_key = ''
1452        for id_key in ('student_id','matric_no'):
1453            id_field = mapping.get(id_key,None)
1454            if id_field is not None:
1455                student_id = id_field
1456                break
1457        query = Eq(id_key,id_field)
1458        res = self.students_catalog.evalAdvancedQuery(query)
1459        if not res:
1460            return '', "no student with %(id_key)s %(id_field)s" % vars()
1461        student_rec = res[0]
1462        if id_field != "student_id":
1463            mapping['student_id'] = student_rec.id
1464        student_id = student_rec.id
1465        level_id = mapping['level_id']
1466        code = mapping['code']
1467        if student_id not in self._v_level_created:
1468            try:
1469                context = getattr(getattr(students_folder,
1470                                          "%(student_id)s" % vars()),
1471                                  'study_course')
1472            except:
1473                return '', "could not create level %(level_id)s for %(student_id)s" % vars()
1474            if level_id not in context.objectIds():
1475                context.invokeFactory('StudentStudyLevel',"%(level_id)s" % vars())
1476                level = getattr(context,"%(level_id)s" % vars())
1477                self.portal_workflow.doActionFor(level,'open')
1478                # the session string must not be copied into the level object
1479                current_verdict = getattr(student_rec,'current_verdict','')
1480                current_session = getattr(student_rec,'current_session','')
1481                if current_verdict and student_rec.current_level == level_id:
1482                    level.getContent().edit(mapping={'verdict': "%s" %
1483                                                     current_verdict,
1484                                                     'session': "%s" %
1485                                                     current_session,
1486                                                    })
1487                    self.portal_workflow.doActionFor(level,'close')
1488            self._v_level_created += student_id,
1489        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
1490        for k in ('semester','credits',):
1491            mapping[k] = getattr(self._v_courses[course_id],k)
1492        try:
1493            self.course_results.addRecord(**mapping)
1494        except ValueError:
1495            return '', "course result already exists: %s" % key
1496        return key,''
1497    ###)
1498
1499    security.declareProtected(ModifyPortalContent,'mass_edit_course_result') ###(
1500    def mass_edit_course_result(self,mapping):
1501        #import pdb;pdb.set_trace()
1502        # if getattr(self,'_v_courses',None) is None:
1503        #     res = self.courses_catalog()
1504        #     self._v_courses = {}
1505        #     for brain in res:
1506        #         self._v_courses[brain.code] = brain
1507        # course_id = mapping.get('code')
1508        # if course_id not in self._v_courses.keys():
1509        #     return '', "No course with ID: %s" % did
1510        id_key = ''
1511        for id_key in ('student_id','matric_no'):
1512            id_field = mapping.get(id_key,None)
1513            if id_field is not None:
1514                student_id = id_field
1515                break
1516        query = Eq(id_key,id_field)
1517        res = self.students_catalog.evalAdvancedQuery(query)
1518        if not res:
1519            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1520        if id_field != "student_id":
1521            mapping['student_id'] = res[0].id
1522        if not res:
1523            return '', "no student with %(id_key)s %(id_field)s" % vars()
1524        student_rec = res[0]
1525        student_id = student_rec.id
1526        level_id = mapping['level_id']
1527        code = mapping['code']
1528        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
1529        # for k in ('semester',):
1530        #     mapping[k] = getattr(self._v_courses[course_id],k)
1531        try:
1532            self.course_results.modifyRecord(**mapping)
1533        except KeyError:
1534            return '', "No course result to edit: %s" % key
1535        return key,''
1536    ###)
1537
1538    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1539    def mass_create_certificate_course(self,mapping):
1540        if getattr(self,'_v_courses',None) is None:
1541            res = self.courses_catalog()
1542            self._v_courses= [course.code for course in res]
1543        if getattr(self,'_v_ceritficates',None) is None:
1544            res = self.portal_catalog(portal_type = "Certificate")
1545            self._v_certificates = {}
1546            for cert in res:
1547                self._v_certificates[cert.getId] = cert.getObject()
1548        certificate_course_id = mapping.get('code')
1549        if certificate_course_id not in self._v_courses:
1550            return '', "No Course with ID: %s" % certificate_course_id
1551        cert_id = mapping['certificate_code']
1552        cert = self._v_certificates.get(cert_id,None)
1553        if cert is None:
1554            return '', "No Certificate with ID: %s" % cert_id
1555        level_id = mapping.get('level')
1556        level = getattr(cert,level_id,None)
1557        if level is None:
1558            cert.invokeFactory('StudyLevel', level_id)
1559            level = getattr(cert,level_id,None)
1560        elif hasattr(level,certificate_course_id):
1561            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1562            (certificate_course_id,cert_id,level_id)
1563        level.invokeFactory('CertificateCourse', certificate_course_id)
1564        c = getattr(level,certificate_course_id)
1565        c.getContent().edit(mapping=mapping)
1566        return certificate_course_id,''
1567    ###)
1568
1569    field2types_student = {   ###(
1570                      'StudentApplication':
1571                          {'id': 'application',
1572                           'title': 'Application Data',
1573                           'wf_transition_return': 'close',
1574                           'wf_transition_admit': 'remain',
1575                           'fields':
1576                             ('jamb_reg_no',
1577                              'entry_mode',
1578                              'entry_session',
1579                              'jamb_score',
1580                              'app_email',
1581                              'jamb_age',
1582                              'jamb_state',
1583                              'jamb_lga',
1584                              )
1585                              },
1586                      #'StudentPume':
1587                      #    {'id': 'pume',
1588                      #     'title': 'Pume Data',
1589                      #     'wf_transition_return': 'close',
1590                      #     'wf_transition_admit': 'close',
1591                      #     'fields':
1592                      #       ('pume_score',
1593                      #        )
1594                      #        },
1595                      'StudentClearance':
1596                          {'id': 'clearance',
1597                           'title': 'Clearance/Eligibility Record',
1598                           'wf_transition_return': 'close',
1599                           'wf_transition_admit': 'remain',
1600                           'fields':
1601                             ('matric_no',
1602                              'nationality',
1603                              'lga',
1604                              'birthday',
1605                              )
1606                              },
1607                         'StudentPersonal':
1608                          {'id': 'personal',
1609                           'title': 'Personal Data',
1610                           'wf_transition_return': 'open',
1611                           'wf_transition_admit': 'remain',
1612                           'fields':
1613                             ('firstname',
1614                              'middlename',
1615                              'lastname',
1616                              'sex',
1617                              'email',
1618                              'phone',
1619                              'perm_address',
1620                              )
1621                              },
1622                         'StudentStudyCourse':
1623                          {'id': 'study_course',
1624                           'title': 'Study Course',
1625                           'wf_transition_return': 'open',
1626                           'wf_transition_admit': 'remain',
1627                           'fields':
1628                             ('study_course',
1629                              'current_level',
1630                              'current_session',
1631                              'current_mode',
1632                              'current_verdict',
1633                              'previous_verdict',
1634                              )
1635                              },
1636                         # 'StudentStudyLevel':
1637                         #  {'id': 'current_level',
1638                         #   'title': '',
1639                         #   'wf_transition_return': 'open',
1640                         #   'wf_transition_admit': 'remain',
1641                         #   'fields':
1642                         #     ('verdict',
1643                         #      'session',
1644                         #      )
1645                         #      },
1646                         'PaymentsFolder':
1647                          {'id': 'payments',
1648                           'title': 'Payments',
1649                           'wf_transition_return': 'open',
1650                           'wf_transition_admit': 'open',
1651                           'fields':
1652                             ()
1653                              },
1654                         }
1655    ###)
1656
1657    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1658    def mass_create_student(self,mapping):
1659        "create a students record due import"
1660        logger = logging.getLogger('WAeUPTool.mass_create_student')
1661        students_folder = self.portal_url.getPortalObject().campus.students
1662        jamb_reg_no = mapping.get('jamb_reg_no',None)
1663        if jamb_reg_no:
1664            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1665            if res:
1666                return '',"jamb_reg_no exists"
1667        matric_no = mapping.get('matric_no',None)
1668        if matric_no:
1669            res = self.students_catalog(matric_no = matric_no)
1670            if res:
1671                return '',"matric_no exists"
1672        sid = self.waeup_tool.generateStudentId('?')
1673        students_folder.invokeFactory('Student', sid)
1674        student_obj = getattr(students_folder,sid)
1675        f2t = self.field2types_student
1676        d = {}
1677        transition = mapping.get('reg_transition','admit')
1678        if transition not in ('admit','return'):
1679            return '',"no valid transition provided"
1680        for pt in f2t.keys():
1681            student_obj.invokeFactory(pt,f2t[pt]['id'])
1682            sub_obj = getattr(student_obj,f2t[pt]['id'])
1683            sub_doc = sub_obj.getContent()
1684            d['Title'] = f2t[pt]['title']
1685            for field in f2t[pt]['fields']:
1686                d[field] = mapping.get(field,'')
1687
1688            if pt == "StudentApplication":
1689                d['jamb_sex']  = 'M'
1690                if mapping.get('sex'):
1691                    d['jamb_sex']  = 'F'
1692                d['jamb_firstname'] = mapping.get('firstname',None)
1693                d['jamb_middlename'] = mapping.get('middlename',None)
1694                d['jamb_lastname'] = mapping.get('lastname',None)
1695
1696            # if pt == "StudyCourse":
1697            #     for von,zu in (('entry_mode','current_mode'),
1698            #                    ('entry_session','current_session')):
1699            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1700            #             d[zu] = mapping[von]
1701            sub_doc.edit(mapping = d)
1702
1703            #import pdb;pdb.set_trace()
1704            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
1705            if new_state != "remain":
1706                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1707        self.portal_workflow.doActionFor(student_obj,transition)
1708        student_obj.manage_setLocalRoles(sid, ['Owner',])
1709        return sid,''
1710    ###)
1711
1712    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1713    def mass_edit_student(self,mapping):
1714        wftool = self.portal_workflow
1715        "edit a students record due import"
1716        logger = logging.getLogger('WAeUPTool.mass_edit_student')
1717        students_folder = self.portal_url.getPortalObject().campus.students
1718        sid = mapping.get('id',None)
1719        jamb_reg_no = mapping.get('jamb_reg_no',None)
1720        matric_no = mapping.get('matric_no',None)
1721        editable_keys = mapping.keys()
1722        if sid:
1723            res = self.students_catalog(id = sid)
1724            if not res:
1725                return '',"no student with id %s" % sid
1726            if matric_no and res[0].matric_no and\
1727              matric_no != res[0].matric_no:
1728                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1729            if jamb_reg_no and res[0].jamb_reg_no and\
1730              jamb_reg_no != res[0].jamb_reg_no:
1731                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
1732        elif jamb_reg_no:
1733            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1734            if not res:
1735                return '',"no student with jamb_reg_no %s" % jamb_reg_no
1736            editable_keys.remove('jamb_reg_no')
1737        elif matric_no:
1738            res = self.students_catalog(matric_no = matric_no)
1739            if not res:
1740                return '',"no student with matric_no %s" % matric_no
1741            editable_keys.remove('matric_no')
1742
1743        ## included only to change wf state from admitted to returning
1744        #if res[0].review_state not in ('admitted','objection_raised'):
1745        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1746        ## end inclusion
1747
1748        sid = res[0].id
1749        student_obj = getattr(students_folder,sid)
1750        f2t = self.field2types_student
1751        d = {}
1752        #import pdb;pdb.set_trace()
1753        any_change = False
1754        #special treatment for StudentStudyLevel
1755        d['verdict']  = mapping.get('current_verdict','')
1756        d['session']  = mapping.get('current_session','')
1757        current_level = mapping.get('current_level','')
1758        while d['session'] and d['verdict'] and current_level:
1759            sub_obj = getattr(student_obj,'study_course',None)
1760            if sub_obj is None:
1761                break
1762            level_obj = getattr(sub_obj,current_level,None)
1763            if  level_obj is None:
1764                break
1765            any_change = True
1766            level_obj.getContent().edit(mapping = d)
1767            try:
1768                wftool.doActionFor(level_obj,'close')
1769            except:
1770                pass
1771            break
1772        for pt in f2t.keys():
1773            if pt == "StudentApplication":
1774                d['jamb_sex']  = 'M'
1775                if mapping.get('sex'):
1776                    d['jamb_sex']  = 'F'
1777            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
1778            if intersect and pt not in ('StudentStudyLevel',):
1779                object_id = f2t[pt]['id']
1780                sub_obj = getattr(student_obj,object_id,None)
1781                if sub_obj is None:
1782                    try:
1783                        student_obj.invokeFactory(pt,object_id)
1784                    except:
1785                        continue
1786                    sub_obj = getattr(student_obj,object_id)
1787                    if f2t[pt]['title'] != '':
1788                        d['Title'] = f2t[pt]['title']
1789                sub_doc = sub_obj.getContent()
1790                for field in intersect:
1791                    changed = False
1792                    if getattr(sub_doc,field,None) != mapping.get(field,''):
1793                        any_change = True
1794                        changed = True
1795                        d[field] = mapping.get(field,'')
1796                    if changed:
1797                        sub_doc.edit(mapping = d)
1798
1799
1800        ## included only to change wf state from admitted to returning
1801        #    if res[0].review_state in ('admitted','objection_raised'):
1802        #        new_state = f2t[pt]['wf_transition_return']
1803        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1804        #        if sub_obj and new_state != "remain":
1805        #            try:
1806        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1807        #            except:
1808        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1809        #                pass
1810        #if res[0].review_state in ('admitted','objection_raised'):
1811        #    wfaction = 'return'
1812        #    try:
1813        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1814        #        logger.info('%s, wf state changed' % sid)
1815        #        any_change = True
1816        #    except:
1817        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1818        #        pass
1819        ## end inclusion
1820
1821
1822        if any_change:
1823            return sid,''
1824        else:
1825            return sid,'not modified'
1826    ###)
1827
1828    security.declareProtected(ModifyPortalContent,"importData")###(
1829    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
1830        """load data from CSV values"""
1831        import transaction
1832        import random
1833
1834        pm = self.portal_membership
1835        member = pm.getAuthenticatedMember()
1836
1837        logger = logging.getLogger('WAeUPTool.importData')
1838        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1839        students_folder = self.portal_url.getPortalObject().campus.students
1840        start = True
1841        tr_count = 0
1842        total_imported = 0
1843        total_not_imported = 0
1844        total = 0
1845        iname = "import_%s" % name
1846        if iname in ('import_application','import_course_result',):
1847            commit_after = 2000
1848        else:
1849            commit_after = 100
1850        stool = getToolByName(self, 'portal_schemas')
1851        ltool = getToolByName(self, 'portal_layouts')
1852        schema = stool._getOb(iname)
1853        if schema is None:
1854            em = 'No such schema %s' % iname
1855            logger.error('No such schema %s' % iname)
1856            return em
1857        layout = ltool._getOb(iname)
1858        if layout is None:
1859            em = 'No such layout %s' % iname
1860            logger.error(em)
1861            return em
1862        validators = {}
1863        for widget in layout.keys():
1864            validators[widget] = layout[widget].validate
1865        mode = "create"
1866        if edit:
1867            mode = "edit"
1868        importer_name = "mass_%(mode)s_%(name)s" % vars()
1869        importer = getattr(self, '%s' % importer_name,None)
1870        if importer is None:
1871            em = 'No importer function %s' % importer_name
1872            logger.error(em)
1873            return em
1874        not_imported = []
1875        imported = []
1876        try:
1877            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
1878        except:
1879            em = 'Error reading %s.csv' % filename
1880            logger.error(em)
1881            return em
1882        for item in items:
1883            #import pdb;pdb.set_trace()
1884            item = dict((k.strip(),l.strip()) for (k,l) in item.items())
1885            if start:
1886                start = False
1887                adapters = [MappingStorageAdapter(schema, item)]
1888                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
1889                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
1890                import_keys = [k.strip() for k in attrs if not k.startswith('ignore')]
1891                diff2schema = set(import_keys).difference(set(schema.keys()))
1892                diff2layout = set(import_keys).difference(set(layout.keys()))
1893                if diff2schema:
1894                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
1895                    return em
1896                if mode == "create":
1897                    required_keys = [layout.getIdUnprefixed(id)
1898                                     for id,widget in layout.objectItems()
1899                                     if widget.is_required]
1900                    if not set(required_keys).issubset(set(import_keys)):
1901                        diff2import = set(required_keys).difference(set(import_keys))
1902                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
1903                        return em
1904                s = ','.join(['"%s"' % fn for fn in import_keys])
1905                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
1906                s = '"id",' + s
1907                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
1908                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
1909                format_error = format + ',"%(Error)s"'
1910                format = '"%(id)s",'+ format
1911
1912            dm = DataModel(item, adapters,context=self)
1913            ds = DataStructure(data=item,datamodel=dm)
1914            error_string = ""
1915            total += 1
1916            error_count = 0
1917            for k in import_keys:
1918                if not validators[k](ds,mode=mode):
1919                    if error_count:
1920                        error_string += ' ++ '
1921                    error_string += "%s: %s" % (k,
1922                                                  self.translation_service(ds.getError(k),
1923                                                                           ds.getErrorMapping(k)))
1924                    error_count += 1
1925            if not error_string:
1926                temp_item = item.copy()
1927                temp_item.update(dm)
1928                temp_item['id'],error = importer(temp_item)
1929                if error:
1930                    error_string += error
1931                else:
1932                    item = temp_item
1933            if error_string:
1934                item['Error'] = error_string
1935                not_imported.append(format_error % item)
1936                total_not_imported += 1
1937            else:
1938                em = format % item
1939                imported.append(em)
1940                tr_count += 1
1941                total_imported += 1
1942                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
1943
1944            if total and not total % commit_after:
1945                transaction.commit()
1946                if len(not_imported) > 0:
1947                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1948                             '\n'.join(not_imported) + '\n')
1949                    not_imported = []
1950                if len(imported) > 0:
1951                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1952                             '\n'.join(imported) + '\n')
1953                    imported = []
1954                em = '%d transactions committed\n' % (tr_count)
1955                regs = []
1956                logger.info(em)
1957                tr_count = 0
1958                #if total > 100:
1959                #    return
1960        if len(imported) > 0:
1961            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1962                                                '\n'.join(imported))
1963        if len(not_imported) > 0:
1964            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1965                                                '\n'.join(not_imported))
1966        em = "Finished import from %s.csv: %d imported, %d not imported (of total %d)" % (filename,total_imported,total_not_imported,total)
1967        logger.info(em)
1968        return em
1969    ###)
1970
1971    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
1972    def moveImagesToFS(self,student_id="O738726"):
1973        "move the images to the filesystem"
1974        images_dir = getImagesDir(student_id)
1975        #images_dir = os.path.join("%s" % images_base,student_id)
1976        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1977        stool = getToolByName(self, 'portal_schemas')
1978        schemas = ['student_application',
1979                   'student_clearance',
1980                   ]
1981        created = False
1982        for schema_id in schemas:
1983            schema = stool._getOb(schema_id)
1984            object = getattr(student_folder,schema_id[len('student_'):],None)
1985            if object is None:
1986                continue
1987            doc = object.getContent()
1988            for key in schema.keys():
1989                if schema[key].meta_type != "CPS Image Field":
1990                    continue
1991                #import pdb;pdb.set_trace()
1992                image = getattr(doc,key,None)
1993                if not image or not hasattr(image,"data"):
1994                    continue
1995                if not created:
1996                    if not os.path.exists(images_dir):
1997                        os.mkdir(images_dir)
1998                    created = True
1999                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
2000                open(filename,"wb").write(str(image.data))
2001    ###)
2002
2003    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
2004    def movePassportToFS(self,student_id="O738726"):
2005        "move the passports to the filesystem"
2006        images_dir = os.path.join("%s" % i_home,'passports')
2007        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
2008        stool = getToolByName(self, 'portal_schemas')
2009        schemas = ['student_application',
2010                   #'student_clearance',
2011                   ]
2012        created = False
2013        for schema_id in schemas:
2014            schema = stool._getOb(schema_id)
2015            object = getattr(student_folder,schema_id[len('student_'):],None)
2016            if object is None:
2017                continue
2018            doc = object.getContent()
2019            for key in schema.keys():
2020                if schema[key].meta_type != "CPS Image Field":
2021                    continue
2022                #import pdb;pdb.set_trace()
2023                image = getattr(doc,key)
2024                if not hasattr(image,"data"):
2025                    continue
2026                if not created:
2027                    if not os.path.exists(images_dir):
2028                        os.mkdir(images_dir)
2029                    created = True
2030                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
2031                open(filename,"wb").write(str(image.data))
2032    ###)
2033
2034InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.