source: WAeUP_SRP/base/WAeUPTool.py @ 2548

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

application statistics customized (in custom)

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