source: WAeUP_SRP/base/WAeUPTool.py @ 2494

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

enable import of previous_verdict

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