source: WAeUP_SRP/base/WAeUPTool.py @ 3049

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

fix mass_edit_certificate

  • Property svn:keywords set to Id
File size: 92.0 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 3042 2008-01-24 09:54:57Z 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        student_obj.invokeFactory('StudentApplication','application')
786        application = student_obj.application
787        self.portal_workflow.doActionFor(application,'open',dest_container=application)
788        da = {'Title': 'Application Data'}
789        student_obj.invokeFactory('StudentPersonal','personal')
790        da['jamb_reg_no'] = student.Entryregno
791        em = self.getEntryMode(student.Entryregno)
792        da['entry_mode'] = em
793        personal = student_obj.personal
794        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
795        dp = {'Title': 'Personal Data'}
796        student_obj.invokeFactory('StudentClearance','clearance')
797        clearance = student_obj.clearance
798        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
799        dc = {'Title': 'Clearance/Eligibility Record'}
800        dc['matric_no'] = matric_no
801        state = student.State
802        lga = student.LGA
803        if state and lga:
804            lga =  state + ' / ' + lga
805        else:
806            lga = "None"
807        da['jamb_lga'] = dc['lga'] = lga
808        da['app_email'] = dp['email'] = email
809        da['app_mobile'] = dp['phone'] = phone_nr
810        dp['firstname'] = student.Firstname
811        dp['middlename'] = student.Middlename
812        dp['lastname'] = student.Lastname
813        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
814        da['jamb_sex'] = student.Sex
815        dp['sex'] = student.Sex == 'F'
816        dp['perm_address'] = student.Permanent_Address
817        application.getContent().edit(mapping=da)
818        self.portal_workflow.doActionFor(application,'close',dest_container=application)
819        personal.getContent().edit(mapping=dp)
820        clearance.getContent().edit(mapping=dc)
821        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
822        #
823        # Study Course
824        #
825        student_obj.invokeFactory('StudentStudyCourse','study_course')
826        studycourse = student_obj.study_course
827        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
828        dsc = {}
829        dsc['study_course'] = certcode
830        dsc['current_level'] = level
831        dsc['current_verdict'] = verdict
832        dsc['current_mode'] = em
833        dsc['current_session'] = '05'
834        studycourse.getContent().edit(mapping=dsc)
835        #
836        # Level
837        #
838##        l = getattr(studycourse,level,None)
839##        if l is None:
840##            studycourse.invokeFactory('StudentStudyLevel', level)
841##            l = getattr(studycourse, level)
842##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
843##            l.getContent().edit(mapping={'Title': "Level %s" % level})
844###)
845
846    security.declareProtected(ModifyPortalContent,'admitOneStudent') ###(
847    def admitOneStudent(self,brain,entry_session,pin_password):
848        "create Datastructure for an admitted Student"
849        #import pdb;pdb.set_trace()
850        if not hasattr(self,"_v_certificates"):
851            self._v_certificates = [entry[0] for entry in self.getCertificatesVoc()]
852        students_folder = self.portal_url.getPortalObject().campus.students
853        logger = logging.getLogger('WAeUPTool.admitOneStudent')
854        if brain.status != "admitted":
855            logger.info('status of %s is %s' % (brain.reg_no,brain.status))
856            return
857        pin_parts = brain.pin.split('-')
858        if pin_parts and len(pin_parts) != 3:
859            logger.info('invalid pin %s for %s' % (brain.pin,brain.reg_no))
860            return
861        if brain.course_admitted not in self._v_certificates:
862            logger.info('certificate %s not found for %s' % (brain.course_admitted,brain.reg_no))
863            return
864        if brain.sex not in (True,False):
865            logger.info('sex of %s not available' % (brain.reg_no))
866            return
867        student_id = self.generateStudentId('?')
868        students_folder.invokeFactory('Student', student_id)
869        student_object = getattr(students_folder,student_id)
870        if pin_password:
871            password = pin_parts[2]
872            self.makeStudentMember(student_id,password = password)
873        student_object.manage_setLocalRoles(student_id, ['Owner',])
874        #logger.info("creating %s reg_no %s" % (student_id,brain.reg_no))
875        #
876        # application
877        #
878        student_object.invokeFactory('StudentApplication','application')
879        application = student_object.application
880        #self.portal_workflow.doActionFor(application,'open',dest_container=application)
881        da = {'Title': 'Application Data'}
882        da['jamb_reg_no'] = brain.reg_no
883
884        sex = 'M'
885        if brain.sex:
886            sex = 'F'
887        da['jamb_sex'] = sex
888        da['jamb_age'] = brain.jamb_age
889        #da['app_ac_pin'] = brain.pin
890        da['jamb_lga'] = brain.jamb_lga
891        da['jamb_state'] = brain.jamb_state
892        da['jamb_score'] = brain.aggregate
893        da['app_email'] = brain.email
894        da['app_mobile'] = brain.phone
895        if brain.entry_mode:
896            da['entry_mode'] = brain.entry_mode
897        elif brain.screening_type == 'pume':
898            da['entry_mode'] = 'ume_ft'
899        elif brain.screening_type == 'pde':
900            da['entry_mode'] = 'de_ft'
901        elif brain.screening_type == 'pce':
902            da['entry_mode'] = 'pce'
903        elif brain.screening_type == 'prence':
904            da['entry_mode'] = 'prence'
905        else:
906            da['entry_mode'] = ''
907        da['entry_session'] = entry_session
908        da['jamb_lastname'] = brain.lastname
909        da['jamb_middlename'] = brain.middlenames   # different field names!
910        da['jamb_firstname'] = brain.firstname
911        da['screening_application_date'] = brain.application_date
912        da['date_of_birth'] = brain.date_of_birth
913        da['jamb_first_cos'] = brain.course1
914        da['jamb_second_cos'] = brain.course2
915        da['course3'] = brain.course3
916        da['screening_type'] = brain.screening_type
917        da['screening_score'] = brain.screening_score
918        da['screening_date'] = brain.screening_date
919        da['hq_type'] = brain.hq_type
920        da['hq_grade'] = brain.hq_grade
921        da['aos'] = brain.aos
922
923        application.getContent().edit(mapping=da)
924        #self.portal_workflow.doActionFor(application,'close',dest_container=application)
925        #
926        # personal
927        #
928        student_object.invokeFactory('StudentPersonal','personal')
929        personal = student_object.personal
930        #self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
931        dp = {'Title': 'Personal Data'}
932        dp['sex'] = brain.sex
933        dp['email'] = brain.email
934        dp['phone'] = brain.phone
935        dp['lastname'] = brain.lastname
936        dp['middlename'] = brain.middlenames   # different field names!
937        dp['firstname'] = brain.firstname
938        personal.getContent().edit(mapping=dp)
939        #
940        # clearance
941        #
942        student_object.invokeFactory('StudentClearance','clearance')
943        clearance = student_object.clearance
944        #self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
945        dc = {'Title': 'Clearance/Eligibility Record'}
946        dc['lga'] = brain.lga
947        dc['birthday'] = brain.date_of_birth
948        clearance.getContent().edit(mapping=dc)
949        #self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
950        #
951        # study Course
952        #
953        student_object.invokeFactory('StudentStudyCourse','study_course')
954        studycourse = student_object.study_course
955        #self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
956        dsc = {}
957        dsc['study_course'] = brain.course_admitted
958        dsc['current_verdict'] = ''
959        dsc['current_mode'] = da['entry_mode']
960        if da['entry_mode'].startswith('de'):
961            dsc['current_level'] = '200'
962        elif da['entry_mode'].startswith('pre'):
963            dsc['current_level'] = '000'
964        else:
965            dsc['current_level'] = '100'
966        dsc['current_session'] = entry_session
967        studycourse.getContent().edit(mapping=dsc)
968        #
969        # payments folder
970        student_object.invokeFactory('PaymentsFolder','payments')
971        payments = getattr(student_object,'payments')
972        dpay = {}
973        dpay['Title'] = 'Payments'
974        payments.getContent().edit(mapping=dpay)
975        self.portal_workflow.doActionFor(payments,'open')
976        #
977        # passport foto
978        app_picture ="%s/import/images/%s/%s_passport.jpg" % (i_home,
979                                                              brain.screening_type,
980                                                              brain.reg_no)
981        images_dir = getImagesDir(student_id)
982        #images_dir = os.path.join("%s" % images_base,student_id)
983        letter_dir,student_dir = os.path.split(images_dir)
984        if not os.path.exists(letter_dir):
985            os.mkdir(letter_dir)
986        if not os.path.exists(images_dir):
987            os.mkdir(images_dir)
988        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
989        if os.path.exists(app_picture):
990            copy2(app_picture,image_name)
991        else:
992            logger.info('passport of %s/%s not found: %s' % (student_id,
993                                                             brain.reg_no,
994                                                             app_picture))
995
996        return student_id
997    ###)
998
999    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
1000    def makeStudentLevel(self,student_id):
1001        "create the StudyLevel for a returning Student"
1002        #import pdb;pdb.set_trace()
1003        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
1004        students_folder = self.portal_url.getPortalObject().campus.students
1005        res = self.students_catalog(id=student_id)
1006        if res:
1007            st = res[0]
1008        course = st.course
1009        matric_no = st.matric_no
1010        level = st.level
1011        res = self.results_import(matric_no = matric_no)
1012        if res:
1013            results = res
1014        logger.info('%s creating Level %s' % (student_id,level))
1015        #
1016        # Level
1017        #
1018        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1019        studycourse = getattr(student_obj,"study_course",None)
1020        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
1021        l = getattr(studycourse,level,None)
1022        if l is None:
1023            studycourse.invokeFactory('StudentStudyLevel', level)
1024            l = getattr(studycourse, level)
1025            self.portal_workflow.doActionFor(l,'open',dest_container=l)
1026            l.getContent().edit(mapping={'Title': "Level %s" % level})
1027        ###)
1028
1029    security.declarePublic('getHallInfo') ###(
1030    def getHallInfo(self,bed):
1031        """return Hall Info"""
1032        info = {}
1033        hall,block,room,letter = bed.split('_')
1034        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
1035        if res and len(res) == 1:
1036            hall_brain = res[0]
1037            hall_doc = hall_brain.getObject().getContent()
1038        else:
1039            return info
1040        info['hall_title'] = hall_brain.Title
1041        info['maintenance_code'] = hall_doc.maintenance_code
1042        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
1043        batch_doc = None
1044        for brain in res:
1045            if brain.id.startswith(info['maintenance_code']):
1046                batch_doc = brain.getObject().getContent()
1047                break
1048        if batch_doc is None:
1049            info['maintenance_fee'] = ''
1050        else:
1051            info['maintenance_fee'] = batch_doc.cost
1052        return info
1053    ###)
1054
1055    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
1056    def removePictureFolder(self,student_id):
1057        """remove picture_folder by renaming it"""
1058        path = 'images'
1059        picture_path = os.path.join(i_home,path,student_id)
1060        if not os.path.exists(picture_path):
1061            return False
1062        os.rename(picture_path,picture_path + "_removed")
1063        return True
1064    ###)
1065
1066    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
1067    def restorePictureFolder(self,student_id):
1068        """restore picture_folder by renaming it"""
1069        path = 'images'
1070        picture_path = os.path.join(i_home,path,student_id)
1071        if not os.path.exists(picture_path + "_removed"):
1072            return False
1073        os.rename(picture_path + "_removed",picture_path)
1074        return True
1075    ###)
1076
1077    security.declarePublic('picturesExist') ###(
1078    def picturesExist(self, ids,student_id=None):
1079        """check if pictures exist in the filesystem"""
1080        if student_id is None:
1081            student_id = self.getStudentId()
1082        if student_id is None:
1083            return False
1084        picture_path = getImagesDir(student_id)
1085        #picture_path = os.path.join(images_base,student_id)
1086        if not os.path.exists(picture_path):
1087            return False
1088        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1089        return set(ids).issubset(set(pictures))
1090    ###)
1091
1092    security.declarePublic('picturesList') ###(
1093    def picturesList(self):
1094        """check if pictures exist in the filesystem"""
1095        path = 'images'
1096        student_id = self.getStudentId()
1097        #picture_path = os.path.join(i_home,path,student_id)
1098        picture_path = getImagesDir(student_id)
1099        if not os.path.exists(picture_path):
1100            return []
1101        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1102    ###)
1103
1104    security.declarePublic('showFsPicture') ###(
1105    def showFsPicture(self,path):
1106        """return a picture from the filesystem"""
1107        #picture_path = os.path.join(i_home,path)
1108        picture_path = os.path.join(images_base,path)
1109        response = self.REQUEST.RESPONSE
1110        #import pdb;pdb.set_trace()
1111        registry = getToolByName(self, 'mimetypes_registry')
1112        mimetype = str(registry.lookupExtension(path.lower()) or
1113                    registry.lookupExtension('file.bin'))
1114        if os.path.exists(picture_path):
1115            response.setHeader('Content-type',mimetype)
1116            return open(picture_path).read()
1117        picture_path = os.path.join(i_home,'import',path)
1118        if os.path.exists(picture_path):
1119            return open(picture_path).read()
1120    ###)
1121
1122    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
1123    def deleteAllCourses(self,department="All"):
1124        ''' delete the courses'''
1125        pm = self.portal_membership
1126        member = pm.getAuthenticatedMember()
1127
1128        if str(member) not in ("henrik","joachim"):
1129            return "not possible"
1130        if department == "All":
1131            res = self.portal_catalog({'meta_type': 'Department'})
1132        if len(res) < 1:
1133            return "No Departments found"
1134
1135        deleted = []
1136        for dep in res:
1137            cf = dep.getObject().courses
1138            if cf:
1139                cf.manage_delObjects(ids=cf.objectIds())
1140                deleted.append("deleted Courses in %s" % dep.getId)
1141        return "\r".join(deleted)
1142    ###)
1143
1144    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
1145    def getLogfileLines(self,filename="event.log",numlines=20):
1146        """Get last NUMLINES lines of logfile FILENAME.
1147
1148        Return last lines' of a file in the instances logfile directory as
1149        a list. The number of returned lines equals `numlines' or less. If
1150        less than `numlines' lines are available, the whole file ist
1151        returned. If the file can not be opened or some other error
1152        occurs, empty list is returend.
1153        """
1154        result = []
1155        lines_hit = 0
1156
1157        # We only handle files in instances' log directory...
1158        logpath = os.path.join(i_home, "log")
1159        filename = str(os.path.abspath( os.path.join( logpath, filename )))
1160        if not filename.startswith( logpath ):
1161            # Attempt to access file outside log-dir...
1162            return []
1163
1164        try:
1165            fd = file( filename, "rb" )
1166        except IOError:
1167            return []
1168        if not fd:
1169            return []
1170
1171        if os.linesep == None:
1172            linesep = '\n'
1173        else:
1174            linesep = os.linesep
1175
1176        # Try to find 'numlines' times a lineseparator, searching from end
1177        # and moving to the beginning of file...
1178        fd.seek( 0, 2) # Move to end of file...
1179        while lines_hit < numlines:
1180            if fd.read(1) == linesep[-1]: # This moves filedescriptor
1181                                          # one step forward...
1182                lines_hit += 1
1183            try:
1184                fd.seek( -2, 1) # Go two bytes back from current pos...
1185            except IOError:
1186                # We cannot go back two bytes. Maybe the file is too small...
1187                break
1188        fd.seek(2,1)
1189
1190        # Read all lines from current position...
1191        result = fd.readlines()
1192        # Remove line endings...
1193        result = [x.strip() for x in result]
1194        fd.close()
1195        return result
1196    ###)
1197
1198    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
1199    def getCallbacksFromLog(self,filename):
1200        """fix Online Payment Transactions from Z2.log entries"""
1201        import transaction
1202        import random
1203        from cgi import parse_qs
1204        from urlparse import urlparse
1205        #from pdb import set_trace
1206        wftool = self.portal_workflow
1207        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1208        students_folder = self.portal_url.getPortalObject().campus.students
1209        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
1210        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
1211        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
1212        data = re.compile(s)
1213        start = True
1214        tr_count = 1
1215        total = 0
1216        #name = 'pume_results'
1217        #name = 'epaymentsuccessful_z2log2'
1218        name = filename
1219        no_import = []
1220        imported = []
1221        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
1222        try:
1223            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
1224        except:
1225            logger.error('Error reading %s' % name)
1226            return
1227        tas = []
1228        for line in transactions:
1229            dict = {}
1230            items = data.search(line)
1231            dict['idict'] = idict = items.groupdict()
1232            #print idict
1233            #from pdb import set_trace;set_trace()
1234            urlparsed = urlparse(idict['get'][4:])
1235            #print urlparsed
1236            path = urlparsed[2].split('/')
1237            dict['student_id'] = student_id = path[8]
1238            dict['payment_id'] = payment_id = path[10]
1239            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
1240            tas.append(dict)
1241            tr_count += 1
1242        return tas
1243    ###)
1244
1245    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
1246    def importOnlinePaymentTransactions(self):
1247        """load Online Payment Transactions from CSV values"""
1248        import transaction
1249        import random
1250        #from pdb import set_trace
1251        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1252        opt = self.online_payments_import
1253        students_folder = self.portal_url.getPortalObject().campus.students
1254        start = True
1255        tr_count = 1
1256        total = 0
1257        #name = 'pume_results'
1258        name = 'OnlineTransactions'
1259        no_import = []
1260        imported = []
1261        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
1262        try:
1263            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
1264        except:
1265            logger.error('Error reading %s.csv' % name)
1266            return
1267        for pay_transaction in transactions:
1268            if start:
1269                start = False
1270                logger.info('Start loading from %s.csv' % name)
1271                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
1272                no_import.append('%s,"Error"' % s)
1273                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
1274                format_error = format + ',"%(Error)s"'
1275            data = {}
1276
1277            # format of the first file sent by Tayo
1278            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
1279            #data['student_id'] = student_id = pay_transaction['Payer ID']
1280            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1281            #data['response_code'] = response_code = pay_transaction['Resp Code']
1282            #data['amount'] = amount = pay_transaction['Amount']
1283
1284            # format of the second file sent by Tayo
1285            #data['datetime'] = date = 0
1286            #data['student_id'] = student_id = pay_transaction['Payer ID']
1287            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1288            #data['response_code'] = response_code = '00'
1289            #data['amount'] = amount = pay_transaction['Amount']
1290
1291            # format of the third file sent by Kehinde
1292            data['datetime'] = date = 0
1293            data['student_id'] = student_id = pay_transaction['customer_id']
1294            data['order_id'] = order_id = pay_transaction['merchant_reference']
1295            data['response_code'] = response_code = '00'
1296            data['amount'] = amount = pay_transaction['Amount']
1297
1298            dup = False
1299            if response_code == "12":
1300                continue
1301            try:
1302                opt.addRecord(**data)
1303            except ValueError:
1304                dup = True
1305            #from pdb import set_trace;set_trace()
1306            if dup:
1307                if response_code == "00":
1308                    try:
1309                        opt.modifyRecord(**data)
1310                    except:
1311                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
1312                        continue
1313                else:
1314                    pay_transaction['Error'] = "Duplicate order_id"
1315                    no_import.append( format_error % pay_transaction)
1316                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
1317                    continue
1318            tr_count += 1
1319            if tr_count > 1000:
1320                if len(no_import) > 0:
1321                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1322                             '\n'.join(no_import) + '\n')
1323                    no_import = []
1324                em = '%d transactions committed\n' % (tr_count)
1325                transaction.commit()
1326                regs = []
1327                logger.info(em)
1328                total += tr_count
1329                tr_count = 0
1330        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1331                                                '\n'.join(no_import))
1332        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
1333    ###)
1334
1335    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
1336    def mass_create_faculty(self,mapping):
1337        "create a faculty"
1338        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
1339        academics_folder = self.portal_url.getPortalObject().campus.academics
1340        fid = mapping['code']
1341        if getattr(academics_folder,fid,None) is not None:
1342            return '', "Faculty with ID: %s exists" % fid
1343        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
1344        try:
1345            academics_folder.invokeFactory('Faculty', fid)
1346        except BadRequest,E:
1347            return '', "%s" % E
1348        f = getattr(academics_folder,fid,None)
1349        f.getContent().edit(mapping=mapping)
1350        return fid,''
1351    ###)
1352
1353    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
1354    def mass_edit_faculty(self,mapping):
1355        "edit a faculty"
1356        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
1357        academics_folder = self.portal_url.getPortalObject().campus.academics
1358        fid = mapping['code']
1359        f = getattr(academics_folder,fid,None)
1360        if f is None:
1361            return '', "Faculty with ID: %s does not exist" % fid
1362        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
1363        f.getContent().edit(mapping=mapping)
1364        return fid,''
1365    ###)
1366
1367    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
1368    def mass_create_department(self,mapping):
1369        "create a department in the correct faculty"
1370        logger = logging.getLogger('WAeUPTool.mass_create_department')
1371        fid = mapping['faculty_code']
1372        if getattr(self,'_v_faculties',None) is None:
1373            res = self.portal_catalog(portal_type = "Faculty")
1374            self._v_faculties = {}
1375            for f in res:
1376                self._v_faculties[f.getId] = f.getObject()
1377        f = self._v_faculties.get(fid,None)
1378        if f is None:
1379            return '', "No Faculty with ID: %s" % fid
1380        else:
1381            did = mapping.get('code')
1382            d = getattr(f,did,None)
1383            if d is None or d.portal_type == "Faculty":
1384                logger.info('Creating Department %(code)s, %(title)s' % mapping)
1385                try:
1386                    f.invokeFactory('Department', did)
1387                except BadRequest,E:
1388                    return '', "%s" % E
1389                d = getattr(f,did)
1390                d.invokeFactory('CoursesFolder','courses')
1391                courses = getattr(d,'courses')
1392                dict = {'Title': 'Courses'}
1393                courses.getContent().edit(mapping=dict)
1394                d.invokeFactory('CertificatesFolder','certificates')
1395                certificates = getattr(d,'certificates')
1396                dict = {'Title': 'Certificates'}
1397                certificates.getContent().edit(mapping=dict)
1398            d.getContent().edit(mapping=mapping)
1399        return did,''
1400    ###)
1401
1402    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
1403    def mass_edit_department(self,mapping):
1404        "create a department in the correct faculty"
1405        logger = logging.getLogger('WAeUPTool.mass_create_department')
1406        academics_folder = self.portal_url.getPortalObject().campus.academics
1407        fid = mapping['faculty_code']
1408        did = mapping.get('code')
1409        try:
1410            d = getattr(getattr(academics_folder,fid),did,None)
1411        except KeyError:
1412            return '', "Department %s or Faculty %s wrong" % (did,fid)
1413        else:
1414            if d is None or d.portal_type == "Faculty":
1415                logger.info('Editing Department %(code)s, %(title)s' % mapping)
1416            d.getContent().edit(mapping=mapping)
1417        return did,''
1418    ###)
1419
1420    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1421    def mass_create_course(self,mapping):
1422        #import pdb;pdb.set_trace()
1423        if getattr(self,'_v_course_list',None) is None:
1424            self._v_course_list = []
1425        if getattr(self,'_v_departments',None) is None:
1426            res = self.portal_catalog(portal_type = "Department")
1427            self._v_department_courses = {}
1428            for d in res:
1429                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
1430        did = mapping['department_code']
1431        d = self._v_department_courses.get(did,None)
1432        if d is None:
1433            return '', "No Department with ID: %s" % did
1434        course_id = mapping.get('code')
1435        if course_id in self._v_course_list:
1436            return '', "Duplicate Course ID: %s" % did
1437        c = getattr(d,course_id,None)
1438        if c is not None:
1439            return '', "Duplicate Course ID: %s" % did
1440        try:
1441            d.invokeFactory('Course', course_id)
1442        except BadRequest,E:
1443            return '', "%s" % E
1444        self._v_course_list.append(course_id)
1445        c = getattr(d,course_id)
1446        c.getContent().edit(mapping=mapping)
1447        return course_id,''
1448    ###)
1449
1450    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1451    def mass_edit_course(self,mapping):
1452        #import pdb;pdb.set_trace()
1453        course_id = mapping.get('code')
1454        res = self.portal_catalog(id=course_id)
1455        if not res:
1456            return '', "No Course with ID: %s" % course_id
1457        c = res[0].getObject()
1458        c.getContent().edit(mapping=mapping)
1459        return course_id,''
1460    ###)
1461
1462    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1463    def mass_create_certificate(self,mapping):
1464        if getattr(self,'_v_certificate_list',None) is None:
1465            self._v_certificate_list = []
1466        if getattr(self,'_v_department_certificates',None) is None:
1467            res = self.portal_catalog(portal_type = "Department")
1468            self._v_department_certificates = {}
1469            for d in res:
1470                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
1471        did = mapping['department_code']
1472        d = self._v_department_certificates.get(did,None)
1473        if d is None:
1474            return '', "No Department with ID: %s" % did
1475        certificate_id = mapping.get('code')
1476        if certificate_id in self._v_certificate_list:
1477            return '', "Duplicate Certificate ID: %s" % did
1478        c = getattr(d,certificate_id,None)
1479        if c is not None:
1480            return '', "Duplicate Certificate ID: %s" % did
1481        try:
1482            d.invokeFactory('Certificate', certificate_id)
1483        except BadRequest,E:
1484            return '', "%s" % E
1485        self._v_certificate_list.append(certificate_id)
1486        c = getattr(d,certificate_id)
1487        c.getContent().edit(mapping=mapping)
1488        return certificate_id,''
1489    ###)
1490
1491    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1492    def mass_edit_certificate(self,mapping):
1493        #import pdb;pdb.set_trace()
1494        certificate_id = mapping.get('code')
1495        res = self.portal_catalog(id=certificate_id)
1496        if not res:
1497            return '', "No Certificate with ID: %s" % certificate_id
1498        c = res[0].getObject()
1499        c.getContent().edit(mapping=mapping)
1500        return certificate_id,''
1501    ###)
1502
1503    security.declareProtected(ModifyPortalContent,'mass_create_application') ###(
1504    def mass_create_application(self,mapping):
1505        #import pdb;pdb.set_trace()
1506        reg_no = mapping.get('reg_no')
1507        try:
1508            self.applicants_catalog.addRecord(**mapping)
1509        except ValueError:
1510            return '', "applicant record with reg_no %s already exists" % reg_no
1511        return reg_no,''
1512    ###)
1513
1514    security.declareProtected(ModifyPortalContent,'mass_edit_application') ###(
1515    def mass_edit_application(self,mapping):
1516        #import pdb;pdb.set_trace()
1517        reg_no = mapping.get('reg_no')
1518        status = mapping.get('status')
1519        res = self.applicants_catalog(reg_no = reg_no)
1520        if len(res):
1521            if res[0].status == 'created' and status != 'created':
1522                return '', "student object with id %s for %s already created, status cannot be changed" % (res[0].student_id, reg_no)
1523            elif status == 'created' and res[0].status != 'created':
1524                return '', "student object for %s has not yet been created, status cannot be set to 'created'" % (reg_no)
1525            else:
1526                self.applicants_catalog.modifyRecord(**mapping)
1527                return reg_no,''
1528        else:
1529            return '', "applicant record with reg_no %s does not exist" % reg_no
1530
1531    ###)
1532
1533    security.declareProtected(ModifyPortalContent,'mass_create_course_result') ###(
1534    def mass_create_course_result(self,mapping):
1535        #import pdb;pdb.set_trace()
1536        students_folder = self.portal_url.getPortalObject().campus.students
1537        if getattr(self,'_v_courses',None) is None:
1538            res = self.courses_catalog()
1539            self._v_courses = {}
1540            for brain in res:
1541                self._v_courses[brain.code] = brain
1542        if getattr(self,'_v_level_created',None) is None:
1543            self._v_level_created = []
1544        course_id = mapping.get('code')
1545        if course_id not in self._v_courses.keys():
1546            return '', "No course with ID: %s" % course_id
1547        id_key = ''
1548        for id_key in ('student_id','matric_no'):
1549            id_field = mapping.get(id_key,None)
1550            if id_field is not None:
1551                student_id = id_field
1552                break
1553        query = Eq(id_key,id_field)
1554        res = self.students_catalog.evalAdvancedQuery(query)
1555        if not res:
1556            return '', "no student with %(id_key)s %(id_field)s" % vars()
1557        student_rec = res[0]
1558        if id_field != "student_id":
1559            mapping['student_id'] = student_rec.id
1560        student_id = student_rec.id
1561        level_id = mapping['level_id']
1562        code = mapping['code']
1563        if student_id not in self._v_level_created:
1564            try:
1565                context = getattr(getattr(students_folder,
1566                                          "%(student_id)s" % vars()),
1567                                  'study_course')
1568            except:
1569                return '', "could not create level %(level_id)s for %(student_id)s" % vars()
1570            if level_id not in context.objectIds():
1571                context.invokeFactory('StudentStudyLevel',"%(level_id)s" % vars())
1572                level = getattr(context,"%(level_id)s" % vars())
1573                self.portal_workflow.doActionFor(level,'open')
1574                # the session string must not be copied into the level object
1575                current_verdict = getattr(student_rec,'current_verdict','')
1576                current_session = getattr(student_rec,'current_session','')
1577                if current_verdict and student_rec.current_level == level_id:
1578                    level.getContent().edit(mapping={'verdict': "%s" %
1579                                                     current_verdict,
1580                                                     'session': "%s" %
1581                                                     current_session,
1582                                                    })
1583                    self.portal_workflow.doActionFor(level,'close')
1584            self._v_level_created += student_id,
1585        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
1586        for k in ('semester','credits',):
1587            mapping[k] = getattr(self._v_courses[course_id],k)
1588        try:
1589            self.course_results.addRecord(**mapping)
1590        except ValueError:
1591            return '', "course result already exists: %s" % key
1592        return key,''
1593    ###)
1594
1595    security.declareProtected(ModifyPortalContent,'mass_edit_course_result') ###(
1596    def mass_edit_course_result(self,mapping):
1597        #import pdb;pdb.set_trace()
1598        # if getattr(self,'_v_courses',None) is None:
1599        #     res = self.courses_catalog()
1600        #     self._v_courses = {}
1601        #     for brain in res:
1602        #         self._v_courses[brain.code] = brain
1603        # course_id = mapping.get('code')
1604        # if course_id not in self._v_courses.keys():
1605        #     return '', "No course with ID: %s" % did
1606        id_key = ''
1607        for id_key in ('student_id','matric_no'):
1608            id_field = mapping.get(id_key,None)
1609            if id_field is not None:
1610                student_id = id_field
1611                break
1612        query = Eq(id_key,id_field)
1613        res = self.students_catalog.evalAdvancedQuery(query)
1614        if not res:
1615            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1616        if id_field != "student_id":
1617            mapping['student_id'] = res[0].id
1618        if not res:
1619            return '', "no student with %(id_key)s %(id_field)s" % vars()
1620        student_rec = res[0]
1621        student_id = student_rec.id
1622        level_id = mapping['level_id']
1623        code = mapping['code']
1624        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
1625        # for k in ('semester',):
1626        #     mapping[k] = getattr(self._v_courses[course_id],k)
1627        try:
1628            self.course_results.modifyRecord(**mapping)
1629        except KeyError:
1630            return '', "No course result to edit: %s" % key
1631        return key,''
1632    ###)
1633
1634    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1635    def mass_create_certificate_course(self,mapping):
1636        if getattr(self,'_v_courses',None) is None:
1637            res = self.courses_catalog()
1638            self._v_courses= [course.code for course in res]
1639        if getattr(self,'_v_ceritficates',None) is None:
1640            res = self.portal_catalog(portal_type = "Certificate")
1641            self._v_certificates = {}
1642            for cert in res:
1643                self._v_certificates[cert.getId] = cert.getObject()
1644        certificate_course_id = mapping.get('code')
1645        if certificate_course_id not in self._v_courses:
1646            return '', "No Course with ID: %s" % certificate_course_id
1647        cert_id = mapping['certificate_code']
1648        cert = self._v_certificates.get(cert_id,None)
1649        if cert is None:
1650            return '', "No Certificate with ID: %s" % cert_id
1651        level_id = mapping.get('level')
1652        level = getattr(cert,level_id,None)
1653        if level is None:
1654            cert.invokeFactory('StudyLevel', level_id)
1655            level = getattr(cert,level_id,None)
1656        elif hasattr(level,certificate_course_id):
1657            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1658            (certificate_course_id,cert_id,level_id)
1659        level.invokeFactory('CertificateCourse', certificate_course_id)
1660        c = getattr(level,certificate_course_id)
1661        c.getContent().edit(mapping=mapping)
1662        return certificate_course_id,''
1663    ###)
1664
1665    field2types_student = {   ###(
1666                      'StudentApplication':
1667                          {'id': 'application',
1668                           'title': 'Application Data',
1669                           'wf_transition_return': 'close',
1670                           'wf_transition_admit': 'remain',
1671                           'fields':
1672                             ('jamb_reg_no',
1673                              'entry_mode',
1674                              'entry_session',
1675                              'jamb_score',
1676                              'app_email',
1677                              'jamb_age',
1678                              'jamb_state',
1679                              'jamb_lga',
1680                              'jamb_sex',
1681                              )
1682                              },
1683                      #'StudentPume':
1684                      #    {'id': 'pume',
1685                      #     'title': 'Pume Data',
1686                      #     'wf_transition_return': 'close',
1687                      #     'wf_transition_admit': 'close',
1688                      #     'fields':
1689                      #       ('pume_score',
1690                      #        )
1691                      #        },
1692                      'StudentClearance':
1693                          {'id': 'clearance',
1694                           'title': 'Clearance/Eligibility Record',
1695                           'wf_transition_return': 'close',
1696                           'wf_transition_admit': 'remain',
1697                           'fields':
1698                             ('matric_no',
1699                              'nationality',
1700                              'lga',
1701                              'birthday',
1702                              )
1703                              },
1704                         'StudentPersonal':
1705                          {'id': 'personal',
1706                           'title': 'Personal Data',
1707                           'wf_transition_return': 'open',
1708                           'wf_transition_admit': 'remain',
1709                           'fields':
1710                             ('firstname',
1711                              'middlename',
1712                              'lastname',
1713                              'sex',
1714                              'email',
1715                              'phone',
1716                              'perm_address',
1717                              )
1718                              },
1719                         'StudentStudyCourse':
1720                          {'id': 'study_course',
1721                           'title': 'Study Course',
1722                           'wf_transition_return': 'open',
1723                           'wf_transition_admit': 'remain',
1724                           'fields':
1725                             ('study_course',
1726                              'current_level',
1727                              'current_session',
1728                              'current_mode',
1729                              'current_verdict',
1730                              'previous_verdict',
1731                              )
1732                              },
1733                         # 'StudentStudyLevel':
1734                         #  {'id': 'current_level',
1735                         #   'title': '',
1736                         #   'wf_transition_return': 'open',
1737                         #   'wf_transition_admit': 'remain',
1738                         #   'fields':
1739                         #     ('verdict',
1740                         #      'session',
1741                         #      )
1742                         #      },
1743                         'PaymentsFolder':
1744                          {'id': 'payments',
1745                           'title': 'Payments',
1746                           'wf_transition_return': 'open',
1747                           'wf_transition_admit': 'open',
1748                           'fields':
1749                             ()
1750                              },
1751                         }
1752    ###)
1753
1754    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1755    def mass_create_student(self,mapping):
1756        "create student records due import"
1757        logger = logging.getLogger('WAeUPTool.mass_create_student')
1758        students_folder = self.portal_url.getPortalObject().campus.students
1759        jamb_reg_no = mapping.get('jamb_reg_no',None)
1760        if jamb_reg_no:
1761            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1762            if res:
1763                return '',"jamb_reg_no exists"
1764        matric_no = mapping.get('matric_no',None)
1765        if matric_no:
1766            res = self.students_catalog(matric_no = matric_no)
1767            if res:
1768                return '',"matric_no exists"
1769        sid = self.waeup_tool.generateStudentId('?')
1770        students_folder.invokeFactory('Student', sid)
1771        student_obj = getattr(students_folder,sid)
1772        f2t = self.field2types_student
1773        d = {}
1774        transition = mapping.get('reg_transition','admit')
1775        if transition not in ('admit','return'):
1776            return '',"no valid transition provided"
1777        for pt in f2t.keys():
1778            student_obj.invokeFactory(pt,f2t[pt]['id'])
1779            sub_obj = getattr(student_obj,f2t[pt]['id'])
1780            sub_doc = sub_obj.getContent()
1781            d['Title'] = f2t[pt]['title']
1782            for field in f2t[pt]['fields']:
1783                d[field] = mapping.get(field,'')
1784
1785            if pt == "StudentApplication":
1786                #d['jamb_sex']  = 'M'
1787                #if mapping.get('sex'):
1788                #    d['jamb_sex']  = 'F'
1789                d['jamb_firstname'] = mapping.get('firstname',None)
1790                d['jamb_middlename'] = mapping.get('middlename',None)
1791                d['jamb_lastname'] = mapping.get('lastname',None)
1792
1793            # if pt == "StudyCourse":
1794            #     for von,zu in (('entry_mode','current_mode'),
1795            #                    ('entry_session','current_session')):
1796            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1797            #             d[zu] = mapping[von]
1798            sub_doc.edit(mapping = d)
1799
1800            #import pdb;pdb.set_trace()
1801            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
1802            if new_state != "remain":
1803                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1804        self.portal_workflow.doActionFor(student_obj,transition)
1805        student_obj.manage_setLocalRoles(sid, ['Owner',])
1806        return sid,''
1807    ###)
1808
1809    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1810    def mass_edit_student(self,mapping):
1811        wftool = self.portal_workflow
1812        "edit student records due import"
1813        logger = logging.getLogger('WAeUPTool.mass_edit_student')
1814        students_folder = self.portal_url.getPortalObject().campus.students
1815        sid = mapping.get('id',None)
1816        jamb_reg_no = mapping.get('jamb_reg_no',None)
1817        matric_no = mapping.get('matric_no',None)
1818        editable_keys = mapping.keys()
1819        if sid:
1820            res = self.students_catalog(id = sid)
1821            if not res:
1822                return '',"no student with id %s" % sid
1823            if matric_no and res[0].matric_no and\
1824              matric_no != res[0].matric_no:
1825                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1826            if jamb_reg_no and res[0].jamb_reg_no and\
1827              jamb_reg_no != res[0].jamb_reg_no:
1828                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
1829        elif jamb_reg_no:
1830            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1831            if not res:
1832                return '',"no student with jamb_reg_no %s" % jamb_reg_no
1833            editable_keys.remove('jamb_reg_no')
1834        elif matric_no:
1835            res = self.students_catalog(matric_no = matric_no)
1836            if not res:
1837                return '',"no student with matric_no %s" % matric_no
1838            editable_keys.remove('matric_no')
1839
1840        ## included only to change wf state from admitted to returning
1841        #if res[0].review_state not in ('admitted','objection_raised'):
1842        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1843        ## end inclusion
1844
1845        sid = res[0].id
1846        student_obj = getattr(students_folder,sid)
1847        f2t = self.field2types_student
1848        d = {}
1849        #import pdb;pdb.set_trace()
1850        any_change = False
1851        #special treatment for StudentStudyLevel
1852        d['verdict']  = mapping.get('current_verdict','')
1853        d['session']  = mapping.get('current_session','')
1854        current_level = mapping.get('current_level','')
1855        while d['session'] and d['verdict'] and current_level:
1856            sub_obj = getattr(student_obj,'study_course',None)
1857            if sub_obj is None:
1858                break
1859            level_obj = getattr(sub_obj,current_level,None)
1860            if  level_obj is None:
1861                break
1862            any_change = True
1863            level_obj.getContent().edit(mapping = d)
1864            try:
1865                wftool.doActionFor(level_obj,'close')
1866            except:
1867                pass
1868            break
1869        for pt in f2t.keys():
1870            #if pt == "StudentApplication":
1871            #    d['jamb_sex']  = 'M'
1872            #    if mapping.get('sex'):
1873            #        d['jamb_sex']  = 'F'
1874            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
1875            if intersect and pt not in ('StudentStudyLevel',):
1876                object_id = f2t[pt]['id']
1877                sub_obj = getattr(student_obj,object_id,None)
1878                if sub_obj is None:
1879                    try:
1880                        student_obj.invokeFactory(pt,object_id)
1881                    except:
1882                        continue
1883                    sub_obj = getattr(student_obj,object_id)
1884                    if f2t[pt]['title'] != '':
1885                        d['Title'] = f2t[pt]['title']
1886                sub_doc = sub_obj.getContent()
1887                for field in intersect:
1888                    changed = False
1889                    if getattr(sub_doc,field,None) != mapping.get(field,''):
1890                        any_change = True
1891                        changed = True
1892                        d[field] = mapping.get(field,'')
1893                    if changed:
1894                        sub_doc.edit(mapping = d)
1895
1896
1897        ## included only to change wf state from admitted to returning
1898        #    if res[0].review_state in ('admitted','objection_raised'):
1899        #        new_state = f2t[pt]['wf_transition_return']
1900        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1901        #        if sub_obj and new_state != "remain":
1902        #            try:
1903        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1904        #            except:
1905        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1906        #                pass
1907        #if res[0].review_state in ('admitted','objection_raised'):
1908        #    wfaction = 'return'
1909        #    try:
1910        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1911        #        logger.info('%s, wf state changed' % sid)
1912        #        any_change = True
1913        #    except:
1914        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1915        #        pass
1916        ## end inclusion
1917
1918
1919        if any_change:
1920            return sid,''
1921        else:
1922            return sid,'not modified'
1923    ###)
1924
1925    security.declareProtected(ModifyPortalContent,'mass_edit_verdict') ###(
1926    def mass_edit_verdict(self,mapping):
1927        wftool = self.portal_workflow
1928        "edit student verdicts"
1929        logger = logging.getLogger('WAeUPTool.mass_edit_verdict')
1930        students_folder = self.portal_url.getPortalObject().campus.students
1931        student_id = mapping.get('id',None)
1932        matric_no = mapping.get('matric_no',None)
1933        editable_keys = mapping.keys()
1934        if student_id:
1935            student_record = self.students_catalog.getRecordById(student_id)
1936            if student_record is None:
1937                return '',"no student with id %s" % student_id
1938            if matric_no and student_record.matric_no and\
1939              matric_no != student_record.matric_no:
1940                return '', 'student %s matric_no %s does not match %s' % (student_record.id,
1941                                                                          student_record.matric_no,
1942                                                                          matric_no)
1943        elif matric_no:
1944            res = self.students_catalog(matric_no = matric_no)
1945            if not res:
1946                return '',"no student with matric_no %s" % matric_no
1947            student_record = res[0]
1948            editable_keys.remove('matric_no')
1949
1950        student_id = student_record.id
1951        student_review_state =  student_record.review_state
1952        if student_review_state not in ('courses_validated','returning'):
1953            return '',"student %s in wrong review_state %s" % (student_id, student_review_state)
1954        student_obj = getattr(students_folder,student_id)
1955        f2t = self.field2types_student
1956        d = {}
1957        #import pdb;pdb.set_trace()
1958        any_change = False
1959        #special treatment for StudentStudyLevel
1960        current_session = mapping.get('current_session','')
1961        if current_session and student_record.session != current_session:
1962            return '','student_id: %s imported session %s does not match current_session %s' % (student_id,
1963                                                                                        current_session,
1964                                                                                        student_record.session)
1965
1966        current_level = mapping.get('current_level','')
1967        if current_level and student_record.level != current_level:
1968            return '','student_id %s: imported level %s does not match current_level %s' % (student_id,
1969                                                                                    current_level,
1970                                                                                    student_record.level)
1971        study_course_obj = getattr(student_obj,'study_course',None)
1972        if study_course_obj is None:
1973            return '','student_id %s: no study_course object' % student_id
1974        level_obj = getattr(study_course_obj,current_level,None)
1975        if  level_obj is None:
1976            return '','student_id %s: no study_level object for level %s' % (student_id,
1977                                                                             current_level)
1978        verdict = d['verdict'] = d['current_verdict']  = mapping.get('current_verdict','')
1979        if verdict == student_record.verdict:
1980            return '','student_id %s: verdict already set to %s' % (student_id,
1981                                                                    verdict)
1982
1983        level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
1984        if level_review_state != "closed":
1985            return '','student_id %s: level %s is not closed' % (student_id,
1986                                                                 current_level)
1987
1988        study_course_obj.getContent().edit(mapping = d)
1989        level_obj.getContent().edit(mapping = d)
1990        if student_review_state != "returning":
1991            wftool.doActionFor(student_obj,'return')
1992        try:
1993            wftool.doActionFor(level_obj,'close')
1994        except:
1995            pass
1996        return student_id,''
1997    ###)
1998
1999    security.declareProtected(ModifyPortalContent,"importData")###(
2000    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
2001        """load data from CSV values"""
2002        import transaction
2003        import random
2004
2005        pm = self.portal_membership
2006        member = pm.getAuthenticatedMember()
2007
2008        logger = logging.getLogger('WAeUPTool.importData')
2009        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
2010        students_folder = self.portal_url.getPortalObject().campus.students
2011        start = True
2012        tr_count = 0
2013        total_imported = 0
2014        total_not_imported = 0
2015        total = 0
2016        iname = "import_%s" % name
2017        if iname in ('import_application','import_course_result',):
2018            commit_after = 2000
2019        else:
2020            commit_after = 100
2021        stool = getToolByName(self, 'portal_schemas')
2022        ltool = getToolByName(self, 'portal_layouts')
2023        schema = stool._getOb(iname)
2024        if schema is None:
2025            em = 'No such schema %s' % iname
2026            logger.error('No such schema %s' % iname)
2027            return em
2028        layout = ltool._getOb(iname)
2029        if layout is None:
2030            em = 'No such layout %s' % iname
2031            logger.error(em)
2032            return em
2033        validators = {}
2034        for widget in layout.keys():
2035            validators[widget] = layout[widget].validate
2036        mode = "create"
2037        if edit:
2038            mode = "edit"
2039        importer_name = "mass_%(mode)s_%(name)s" % vars()
2040        importer = getattr(self, '%s' % importer_name,None)
2041        if importer is None:
2042            em = 'No importer function %s' % importer_name
2043            logger.error(em)
2044            return em
2045        not_imported = []
2046        imported = []
2047        try:
2048            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
2049        except:
2050            em = 'Error reading %s.csv' % filename
2051            logger.error(em)
2052            return em
2053        for item in items:
2054            #import pdb;pdb.set_trace()
2055            item = dict((k.strip(),l.strip()) for (k,l) in item.items())
2056            if start:
2057                start = False
2058                adapters = [MappingStorageAdapter(schema, item)]
2059                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
2060                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
2061                import_keys = [k.strip() for k in attrs if not k.strip().startswith('ignore')]
2062                diff2schema = set(import_keys).difference(set(schema.keys()))
2063                diff2layout = set(import_keys).difference(set(layout.keys()))
2064                if diff2schema:
2065                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
2066                    return em
2067                if mode == "create":
2068                    required_keys = [layout.getIdUnprefixed(id)
2069                                     for id,widget in layout.objectItems()
2070                                     if widget.is_required]
2071                    if not set(required_keys).issubset(set(import_keys)):
2072                        diff2import = set(required_keys).difference(set(import_keys))
2073                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
2074                        return em
2075                s = ','.join(['"%s"' % fn for fn in import_keys])
2076                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
2077                s = '"id",' + s
2078                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
2079                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
2080                format_error = format + ',"%(Error)s"'
2081                format = '"%(id)s",'+ format
2082
2083            dm = DataModel(item, adapters,context=self)
2084            ds = DataStructure(data=item,datamodel=dm)
2085            error_string = ""
2086            total += 1
2087            error_count = 0
2088            for k in import_keys:
2089                if not validators[k](ds,mode=mode):
2090                    if error_count:
2091                        error_string += ' ++ '
2092                    error_string += "%s: %s" % (k,
2093                                                  self.translation_service(ds.getError(k),
2094                                                                           ds.getErrorMapping(k)))
2095                    error_count += 1
2096            if not error_string:
2097                temp_item = item.copy()
2098                temp_item.update(dm)
2099                temp_item['id'],error = importer(temp_item)
2100                if error:
2101                    error_string += error
2102                else:
2103                    item = temp_item
2104            if error_string:
2105                item['Error'] = error_string
2106                not_imported.append(format_error % item)
2107                total_not_imported += 1
2108            else:
2109                em = format % item
2110                imported.append(em)
2111                tr_count += 1
2112                total_imported += 1
2113                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
2114
2115            if total and not total % commit_after:
2116                transaction.commit()
2117                if len(not_imported) > 0:
2118                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
2119                             '\n'.join(not_imported) + '\n')
2120                    not_imported = []
2121                if len(imported) > 0:
2122                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
2123                             '\n'.join(imported) + '\n')
2124                    imported = []
2125                em = '%d transactions committed\n' % (tr_count)
2126                regs = []
2127                logger.info(em)
2128                tr_count = 0
2129                #if total > 100:
2130                #    return
2131        if len(imported) > 0:
2132            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
2133                                                '\n'.join(imported))
2134        if len(not_imported) > 0:
2135            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
2136                                                '\n'.join(not_imported))
2137        em = "Finished import from %s.csv: %d imported, %d not imported (of total %d)" % (filename,total_imported,total_not_imported,total)
2138        logger.info(em)
2139        return em
2140    ###)
2141
2142    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
2143    def moveImagesToFS(self,student_id="O738726"):
2144        "move the images to the filesystem"
2145        images_dir = getImagesDir(student_id)
2146        #images_dir = os.path.join("%s" % images_base,student_id)
2147        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
2148        stool = getToolByName(self, 'portal_schemas')
2149        schemas = ['student_application',
2150                   'student_clearance',
2151                   ]
2152        created = False
2153        for schema_id in schemas:
2154            schema = stool._getOb(schema_id)
2155            object = getattr(student_folder,schema_id[len('student_'):],None)
2156            if object is None:
2157                continue
2158            doc = object.getContent()
2159            for key in schema.keys():
2160                if schema[key].meta_type != "CPS Image Field":
2161                    continue
2162                #import pdb;pdb.set_trace()
2163                image = getattr(doc,key,None)
2164                if not image or not hasattr(image,"data"):
2165                    continue
2166                if not created:
2167                    if not os.path.exists(images_dir):
2168                        os.mkdir(images_dir)
2169                    created = True
2170                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
2171                open(filename,"wb").write(str(image.data))
2172    ###)
2173
2174    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
2175    def movePassportToFS(self,student_id="O738726"):
2176        "move the passports to the filesystem"
2177        images_dir = os.path.join("%s" % i_home,'passports')
2178        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
2179        stool = getToolByName(self, 'portal_schemas')
2180        schemas = ['student_application',
2181                   #'student_clearance',
2182                   ]
2183        created = False
2184        for schema_id in schemas:
2185            schema = stool._getOb(schema_id)
2186            object = getattr(student_folder,schema_id[len('student_'):],None)
2187            if object is None:
2188                continue
2189            doc = object.getContent()
2190            for key in schema.keys():
2191                if schema[key].meta_type != "CPS Image Field":
2192                    continue
2193                #import pdb;pdb.set_trace()
2194                image = getattr(doc,key)
2195                if not hasattr(image,"data"):
2196                    continue
2197                if not created:
2198                    if not os.path.exists(images_dir):
2199                        os.mkdir(images_dir)
2200                    created = True
2201                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
2202                open(filename,"wb").write(str(image.data))
2203    ###)
2204
2205InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.