source: WAeUP_SRP/base/WAeUPTool.py @ 2500

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

put back in mass_create_course_result

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