source: WAeUP_SRP/base/WAeUPTool.py @ 2558

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

unprotect makeStudentData, fix ref

  • Property svn:keywords set to Id
File size: 72.8 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 2557 2007-11-06 15:40:21Z 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(ModifyPortalContent,'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 not self.isStaff():
349            return None
350        if student_entry is None:
351            return None
352        return getattr(student_entry,"password","not set")
353    ###)
354
355    security.declarePublic('checkPassword') ###(
356    def checkPassword(self,student_id,password):
357        "return a student password"
358        student_entry = getattr(self.portal_directories.students,student_id,None)
359        if student_entry is None:
360            return False
361        return getattr(student_entry,"password","not set") == password
362    ###)
363
364    security.declareProtected(ModifyPortalContent,'editPassword') ###(
365    def editPassword(self,student_id,password):
366        "edit a student password"
367        student_entry = getattr(self.portal_directories.students,student_id,None)
368        if student_entry is None:
369            return
370        setattr(student_entry,'password',password)
371    ###)
372
373    security.declareProtected(ModifyPortalContent,'doCommit') ###(
374    def doCommit(self,logger=None):
375        "commit some transactions"
376        transaction.commit()
377    ###)
378
379    security.declarePublic('loadStudentFoto') ###(
380    def loadStudentFoto(self,student,filename,folder):
381        "return a student passport picture"
382        #import pdb;pdb.set_trace()
383        picture ="%s/import/%s/%s" % (i_home,folder,filename)
384        student_id = student.getId()
385        images_dir = os.path.join("%s" % images_base,student_id)
386        if not os.path.exists(images_dir):
387            os.mkdir(images_dir)
388        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
389        for extension in ('.jpg','.JPG'):
390            fullname = "%(picture)s%(extension)s" % vars()
391            if os.path.exists(fullname):
392                copy2(fullname,image_name)
393                return "successfully copied passport picture"
394        return "passport picture not found: %s.jpg or .JPG" % picture
395    ###)
396
397    def old____loadStudentFoto(self,student,filename,folder): ###(
398        "return a student passport picture"
399        app = student.application
400        app_doc = app.getContent()
401        #clear = student.clearance
402        #clear_doc = clear.getContent()
403        #matric_no = clear_doc.matric_no.upper()
404        picture1 ="%s/import/%s/%s.jpg" % (i_home,folder,filename)
405        picture2 ="%s/import/%s/%s.JPG" % (i_home,folder,filename)
406        #import pdb;pdb.set_trace()
407        if os.path.exists(picture1):
408            file = open(picture1)
409        elif os.path.exists(picture2):
410            file = open(picture2)
411        else:
412            return "passport picture not found %s" % picture1
413        reopened = False
414        if self.portal_workflow.getInfoFor(app,'review_state',None) !='opened':
415            self.portal_workflow.doActionFor(app,'open')
416            reopened = True
417        outfile = file.read()
418        app_doc.manage_addFile('passport',
419                               file=outfile,
420                               title="%s.jpg" % filename)
421        if reopened:
422            self.portal_workflow.doActionFor(app,'close')
423        return "successfully loaded passport picture"
424    ###)
425
426    security.declareProtected(ModifyPortalContent,'createOne') ###(
427    def createOne(self,students_folder,student_brain,letter,commit=False):
428        sid = self.waeup_tool.generateStudentId(letter)
429        students_folder.invokeFactory('Student', sid)
430        student = getattr(students_folder,sid)
431        self.portal_workflow.doActionFor(student,'return')
432        student.manage_setLocalRoles(sid, ['Owner',])
433        matric_no = student_brain.matric_no
434        jamb_reg_no = student_brain.Entryregno
435        self.students_catalog.addRecord(id = sid,
436                                           matric_no = matric_no,
437                                           jamb_reg_no = jamb_reg_no,
438                                           sex = student_brain.Sex == "F",
439                                           name = "%s %s %s" % (student_brain.Firstname,
440                                                                student_brain.Middlename,
441                                                                student_brain.Lastname)
442                                        )
443        if commit:
444            transaction.commit()
445        return sid,jamb_reg_no
446    ###)
447
448    security.declareProtected(ModifyPortalContent,'addStudent') ###(
449    def addStudent(self,dict):
450        students_folder = self.portal_url.getPortalObject().campus.students
451        sid = self.waeup_tool.generateStudentId('?')
452        students_folder.invokeFactory('Student', sid)
453        student_obj = getattr(students_folder,sid)
454        f2t = self.student_field2types
455        #from pdb import set_trace; set_trace()
456        d = {}
457        #d['jamb_sex']  = 'M'
458        #if dict.get('sex'):
459        #    d['jamb_sex']  = 'F'
460
461        entry_session = dict.get('entry_session')
462        if entry_session == self.getSessionId()[0]:
463            wfaction = 'admit'
464            wft = 'wf_transition_admit'
465            password = None
466        else:
467            wfaction = 'return'
468            wft = 'wf_transition_return'
469            password = self.generatePassword()
470            self.makeStudentMember(sid,password)
471
472        for pt in f2t.keys():
473            student_obj.invokeFactory(pt,f2t[pt]['id'])
474            sub_obj = getattr(student_obj,f2t[pt]['id'])
475            sub_doc = sub_obj.getContent()
476            #self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
477            d['Title'] = f2t[pt]['title']
478            for field in f2t[pt]['fields']:
479                d[field] = dict.get(field,'')
480            sub_doc.edit(mapping = d)
481            new_state = f2t[pt][wft]
482            if new_state != "remain":
483                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
484        self.portal_workflow.doActionFor(student_obj,wfaction)
485        student_obj.manage_setLocalRoles(sid, ['Owner',])
486        return sid,password
487    ###)
488
489    security.declarePublic('getCertificateBrain') ###(
490    def getCertificateBrain(self,cert_id):
491        "do it"
492        res = ZCatalog.searchResults(self.portal_catalog_real,
493                                {'portal_type':"Certificate",
494                                      'id': cert_id})
495        if res:
496            return res[0]
497        return None
498    ###)
499
500    security.declareProtected(ModifyPortalContent,'get_csv_filenames') ###(
501    def get_csv_filenames(self):
502        "do it"
503        files = [file for file in os.listdir("%s/import/" % (i_home))
504                 if file.endswith('.csv') and file.find('imported') == -1]
505        return files
506    ###)
507
508    security.declarePublic('findStudentByMatricelNo') ###(
509    def findStudentByMatricelNo(self,matric_no):
510        "do it"
511        res = ZCatalog.searchResults(self.portal_catalog_real,
512                                {'portal_type':"StudentClearance",
513                                 'SearchableText': matric_no})
514        if res:
515            return res[0]
516        return None
517    ###)
518
519    security.declarePublic('makeStudentMember') ###(
520    def makeStudentMember(self,sid,password='uNsEt'):
521        """make the student a member"""
522        membership = self.portal_membership
523        membership.addMember(sid,
524                             password ,
525                             roles=('Member',
526                                     'Student',
527                                     ),
528                             domains='',
529                             properties = {'memberareaCreationFlag': False,
530                                           'homeless': True},)
531        member = membership.getMemberById(sid)
532        self.portal_registration.afterAdd(member, sid, password, None)
533        #self.manage_setLocalRoles(sid, ['Owner',])
534    ###)
535
536    security.declareProtected(ModifyPortalContent,'makeStudentData') ###(
537    def makeStudentData(self,student_id,email=None,phone_nr=None):
538        "create Datastructure for a returning Student"
539        #import pdb;pdb.set_trace()
540        logger = logging.getLogger('WAeUPTool.makeStudentData')
541        students_folder = self.portal_url.getPortalObject().campus.students
542        #res = self.students_catalog(id=student_id)
543        #if res:
544        #    st = res[0]
545        #res = self.returning_import(matric_no = st.matric_no)
546        res = self.returning_import(id = student_id)
547        if res:
548            student = res[0]
549        else:
550            logger.info('Id %s not found in returning_import' % student_id)
551            return
552        logger.info('%s creates data structure' % student_id)
553        s_results = self.results_import(matric_no = student.matric_no)
554        if s_results:
555            lnr = self.getLevelFromResultsCosCode(s_results)
556            level = "%d00" % lnr
557            verdict,eligible = self.getVerdict(s_results[0].Verdict)
558            #if eligible:
559            #    level = "%d00" % (lnr + 1)
560        else:
561            logger.info('matric_no %s not found in results_import' % student.matric_no)
562            level = 0
563            verdict = 'N/A'
564        #student should not be allowed to perform this transition
565        #wftool = self.portal_workflow
566        #wftool.doActionFor(student,'return')
567        certcode_org = student.Coursemajorcode
568        certcode = makeCertificateCode(certcode_org)
569        certificate_brain = self.getCertificateBrain(certcode)
570        if not certificate_brain:
571            em = 'Certificate %s org-code %s not found\n' % (certcode, certcode_org)
572            logger.info(em)
573        matric_no = student.matric_no
574        sid = student_id
575        student_obj = getattr(students_folder,sid)
576        student_obj.invokeFactory('StudentApplication','application')
577        application = student_obj.application
578        self.portal_workflow.doActionFor(application,'open',dest_container=application)
579        da = {'Title': 'Application Data'}
580        student_obj.invokeFactory('StudentPersonal','personal')
581        da['jamb_reg_no'] = student.Entryregno
582        em = self.getEntryMode(student.Entryregno)
583        da['entry_mode'] = em
584        personal = student_obj.personal
585        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
586        dp = {'Title': 'Personal Data'}
587        student_obj.invokeFactory('StudentClearance','clearance')
588        clearance = student_obj.clearance
589        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
590        dc = {'Title': 'Clearance/Eligibility Record'}
591        dc['matric_no'] = matric_no
592        state = student.State
593        lga = student.LGA
594        if state and lga:
595            lga =  state + ' / ' + lga
596        else:
597            lga = "None"
598        da['jamb_lga'] = dc['lga'] = lga
599        da['app_email'] = dp['email'] = email
600        da['app_mobile'] = dp['phone'] = phone_nr
601        dp['firstname'] = student.Firstname
602        dp['middlename'] = student.Middlename
603        dp['lastname'] = student.Lastname
604        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
605        da['jamb_sex'] = student.Sex
606        dp['sex'] = student.Sex == 'F'
607        dp['perm_address'] = student.Permanent_Address
608        application.getContent().edit(mapping=da)
609        self.portal_workflow.doActionFor(application,'close',dest_container=application)
610        personal.getContent().edit(mapping=dp)
611        clearance.getContent().edit(mapping=dc)
612        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
613        #
614        # Study Course
615        #
616        student_obj.invokeFactory('StudentStudyCourse','study_course')
617        studycourse = student_obj.study_course
618        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
619        dsc = {}
620        dsc['study_course'] = certcode
621        dsc['current_level'] = level
622        dsc['current_verdict'] = verdict
623        dsc['current_mode'] = em
624        dsc['current_session'] = '05'
625        studycourse.getContent().edit(mapping=dsc)
626        #
627        # Level
628        #
629##        l = getattr(studycourse,level,None)
630##        if l is None:
631##            studycourse.invokeFactory('StudentStudyLevel', level)
632##            l = getattr(studycourse, level)
633##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
634##            l.getContent().edit(mapping={'Title': "Level %s" % level})
635###)
636
637    security.declareProtected(ModifyPortalContent,'admitOneStudent') ###(
638    def admitOneStudent(self,brain):
639        "create Datastructure for an admitted Student"
640        #import pdb;pdb.set_trace()
641        students_folder = self.portal_url.getPortalObject().campus.students
642        logger = logging.getLogger('WAeUPTool.admitStudent')
643        if brain.status != "admitted":
644            logger.info('status of %s is %s' % (brain.reg_no,brain.status))
645            return
646        pin_parts = brain.pin.split('-')
647        if len(pin_parts) != 3:
648            logger.info('invalid pin %s for %s' % (brain.pin,brain.reg_no))
649            return
650        student_id = self.generateStudentId('?')
651        students_folder.invokeFactory('Student', student_id)
652        student_object = getattr(students_folder,student_id)
653        password = pin_parts[2]
654        self.makeStudentMember(student_id,password = password)
655        student_object.manage_setLocalRoles(student_id, ['Owner',])
656        #logger.info("creating %s reg_no %s" % (student_id,brain.reg_no))
657        #
658        # application
659        #
660        student_object.invokeFactory('StudentApplication','application')
661        application = student_object.application
662        self.portal_workflow.doActionFor(application,'open',dest_container=application)
663        da = {'Title': 'Application Data'}
664        da['jamb_reg_no'] = brain.reg_no
665        da['entry_mode'] = brain.entry_mode
666        da['jamb_lastname'] = brain.lastname
667        sex = 'M'
668        if brain.sex:
669            sex = 'F'
670        da['jamb_sex'] = sex
671        da['app_ac_pin'] = brain.pin
672        state_lga = brain.lga.split('_')
673        da['state_lga'] = state_lga[0]
674        da['jamb_lga'] = state_lga[-1]
675        #da['jamb_score'] = brain.????
676        da['app_email'] = brain.email
677        da['app_mobile'] = brain.phone
678        application.getContent().edit(mapping=da)
679        self.portal_workflow.doActionFor(application,'close',dest_container=application)
680        #
681        # personal
682        #
683        student_object.invokeFactory('StudentPersonal','personal')
684        personal = student_object.personal
685        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
686        dp = {'Title': 'Personal Data'}
687        dp['sex'] = brain.sex
688        dp['email'] = brain.email
689        dp['phone'] = brain.phone
690        dp['lastname'] = brain.lastname
691        personal.getContent().edit(mapping=dp)
692        #
693        # clearance
694        #
695        student_object.invokeFactory('StudentClearance','clearance')
696        clearance = student_object.clearance
697        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
698        dc = {'Title': 'Clearance/Eligibility Record'}
699        dc['lga'] = brain.lga
700        clearance.getContent().edit(mapping=dc)
701        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
702        #
703        # study Course
704        #
705        student_object.invokeFactory('StudentStudyCourse','study_course')
706        studycourse = student_object.study_course
707        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
708        dsc = {}
709        dsc['study_course'] = brain.course_admitted
710        dsc['current_verdict'] = ''
711        dsc['current_mode'] = brain.entry_mode
712        studycourse.getContent().edit(mapping=dsc)
713        #
714        # payments folder
715        student_object.invokeFactory('PaymentsFolder','payments')
716        payments = getattr(student_object,'payments')
717        dpay = {}
718        dpay['Title'] = 'Payments'
719        payments.getContent().edit(mapping=dpay)
720        self.portal_workflow.doActionFor(payments,'open')
721        return student_id
722    ###)
723
724    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
725    def makeStudentLevel(self,student_id):
726        "create the StudyLevel for a returning Student"
727        #import pdb;pdb.set_trace()
728        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
729        students_folder = self.portal_url.getPortalObject().campus.students
730        res = self.students_catalog(id=student_id)
731        if res:
732            st = res[0]
733        course = st.course
734        matric_no = st.matric_no
735        level = st.level
736        res = self.results_import(matric_no = matric_no)
737        if res:
738            results = res
739        logger.info('%s creating Level %s' % (student_id,level))
740        #
741        # Level
742        #
743        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
744        studycourse = getattr(student_obj,"study_course",None)
745        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
746        l = getattr(studycourse,level,None)
747        if l is None:
748            studycourse.invokeFactory('StudentStudyLevel', level)
749            l = getattr(studycourse, level)
750            self.portal_workflow.doActionFor(l,'open',dest_container=l)
751            l.getContent().edit(mapping={'Title': "Level %s" % level})
752        ###)
753
754    security.declarePublic('getHallInfo') ###(
755    def getHallInfo(self,bed):
756        """return Hall Info"""
757        info = {}
758        hall,block,room,letter = bed.split('_')
759        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
760        if res and len(res) == 1:
761            hall_brain = res[0]
762            hall_doc = hall_brain.getObject().getContent()
763        else:
764            return info
765        info['hall_title'] = hall_brain.Title
766        info['maintenance_code'] = hall_doc.maintenance_code
767        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
768        batch_doc = None
769        for brain in res:
770            if brain.id.startswith(info['maintenance_code']):
771                batch_doc = brain.getObject().getContent()
772                break
773        if batch_doc is None:
774            info['maintenance_fee'] = None
775        else:
776            info['maintenance_fee'] = batch_doc.cost
777        return info
778    ###)
779
780    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
781    def removePictureFolder(self,student_id):
782        """remove picture_folder by renaming it"""
783        path = 'images'
784        picture_path = os.path.join(i_home,path,student_id)
785        if not os.path.exists(picture_path):
786            return False
787        os.rename(picture_path,picture_path + "_removed")
788        return True
789    ###)
790
791    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
792    def restorePictureFolder(self,student_id):
793        """restore picture_folder by renaming it"""
794        path = 'images'
795        picture_path = os.path.join(i_home,path,student_id)
796        if not os.path.exists(picture_path + "_removed"):
797            return False
798        os.rename(picture_path + "_removed",picture_path)
799        return True
800    ###)
801
802    security.declarePublic('picturesExist') ###(
803    def picturesExist(self, ids,student_id=None):
804        """check if pictures exist in the filesystem"""
805        if student_id is None:
806            student_id = self.getStudentId()
807        if student_id is None:
808            return False
809        picture_path = os.path.join(images_base,student_id)
810        if not os.path.exists(picture_path):
811            return False
812        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
813        return set(ids).issubset(set(pictures))
814    ###)
815
816    security.declarePublic('picturesList') ###(
817    def picturesList(self):
818        """check if pictures exist in the filesystem"""
819        path = 'images'
820        student_id = self.getStudentId()
821        picture_path = os.path.join(i_home,path,student_id)
822        if not os.path.exists(picture_path):
823            return []
824        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
825    ###)
826
827    security.declarePublic('showFsPicture') ###(
828    def showFsPicture(self,path):
829        """return a picture from the filesystem"""
830        picture_path = os.path.join(i_home,path)
831        response = self.REQUEST.RESPONSE
832        #import pdb;pdb.set_trace()
833        registry = getToolByName(self, 'mimetypes_registry')
834        mimetype = str(registry.lookupExtension(path.lower()) or
835                    registry.lookupExtension('file.bin'))
836        if os.path.exists(picture_path):
837            response.setHeader('Content-type',mimetype)
838            return open(picture_path).read()
839        picture_path = os.path.join(i_home,'import',path)
840        if os.path.exists(picture_path):
841            return open(picture_path).read()
842    ###)
843
844    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
845    def deleteAllCourses(self,department="All"):
846        ''' delete the courses'''
847        pm = self.portal_membership
848        member = pm.getAuthenticatedMember()
849
850        if str(member) not in ("henrik","joachim"):
851            return "not possible"
852        if department == "All":
853            res = self.portal_catalog({'meta_type': 'Department'})
854        if len(res) < 1:
855            return "No Departments found"
856
857        deleted = []
858        for dep in res:
859            cf = dep.getObject().courses
860            if cf:
861                cf.manage_delObjects(ids=cf.objectIds())
862                deleted.append("deleted Courses in %s" % dep.getId)
863        return "\r".join(deleted)
864    ###)
865
866    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
867    def getLogfileLines(self,filename="event.log",numlines=20):
868        """Get last NUMLINES lines of logfile FILENAME.
869
870        Return last lines' of a file in the instances logfile directory as
871        a list. The number of returned lines equals `numlines' or less. If
872        less than `numlines' lines are available, the whole file ist
873        returned. If the file can not be opened or some other error
874        occurs, empty list is returend.
875        """
876        result = []
877        lines_hit = 0
878
879        # We only handle files in instances' log directory...
880        logpath = os.path.join(i_home, "log")
881        filename = str(os.path.abspath( os.path.join( logpath, filename )))
882        if not filename.startswith( logpath ):
883            # Attempt to access file outside log-dir...
884            return []
885
886        try:
887            fd = file( filename, "rb" )
888        except IOError:
889            return []
890        if not fd:
891            return []
892
893        if os.linesep == None:
894            linesep = '\n'
895        else:
896            linesep = os.linesep
897
898        # Try to find 'numlines' times a lineseparator, searching from end
899        # and moving to the beginning of file...
900        fd.seek( 0, 2) # Move to end of file...
901        while lines_hit < numlines:
902            if fd.read(1) == linesep[-1]: # This moves filedescriptor
903                                          # one step forward...
904                lines_hit += 1
905            try:
906                fd.seek( -2, 1) # Go two bytes back from current pos...
907            except IOError:
908                # We cannot go back two bytes. Maybe the file is too small...
909                break
910        fd.seek(2,1)
911
912        # Read all lines from current position...
913        result = fd.readlines()
914        # Remove line endings...
915        result = [x.strip() for x in result]
916        fd.close()
917        return result
918    ###)
919
920    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
921    def getCallbacksFromLog(self,filename):
922        """fix Online Payment Transactions from Z2.log entries"""
923        import transaction
924        import random
925        from cgi import parse_qs
926        from urlparse import urlparse
927        #from pdb import set_trace
928        wftool = self.portal_workflow
929        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
930        students_folder = self.portal_url.getPortalObject().campus.students
931        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
932        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
933        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
934        data = re.compile(s)
935        start = True
936        tr_count = 1
937        total = 0
938        #name = 'pume_results'
939        #name = 'epaymentsuccessful_z2log2'
940        name = filename
941        no_import = []
942        imported = []
943        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
944        try:
945            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
946        except:
947            logger.error('Error reading %s' % name)
948            return
949        tas = []
950        for line in transactions:
951            dict = {}
952            items = data.search(line)
953            dict['idict'] = idict = items.groupdict()
954            #print idict
955            #from pdb import set_trace;set_trace()
956            urlparsed = urlparse(idict['get'][4:])
957            #print urlparsed
958            path = urlparsed[2].split('/')
959            dict['student_id'] = student_id = path[8]
960            dict['payment_id'] = payment_id = path[10]
961            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
962            tas.append(dict)
963            tr_count += 1
964        return tas
965    ###)
966
967    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
968    def importOnlinePaymentTransactions(self):
969        """load Online Payment Transactions from CSV values"""
970        import transaction
971        import random
972        #from pdb import set_trace
973        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
974        opt = self.online_payments_import
975        students_folder = self.portal_url.getPortalObject().campus.students
976        start = True
977        tr_count = 1
978        total = 0
979        #name = 'pume_results'
980        name = 'OnlineTransactions'
981        no_import = []
982        imported = []
983        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
984        try:
985            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
986        except:
987            logger.error('Error reading %s.csv' % name)
988            return
989        for pay_transaction in transactions:
990            if start:
991                start = False
992                logger.info('Start loading from %s.csv' % name)
993                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
994                no_import.append('%s,"Error"' % s)
995                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
996                format_error = format + ',"%(Error)s"'
997            data = {}
998
999            # format of the first file sent by Tayo
1000            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
1001            #data['student_id'] = student_id = pay_transaction['Payer ID']
1002            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1003            #data['response_code'] = response_code = pay_transaction['Resp Code']
1004            #data['amount'] = amount = pay_transaction['Amount']
1005
1006            # format of the second file sent by Tayo
1007            #data['datetime'] = date = 0
1008            #data['student_id'] = student_id = pay_transaction['Payer ID']
1009            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1010            #data['response_code'] = response_code = '00'
1011            #data['amount'] = amount = pay_transaction['Amount']
1012
1013            # format of the third file sent by Kehinde
1014            data['datetime'] = date = 0
1015            data['student_id'] = student_id = pay_transaction['customer_id']
1016            data['order_id'] = order_id = pay_transaction['merchant_reference']
1017            data['response_code'] = response_code = '00'
1018            data['amount'] = amount = pay_transaction['Amount']
1019
1020            dup = False
1021            if response_code == "12":
1022                continue
1023            try:
1024                opt.addRecord(**data)
1025            except ValueError:
1026                dup = True
1027            #from pdb import set_trace;set_trace()
1028            if dup:
1029                if response_code == "00":
1030                    try:
1031                        opt.modifyRecord(**data)
1032                    except:
1033                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
1034                        continue
1035                else:
1036                    pay_transaction['Error'] = "Duplicate order_id"
1037                    no_import.append( format_error % pay_transaction)
1038                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
1039                    continue
1040            tr_count += 1
1041            if tr_count > 1000:
1042                if len(no_import) > 0:
1043                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1044                             '\n'.join(no_import) + '\n')
1045                    no_import = []
1046                em = '%d transactions committed\n' % (tr_count)
1047                transaction.commit()
1048                regs = []
1049                logger.info(em)
1050                total += tr_count
1051                tr_count = 0
1052        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1053                                                '\n'.join(no_import))
1054        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
1055    ###)
1056
1057    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
1058    def mass_create_faculty(self,mapping):
1059        "create a faculty"
1060        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
1061        academics_folder = self.portal_url.getPortalObject().campus.academics
1062        fid = mapping['code']
1063        if getattr(academics_folder,fid,None) is not None:
1064            return '', "Faculty with ID: %s exists" % fid
1065        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
1066        try:
1067            academics_folder.invokeFactory('Faculty', fid)
1068        except BadRequest,E:
1069            return '', "%s" % E
1070        f = getattr(academics_folder,fid,None)
1071        f.getContent().edit(mapping=mapping)
1072        return fid,''
1073    ###)
1074
1075    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
1076    def mass_edit_faculty(self,mapping):
1077        "edit a faculty"
1078        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
1079        academics_folder = self.portal_url.getPortalObject().campus.academics
1080        fid = mapping['code']
1081        f = getattr(academics_folder,fid,None)
1082        if f is None:
1083            return '', "Faculty with ID: %s does not exist" % fid
1084        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
1085        f.getContent().edit(mapping=mapping)
1086        return fid,''
1087    ###)
1088
1089    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
1090    def mass_create_department(self,mapping):
1091        "create a department in the correct faculty"
1092        logger = logging.getLogger('WAeUPTool.mass_create_department')
1093        fid = mapping['faculty_code']
1094        if getattr(self,'_v_faculties',None) is None:
1095            res = self.portal_catalog(portal_type = "Faculty")
1096            self._v_faculties = {}
1097            for f in res:
1098                self._v_faculties[f.getId] = f.getObject()
1099        f = self._v_faculties.get(fid,None)
1100        if f is None:
1101            return '', "No Faculty with ID: %s" % fid
1102        else:
1103            did = mapping.get('code')
1104            d = getattr(f,did,None)
1105            if d is None or d.portal_type == "Faculty":
1106                logger.info('Creating Department %(code)s, %(title)s' % mapping)
1107                try:
1108                    f.invokeFactory('Department', did)
1109                except BadRequest,E:
1110                    return '', "%s" % E
1111                d = getattr(f,did)
1112                d.invokeFactory('CoursesFolder','courses')
1113                courses = getattr(d,'courses')
1114                dict = {'Title': 'Courses'}
1115                courses.getContent().edit(mapping=dict)
1116                d.invokeFactory('CertificatesFolder','certificates')
1117                certificates = getattr(d,'certificates')
1118                dict = {'Title': 'Certificates'}
1119                certificates.getContent().edit(mapping=dict)
1120            d.getContent().edit(mapping=mapping)
1121        return did,''
1122    ###)
1123
1124    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
1125    def mass_edit_department(self,mapping):
1126        "create a department in the correct faculty"
1127        logger = logging.getLogger('WAeUPTool.mass_create_department')
1128        academics_folder = self.portal_url.getPortalObject().campus.academics
1129        fid = mapping['faculty_code']
1130        did = mapping.get('code')
1131        try:
1132            d = getattr(getattr(academics_folder,fid),did,None)
1133        except KeyError:
1134            return '', "Department %s or Faculty %s wrong" % (did,fid)
1135        else:
1136            if d is None or d.portal_type == "Faculty":
1137                logger.info('Editing Department %(code)s, %(title)s' % mapping)
1138            d.getContent().edit(mapping=mapping)
1139        return did,''
1140    ###)
1141
1142    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1143    def mass_create_course(self,mapping):
1144        #import pdb;pdb.set_trace()
1145        if getattr(self,'_v_course_list',None) is None:
1146            self._v_course_list = []
1147        if getattr(self,'_v_departments',None) is None:
1148            res = self.portal_catalog(portal_type = "Department")
1149            self._v_department_courses = {}
1150            for d in res:
1151                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
1152        did = mapping['department_code']
1153        d = self._v_department_courses.get(did,None)
1154        if d is None:
1155            return '', "No Department with ID: %s" % did
1156        course_id = mapping.get('code')
1157        if course_id in self._v_course_list:
1158            return '', "Duplicate Course ID: %s" % did
1159        c = getattr(d,course_id,None)
1160        if c is not None:
1161            return '', "Duplicate Course ID: %s" % did
1162        try:
1163            d.invokeFactory('Course', course_id)
1164        except BadRequest,E:
1165            return '', "%s" % E
1166        self._v_course_list.append(course_id)
1167        c = getattr(d,course_id)
1168        c.getContent().edit(mapping=mapping)
1169        return course_id,''
1170    ###)
1171
1172    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1173    def mass_edit_course(self,mapping):
1174        #import pdb;pdb.set_trace()
1175        course_id = mapping.get('code')
1176        res = self.portal_catalog(id=course_id)
1177        if not res:
1178            return '', "No Course with ID: %s" % course_id
1179        c = res[0].getObject()
1180        c.getContent().edit(mapping=mapping)
1181        return course_id,''
1182    ###)
1183
1184    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1185    def mass_create_certificate(self,mapping):
1186        if getattr(self,'_v_certificate_list',None) is None:
1187            self._v_certificate_list = []
1188        if getattr(self,'_v_department_certificates',None) is None:
1189            res = self.portal_catalog(portal_type = "Department")
1190            self._v_department_certificates = {}
1191            for d in res:
1192                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
1193        did = mapping['department_code']
1194        d = self._v_department_certificates.get(did,None)
1195        if d is None:
1196            return '', "No Department with ID: %s" % did
1197        certificate_id = mapping.get('code')
1198        if certificate_id in self._v_certificate_list:
1199            return '', "Duplicate Certificate ID: %s" % did
1200        c = getattr(d,certificate_id,None)
1201        if c is not None:
1202            return '', "Duplicate Certificate ID: %s" % did
1203        try:
1204            d.invokeFactory('Certificate', certificate_id)
1205        except BadRequest,E:
1206            return '', "%s" % E
1207        self._v_certificate_list.append(certificate_id)
1208        c = getattr(d,certificate_id)
1209        c.getContent().edit(mapping=mapping)
1210        return certificate_id,''
1211    ###)
1212
1213    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1214    def mass_edit_certificate(self,mapping):
1215        #import pdb;pdb.set_trace()
1216        certificate_id = mapping.get('code')
1217        res = self.portal_catalog(id=certificate_id)
1218        if not res:
1219            return '', "No Certificate with ID: %s" % did
1220        c = res[0].getObject()
1221        c.getContent().edit(mapping=mapping)
1222        return certificate_id,''
1223    ###)
1224
1225    security.declareProtected(ModifyPortalContent,'mass_create_application') ###(
1226    def mass_create_application(self,mapping):
1227        #import pdb;pdb.set_trace()
1228        reg_no = mapping.get('reg_no')
1229        try:
1230            self.applicants_catalog.addRecord(**mapping)
1231        except ValueError:
1232            return '', "applicant record with reg_no %s already exists" % reg_no
1233        return reg_no,''
1234    ###)
1235
1236    security.declareProtected(ModifyPortalContent,'mass_edit_application') ###(
1237    def mass_edit_application(self,mapping):
1238        #import pdb;pdb.set_trace()
1239        reg_no = mapping.get('reg_no')
1240        try:
1241            self.applicants_catalog.modifyRecord(**mapping)
1242        except KeyError:
1243            return '', "applicant record with reg_no %s does not exist" % reg_no
1244        return reg_no,''
1245    ###)
1246
1247    security.declareProtected(ModifyPortalContent,'mass_create_course_result') ###(
1248    def mass_create_course_result(self,mapping):
1249        #import pdb;pdb.set_trace()
1250        if getattr(self,'_v_courses',None) is None:
1251            res = self.courses_catalog()
1252            self._v_courses = {}
1253            for brain in res:
1254                self._v_courses[brain.code] = brain
1255        course_id = mapping.get('code')
1256        if course_id not in self._v_courses.keys():
1257            return '', "No course with ID: %s" % did
1258        id_key = ''
1259        for id_key in ('student_id','matric_no'):
1260            id_field = mapping.get(id_key,None)
1261            if id_field is not None:
1262                student_id = id_field
1263                break
1264        query = Eq(id_key,id_field)
1265        res = self.students_catalog.evalAdvancedQuery(query)
1266        if not res:
1267            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1268        if id_field != "student_id":
1269            mapping['student_id'] = res[0].id
1270        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % mapping
1271        for k in ('semester',):
1272            mapping[k] = getattr(self._v_courses[course_id],k)
1273        try:
1274            self.course_results.addRecord(**mapping)
1275        except ValueError:
1276            return '', "course result already exists: %s" % key
1277        return key,''
1278    ###)
1279
1280    security.declareProtected(ModifyPortalContent,'mass_edit_course_result') ###(
1281    def mass_edit_course_result(self,mapping):
1282        #import pdb;pdb.set_trace()
1283        # if getattr(self,'_v_courses',None) is None:
1284        #     res = self.courses_catalog()
1285        #     self._v_courses = {}
1286        #     for brain in res:
1287        #         self._v_courses[brain.code] = brain
1288        # course_id = mapping.get('code')
1289        # if course_id not in self._v_courses.keys():
1290        #     return '', "No course with ID: %s" % did
1291        id_key = ''
1292        for id_key in ('student_id','matric_no'):
1293            id_field = mapping.get(id_key,None)
1294            if id_field is not None:
1295                student_id = id_field
1296                break
1297        query = Eq(id_key,id_field)
1298        res = self.students_catalog.evalAdvancedQuery(query)
1299        if not res:
1300            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1301        if id_field != "student_id":
1302            mapping['student_id'] = res[0].id
1303        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % mapping
1304        # for k in ('semester',):
1305        #     mapping[k] = getattr(self._v_courses[course_id],k)
1306        try:
1307            self.course_results.modifyRecord(**mapping)
1308        except KeyError:
1309            return '', "No course result to edit: %s" % key
1310        return key,''
1311    ###)
1312
1313    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1314    def mass_create_certificate_course(self,mapping):
1315        if getattr(self,'_v_courses',None) is None:
1316            res = self.courses_catalog()
1317            self._v_courses= [course.code for course in res]
1318        if getattr(self,'_v_ceritficates',None) is None:
1319            res = self.portal_catalog(portal_type = "Certificate")
1320            self._v_certificates = {}
1321            for cert in res:
1322                self._v_certificates[cert.getId] = cert.getObject()
1323        certificate_course_id = mapping.get('code')
1324        if certificate_course_id not in self._v_courses:
1325            return '', "No Course with ID: %s" % certificate_course_id
1326        cert_id = mapping['certificate_code']
1327        cert = self._v_certificates.get(cert_id,None)
1328        if cert is None:
1329            return '', "No Certificate with ID: %s" % cert_id
1330        level_id = mapping.get('level')
1331        level = getattr(cert,level_id,None)
1332        if level is None:
1333            cert.invokeFactory('StudyLevel', level_id)
1334            level = getattr(cert,level_id,None)
1335        elif hasattr(level,certificate_course_id):
1336            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1337            (certificate_course_id,cert_id,level_id)
1338        level.invokeFactory('CertificateCourse', certificate_course_id)
1339        c = getattr(level,certificate_course_id)
1340        c.getContent().edit(mapping=mapping)
1341        return certificate_course_id,''
1342    ###)
1343
1344    field2types_student = {   ###(
1345                      'StudentApplication':
1346                          {'id': 'application',
1347                           'title': 'Application Data',
1348                           'wf_transition_return': 'close',
1349                           'wf_transition_admit': 'remain',
1350                           'fields':
1351                             ('jamb_reg_no',
1352                              'entry_mode',
1353                              'entry_session',
1354                              'jamb_score',
1355                              'app_email',
1356                              'jamb_age',
1357                              'jamb_state',
1358                              'jamb_lga',
1359                              )
1360                              },
1361                      #'StudentPume':
1362                      #    {'id': 'pume',
1363                      #     'title': 'Pume Data',
1364                      #     'wf_transition_return': 'close',
1365                      #     'wf_transition_admit': 'close',
1366                      #     'fields':
1367                      #       ('pume_score',
1368                      #        )
1369                      #        },
1370                      'StudentClearance':
1371                          {'id': 'clearance',
1372                           'title': 'Clearance/Eligibility Record',
1373                           'wf_transition_return': 'close',
1374                           'wf_transition_admit': 'remain',
1375                           'fields':
1376                             ('matric_no',
1377                              'nationality',
1378                              'lga',
1379                              'birthday',
1380                              )
1381                              },
1382                         'StudentPersonal':
1383                          {'id': 'personal',
1384                           'title': 'Personal Data',
1385                           'wf_transition_return': 'open',
1386                           'wf_transition_admit': 'remain',
1387                           'fields':
1388                             ('firstname',
1389                              'middlename',
1390                              'lastname',
1391                              'sex',
1392                              'email',
1393                              'phone',
1394                              'perm_address',
1395                              )
1396                              },
1397                         'StudentStudyCourse':
1398                          {'id': 'study_course',
1399                           'title': 'Study Course',
1400                           'wf_transition_return': 'open',
1401                           'wf_transition_admit': 'remain',
1402                           'fields':
1403                             ('study_course',
1404                              'current_level',
1405                              'current_session',
1406                              'current_mode',
1407                              'current_verdict',
1408                              'previous_verdict',
1409                              )
1410                              },
1411
1412                         'PaymentsFolder':
1413                          {'id': 'payments',
1414                           'title': 'Payments',
1415                           'wf_transition_return': 'open',
1416                           'wf_transition_admit': 'open',
1417                           'fields':
1418                             ()
1419                              },
1420                         }
1421    ###)
1422
1423    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1424    def mass_create_student(self,mapping):
1425        "create a students record due import"
1426        logger = logging.getLogger('WAeUPTool.mass_create_student')
1427        students_folder = self.portal_url.getPortalObject().campus.students
1428        jamb_reg_no = mapping.get('jamb_reg_no',None)
1429        if jamb_reg_no:
1430            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1431            if res:
1432                return '',"jamb_reg_no exists"
1433        matric_no = mapping.get('matric_no',None)
1434        if matric_no:
1435            res = self.students_catalog(matric_no = matric_no)
1436            if res:
1437                return '',"matric_no exists"
1438        sid = self.waeup_tool.generateStudentId('?')
1439        students_folder.invokeFactory('Student', sid)
1440        student_obj = getattr(students_folder,sid)
1441        f2t = self.field2types_student
1442        d = {}
1443        transition = mapping.get('reg_transition','admit')
1444        if transition not in ('admit','return'):
1445            return '',"no valid transition provided"
1446        for pt in f2t.keys():
1447            student_obj.invokeFactory(pt,f2t[pt]['id'])
1448            sub_obj = getattr(student_obj,f2t[pt]['id'])
1449            sub_doc = sub_obj.getContent()
1450            d['Title'] = f2t[pt]['title']
1451            for field in f2t[pt]['fields']:
1452                d[field] = mapping.get(field,'')
1453
1454            if pt == "StudentApplication":
1455                d['jamb_sex']  = 'M'
1456                if mapping.get('sex'):
1457                    d['jamb_sex']  = 'F'
1458                d['jamb_firstname'] = mapping.get('firstname',None)
1459                d['jamb_middlename'] = mapping.get('middlename',None)
1460                d['jamb_lastname'] = mapping.get('lastname',None)
1461
1462            # if pt == "StudyCourse":
1463            #     for von,zu in (('entry_mode','current_mode'),
1464            #                    ('entry_session','current_session')):
1465            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1466            #             d[zu] = mapping[von]
1467            sub_doc.edit(mapping = d)
1468
1469            #import pdb;pdb.set_trace()
1470            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
1471            if new_state != "remain":
1472                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1473        self.portal_workflow.doActionFor(student_obj,transition)
1474        student_obj.manage_setLocalRoles(sid, ['Owner',])
1475        return sid,''
1476    ###)
1477
1478    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1479    def mass_edit_student(self,mapping):
1480        "edit a students record due import"
1481        logger = logging.getLogger('WAeUPTool.mass_edit_student')
1482        students_folder = self.portal_url.getPortalObject().campus.students
1483        sid = mapping.get('id',None)
1484        jamb_reg_no = mapping.get('jamb_reg_no',None)
1485        matric_no = mapping.get('matric_no',None)
1486        editable_keys = mapping.keys()
1487        if sid:
1488            res = self.students_catalog(id = sid)
1489            if not res:
1490                return '',"no student with id %s" % sid
1491            if matric_no and res[0].matric_no and\
1492              matric_no != res[0].matric_no:
1493                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1494            if jamb_reg_no and res[0].jamb_reg_no and\
1495              jamb_reg_no != res[0].jamb_reg_no:
1496                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
1497        elif jamb_reg_no:
1498            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1499            if not res:
1500                return '',"no student with jamb_reg_no %s" % jamb_reg_no
1501            editable_keys.remove('jamb_reg_no')
1502        elif matric_no:
1503            res = self.students_catalog(matric_no = matric_no)
1504            if not res:
1505                return '',"no student with matric_no %s" % matric_no
1506            editable_keys.remove('matric_no')
1507
1508        ## included only to change wf state from admitted to returning
1509        #if res[0].review_state not in ('admitted','objection_raised'):
1510        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1511        ## end inclusion
1512
1513        sid = res[0].id
1514        student_obj = getattr(students_folder,sid)
1515        f2t = self.field2types_student
1516        d = {}
1517        #import pdb;pdb.set_trace()
1518        any_change = False
1519        for pt in f2t.keys():
1520            if pt == "student_application":
1521                d['jamb_sex']  = 'M'
1522                if mapping.get('sex'):
1523                    d['jamb_sex']  = 'F'
1524            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
1525            if intersect:
1526                sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1527                if sub_obj is None:
1528                    try:
1529                        student_obj.invokeFactory(pt,f2t[pt]['id'])
1530                    except:
1531                        continue
1532                    sub_obj = getattr(student_obj,f2t[pt]['id'])
1533                    d['Title'] = f2t[pt]['title']
1534                sub_doc = sub_obj.getContent()
1535                for field in intersect:
1536                    changed = False
1537                    if getattr(sub_doc,field,None) != mapping.get(field,''):
1538                        any_change = True
1539                        changed = True
1540                        d[field] = mapping.get(field,'')
1541                    if changed:
1542                        sub_doc.edit(mapping = d)
1543
1544
1545        ## included only to change wf state from admitted to returning
1546        #    if res[0].review_state in ('admitted','objection_raised'):
1547        #        new_state = f2t[pt]['wf_transition_return']
1548        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1549        #        if sub_obj and new_state != "remain":
1550        #            try:
1551        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1552        #            except:
1553        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1554        #                pass
1555        #if res[0].review_state in ('admitted','objection_raised'):
1556        #    wfaction = 'return'
1557        #    try:
1558        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1559        #        logger.info('%s, wf state changed' % sid)
1560        #        any_change = True
1561        #    except:
1562        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1563        #        pass
1564        ## end inclusion
1565
1566
1567        if any_change:
1568            return sid,''
1569        else:
1570            return sid,'not modified'
1571    ###)
1572
1573    security.declareProtected(ModifyPortalContent,"importData")###(
1574    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
1575        """load data from CSV values"""
1576        import transaction
1577        import random
1578
1579        pm = self.portal_membership
1580        member = pm.getAuthenticatedMember()
1581
1582        logger = logging.getLogger('WAeUPTool.importData')
1583        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1584        students_folder = self.portal_url.getPortalObject().campus.students
1585        start = True
1586        tr_count = 0
1587        total_imported = 0
1588        total_not_imported = 0
1589        total = 0
1590        iname = "import_%s" % name
1591        if iname == 'import_application':
1592            commit_after = 2000
1593        else:
1594            commit_after = 100
1595        stool = getToolByName(self, 'portal_schemas')
1596        ltool = getToolByName(self, 'portal_layouts')
1597        schema = stool._getOb(iname)
1598        if schema is None:
1599            em = 'No such schema %s' % iname
1600            logger.error('No such schema %s' % iname)
1601            return em
1602        layout = ltool._getOb(iname)
1603        if layout is None:
1604            em = 'No such layout %s' % iname
1605            logger.error(em)
1606            return em
1607        validators = {}
1608        for widget in layout.keys():
1609            validators[widget] = layout[widget].validate
1610        #import pdb;pdb.set_trace()
1611        mode = "create"
1612        if edit:
1613            mode = "edit"
1614        importer_name = "mass_%(mode)s_%(name)s" % vars()
1615        importer = getattr(self, '%s' % importer_name,None)
1616        if importer is None:
1617            em = 'No importer function %s' % importer_name
1618            logger.error(em)
1619            return em
1620        not_imported = []
1621        imported = []
1622        try:
1623            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
1624        except:
1625            em = 'Error reading %s.csv' % filename
1626            logger.error(em)
1627            return em
1628        for item in items:
1629            if start:
1630                start = False
1631                adapters = [MappingStorageAdapter(schema, item)]
1632                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
1633                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
1634                import_keys = [k for k in attrs if not k.startswith('ignore')]
1635                diff2schema = set(import_keys).difference(set(schema.keys()))
1636                diff2layout = set(import_keys).difference(set(layout.keys()))
1637                if diff2schema:
1638                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
1639                    return em
1640                if mode == "create":
1641                    required_keys = [layout.getIdUnprefixed(id)
1642                                     for id,widget in layout.objectItems()
1643                                     if widget.is_required]
1644                    if not set(required_keys).issubset(set(import_keys)):
1645                        diff2import = set(required_keys).difference(set(import_keys))
1646                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
1647                        return em
1648                s = ','.join(['"%s"' % fn for fn in import_keys])
1649                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
1650                s = '"id",' + s
1651                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
1652                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
1653                format_error = format + ',"%(Error)s"'
1654                format = '"%(id)s",'+ format
1655
1656            dm = DataModel(item, adapters,context=self)
1657            ds = DataStructure(data=item,datamodel=dm)
1658            error_string = ""
1659            total += 1
1660            for k in import_keys:
1661                if not validators[k](ds,mode=mode):
1662                    error_string += " %s : %s" % (k,
1663                                                  self.translation_service(ds.getError(k),
1664                                                                           ds.getErrorMapping(k)))
1665            if not error_string:
1666                temp_item = item.copy()
1667                temp_item.update(dm)
1668                temp_item['id'],error = importer(temp_item)
1669                if error:
1670                    error_string += error
1671                else:
1672                    item = temp_item
1673            if error_string:
1674                item['Error'] = error_string
1675                not_imported.append(format_error % item)
1676                total_not_imported += 1
1677            else:
1678                em = format % item
1679                imported.append(em)
1680                tr_count += 1
1681                total_imported += 1
1682                logger.info("%(total_imported)d of %(total)d %(em)s" % vars())
1683
1684            if total and not total % commit_after:
1685                transaction.commit()
1686                if len(not_imported) > 0:
1687                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1688                             '\n'.join(not_imported) + '\n')
1689                    not_imported = []
1690                if len(imported) > 0:
1691                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1692                             '\n'.join(imported) + '\n')
1693                    imported = []
1694                em = '%d transactions committed\n' % (tr_count)
1695                regs = []
1696                logger.info(em)
1697                tr_count = 0
1698                #if total > 100:
1699                #    return
1700        if len(imported) > 0:
1701            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
1702                                                '\n'.join(imported))
1703        if len(not_imported) > 0:
1704            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
1705                                                '\n'.join(not_imported))
1706        em = "Finished: %d imported, %d not imported (of total %d)" % (total_imported,total_not_imported,total)
1707        logger.info(em)
1708        return em
1709    ###)
1710
1711    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
1712    def moveImagesToFS(self,student_id="O738726"):
1713        "move the images to the filesystem"
1714        images_dir = os.path.join("%s" % images_base,student_id)
1715        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1716        stool = getToolByName(self, 'portal_schemas')
1717        schemas = ['student_application',
1718                   'student_clearance',
1719                   ]
1720        created = False
1721        for schema_id in schemas:
1722            schema = stool._getOb(schema_id)
1723            object = getattr(student_folder,schema_id[len('student_'):],None)
1724            if object is None:
1725                continue
1726            doc = object.getContent()
1727            for key in schema.keys():
1728                if schema[key].meta_type != "CPS Image Field":
1729                    continue
1730                #import pdb;pdb.set_trace()
1731                image = getattr(doc,key,None)
1732                if not image or not hasattr(image,"data"):
1733                    continue
1734                if not created:
1735                    if not os.path.exists(images_dir):
1736                        os.mkdir(images_dir)
1737                    created = True
1738                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
1739                open(filename,"wb").write(str(image.data))
1740    ###)
1741
1742    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
1743    def movePassportToFS(self,student_id="O738726"):
1744        "move the passports to the filesystem"
1745        images_dir = os.path.join("%s" % i_home,'passports')
1746        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1747        stool = getToolByName(self, 'portal_schemas')
1748        schemas = ['student_application',
1749                   #'student_clearance',
1750                   ]
1751        created = False
1752        for schema_id in schemas:
1753            schema = stool._getOb(schema_id)
1754            object = getattr(student_folder,schema_id[len('student_'):],None)
1755            if object is None:
1756                continue
1757            doc = object.getContent()
1758            for key in schema.keys():
1759                if schema[key].meta_type != "CPS Image Field":
1760                    continue
1761                #import pdb;pdb.set_trace()
1762                image = getattr(doc,key)
1763                if not hasattr(image,"data"):
1764                    continue
1765                if not created:
1766                    if not os.path.exists(images_dir):
1767                        os.mkdir(images_dir)
1768                    created = True
1769                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
1770                open(filename,"wb").write(str(image.data))
1771    ###)
1772
1773InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.