source: WAeUP_SRP/base/WAeUPTool.py @ 2984

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