source: WAeUP_SRP/base/WAeUPTool.py @ 2402

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

added remove_students

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