source: WAeUP_SRP/base/WAeUPTool.py @ 3114

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

fix

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