source: WAeUP_SRP/base/WAeUPTool.py @ 2436

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

copy student names into application object

  • Property svn:keywords set to Id
File size: 66.2 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 2436 2007-10-25 20:31:49Z 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
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,.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()[-2:]:
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##        em = student.Mode_of_Entry
582##        if em in ('DIRECT', 'DIRECT ENTRY',):
583##            em = 'DE'
584##        elif em in ('U.M.E', 'UNE',):
585##            em = 'UME'
586##        elif not em:
587##            em = "unknown"
588        da['entry_mode'] = em
589        personal = student_obj.personal
590        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
591        dp = {'Title': 'Personal Data'}
592        student_obj.invokeFactory('StudentClearance','clearance')
593        clearance = student_obj.clearance
594        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
595        dc = {'Title': 'Clearance/Eligibility Record'}
596        dc['matric_no'] = matric_no
597        state = student.State
598        lga = student.LGA
599        if state and lga:
600            lga =  state + ' / ' + lga
601        else:
602            lga = "None"
603        da['jamb_lga'] = dc['lga'] = lga
604        da['app_email'] = dp['email'] = email
605        da['app_mobile'] = dp['phone'] = phone_nr
606        dp['firstname'] = student.Firstname
607        dp['middlename'] = student.Middlename
608        dp['lastname'] = student.Lastname
609        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
610        da['jamb_sex'] = student.Sex
611        dp['sex'] = student.Sex == 'F'
612        dp['perm_address'] = student.Permanent_Address
613        application.getContent().edit(mapping=da)
614        self.portal_workflow.doActionFor(application,'close',dest_container=application)
615        personal.getContent().edit(mapping=dp)
616        clearance.getContent().edit(mapping=dc)
617        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
618##        catd = {}
619##        catd['id'] = sid
620##        catd['entry_mode']= da['entry_mode']
621##        catd['matric_no'] = matric_no
622##        catd['jamb_reg_no'] = da['jamb_reg_no']
623##        catd['name'] = "%(firstname)s %(middlename)s %(lastname)s" % dp
624##        catd['sex'] = dp['sex']
625##        catd['level'] = level
626##        catd['verdict'] = verdict
627##        if certificate_brain:
628##            cpath = certificate_brain.getPath().split('/')
629##            catd['faculty'] = cpath[-4]
630##            catd['department'] = cpath[-3]
631##            catd['course'] = certcode
632##        self.students_catalog.modifyRecord(**catd)
633        #
634        # Study Course
635        #
636        student_obj.invokeFactory('StudentStudyCourse','study_course')
637        studycourse = student_obj.study_course
638        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
639        dsc = {}
640        dsc['study_course'] = certcode
641        dsc['current_level'] = level
642        dsc['current_verdict'] = verdict
643        dsc['current_mode'] = em
644        dsc['current_session'] = '06'
645        studycourse.getContent().edit(mapping=dsc)
646        #
647        # Level
648        #
649##        l = getattr(studycourse,level,None)
650##        if l is None:
651##            studycourse.invokeFactory('StudentStudyLevel', level)
652##            l = getattr(studycourse, level)
653##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
654##            l.getContent().edit(mapping={'Title': "Level %s" % level})
655###)
656
657    security.declarePublic('makeStudentLevel') ###(
658    def makeStudentLevel(self,student_id):
659        "create the StudyLevel for a returning Student"
660        #import pdb;pdb.set_trace()
661        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
662        students_folder = self.portal_url.getPortalObject().campus.students
663        res = self.students_catalog(id=student_id)
664        if res:
665            st = res[0]
666        course = st.course
667        matric_no = st.matric_no
668        level = st.level
669        res = self.results_import(matric_no = matric_no)
670        if res:
671            results = res
672        logger.info('%s creating Level %s' % (student_id,level))
673        #
674        # Level
675        #
676        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
677        studycourse = getattr(student_obj,"study_course",None)
678        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
679        l = getattr(studycourse,level,None)
680        if l is None:
681            studycourse.invokeFactory('StudentStudyLevel', level)
682            l = getattr(studycourse, level)
683            self.portal_workflow.doActionFor(l,'open',dest_container=l)
684            l.getContent().edit(mapping={'Title': "Level %s" % level})
685        ###)
686
687    security.declarePublic('getHallInfo') ###(
688    def getHallInfo(self,bed):
689        """return Hall Info"""
690        info = {}
691        hall,block,room,letter = bed.split('_')
692        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
693        if res and len(res) == 1:
694            hall_brain = res[0]
695            hall_doc = hall_brain.getObject().getContent()
696        else:
697            return info
698        info['hall_title'] = hall_brain.Title
699        info['maintenance_code'] = hall_doc.maintenance_code
700        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
701        batch_doc = None
702        for brain in res:
703            if brain.id.startswith(info['maintenance_code']):
704                batch_doc = brain.getObject().getContent()
705                break
706        if batch_doc is None:
707            info['maintenance_fee'] = None
708        else:
709            info['maintenance_fee'] = batch_doc.cost
710        return info
711    ###)
712
713    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
714    def removePictureFolder(self,student_id):
715        """remove picture_folder by renaming it"""
716        path = 'images'
717        picture_path = os.path.join(i_home,path,student_id)
718        if not os.path.exists(picture_path):
719            return False
720        os.rename(picture_path,picture_path + "_removed")
721        return True
722    ###)
723
724    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
725    def restorePictureFolder(self,student_id):
726        """restore picture_folder by renaming it"""
727        path = 'images'
728        picture_path = os.path.join(i_home,path,student_id)
729        if not os.path.exists(picture_path + "_removed"):
730            return False
731        os.rename(picture_path + "_removed",picture_path)
732        return True
733    ###)
734
735    security.declarePublic('picturesExist') ###(
736    def picturesExist(self, ids,student_id=None):
737        """check if pictures exist in the filesystem"""
738        if student_id is None:
739            student_id = self.getStudentId()
740        if student_id is None:
741            return False
742        picture_path = os.path.join(images_base,student_id)
743        if not os.path.exists(picture_path):
744            return False
745        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
746        return set(ids).issubset(set(pictures))
747    ###)
748
749    security.declarePublic('picturesList') ###(
750    def picturesList(self):
751        """check if pictures exist in the filesystem"""
752        path = 'images'
753        student_id = self.getStudentId()
754        picture_path = os.path.join(i_home,path,student_id)
755        if not os.path.exists(picture_path):
756            return []
757        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
758    ###)
759
760    security.declarePublic('showFsPicture') ###(
761    def showFsPicture(self,path):
762        """return a picture from the filesystem"""
763        picture_path = os.path.join(i_home,path)
764        response = self.REQUEST.RESPONSE
765        #import pdb;pdb.set_trace()
766        registry = getToolByName(self, 'mimetypes_registry')
767        mimetype = str(registry.lookupExtension(path.lower()) or
768                    registry.lookupExtension('file.bin'))
769        if os.path.exists(picture_path):
770            response.setHeader('Content-type',mimetype)
771            return open(picture_path).read()
772        picture_path = os.path.join(i_home,'import',path)
773        if os.path.exists(picture_path):
774            return open(picture_path).read()
775    ###)
776
777    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
778    def deleteAllCourses(self,department="All"):
779        ''' delete the courses'''
780        pm = self.portal_membership
781        member = pm.getAuthenticatedMember()
782
783        if str(member) not in ("henrik","joachim"):
784            return "not possible"
785        if department == "All":
786            res = self.portal_catalog({'meta_type': 'Department'})
787        if len(res) < 1:
788            return "No Departments found"
789
790        deleted = []
791        for dep in res:
792            cf = dep.getObject().courses
793            if cf:
794                cf.manage_delObjects(ids=cf.objectIds())
795                deleted.append("deleted Courses in %s" % dep.getId)
796        return "\r".join(deleted)
797    ###)
798
799    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
800    def getLogfileLines(self,filename="event.log",numlines=20):
801        """Get last NUMLINES lines of logfile FILENAME.
802
803        Return last lines' of a file in the instances logfile directory as
804        a list. The number of returned lines equals `numlines' or less. If
805        less than `numlines' lines are available, the whole file ist
806        returned. If the file can not be opened or some other error
807        occurs, empty list is returend.
808        """
809        result = []
810        lines_hit = 0
811
812        # We only handle files in instances' log directory...
813        logpath = os.path.join(i_home, "log")
814        filename = str(os.path.abspath( os.path.join( logpath, filename )))
815        if not filename.startswith( logpath ):
816            # Attempt to access file outside log-dir...
817            return []
818
819        try:
820            fd = file( filename, "rb" )
821        except IOError:
822            return []
823        if not fd:
824            return []
825
826        if os.linesep == None:
827            linesep = '\n'
828        else:
829            linesep = os.linesep
830
831        # Try to find 'numlines' times a lineseparator, searching from end
832        # and moving to the beginning of file...
833        fd.seek( 0, 2) # Move to end of file...
834        while lines_hit < numlines:
835            if fd.read(1) == linesep[-1]: # This moves filedescriptor
836                                          # one step forward...
837                lines_hit += 1
838            try:
839                fd.seek( -2, 1) # Go two bytes back from current pos...
840            except IOError:
841                # We cannot go back two bytes. Maybe the file is too small...
842                break
843        fd.seek(2,1)
844
845        # Read all lines from current position...
846        result = fd.readlines()
847        # Remove line endings...
848        result = [x.strip() for x in result]
849        fd.close()
850        return result
851    ###)
852
853    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
854    def getCallbacksFromLog(self,filename):
855        """fix Online Payment Transactions from Z2.log entries"""
856        import transaction
857        import random
858        from cgi import parse_qs
859        from urlparse import urlparse
860        #from pdb import set_trace
861        wftool = self.portal_workflow
862        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
863        students_folder = self.portal_url.getPortalObject().campus.students
864        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
865        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
866        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
867        data = re.compile(s)
868        start = True
869        tr_count = 1
870        total = 0
871        #name = 'pume_results'
872        #name = 'epaymentsuccessful_z2log2'
873        name = filename
874        no_import = []
875        imported = []
876        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
877        try:
878            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
879        except:
880            logger.error('Error reading %s' % name)
881            return
882        tas = []
883        for line in transactions:
884            dict = {}
885            items = data.search(line)
886            dict['idict'] = idict = items.groupdict()
887            #print idict
888            #from pdb import set_trace;set_trace()
889            urlparsed = urlparse(idict['get'][4:])
890            #print urlparsed
891            path = urlparsed[2].split('/')
892            dict['student_id'] = student_id = path[8]
893            dict['payment_id'] = payment_id = path[10]
894            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
895            tas.append(dict)
896            tr_count += 1
897        return tas
898    ###)
899
900    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
901    def importOnlinePaymentTransactions(self):
902        """load Online Payment Transactions from CSV values"""
903        import transaction
904        import random
905        #from pdb import set_trace
906        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
907        opt = self.online_payments_import
908        students_folder = self.portal_url.getPortalObject().campus.students
909        start = True
910        tr_count = 1
911        total = 0
912        #name = 'pume_results'
913        name = 'OnlineTransactions'
914        no_import = []
915        imported = []
916        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
917        try:
918            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
919        except:
920            logger.error('Error reading %s.csv' % name)
921            return
922        for pay_transaction in transactions:
923            if start:
924                start = False
925                logger.info('Start loading from %s.csv' % name)
926                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
927                no_import.append('%s,"Error"' % s)
928                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
929                format_error = format + ',"%(Error)s"'
930            data = {}
931
932            # format of the first file sent by Tayo
933            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
934            #data['student_id'] = student_id = pay_transaction['Payer ID']
935            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
936            #data['response_code'] = response_code = pay_transaction['Resp Code']
937            #data['amount'] = amount = pay_transaction['Amount']
938
939            # format of the second file sent by Tayo
940            #data['datetime'] = date = 0
941            #data['student_id'] = student_id = pay_transaction['Payer ID']
942            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
943            #data['response_code'] = response_code = '00'
944            #data['amount'] = amount = pay_transaction['Amount']
945
946            # format of the third file sent by Kehinde
947            data['datetime'] = date = 0
948            data['student_id'] = student_id = pay_transaction['customer_id']
949            data['order_id'] = order_id = pay_transaction['merchant_reference']
950            data['response_code'] = response_code = '00'
951            data['amount'] = amount = pay_transaction['Amount']
952
953            dup = False
954            if response_code == "12":
955                continue
956            try:
957                opt.addRecord(**data)
958            except ValueError:
959                dup = True
960            #from pdb import set_trace;set_trace()
961            if dup:
962                if response_code == "00":
963                    try:
964                        opt.modifyRecord(**data)
965                    except:
966                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
967                        continue
968                else:
969                    pay_transaction['Error'] = "Duplicate order_id"
970                    no_import.append( format_error % pay_transaction)
971                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
972                    continue
973            tr_count += 1
974            if tr_count > 1000:
975                if len(no_import) > 0:
976                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
977                             '\n'.join(no_import) + '\n')
978                    no_import = []
979                em = '%d transactions committed\n' % (tr_count)
980                transaction.commit()
981                regs = []
982                logger.info(em)
983                total += tr_count
984                tr_count = 0
985        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
986                                                '\n'.join(no_import))
987        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
988    ###)
989
990    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
991    def mass_create_faculty(self,mapping):
992        "create a faculty"
993        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
994        academics_folder = self.portal_url.getPortalObject().campus.academics
995        fid = mapping['code']
996        if getattr(academics_folder,fid,None) is not None:
997            return '', "Faculty with ID: %s exists" % fid
998        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
999        try:
1000            academics_folder.invokeFactory('Faculty', fid)
1001        except BadRequest,E:
1002            return '', "%s" % E
1003        f = getattr(academics_folder,fid,None)
1004        f.getContent().edit(mapping=mapping)
1005        return fid,''
1006    ###)
1007
1008    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
1009    def mass_edit_faculty(self,mapping):
1010        "edit a faculty"
1011        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
1012        academics_folder = self.portal_url.getPortalObject().campus.academics
1013        fid = mapping['code']
1014        f = getattr(academics_folder,fid,None)
1015        if f is None:
1016            return '', "Faculty with ID: %s does not exist" % fid
1017        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
1018        f.getContent().edit(mapping=mapping)
1019        return fid,''
1020    ###)
1021
1022    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
1023    def mass_create_department(self,mapping):
1024        "create a department in the correct faculty"
1025        logger = logging.getLogger('WAeUPTool.mass_create_department')
1026        fid = mapping['faculty_code']
1027        if getattr(self,'_v_faculties',None) is None:
1028            res = self.portal_catalog(portal_type = "Faculty")
1029            self._v_faculties = {}
1030            for f in res:
1031                self._v_faculties[f.getId] = f.getObject()
1032        f = self._v_faculties.get(fid,None)
1033        if f is None:
1034            return '', "No Faculty with ID: %s" % fid
1035        else:
1036            did = mapping.get('code')
1037            d = getattr(f,did,None)
1038            if d is None or d.portal_type == "Faculty":
1039                logger.info('Creating Department %(code)s, %(title)s' % mapping)
1040                try:
1041                    f.invokeFactory('Department', did)
1042                except BadRequest,E:
1043                    return '', "%s" % E
1044                d = getattr(f,did)
1045                d.invokeFactory('CoursesFolder','courses')
1046                courses = getattr(d,'courses')
1047                dict = {'Title': 'Courses'}
1048                courses.getContent().edit(mapping=dict)
1049                d.invokeFactory('CertificatesFolder','certificates')
1050                certificates = getattr(d,'certificates')
1051                dict = {'Title': 'Certificates'}
1052                certificates.getContent().edit(mapping=dict)
1053            d.getContent().edit(mapping=mapping)
1054        return did,''
1055    ###)
1056
1057    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
1058    def mass_edit_department(self,mapping):
1059        "create a department in the correct faculty"
1060        logger = logging.getLogger('WAeUPTool.mass_create_department')
1061        academics_folder = self.portal_url.getPortalObject().campus.academics
1062        fid = mapping['faculty_code']
1063        did = mapping.get('code')
1064        try:
1065            d = getattr(getattr(academics_folder,fid),did,None)
1066        except KeyError:
1067            return '', "Department %s or Faculty %s wrong" % (did,fid)
1068        else:
1069            if d is None or d.portal_type == "Faculty":
1070                logger.info('Editing Department %(code)s, %(title)s' % mapping)
1071            d.getContent().edit(mapping=mapping)
1072        return did,''
1073    ###)
1074
1075    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1076    def mass_create_course(self,mapping):
1077        #import pdb;pdb.set_trace()
1078        if getattr(self,'_v_course_list',None) is None:
1079            self._v_course_list = []
1080        if getattr(self,'_v_departments',None) is None:
1081            res = self.portal_catalog(portal_type = "Department")
1082            self._v_department_courses = {}
1083            for d in res:
1084                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
1085        did = mapping['department_code']
1086        d = self._v_department_courses.get(did,None)
1087        if d is None:
1088            return '', "No Department with ID: %s" % did
1089        course_id = mapping.get('code')
1090        if course_id in self._v_course_list:
1091            return '', "Duplicate Course ID: %s" % did
1092        c = getattr(d,course_id,None)
1093        if c is not None:
1094            return '', "Duplicate Course ID: %s" % did
1095        try:
1096            d.invokeFactory('Course', course_id)
1097        except BadRequest,E:
1098            return '', "%s" % E
1099        self._v_course_list.append(course_id)
1100        c = getattr(d,course_id)
1101        c.getContent().edit(mapping=mapping)
1102        return course_id,''
1103    ###)
1104
1105    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1106    def mass_edit_course(self,mapping):
1107        #import pdb;pdb.set_trace()
1108        course_id = mapping.get('code')
1109        res = self.portal_catalog(id=course_id)
1110        if not res:
1111            return '', "No Course with ID: %s" % course_id
1112        c = res[0].getObject()
1113        c.getContent().edit(mapping=mapping)
1114        return course_id,''
1115    ###)
1116
1117    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1118    def mass_create_certificate(self,mapping):
1119        if getattr(self,'_v_certificate_list',None) is None:
1120            self._v_certificate_list = []
1121        if getattr(self,'_v_department_certificates',None) is None:
1122            res = self.portal_catalog(portal_type = "Department")
1123            self._v_department_certificates = {}
1124            for d in res:
1125                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
1126        did = mapping['department_code']
1127        d = self._v_department_certificates.get(did,None)
1128        if d is None:
1129            return '', "No Department with ID: %s" % did
1130        certificate_id = mapping.get('code')
1131        if certificate_id in self._v_certificate_list:
1132            return '', "Duplicate Certificate ID: %s" % did
1133        c = getattr(d,certificate_id,None)
1134        if c is not None:
1135            return '', "Duplicate Certificate ID: %s" % did
1136        try:
1137            d.invokeFactory('Certificate', certificate_id)
1138        except BadRequest,E:
1139            return '', "%s" % E
1140        self._v_certificate_list.append(certificate_id)
1141        c = getattr(d,certificate_id)
1142        c.getContent().edit(mapping=mapping)
1143        return certificate_id,''
1144    ###)
1145
1146    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1147    def mass_edit_certificate(self,mapping):
1148        #import pdb;pdb.set_trace()
1149        certificate_id = mapping.get('code')
1150        res = self.portal_catalog(id=certificate_id)
1151        if not res:
1152            return '', "No Certificate with ID: %s" % did
1153        c = res[0].getObject()
1154        c.getContent().edit(mapping=mapping)
1155        return certificate_id,''
1156    ###)
1157
1158    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1159    def mass_create_certificate_course(self,mapping):
1160        if getattr(self,'_v_courses',None) is None:
1161            res = self.courses_catalog()
1162            self._v_courses= [course.code for course in res]
1163        if getattr(self,'_v_ceritficates',None) is None:
1164            res = self.portal_catalog(portal_type = "Certificate")
1165            self._v_certificates = {}
1166            for cert in res:
1167                self._v_certificates[cert.getId] = cert.getObject()
1168        certificate_course_id = mapping.get('code')
1169        if certificate_course_id not in self._v_courses:
1170            return '', "No Course with ID: %s" % certificate_course_id
1171        cert_id = mapping['certificate_code']
1172        cert = self._v_certificates.get(cert_id,None)
1173        if cert is None:
1174            return '', "No Certificate with ID: %s" % cert_id
1175        level_id = mapping.get('level')
1176        level = getattr(cert,level_id,None)
1177        if level is None:
1178            cert.invokeFactory('StudyLevel', level_id)
1179            level = getattr(cert,level_id,None)
1180        elif hasattr(level,certificate_course_id):
1181            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1182            (certificate_course_id,cert_id,level_id)
1183        level.invokeFactory('CertificateCourse', certificate_course_id)
1184        c = getattr(level,certificate_course_id)
1185        c.getContent().edit(mapping=mapping)
1186        return certificate_course_id,''
1187    ###)
1188
1189    field2types_student = {   ###(
1190                      'StudentApplication':
1191                          {'id': 'application',
1192                           'title': 'Application Data',
1193                           'wf_transition_return': 'close',
1194                           'wf_transition_admit': 'remain',
1195                           'fields':
1196                             ('jamb_reg_no',
1197                              'entry_mode',
1198                              'entry_session',
1199                              'jamb_score',
1200                              'app_email',
1201                              'jamb_age',
1202                              'jamb_state',
1203                              'jamb_lga',
1204                              )
1205                              },
1206                      #'StudentPume':
1207                      #    {'id': 'pume',
1208                      #     'title': 'Pume Data',
1209                      #     'wf_transition_return': 'close',
1210                      #     'wf_transition_admit': 'close',
1211                      #     'fields':
1212                      #       ('pume_score',
1213                      #        )
1214                      #        },
1215                      'StudentClearance':
1216                          {'id': 'clearance',
1217                           'title': 'Clearance/Eligibility Record',
1218                           'wf_transition_return': 'close',
1219                           'wf_transition_admit': 'remain',
1220                           'fields':
1221                             ('matric_no',
1222                              'nationality',
1223                              'lga',
1224                              'birthday',
1225                              )
1226                              },
1227                         'StudentPersonal':
1228                          {'id': 'personal',
1229                           'title': 'Personal Data',
1230                           'wf_transition_return': 'open',
1231                           'wf_transition_admit': 'remain',
1232                           'fields':
1233                             ('firstname',
1234                              'middlename',
1235                              'lastname',
1236                              'sex',
1237                              'email',
1238                              'phone',
1239                              'perm_address',
1240                              )
1241                              },
1242                         'StudentStudyCourse':
1243                          {'id': 'study_course',
1244                           'title': 'Study Course',
1245                           'wf_transition_return': 'open',
1246                           'wf_transition_admit': 'remain',
1247                           'fields':
1248                             ('study_course',
1249                              'current_level',
1250                              'current_session',
1251                              'current_mode',
1252                              'current_verdict',
1253                              )
1254                              },
1255
1256                         'PaymentsFolder':
1257                          {'id': 'payments',
1258                           'title': 'Payments',
1259                           'wf_transition_return': 'open',
1260                           'wf_transition_admit': 'open',
1261                           'fields':
1262                             ()
1263                              },
1264                         }
1265    ###)
1266
1267    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1268    def mass_create_student(self,mapping):
1269        "create a students record due import"
1270        logger = logging.getLogger('WAeUPTool.mass_create_student')
1271        students_folder = self.portal_url.getPortalObject().campus.students
1272        jamb_reg_no = mapping.get('jamb_reg_no',None)
1273        if jamb_reg_no:
1274            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1275            if res:
1276                return '',"jamb_reg_no exists"
1277        matric_no = mapping.get('matric_no',None)
1278        if matric_no:
1279            res = self.students_catalog(matric_no = matric_no)
1280            if res:
1281                return '',"matric_no exists"
1282        sid = self.waeup_tool.generateStudentId('?')
1283        students_folder.invokeFactory('Student', sid)
1284        student_obj = getattr(students_folder,sid)
1285        f2t = self.field2types_student
1286        d = {}
1287        transition = mapping.get('reg_transition','admit')
1288        if transition not in ('admit','return'):
1289            return '',"no valid transition provided"
1290        for pt in f2t.keys():
1291            student_obj.invokeFactory(pt,f2t[pt]['id'])
1292            sub_obj = getattr(student_obj,f2t[pt]['id'])
1293            sub_doc = sub_obj.getContent()
1294            d['Title'] = f2t[pt]['title']
1295            for field in f2t[pt]['fields']:
1296                d[field] = mapping.get(field,'')
1297               
1298            if pt == "StudentApplication":   
1299                d['jamb_sex']  = 'M'
1300                if mapping.get('sex'):
1301                    d['jamb_sex']  = 'F'
1302                d['jamb_firstname'] = mapping.get('firstname',None)
1303                d['jamb_middlename'] = mapping.get('middlename',None)
1304                d['jamb_lastname'] = mapping.get('lastname',None)
1305
1306            # if pt == "StudyCourse":
1307            #     for von,zu in (('entry_mode','current_mode'),
1308            #                    ('entry_session','current_session')):
1309            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1310            #             d[zu] = mapping[von]
1311            sub_doc.edit(mapping = d)
1312
1313            #import pdb;pdb.set_trace()
1314            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
1315            if new_state != "remain":
1316                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1317        self.portal_workflow.doActionFor(student_obj,transition)
1318        student_obj.manage_setLocalRoles(sid, ['Owner',])
1319        return sid,''
1320    ###)
1321
1322    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1323    def mass_edit_student(self,mapping):
1324        "edit a students record due import"
1325        logger = logging.getLogger('WAeUPTool.mass_edit_student')
1326        students_folder = self.portal_url.getPortalObject().campus.students
1327        sid = mapping.get('id',None)
1328        jamb_reg_no = mapping.get('jamb_reg_no',None)
1329        matric_no = mapping.get('matric_no',None)
1330        editable_keys = mapping.keys()
1331        if sid:
1332            res = self.students_catalog(id = sid)
1333            if not res:
1334                return '',"no student with id %s" % sid
1335            if matric_no and res[0].matric_no and\
1336              matric_no != res[0].matric_no:
1337                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1338            if jamb_reg_no and res[0].jamb_reg_no and\
1339              jamb_reg_no != res[0].jamb_reg_no:
1340                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
1341        elif jamb_reg_no:
1342            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1343            if not res:
1344                return '',"no student with jamb_reg_no %s" % jamb_reg_no
1345            editable_keys.remove('jamb_reg_no')
1346        elif matric_no:
1347            res = self.students_catalog(matric_no = matric_no)
1348            if not res:
1349                return '',"no student with matric_no %s" % matric_no
1350            editable_keys.remove('matric_no')
1351
1352        ## included only to change wf state from admitted to returning
1353        #if res[0].review_state not in ('admitted','objection_raised'):
1354        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1355        ## end inclusion
1356
1357        sid = res[0].id
1358        student_obj = getattr(students_folder,sid)
1359        f2t = self.field2types_student
1360        d = {}
1361        #import pdb;pdb.set_trace()
1362        any_change = False
1363        for pt in f2t.keys():
1364            if pt == "student_application":
1365                d['jamb_sex']  = 'M'
1366                if mapping.get('sex'):
1367                    d['jamb_sex']  = 'F'
1368            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
1369            if intersect:
1370                sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1371                if sub_obj is None:
1372                    try:
1373                        student_obj.invokeFactory(pt,f2t[pt]['id'])
1374                    except:
1375                        continue
1376                    sub_obj = getattr(student_obj,f2t[pt]['id'])
1377                    d['Title'] = f2t[pt]['title']
1378                sub_doc = sub_obj.getContent()
1379                for field in intersect:
1380                    changed = False
1381                    if getattr(sub_doc,field) != mapping.get(field,''):
1382                        any_change = True
1383                        changed = True
1384                        d[field] = mapping.get(field,'')
1385                    if changed:
1386                        sub_doc.edit(mapping = d)
1387
1388
1389        ## included only to change wf state from admitted to returning
1390        #    if res[0].review_state in ('admitted','objection_raised'):
1391        #        new_state = f2t[pt]['wf_transition_return']
1392        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1393        #        if sub_obj and new_state != "remain":
1394        #            try:
1395        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1396        #            except:
1397        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1398        #                pass
1399        #if res[0].review_state in ('admitted','objection_raised'):
1400        #    wfaction = 'return'
1401        #    try:
1402        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1403        #        logger.info('%s, wf state changed' % sid)
1404        #        any_change = True
1405        #    except:
1406        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1407        #        pass
1408        ## end inclusion
1409
1410
1411        if any_change:
1412            return sid,''
1413        else:
1414            return sid,'not modified'
1415    ###)
1416
1417    security.declareProtected(ModifyPortalContent,"importData")###(
1418    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
1419        """load data from CSV values"""
1420        import transaction
1421        import random
1422
1423        pm = self.portal_membership
1424        member = pm.getAuthenticatedMember()
1425
1426        logger = logging.getLogger('WAeUPTool.importData')
1427        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1428        students_folder = self.portal_url.getPortalObject().campus.students
1429        start = True
1430        tr_count = 1
1431        total_imported = 0
1432        total_not_imported = 0
1433        total = 0
1434        iname = "import_%s" % name
1435        stool = getToolByName(self, 'portal_schemas')
1436        ltool = getToolByName(self, 'portal_layouts')
1437        schema = stool._getOb(iname)
1438        if schema is None:
1439            em = 'No such schema %s' % iname
1440            logger.error('No such schema %s' % iname)
1441            return em
1442        layout = ltool._getOb(iname)
1443        if layout is None:
1444            em = 'No such layout %s' % iname
1445            logger.error(em)
1446            return em
1447        validators = {}
1448        for widget in layout.keys():
1449            validators[widget] = layout[widget].validate
1450        #import pdb;pdb.set_trace()
1451        mode = "create"
1452        if edit:
1453            mode = "edit"
1454        importer_name = "mass_%(mode)s_%(name)s" % vars()
1455        importer = getattr(self, '%s' % importer_name,None)
1456        if importer is None:
1457            em = 'No importer function %s' % importer_name
1458            logger.error(em)
1459            return em
1460        not_imported = []
1461        imported = []
1462        try:
1463            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
1464        except:
1465            em = 'Error reading %s.csv' % filename
1466            logger.error(em)
1467            return em
1468        for item in items:
1469            if start:
1470                start = False
1471                adapters = [MappingStorageAdapter(schema, item)]
1472                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
1473                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
1474                import_keys = [k for k in attrs if not k.startswith('ignore')]
1475                diff2schema = set(import_keys).difference(set(schema.keys()))
1476                diff2layout = set(import_keys).difference(set(layout.keys()))
1477                if diff2schema:
1478                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
1479                    return em
1480                if mode == "create":
1481                    required_keys = [layout.getIdUnprefixed(id)
1482                                     for id,widget in layout.objectItems()
1483                                     if widget.is_required]
1484                    #import pdb;pdb.set_trace()
1485                    if not set(required_keys).issubset(set(import_keys)):
1486                        diff2import = set(required_keys).difference(set(import_keys))
1487                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
1488                        return em
1489                s = ','.join(['"%s"' % fn for fn in import_keys])
1490                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
1491                s = '"id",' + s
1492                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
1493                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
1494                format_error = format + ',"%(Error)s"'
1495                format = '"%(id)s",'+ format
1496
1497            dm = DataModel(item, adapters,context=self)
1498            ds = DataStructure(data=item,datamodel=dm)
1499            error_string = ""
1500            for k in import_keys:
1501                if not validators[k](ds,mode=mode):
1502                    error_string += " %s : %s" % (k,
1503                                                  self.translation_service(ds.getError(k),
1504                                                                           ds.getErrorMapping(k)))
1505            if not error_string:
1506                temp_item = item.copy()
1507                temp_item.update(dm)
1508                temp_item['id'],error = importer(temp_item)
1509                if error:
1510                    error_string += error
1511                else:
1512                    item = temp_item
1513            if error_string:
1514                item['Error'] = error_string
1515                not_imported.append(format_error % item)
1516                total_not_imported += 1
1517            else:
1518                em = format % item
1519                imported.append(em)
1520                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
1521                tr_count += 1
1522                total_imported += 1
1523            total += 1
1524            if total and not total % 100:
1525                transaction.commit()
1526                if len(not_imported) > 0:
1527                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1528                             '\n'.join(not_imported) + '\n')
1529                    not_imported = []
1530                if len(imported) > 0:
1531                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1532                             '\n'.join(imported) + '\n')
1533                    imported = []
1534                em = '%d transactions committed\n' % (tr_count)
1535                regs = []
1536                logger.info(em)
1537                tr_count = 0
1538        if len(imported) > 0:
1539            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1540                                                '\n'.join(imported))
1541        if len(not_imported) > 0:
1542            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1543                                                '\n'.join(not_imported))
1544        em = "Imported: %d, not imported: %d of total %d" % (total_imported,total_not_imported,total)
1545        return em
1546    ###)
1547
1548    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
1549    def moveImagesToFS(self,student_id="O738726"):
1550        "move the images to the filesystem"
1551        images_dir = os.path.join("%s" % images_base,student_id)
1552        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1553        stool = getToolByName(self, 'portal_schemas')
1554        schemas = ['student_application',
1555                   'student_clearance',
1556                   ]
1557        created = False
1558        for schema_id in schemas:
1559            schema = stool._getOb(schema_id)
1560            object = getattr(student_folder,schema_id[len('student_'):],None)
1561            if object is None:
1562                continue
1563            doc = object.getContent()
1564            for key in schema.keys():
1565                if schema[key].meta_type != "CPS Image Field":
1566                    continue
1567                #import pdb;pdb.set_trace()
1568                image = getattr(doc,key,None)
1569                if not image or not hasattr(image,"data"):
1570                    continue
1571                if not created:
1572                    if not os.path.exists(images_dir):
1573                        os.mkdir(images_dir)
1574                    created = True
1575                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
1576                open(filename,"wb").write(str(image.data))
1577
1578    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
1579    def movePassportToFS(self,student_id="O738726"):
1580        "move the passports to the filesystem"
1581        images_dir = os.path.join("%s" % i_home,'passports')
1582        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1583        stool = getToolByName(self, 'portal_schemas')
1584        schemas = ['student_application',
1585                   #'student_clearance',
1586                   ]
1587        created = False
1588        for schema_id in schemas:
1589            schema = stool._getOb(schema_id)
1590            object = getattr(student_folder,schema_id[len('student_'):],None)
1591            if object is None:
1592                continue
1593            doc = object.getContent()
1594            for key in schema.keys():
1595                if schema[key].meta_type != "CPS Image Field":
1596                    continue
1597                #import pdb;pdb.set_trace()
1598                image = getattr(doc,key)
1599                if not hasattr(image,"data"):
1600                    continue
1601                if not created:
1602                    if not os.path.exists(images_dir):
1603                        os.mkdir(images_dir)
1604                    created = True
1605                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
1606                open(filename,"wb").write(str(image.data))
1607
1608InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.