source: WAeUP_SRP/base/WAeUPTool.py @ 3113

Last change on this file since 3113 was 3095, checked in by joachim, 17 years ago

should fix traceback, but there must be something wrong with the data

  • Property svn:keywords set to Id
File size: 93.0 KB
RevLine 
[1991]1#-*- mode: python; mode: fold -*-
[197]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 3095 2008-02-03 10:02:35Z joachim $
[1174]20"""The WAeUP Tool Box.
[197]21"""
22
23from AccessControl import ClassSecurityInfo
[828]24from Acquisition import aq_inner
25from Acquisition import aq_parent
26from Globals import DTMLFile
27from Globals import InitializeClass
28from OFS.SimpleItem import SimpleItem
[2283]29from zExceptions import BadRequest
[197]30
[1890]31from Products.CMFCore.utils import getToolByName
[1747]32from Products.CPSSchemas.DataStructure import DataStructure
33from Products.CPSSchemas.DataModel import DataModel
34from Products.CPSSchemas.StorageAdapter import MappingStorageAdapter
[828]35from Products.CMFCore.ActionProviderBase import ActionProviderBase
36from Products.CMFCore.permissions import View
37from Products.ZCatalog.ZCatalog import ZCatalog
38from Products.CMFCore.permissions import ModifyPortalContent
[1890]39from Products.CMFCore.permissions import ManagePortal
[197]40from Products.CMFCore.utils import UniqueObject
[1194]41from Products.CMFCore.URLTool import URLTool
[1747]42from Products.CMFCore.utils import getToolByName
[1151]43from Students import makeCertificateCode
[1285]44from Globals import package_home,INSTANCE_HOME
[2094]45import DateTime,time
[1620]46import logging
[1170]47import transaction
[2193]48import csv,re,os,sys
[2413]49from shutil import copy2
[1707]50from Products.AdvancedQuery import Eq, Between, Le,In
[197]51
[2413]52p_home = package_home(globals())
53i_home = INSTANCE_HOME
54images_base = os.path.join(i_home,"images")
55
[2675]56def getImagesDir(student_id):
57    return os.path.join("%s" % images_base,student_id[0],student_id)
[2413]58
[1707]59def getObject(object,name):
60    if object.hasObject(name):
61        return getattr(object,name)
62    return None
[1720]63
[2999]64
[828]65class WAeUPTool(UniqueObject, SimpleItem, ActionProviderBase):
[197]66    """WAeUP tool"""
67
[828]68    id = 'waeup_tool'
[197]69    meta_type = 'WAeUP Tool'
[828]70    _actions = ()
[197]71    security = ClassSecurityInfo()
[828]72    security.declareObjectProtected(View)
73    manage_options = ( ActionProviderBase.manage_options
74                     + SimpleItem.manage_options
75                     )
76
[2999]77    security.declareProtected(View,'re_split') ###(
78    def re_split(self,split_string,string):
79        return re.split(split_string,string)
[3014]80    ###)
[2999]81
82    security.declareProtected(View,'difference') ###(
83    def difference(self,l1,l2):
84        return set(l1).difference(set(l2))
[3014]85    ###)
[2999]86
[1818]87    def rwrite(self,s): ###(
[1707]88        response = self.REQUEST.RESPONSE
89        response.setHeader('Content-type','text/html; charset=ISO-8859-15')
90        response.write("%s<br />\r\n" % s)
[1818]91    ###)
[1174]92
[2695]93    def addtodict(self,d,key,item): ###(
94        d[key].append(item)
95        return d[key]
96    ###)
97
[1818]98    def sleep(self,secs): ###(
99        "sleep"
100        import time
101        time.sleep(secs)
102        return
[1827]103
[1818]104###)
105
[2695]106    security.declareProtected(View,'updateRoleMappingsFor') ###(
107    def updateRoleMappingsFor(self,wf_definition,ob):
108        "do so for public"
109        wf_def = getattr(self.portal_workflow,wf_definition)
110        wf_def.updateRoleMappingsFor(ob)
111    ###)
[2699]112
[2999]113    security.declareProtected(View,'getStatesLgas') ###(
114    def getStatesLgas(self):
115        """return lga info"""
116        voc = getattr(self.portal_vocabularies,'local_gov_areas')
117        states = []
118        lgas  = []
119        d = {}
120        wd = {}
121        for k,v in voc.items():
122            parts = v.split(' / ')
123            if len(parts) == 1:
124                state = parts[0].lower()
125                lga = ""
126            elif len(parts) == 2:
127                state = "_".join(re.split('[^a-zA-Z0-9/]',parts[0].lower()))
128                lga = "-".join(re.split('[^a-zA-Z0-9/]',parts[1].lower()))
129            else:
130                continue
131            if state not in states:
132                states.append(state)
133            if lga not in lgas:
134                lgas.append(lga)
135            words = re.split('[^a-zA-Z0-9/]',k)
136            words.sort()
137            wd[k] = words
138            d[k] = v
139        mapping = {}
140        mapping['word_dict'] = wd
141        mapping['lga_dict'] = d
142        mapping['states'] = states
143        mapping['lgas'] = lgas
144        return mapping
145    ###)
146
[3014]147    security.declareProtected(View,'findLga') ###(
148    def findLga(self,words,words_dict):
149        words = re.split('[^a-zA-Z0-9/]',words)
150        lga_words = []
151        for word in words:
152            if word:
153                lga_words += word.strip().lower(),
154        lga_words.sort()
155        state_lga = ''
156        while not state_lga:
157            for k,l in words_dict.items():
158                if lga_words == l:
159                    state_lga = k
160                    break
161            break
162        return state_lga
163    ###)
[2975]164    security.declareProtected(View,'getAccessInfo') ###(
165    def getAccessInfo(self,context):
166        "return a dict with access_info"
167        logger = logging.getLogger('WAeUPTool.getAccessInfo')
168        mtool = self.portal_membership
169        member = mtool.getAuthenticatedMember()
170        member_id = str(member)
171        info = {}
172        is_anonymous = info['is_anonymous'] = mtool.isAnonymousUser()
173        is_student = info['is_student'] = ord(member_id[1]) > 48 and ord(member_id[1]) <= 57
174        is_staff = info['is_staff'] = not is_anonymous and not is_student
175        roles = member.getRolesInContext(context)
176        is_sectionofficer = info['is_sectionofficer'] = not is_student and ("SectionOfficer" in roles or
177                                                                            "SectionManager" in roles or
178                                                                            "Manager" in roles)
179        is_allowed = info['is_allowed'] = not is_anonymous
180        requested_id = context.getStudentId()
181        student_id  = None
[3025]182        if is_allowed:
183            if not is_student and requested_id:
184                student_id  = requested_id
185            elif is_anonymous or member_id != requested_id:
186                logger.info('%s tried to access %s of %s' % (member_id,context.portal_type,requested_id))
187            else:
188                student_id = member_id
[2975]189        info['student_id'] = student_id
190        return info
191    ###)
192
[1818]193    security.declareProtected(ModifyPortalContent,'openLog') ###(
[1716]194    def openLog(self,name):
195        """open a log file"""
196        version = 1
197        path = "%s/log/%s_%d.log" % (i_home,name,version)
198        while os.path.exists(path):
199            version += 1
200            path = "%s/log/%s_%d.log" % (i_home,name,version)
201        log = open(path,"w")
202        return log
[2259]203    ###)
[1716]204
[2259]205    security.declareProtected(ModifyPortalContent,'bypassQueueCatalog') ###(
206    def bypassQueueCatalog(self,enable=True):
207        """bypass the QueueCatalog by setting all indexes to process imediate,
208        if enable is True (default) the old settings are restored
209        """
[1818]210
[2259]211    ###)
212
[2094]213    security.declareProtected(ModifyPortalContent,'measureOaT') ###(
214    def measureOaT(self,method="a",probe="1000",nr_pts="1"):
215        """measure Object access Time"""
216        import random
217        if hasattr(self,'portal_catalog_real'):
218            aq_portal = self.portal_catalog_real.evalAdvancedQuery
219        else:
220            aq_portal = self.portal_catalog.evalAdvancedQuery
221        nr_pts = int(nr_pts)
222        probe = int(probe)
223        intervall = probe/10
224        objects = ("application","clearance","personal")
225        portal_types = ("StudentApplication","StudentClearance","StudentPersonal")
226        #i = random.randrange(num_objects)
227        count = 0
228        found = 0
229        not_found = 0
230        t_found = 0
231        t_not_found = 0
232        time_found = time_not_found = 0.0
233        t_time_found = t_time_not_found = 0.0
234        accessed = []
235        t_min = 1000
236        t_max = 0
237        #import pdb;pdb.set_trace()
238        students = self.portal_catalog(portal_type="Student")
239        num_students = len(students)
240        if method == "d":
241            query = Eq('path','/uniben/campus/students') & In('portal_type',portal_types[:nr_pts])
242            res = aq_portal(query)
243            brains = {}
244            for r in res:
245                sid = r.relative_path.split('/')[-2]
246                if brains.has_key(sid):
247                    brains[sid][r.portal_type] = r
248                else:
249                    brains[sid] = {r.portal_type : r}
250            brains_list = brains.keys()
251            num_objects = len(brains_list)
252        else:
253            num_objects = num_students
254        print "="*40
255        print "method: %s probes: %d nr_pts: %d num_objects: %d" % (method,
256                                                                        probe,
257                                                                        nr_pts,
258                                                                        num_objects)
259        print "nr found/not time found/not min/max"
260        elapse = time.time()
261        i_elapse = time.time()
262        c_elapse = time.clock()
263        for c in range(1,probe + 1):
264            i = random.randrange(num_objects)
265            if method in ('a','b','c'):
266                student_brain = students[i]
267            elif method == "d":
268                #import pdb;pdb.set_trace()
269                student_brain = brains[brains_list[i]]
270            if method == "c":
271                query = Eq('path',student_brain.getPath()) & In('portal_type',portal_types[:nr_pts])
272                res = aq_portal(query)
273                this_portal_types = [r.portal_type for r in res]
274            for i in range(nr_pts):
275                oid = objects[i]
276                if method == "a":
277                    try:
278                        student_path = student_brain.getPath()
279                        path = "%s/%s" % (student_path,oid)
280                        doc = self.unrestrictedTraverse(path).getContent()
281                        found += 1
282                        i_time = time.time() - i_elapse
283                        time_found += i_time
284                    except:
285                        not_found += 1
286                        i_time = time.time() - i_elapse
287                        time_not_found += i_time
288                        pass
289                elif method == "b":
290                    try:
291                        student_object = student_brain.getObject()
292                        doc = getattr(student_object,oid).getContent()
293                        found += 1
294                        i_time = time.time() - i_elapse
295                        time_found += i_time
296                    except:
297                        i_time = time.time() - i_elapse
298                        time_not_found += i_time
299                        not_found += 1
300                        pass
301                elif method == "c":
302                    if portal_types[i] in this_portal_types:
303                        found += 1
304                        doc = res[this_portal_types.index(portal_types[i])].getObject().getContent()
305                        i_time = time.time() - i_elapse
306                        time_found += i_time
307                    else:
308                        not_found += 1
309                        i_time = time.time() - i_elapse
310                        time_not_found += i_time
311                elif method == "d":
312                    if student_brain.has_key(portal_types[i]):
313                        found += 1
314                        doc = student_brain[portal_types[i]].getObject().getContent()
315                        i_time = time.time() - i_elapse
316                        time_found += i_time
317                    else:
318                        not_found += 1
319                        i_time = time.time() - i_elapse
320                        time_not_found += i_time
321                i_elapse = time.time()
322            if c and (c % intervall == 0):
323                #i_time = time.time() - i_elapse
324                t_per = 0.0
325                if found:
326                    t_per = time_found/found
327                if t_per > t_max:
328                    t_max = t_per
329                if t_per > 0.0 and t_per < t_min:
[2119]330                    t_min = t_per
[2094]331                itf = 0.0
332                if found:
333                    itf = time_found/found
334                itnf = 0.0
335                if not_found :
336                    itnf = time_not_found / not_found
[2119]337                interval_time = time_found + time_not_found
338                s = "%(c)d: %(found)d/%(not_found)d " % vars()
[2094]339                s += "%(interval_time)6.2f %(itf)6.4f/%(itnf)6.4f " % vars()
340                s += "%(t_min)6.4f/%(t_max)6.4f" %  vars()
341                print s
342                t_found += found
343                t_not_found += not_found
344                t_time_found += time_found
345                t_time_not_found += time_not_found
346                time_found = time_not_found = 0.0
347                found = not_found = 0
348        # t_found += found
349        # t_not_found += not_found
350        elapse = time.time() - elapse
351        itf = 0.0
352        if t_found:
353            itf = t_time_found/t_found
354        itnf = 0.0
355        if t_not_found:
356            itnf = t_time_not_found / t_not_found
357        #c_elapse = time.clock() - c_elapse
[2119]358        s = "%(probe)d: %(t_found)d/%(t_not_found)d " % vars()
[2094]359        s += "%(elapse)6.2f %(itf)6.4f/%(itnf)6.4f " % vars()
360        s += "%(t_min)6.4f/%(t_max)6.4f" %  vars()
361        print "-"*40
362        print s
363        rel_found = float(t_found)/probe
364        rel_not_found = float(t_not_found)/probe
365        estimated_total_time = num_objects*(rel_found*itf + rel_not_found*itnf)
366        print estimated_total_time
367    ###)
368
[1818]369    security.declareProtected(ModifyPortalContent,'writeLog') ###(
[1716]370    def writeLog(self,logfile,s):
371        """write to the log file"""
372        logfile.write(s)
373
[1818]374###)
[1720]375
[1151]376    def generateStudentId(self,letter): ###(
377        import random
378        r = random
[1194]379        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
380        if letter == '?':
[2695]381            letter= r.choice('ABCDEFGHKLMNPQRSTUVWXY')
[1151]382        sid = "%c%d" % (letter,r.randint(99999,1000000))
[1720]383        students = self.portal_url.getPortalObject().campus.students
[1721]384##        while hasattr(students, sid):
385##            sid = "%c%d" % (letter,r.randint(99999,1000000))
386        while self.students_catalog(id = sid):
[1720]387            sid = "%c%d" % (letter,r.randint(99999,1000000))
[1151]388        return sid
[1460]389    ###)
[1415]390
391    def generatePassword(self,s=None): ###(
392        import random
393        r = random
394        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
395        if s is None:
396            s = 'abcdefghklmnpqrstuvwxy23456789'
397        pw = ''
398        while len(pw) < 6:
399            pw += r.choice(s)
400        return pw
[1151]401    ###)
[828]402
[2645]403    security.declareProtected(ModifyPortalContent, 'dumpSchoolfeePayments') ###(
404    def dumpSchoolfeePayments(self):
405        "dump paid schoolfees"
[2666]406        mtool = self.portal_membership
407        member = mtool.getAuthenticatedMember()
[2645]408        logger = logging.getLogger('WAeUPTool.dumpSchoolfees')
409        aq_student = self.students_catalog.evalAdvancedQuery
410        query = In('review_state',('schoolfee_paid',
411                                   'courses_registered',
412                                   'courses_validated',
413                                   ))
414        res = aq_student(query)
[2666]415        #import pdb;pdb.set_trace()
[2645]416        l = []
417        logger.info("start for %d" % len(res))
418        count = 1
419        log_after = 100
420        for student in res:
[2656]421            if not count % log_after:
[2645]422                logger.info("processed %d total %d" % (log_after,count))
423            count += 1
424            fee_dict =self.getSchoolFee(student)
425            fulltime = student.mode.endswith('_ft')
426            d = {}
427            d['student_id'] = student.id
[2666]428            d['name'] = student.name
429            d['amount'] = fee_dict.get(new_returning)
[2645]430            l += d,
[2666]431        csv_name = self.dumpListToCSV(l,'payments')
432        logger.info('%s dumped payments to %s' % (member,export_file))
[2645]433    ###)
434
[2666]435    security.declarePublic('dumpListToCSV') ###(
436    def dumpListToCSV(self,l,filename,fields=None):
437        """dump a list of dicts to a CSV file"""
438        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
439        export_file = "%s/export/%s_%s.csv" % (i_home,filename,current,)
440        if fields is None:
441            fields = l[0].keys()
442        headline = ','.join(fields)
443        out = open(export_file,"wb")
444        out.write(headline +'\n')
445        out.close()
446        out = open(export_file,"a")
447        csv_writer = csv.DictWriter(out,fields,)
448        csv_writer.writerows(l)
449        return export_file
450    ###)
451
[2643]452    security.declareProtected(ManagePortal, 'listMembers') ###(
453    def listMembers(self):
454        "list all members"
455        mtool = self.portal_membership
456        member = mtool.getAuthenticatedMember()
457        logger = logging.getLogger('WAeUPTool.listMembers')
458        if str(member) not in ('admin','joachim'):
459            logger.info('%s tried to list members' % (member))
460            return None
461        members = self.portal_directories.members
462        all = members.listEntryIdsAndTitles()
463        l = []
464        for user_id,name in all:
465            d = {}
466            d['user_id'] = user_id
467            d['name'] = name
468            d['pw'] = getattr(getattr(members,user_id),'password')
[2645]469            d['email'] = getattr(getattr(members,user_id),'email')
470            d['groups'] = " ".join(getattr(getattr(members,user_id),'groups'))
471            d['roles'] = " ".join(getattr(getattr(members,user_id),'roles'))
[2643]472            l += d,
473        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
474        export_file = "%s/export/member_list_%s.csv" % (i_home,current,)
475        logger.info('%s dumped memberlist to %s' % (member,export_file))
476        fields = l[0].keys()
477        headline = ','.join(fields)
478        out = open(export_file,"wb")
479        out.write(headline +'\n')
480        out.close()
481        out = open(export_file,"a")
482        csv_writer = csv.DictWriter(out,fields,)
483        csv_writer.writerows(l)
484    ###)
[2656]485
[1890]486    security.declareProtected(ManagePortal, 'removeDeletedDocIds') ###(
487    def removeDeletedDocIds(self, max=1000):
488        """
489        remove deleted docids from repository commit after max
490        """
491        logger = logging.getLogger('WAeUPTool.removeDeletedDocIds')
492        repository = getToolByName(self, 'portal_repository')
493        pxtool = getToolByName(self, 'portal_proxies')
[2632]494        logger.info('start')
[1890]495        pxtool_infos = pxtool.getRevisionsUsed()
[2632]496        logger.info('found  %d used revisions ' % (len(pxtool_infos)))
[1895]497
[1890]498        nb_revs = 0
499        docids_d = {} # all docids
500        unused_docids_d = {} # all docids that are unused
501        ids_unused_revs_docids = [] # ids for revs of unused docids
[2632]502        unused_ids = [] # ids for unused revs
[1890]503        total = 0
[1895]504        idlist = repository.objectIds()
[2632]505        to_delete = 0
506        found = False
[1895]507        for id in idlist:
[1890]508            docid, rev = repository._splitId(id)
509            if docid is None:
510                logger.info("invalid doc_id %s" % docid)
511                continue
512            nb_revs += 1
513            if not pxtool_infos.has_key(docid):
[2632]514                found = True
515                to_delete += 1
516                unused_ids.append(id)
[1890]517            elif not pxtool_infos[docid].has_key(rev):
[2632]518                found = True
519                to_delete += 1
520                unused_ids.append(id)
521            if found and not to_delete % max:
522                found = False
[1890]523                #import pdb;pdb.set_trace()
[2632]524                repository.manage_delObjects(unused_ids)
[1890]525                transaction.commit()
[2632]526                logger.info('removed %d total %d unused docids ' % (max,to_delete))
527        else:
528            if unused_ids:
529                repository.manage_delObjects(unused_ids)
530                transaction.commit()
531        logger.info('finished removing %d unused docids ' % (to_delete))
[1890]532
[1895]533
[1890]534###)
535
[2562]536    security.declareProtected(View,'getCredential') ###(
[1250]537    def getCredential(self,student_id):
538        student_entry = getattr(self.portal_directories.students,student_id,None)
[2555]539        if not self.isStaff():
[2563]540            mtool = self.portal_membership
541            member = mtool.getAuthenticatedMember()
542            logger = logging.getLogger('WAeUPTool.getCredential')
543            logger.info('%s tried to access password of %s' % (member,student_id))
[2555]544            return None
[1250]545        if student_entry is None:
546            return None
[1263]547        return getattr(student_entry,"password","not set")
[1261]548    ###)
[1250]549
[2747]550    security.declarePublic('checkPassword') ###(
[1467]551    def checkPassword(self,student_id,password):
[1460]552        student_entry = getattr(self.portal_directories.students,student_id,None)
553        if student_entry is None:
554            return False
555        return getattr(student_entry,"password","not set") == password
[2747]556    ###)
[2712]557
[2747]558    security.declarePublic('checkGenericPassword') ###(
[2710]559    def checkGenericPassword(self,member_id):
560        member_entry = getattr(self.portal_directories.members,member_id,None)
561        if member_entry is None:
562            return False
[2712]563        ltool = getToolByName(self, 'portal_layouts')
[2710]564        unsecure_words = ltool._getOb('members')['w__password'].check_words
[2712]565        password = getattr(member_entry,"password","not set")
566        is_unsecure = password in unsecure_words
567        if is_unsecure:
[2713]568            logger = logging.getLogger('WAeUPTool.checkGenericPassword')
[2712]569            logger.info('Member %s tried to log in with unsecure password %s' %(member_id,password))
570        return is_unsecure
[2747]571    ###)
[1460]572
[2556]573    security.declareProtected(ModifyPortalContent,'editPassword') ###(
[1467]574    def editPassword(self,student_id,password):
575        "edit a student password"
576        student_entry = getattr(self.portal_directories.students,student_id,None)
577        if student_entry is None:
[1571]578            return
[1467]579        setattr(student_entry,'password',password)
580    ###)
581
[2555]582    security.declareProtected(ModifyPortalContent,'doCommit') ###(
[1401]583    def doCommit(self,logger=None):
584        "commit some transactions"
585        transaction.commit()
586    ###)
587
[1285]588    security.declarePublic('loadStudentFoto') ###(
[1813]589    def loadStudentFoto(self,student,filename,folder):
[1285]590        "return a student passport picture"
[2413]591        #import pdb;pdb.set_trace()
592        picture ="%s/import/%s/%s" % (i_home,folder,filename)
593        student_id = student.getId()
[2675]594        images_dir = getImagesDir(student_id)
[2413]595        if not os.path.exists(images_dir):
596            os.mkdir(images_dir)
597        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
598        for extension in ('.jpg','.JPG'):
599            fullname = "%(picture)s%(extension)s" % vars()
600            if os.path.exists(fullname):
601                copy2(fullname,image_name)
602                return "successfully copied passport picture"
[2467]603        return "passport picture not found: %s.jpg or .JPG" % picture
[2413]604    ###)
605
[2420]606    def old____loadStudentFoto(self,student,filename,folder): ###(
[2413]607        "return a student passport picture"
[1921]608        app = student.application
609        app_doc = app.getContent()
[1813]610        #clear = student.clearance
611        #clear_doc = clear.getContent()
612        #matric_no = clear_doc.matric_no.upper()
613        picture1 ="%s/import/%s/%s.jpg" % (i_home,folder,filename)
614        picture2 ="%s/import/%s/%s.JPG" % (i_home,folder,filename)
[1285]615        #import pdb;pdb.set_trace()
[1286]616        if os.path.exists(picture1):
617            file = open(picture1)
618        elif os.path.exists(picture2):
[1287]619            file = open(picture2)
[1286]620        else:
[1287]621            return "passport picture not found %s" % picture1
[1921]622        reopened = False
623        if self.portal_workflow.getInfoFor(app,'review_state',None) !='opened':
624            self.portal_workflow.doActionFor(app,'open')
625            reopened = True
[1285]626        outfile = file.read()
627        app_doc.manage_addFile('passport',
628                               file=outfile,
[1818]629                               title="%s.jpg" % filename)
[1921]630        if reopened:
631            self.portal_workflow.doActionFor(app,'close')
[1286]632        return "successfully loaded passport picture"
[1285]633    ###)
634
[1170]635    security.declareProtected(ModifyPortalContent,'createOne') ###(
[1194]636    def createOne(self,students_folder,student_brain,letter,commit=False):
637        sid = self.waeup_tool.generateStudentId(letter)
[1170]638        students_folder.invokeFactory('Student', sid)
639        student = getattr(students_folder,sid)
640        self.portal_workflow.doActionFor(student,'return')
641        student.manage_setLocalRoles(sid, ['Owner',])
642        matric_no = student_brain.matric_no
643        jamb_reg_no = student_brain.Entryregno
644        self.students_catalog.addRecord(id = sid,
645                                           matric_no = matric_no,
646                                           jamb_reg_no = jamb_reg_no,
647                                           sex = student_brain.Sex == "F",
648                                           name = "%s %s %s" % (student_brain.Firstname,
649                                                                student_brain.Middlename,
650                                                                student_brain.Lastname)
651                                        )
652        if commit:
653            transaction.commit()
654        return sid,jamb_reg_no
655    ###)
656
[1752]657    security.declareProtected(ModifyPortalContent,'addStudent') ###(
658    def addStudent(self,dict):
[1415]659        students_folder = self.portal_url.getPortalObject().campus.students
660        sid = self.waeup_tool.generateStudentId('?')
661        students_folder.invokeFactory('Student', sid)
662        student_obj = getattr(students_folder,sid)
[3027]663        f2t = self.field2types_student
[1772]664        #from pdb import set_trace; set_trace()
665        d = {}
[2297]666        #d['jamb_sex']  = 'M'
667        #if dict.get('sex'):
668        #    d['jamb_sex']  = 'F'
[1904]669
[1898]670        entry_session = dict.get('entry_session')
[2454]671        if entry_session == self.getSessionId()[0]:
[1898]672            wfaction = 'admit'
[1991]673            wft = 'wf_transition_admit'
[1900]674            password = None
[1904]675        else:
[1900]676            wfaction = 'return'
[1991]677            wft = 'wf_transition_return'
[1900]678            password = self.generatePassword()
[1904]679            self.makeStudentMember(sid,password)
680
[1728]681        for pt in f2t.keys():
682            student_obj.invokeFactory(pt,f2t[pt]['id'])
683            sub_obj = getattr(student_obj,f2t[pt]['id'])
684            sub_doc = sub_obj.getContent()
[1898]685            #self.portal_workflow.doActionFor(sub_obj,'open',dest_container=sub_obj)
[1772]686            d['Title'] = f2t[pt]['title']
[1728]687            for field in f2t[pt]['fields']:
[1749]688                d[field] = dict.get(field,'')
[1728]689            sub_doc.edit(mapping = d)
[1898]690            new_state = f2t[pt][wft]
[1772]691            if new_state != "remain":
692                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
[1415]693        self.portal_workflow.doActionFor(student_obj,wfaction)
694        student_obj.manage_setLocalRoles(sid, ['Owner',])
695        return sid,password
696    ###)
697
[1151]698    security.declarePublic('getCertificateBrain') ###(
699    def getCertificateBrain(self,cert_id):
700        "do it"
[1849]701        res = ZCatalog.searchResults(self.portal_catalog_real,
[1151]702                                {'portal_type':"Certificate",
703                                      'id': cert_id})
704        if res:
705            return res[0]
706        return None
707    ###)
[1160]708
[1756]709    security.declareProtected(ModifyPortalContent,'get_csv_filenames') ###(
710    def get_csv_filenames(self):
711        "do it"
[1759]712        files = [file for file in os.listdir("%s/import/" % (i_home))
[1756]713                 if file.endswith('.csv') and file.find('imported') == -1]
714        return files
715    ###)
716
[1151]717    security.declarePublic('findStudentByMatricelNo') ###(
718    def findStudentByMatricelNo(self,matric_no):
719        "do it"
[1849]720        res = ZCatalog.searchResults(self.portal_catalog_real,
[1151]721                                {'portal_type':"StudentClearance",
722                                 'SearchableText': matric_no})
723        if res:
724            return res[0]
725        return None
726    ###)
727
[2557]728    security.declarePublic('makeStudentMember') ###(
[1151]729    def makeStudentMember(self,sid,password='uNsEt'):
730        """make the student a member"""
731        membership = self.portal_membership
732        membership.addMember(sid,
733                             password ,
734                             roles=('Member',
735                                     'Student',
736                                     ),
737                             domains='',
738                             properties = {'memberareaCreationFlag': False,
739                                           'homeless': True},)
740        member = membership.getMemberById(sid)
741        self.portal_registration.afterAdd(member, sid, password, None)
[1261]742        #self.manage_setLocalRoles(sid, ['Owner',])
[1151]743    ###)
[1160]744
[2560]745    security.declareProtected(View,'makeStudentData') ###(
[1158]746    def makeStudentData(self,student_id,email=None,phone_nr=None):
[1151]747        "create Datastructure for a returning Student"
[1406]748        #import pdb;pdb.set_trace()
[1571]749        logger = logging.getLogger('WAeUPTool.makeStudentData')
[1151]750        students_folder = self.portal_url.getPortalObject().campus.students
[1794]751        #res = self.students_catalog(id=student_id)
752        #if res:
753        #    st = res[0]
754        #res = self.returning_import(matric_no = st.matric_no)
[1798]755        res = self.returning_import(id = student_id)
[1151]756        if res:
[1160]757            student = res[0]
[1794]758        else:
[1816]759            logger.info('Id %s not found in returning_import' % student_id)
[1794]760            return
[1580]761        logger.info('%s creates data structure' % student_id)
[1794]762        s_results = self.results_import(matric_no = student.matric_no)
[1816]763        if s_results:
764            lnr = self.getLevelFromResultsCosCode(s_results)
765            level = "%d00" % lnr
766            verdict,eligible = self.getVerdict(s_results[0].Verdict)
[2454]767            #if eligible:
768            #    level = "%d00" % (lnr + 1)
[1816]769        else:
770            logger.info('matric_no %s not found in results_import' % student.matric_no)
[2656]771            level = ''
772            verdict = ''
[1171]773        #student should not be allowed to perform this transition
[1174]774        #wftool = self.portal_workflow
775        #wftool.doActionFor(student,'return')
[1151]776        certcode_org = student.Coursemajorcode
777        certcode = makeCertificateCode(certcode_org)
778        certificate_brain = self.getCertificateBrain(certcode)
779        if not certificate_brain:
780            em = 'Certificate %s org-code %s not found\n' % (certcode, certcode_org)
781            logger.info(em)
782        matric_no = student.matric_no
783        sid = student_id
784        student_obj = getattr(students_folder,sid)
785        student_obj.invokeFactory('StudentApplication','application')
786        application = student_obj.application
[1169]787        self.portal_workflow.doActionFor(application,'open',dest_container=application)
[1151]788        da = {'Title': 'Application Data'}
789        student_obj.invokeFactory('StudentPersonal','personal')
790        da['jamb_reg_no'] = student.Entryregno
[1462]791        em = self.getEntryMode(student.Entryregno)
[1401]792        da['entry_mode'] = em
[1151]793        personal = student_obj.personal
794        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
795        dp = {'Title': 'Personal Data'}
796        student_obj.invokeFactory('StudentClearance','clearance')
797        clearance = student_obj.clearance
[1169]798        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
[1151]799        dc = {'Title': 'Clearance/Eligibility Record'}
800        dc['matric_no'] = matric_no
801        state = student.State
802        lga = student.LGA
803        if state and lga:
804            lga =  state + ' / ' + lga
805        else:
806            lga = "None"
[1174]807        da['jamb_lga'] = dc['lga'] = lga
[1173]808        da['app_email'] = dp['email'] = email
809        da['app_mobile'] = dp['phone'] = phone_nr
[1411]810        dp['firstname'] = student.Firstname
811        dp['middlename'] = student.Middlename
812        dp['lastname'] = student.Lastname
813        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
[1174]814        da['jamb_sex'] = student.Sex
[1151]815        dp['sex'] = student.Sex == 'F'
816        dp['perm_address'] = student.Permanent_Address
817        application.getContent().edit(mapping=da)
[1169]818        self.portal_workflow.doActionFor(application,'close',dest_container=application)
[1151]819        personal.getContent().edit(mapping=dp)
820        clearance.getContent().edit(mapping=dc)
[1169]821        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
[1151]822        #
823        # Study Course
824        #
825        student_obj.invokeFactory('StudentStudyCourse','study_course')
826        studycourse = student_obj.study_course
827        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
828        dsc = {}
829        dsc['study_course'] = certcode
[1401]830        dsc['current_level'] = level
831        dsc['current_verdict'] = verdict
[1827]832        dsc['current_mode'] = em
[2466]833        dsc['current_session'] = '05'
[1151]834        studycourse.getContent().edit(mapping=dsc)
835        #
836        # Level
837        #
[1198]838##        l = getattr(studycourse,level,None)
839##        if l is None:
840##            studycourse.invokeFactory('StudentStudyLevel', level)
841##            l = getattr(studycourse, level)
842##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
843##            l.getContent().edit(mapping={'Title': "Level %s" % level})
[1194]844###)
[1160]845
[2556]846    security.declareProtected(ModifyPortalContent,'admitOneStudent') ###(
[2576]847    def admitOneStudent(self,brain,entry_session,pin_password):
[2514]848        "create Datastructure for an admitted Student"
849        #import pdb;pdb.set_trace()
[2727]850        if not hasattr(self,"_v_certificates"):
851            self._v_certificates = [entry[0] for entry in self.getCertificatesVoc()]
[2514]852        students_folder = self.portal_url.getPortalObject().campus.students
[2716]853        logger = logging.getLogger('WAeUPTool.admitOneStudent')
[2514]854        if brain.status != "admitted":
855            logger.info('status of %s is %s' % (brain.reg_no,brain.status))
[2540]856            return
[2514]857        pin_parts = brain.pin.split('-')
[2755]858        if pin_parts and len(pin_parts) != 3:
[2695]859            logger.info('invalid pin %s for %s' % (brain.pin,brain.reg_no))
[2540]860            return
[2727]861        if brain.course_admitted not in self._v_certificates:
862            logger.info('certificate %s not found for %s' % (brain.course_admitted,brain.reg_no))
863            return
[2959]864        if brain.sex not in (True,False):
865            logger.info('sex of %s not available' % (brain.reg_no))
[3002]866            return
[2540]867        student_id = self.generateStudentId('?')
[2514]868        students_folder.invokeFactory('Student', student_id)
869        student_object = getattr(students_folder,student_id)
[2576]870        if pin_password:
871            password = pin_parts[2]
872            self.makeStudentMember(student_id,password = password)
[2540]873        student_object.manage_setLocalRoles(student_id, ['Owner',])
874        #logger.info("creating %s reg_no %s" % (student_id,brain.reg_no))
[2514]875        #
876        # application
877        #
[2540]878        student_object.invokeFactory('StudentApplication','application')
879        application = student_object.application
[2575]880        #self.portal_workflow.doActionFor(application,'open',dest_container=application)
[2514]881        da = {'Title': 'Application Data'}
882        da['jamb_reg_no'] = brain.reg_no
[2576]883
[2540]884        sex = 'M'
885        if brain.sex:
886            sex = 'F'
887        da['jamb_sex'] = sex
[2670]888        da['jamb_age'] = brain.jamb_age
[2575]889        #da['app_ac_pin'] = brain.pin
[2670]890        da['jamb_lga'] = brain.jamb_lga
891        da['jamb_state'] = brain.jamb_state
[2575]892        da['jamb_score'] = brain.aggregate
[2514]893        da['app_email'] = brain.email
[2540]894        da['app_mobile'] = brain.phone
[2575]895        if brain.entry_mode:
896            da['entry_mode'] = brain.entry_mode
897        elif brain.screening_type == 'pume':
898            da['entry_mode'] = 'ume_ft'
899        elif brain.screening_type == 'pde':
900            da['entry_mode'] = 'de_ft'
[2950]901        elif brain.screening_type == 'pce':
[2959]902            da['entry_mode'] = 'pce'
[2950]903        elif brain.screening_type == 'prence':
[2959]904            da['entry_mode'] = 'prence'
[2575]905        else:
[2921]906            da['entry_mode'] = ''
[2575]907        da['entry_session'] = entry_session
908        da['jamb_lastname'] = brain.lastname
909        da['jamb_middlename'] = brain.middlenames   # different field names!
[2670]910        da['jamb_firstname'] = brain.firstname
[2575]911        da['screening_application_date'] = brain.application_date
912        da['date_of_birth'] = brain.date_of_birth
913        da['jamb_first_cos'] = brain.course1
914        da['jamb_second_cos'] = brain.course2
915        da['course3'] = brain.course3
916        da['screening_type'] = brain.screening_type
917        da['screening_score'] = brain.screening_score
918        da['screening_date'] = brain.screening_date
919        da['hq_type'] = brain.hq_type
920        da['hq_grade'] = brain.hq_grade
921        da['aos'] = brain.aos
[2576]922
[2514]923        application.getContent().edit(mapping=da)
[2575]924        #self.portal_workflow.doActionFor(application,'close',dest_container=application)
[2514]925        #
926        # personal
927        #
[2540]928        student_object.invokeFactory('StudentPersonal','personal')
929        personal = student_object.personal
[2575]930        #self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
[2514]931        dp = {'Title': 'Personal Data'}
932        dp['sex'] = brain.sex
933        dp['email'] = brain.email
[2540]934        dp['phone'] = brain.phone
[2514]935        dp['lastname'] = brain.lastname
[2575]936        dp['middlename'] = brain.middlenames   # different field names!
[2576]937        dp['firstname'] = brain.firstname
[2514]938        personal.getContent().edit(mapping=dp)
939        #
940        # clearance
941        #
[2540]942        student_object.invokeFactory('StudentClearance','clearance')
943        clearance = student_object.clearance
[2575]944        #self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
[2514]945        dc = {'Title': 'Clearance/Eligibility Record'}
946        dc['lga'] = brain.lga
[2670]947        dc['birthday'] = brain.date_of_birth
[2514]948        clearance.getContent().edit(mapping=dc)
[2575]949        #self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
[2514]950        #
951        # study Course
952        #
[2540]953        student_object.invokeFactory('StudentStudyCourse','study_course')
954        studycourse = student_object.study_course
[2575]955        #self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
[2514]956        dsc = {}
957        dsc['study_course'] = brain.course_admitted
958        dsc['current_verdict'] = ''
[2575]959        dsc['current_mode'] = da['entry_mode']
960        if da['entry_mode'].startswith('de'):
961            dsc['current_level'] = '200'
[3040]962        elif da['entry_mode'].startswith('pre'):
963            dsc['current_level'] = '000'
[2575]964        else:
965            dsc['current_level'] = '100'
966        dsc['current_session'] = entry_session
[2514]967        studycourse.getContent().edit(mapping=dsc)
968        #
969        # payments folder
[2540]970        student_object.invokeFactory('PaymentsFolder','payments')
971        payments = getattr(student_object,'payments')
[2514]972        dpay = {}
973        dpay['Title'] = 'Payments'
974        payments.getContent().edit(mapping=dpay)
[2540]975        self.portal_workflow.doActionFor(payments,'open')
[2580]976        #
977        # passport foto
978        app_picture ="%s/import/images/%s/%s_passport.jpg" % (i_home,
979                                                              brain.screening_type,
980                                                              brain.reg_no)
[2675]981        images_dir = getImagesDir(student_id)
982        #images_dir = os.path.join("%s" % images_base,student_id)
983        letter_dir,student_dir = os.path.split(images_dir)
984        if not os.path.exists(letter_dir):
985            os.mkdir(letter_dir)
[2580]986        if not os.path.exists(images_dir):
987            os.mkdir(images_dir)
988        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
989        if os.path.exists(app_picture):
990            copy2(app_picture,image_name)
991        else:
992            logger.info('passport of %s/%s not found: %s' % (student_id,
993                                                             brain.reg_no,
994                                                             app_picture))
[2656]995
[2514]996        return student_id
997    ###)
998
[2556]999    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
[1194]1000    def makeStudentLevel(self,student_id):
1001        "create the StudyLevel for a returning Student"
1002        #import pdb;pdb.set_trace()
[1571]1003        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
[1194]1004        students_folder = self.portal_url.getPortalObject().campus.students
1005        res = self.students_catalog(id=student_id)
1006        if res:
1007            st = res[0]
1008        course = st.course
1009        matric_no = st.matric_no
1010        level = st.level
1011        res = self.results_import(matric_no = matric_no)
1012        if res:
1013            results = res
[1571]1014        logger.info('%s creating Level %s' % (student_id,level))
[1194]1015        #
1016        # Level
1017        #
1018        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1019        studycourse = getattr(student_obj,"study_course",None)
1020        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
1021        l = getattr(studycourse,level,None)
1022        if l is None:
1023            studycourse.invokeFactory('StudentStudyLevel', level)
1024            l = getattr(studycourse, level)
1025            self.portal_workflow.doActionFor(l,'open',dest_container=l)
1026            l.getContent().edit(mapping={'Title': "Level %s" % level})
1027        ###)
1028
[2000]1029    security.declarePublic('getHallInfo') ###(
1030    def getHallInfo(self,bed):
1031        """return Hall Info"""
[828]1032        info = {}
1033        hall,block,room,letter = bed.split('_')
[1846]1034        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
[828]1035        if res and len(res) == 1:
1036            hall_brain = res[0]
1037            hall_doc = hall_brain.getObject().getContent()
1038        else:
1039            return info
1040        info['hall_title'] = hall_brain.Title
1041        info['maintenance_code'] = hall_doc.maintenance_code
[1846]1042        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
[828]1043        batch_doc = None
1044        for brain in res:
1045            if brain.id.startswith(info['maintenance_code']):
1046                batch_doc = brain.getObject().getContent()
1047                break
1048        if batch_doc is None:
[2913]1049            info['maintenance_fee'] = ''
[828]1050        else:
1051            info['maintenance_fee'] = batch_doc.cost
1052        return info
[1151]1053    ###)
[828]1054
[2396]1055    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
1056    def removePictureFolder(self,student_id):
1057        """remove picture_folder by renaming it"""
1058        path = 'images'
1059        picture_path = os.path.join(i_home,path,student_id)
1060        if not os.path.exists(picture_path):
1061            return False
1062        os.rename(picture_path,picture_path + "_removed")
1063        return True
1064    ###)
1065
1066    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
1067    def restorePictureFolder(self,student_id):
1068        """restore picture_folder by renaming it"""
1069        path = 'images'
1070        picture_path = os.path.join(i_home,path,student_id)
1071        if not os.path.exists(picture_path + "_removed"):
1072            return False
1073        os.rename(picture_path + "_removed",picture_path)
1074        return True
1075    ###)
1076
[2363]1077    security.declarePublic('picturesExist') ###(
[2420]1078    def picturesExist(self, ids,student_id=None):
[2363]1079        """check if pictures exist in the filesystem"""
[2420]1080        if student_id is None:
1081            student_id = self.getStudentId()
1082        if student_id is None:
1083            return False
[2675]1084        picture_path = getImagesDir(student_id)
1085        #picture_path = os.path.join(images_base,student_id)
[2363]1086        if not os.path.exists(picture_path):
1087            return False
1088        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1089        return set(ids).issubset(set(pictures))
1090    ###)
1091
[2364]1092    security.declarePublic('picturesList') ###(
1093    def picturesList(self):
1094        """check if pictures exist in the filesystem"""
1095        path = 'images'
1096        student_id = self.getStudentId()
[2677]1097        #picture_path = os.path.join(i_home,path,student_id)
1098        picture_path = getImagesDir(student_id)
[2364]1099        if not os.path.exists(picture_path):
1100            return []
1101        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1102    ###)
1103
[2114]1104    security.declarePublic('showFsPicture') ###(
1105    def showFsPicture(self,path):
1106        """return a picture from the filesystem"""
[2675]1107        #picture_path = os.path.join(i_home,path)
1108        picture_path = os.path.join(images_base,path)
[2335]1109        response = self.REQUEST.RESPONSE
[2342]1110        #import pdb;pdb.set_trace()
[2354]1111        registry = getToolByName(self, 'mimetypes_registry')
1112        mimetype = str(registry.lookupExtension(path.lower()) or
1113                    registry.lookupExtension('file.bin'))
[2114]1114        if os.path.exists(picture_path):
[2354]1115            response.setHeader('Content-type',mimetype)
[2114]1116            return open(picture_path).read()
[2335]1117        picture_path = os.path.join(i_home,'import',path)
1118        if os.path.exists(picture_path):
1119            return open(picture_path).read()
[2114]1120    ###)
1121
[1151]1122    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
1123    def deleteAllCourses(self,department="All"):
1124        ''' delete the courses'''
1125        pm = self.portal_membership
1126        member = pm.getAuthenticatedMember()
[1160]1127
[1151]1128        if str(member) not in ("henrik","joachim"):
1129            return "not possible"
1130        if department == "All":
1131            res = self.portal_catalog({'meta_type': 'Department'})
1132        if len(res) < 1:
1133            return "No Departments found"
[1160]1134
[1151]1135        deleted = []
1136        for dep in res:
1137            cf = dep.getObject().courses
1138            if cf:
1139                cf.manage_delObjects(ids=cf.objectIds())
1140                deleted.append("deleted Courses in %s" % dep.getId)
1141        return "\r".join(deleted)
[1160]1142    ###)
[1151]1143
[1572]1144    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
1145    def getLogfileLines(self,filename="event.log",numlines=20):
1146        """Get last NUMLINES lines of logfile FILENAME.
[1160]1147
[1572]1148        Return last lines' of a file in the instances logfile directory as
1149        a list. The number of returned lines equals `numlines' or less. If
1150        less than `numlines' lines are available, the whole file ist
1151        returned. If the file can not be opened or some other error
1152        occurs, empty list is returend.
1153        """
1154        result = []
1155        lines_hit = 0
1156
1157        # We only handle files in instances' log directory...
1158        logpath = os.path.join(i_home, "log")
1159        filename = str(os.path.abspath( os.path.join( logpath, filename )))
1160        if not filename.startswith( logpath ):
1161            # Attempt to access file outside log-dir...
1162            return []
1163
1164        try:
1165            fd = file( filename, "rb" )
1166        except IOError:
1167            return []
1168        if not fd:
1169            return []
1170
1171        if os.linesep == None:
1172            linesep = '\n'
1173        else:
1174            linesep = os.linesep
1175
1176        # Try to find 'numlines' times a lineseparator, searching from end
1177        # and moving to the beginning of file...
1178        fd.seek( 0, 2) # Move to end of file...
1179        while lines_hit < numlines:
1180            if fd.read(1) == linesep[-1]: # This moves filedescriptor
1181                                          # one step forward...
1182                lines_hit += 1
1183            try:
1184                fd.seek( -2, 1) # Go two bytes back from current pos...
1185            except IOError:
1186                # We cannot go back two bytes. Maybe the file is too small...
1187                break
1188        fd.seek(2,1)
1189
1190        # Read all lines from current position...
1191        result = fd.readlines()
1192        # Remove line endings...
1193        result = [x.strip() for x in result]
1194        fd.close()
1195        return result
1196    ###)
1197
[1700]1198    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
[1665]1199    def getCallbacksFromLog(self,filename):
1200        """fix Online Payment Transactions from Z2.log entries"""
1201        import transaction
1202        import random
1203        from cgi import parse_qs
1204        from urlparse import urlparse
1205        #from pdb import set_trace
1206        wftool = self.portal_workflow
1207        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1208        students_folder = self.portal_url.getPortalObject().campus.students
1209        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
1210        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
1211        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
1212        data = re.compile(s)
1213        start = True
1214        tr_count = 1
1215        total = 0
1216        #name = 'pume_results'
1217        #name = 'epaymentsuccessful_z2log2'
1218        name = filename
1219        no_import = []
1220        imported = []
1221        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
1222        try:
1223            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
1224        except:
1225            logger.error('Error reading %s' % name)
1226            return
1227        tas = []
1228        for line in transactions:
1229            dict = {}
1230            items = data.search(line)
1231            dict['idict'] = idict = items.groupdict()
1232            #print idict
1233            #from pdb import set_trace;set_trace()
1234            urlparsed = urlparse(idict['get'][4:])
1235            #print urlparsed
1236            path = urlparsed[2].split('/')
1237            dict['student_id'] = student_id = path[8]
1238            dict['payment_id'] = payment_id = path[10]
1239            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
1240            tas.append(dict)
1241            tr_count += 1
1242        return tas
1243    ###)
1244
[1620]1245    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
1246    def importOnlinePaymentTransactions(self):
1247        """load Online Payment Transactions from CSV values"""
1248        import transaction
1249        import random
1250        #from pdb import set_trace
1251        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
[1625]1252        opt = self.online_payments_import
[1620]1253        students_folder = self.portal_url.getPortalObject().campus.students
1254        start = True
1255        tr_count = 1
1256        total = 0
1257        #name = 'pume_results'
1258        name = 'OnlineTransactions'
1259        no_import = []
1260        imported = []
1261        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
1262        try:
1263            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
1264        except:
1265            logger.error('Error reading %s.csv' % name)
1266            return
1267        for pay_transaction in transactions:
1268            if start:
1269                start = False
1270                logger.info('Start loading from %s.csv' % name)
1271                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
1272                no_import.append('%s,"Error"' % s)
1273                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
1274                format_error = format + ',"%(Error)s"'
1275            data = {}
[1644]1276
[1781]1277            # format of the first file sent by Tayo
[1643]1278            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
1279            #data['student_id'] = student_id = pay_transaction['Payer ID']
1280            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1281            #data['response_code'] = response_code = pay_transaction['Resp Code']
1282            #data['amount'] = amount = pay_transaction['Amount']
[1644]1283
[1781]1284            # format of the second file sent by Tayo
[1798]1285            #data['datetime'] = date = 0
1286            #data['student_id'] = student_id = pay_transaction['Payer ID']
1287            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1288            #data['response_code'] = response_code = '00'
1289            #data['amount'] = amount = pay_transaction['Amount']
[1813]1290
[1798]1291            # format of the third file sent by Kehinde
[1643]1292            data['datetime'] = date = 0
[1798]1293            data['student_id'] = student_id = pay_transaction['customer_id']
1294            data['order_id'] = order_id = pay_transaction['merchant_reference']
[1644]1295            data['response_code'] = response_code = '00'
[1813]1296            data['amount'] = amount = pay_transaction['Amount']
[1644]1297
[1620]1298            dup = False
1299            if response_code == "12":
1300                continue
1301            try:
1302                opt.addRecord(**data)
1303            except ValueError:
1304                dup = True
1305            #from pdb import set_trace;set_trace()
1306            if dup:
1307                if response_code == "00":
[1798]1308                    try:
1309                        opt.modifyRecord(**data)
1310                    except:
1311                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
1312                        continue
[1620]1313                else:
[1674]1314                    pay_transaction['Error'] = "Duplicate order_id"
[1620]1315                    no_import.append( format_error % pay_transaction)
[1674]1316                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
[1620]1317                    continue
1318            tr_count += 1
1319            if tr_count > 1000:
1320                if len(no_import) > 0:
1321                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1322                             '\n'.join(no_import) + '\n')
1323                    no_import = []
[1645]1324                em = '%d transactions committed\n' % (tr_count)
[1620]1325                transaction.commit()
1326                regs = []
1327                logger.info(em)
1328                total += tr_count
1329                tr_count = 0
1330        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1331                                                '\n'.join(no_import))
1332        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
1333    ###)
[2237]1334
[2264]1335    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
1336    def mass_create_faculty(self,mapping):
1337        "create a faculty"
1338        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
1339        academics_folder = self.portal_url.getPortalObject().campus.academics
1340        fid = mapping['code']
1341        if getattr(academics_folder,fid,None) is not None:
1342            return '', "Faculty with ID: %s exists" % fid
[2267]1343        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
[2283]1344        try:
1345            academics_folder.invokeFactory('Faculty', fid)
1346        except BadRequest,E:
1347            return '', "%s" % E
[2264]1348        f = getattr(academics_folder,fid,None)
1349        f.getContent().edit(mapping=mapping)
1350        return fid,''
1351    ###)
1352
[2288]1353    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
[2264]1354    def mass_edit_faculty(self,mapping):
1355        "edit a faculty"
1356        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
1357        academics_folder = self.portal_url.getPortalObject().campus.academics
1358        fid = mapping['code']
1359        f = getattr(academics_folder,fid,None)
1360        if f is None:
1361            return '', "Faculty with ID: %s does not exist" % fid
[2267]1362        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
[2264]1363        f.getContent().edit(mapping=mapping)
1364        return fid,''
1365    ###)
1366
[2234]1367    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
[2193]1368    def mass_create_department(self,mapping):
1369        "create a department in the correct faculty"
1370        logger = logging.getLogger('WAeUPTool.mass_create_department')
1371        fid = mapping['faculty_code']
1372        if getattr(self,'_v_faculties',None) is None:
1373            res = self.portal_catalog(portal_type = "Faculty")
1374            self._v_faculties = {}
1375            for f in res:
1376                self._v_faculties[f.getId] = f.getObject()
1377        f = self._v_faculties.get(fid,None)
1378        if f is None:
1379            return '', "No Faculty with ID: %s" % fid
1380        else:
1381            did = mapping.get('code')
1382            d = getattr(f,did,None)
1383            if d is None or d.portal_type == "Faculty":
[2267]1384                logger.info('Creating Department %(code)s, %(title)s' % mapping)
[2283]1385                try:
1386                    f.invokeFactory('Department', did)
1387                except BadRequest,E:
1388                    return '', "%s" % E
[2193]1389                d = getattr(f,did)
1390                d.invokeFactory('CoursesFolder','courses')
1391                courses = getattr(d,'courses')
1392                dict = {'Title': 'Courses'}
1393                courses.getContent().edit(mapping=dict)
1394                d.invokeFactory('CertificatesFolder','certificates')
1395                certificates = getattr(d,'certificates')
1396                dict = {'Title': 'Certificates'}
1397                certificates.getContent().edit(mapping=dict)
1398            d.getContent().edit(mapping=mapping)
1399        return did,''
1400    ###)
[1620]1401
[2234]1402    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
[2193]1403    def mass_edit_department(self,mapping):
1404        "create a department in the correct faculty"
1405        logger = logging.getLogger('WAeUPTool.mass_create_department')
1406        academics_folder = self.portal_url.getPortalObject().campus.academics
1407        fid = mapping['faculty_code']
1408        did = mapping.get('code')
1409        try:
1410            d = getattr(getattr(academics_folder,fid),did,None)
1411        except KeyError:
1412            return '', "Department %s or Faculty %s wrong" % (did,fid)
1413        else:
1414            if d is None or d.portal_type == "Faculty":
[2267]1415                logger.info('Editing Department %(code)s, %(title)s' % mapping)
[2193]1416            d.getContent().edit(mapping=mapping)
1417        return did,''
1418    ###)
[1786]1419
[2265]1420    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1421    def mass_create_course(self,mapping):
[2315]1422        #import pdb;pdb.set_trace()
[2265]1423        if getattr(self,'_v_course_list',None) is None:
1424            self._v_course_list = []
1425        if getattr(self,'_v_departments',None) is None:
1426            res = self.portal_catalog(portal_type = "Department")
[2313]1427            self._v_department_courses = {}
[2265]1428            for d in res:
[2313]1429                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
[2265]1430        did = mapping['department_code']
[2313]1431        d = self._v_department_courses.get(did,None)
[2265]1432        if d is None:
[2282]1433            return '', "No Department with ID: %s" % did
[2265]1434        course_id = mapping.get('code')
1435        if course_id in self._v_course_list:
[2313]1436            return '', "Duplicate Course ID: %s" % did
[2265]1437        c = getattr(d,course_id,None)
1438        if c is not None:
[2313]1439            return '', "Duplicate Course ID: %s" % did
[2283]1440        try:
1441            d.invokeFactory('Course', course_id)
1442        except BadRequest,E:
1443            return '', "%s" % E
[2265]1444        self._v_course_list.append(course_id)
1445        c = getattr(d,course_id)
1446        c.getContent().edit(mapping=mapping)
1447        return course_id,''
1448    ###)
1449
[2282]1450    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1451    def mass_edit_course(self,mapping):
1452        #import pdb;pdb.set_trace()
1453        course_id = mapping.get('code')
1454        res = self.portal_catalog(id=course_id)
1455        if not res:
[2289]1456            return '', "No Course with ID: %s" % course_id
[2282]1457        c = res[0].getObject()
1458        c.getContent().edit(mapping=mapping)
1459        return course_id,''
1460    ###)
1461
1462    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1463    def mass_create_certificate(self,mapping):
1464        if getattr(self,'_v_certificate_list',None) is None:
1465            self._v_certificate_list = []
[2313]1466        if getattr(self,'_v_department_certificates',None) is None:
[2282]1467            res = self.portal_catalog(portal_type = "Department")
[2313]1468            self._v_department_certificates = {}
[2282]1469            for d in res:
[2313]1470                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
[2282]1471        did = mapping['department_code']
[2313]1472        d = self._v_department_certificates.get(did,None)
[2282]1473        if d is None:
1474            return '', "No Department with ID: %s" % did
1475        certificate_id = mapping.get('code')
1476        if certificate_id in self._v_certificate_list:
[2313]1477            return '', "Duplicate Certificate ID: %s" % did
[2282]1478        c = getattr(d,certificate_id,None)
1479        if c is not None:
[2313]1480            return '', "Duplicate Certificate ID: %s" % did
[2283]1481        try:
1482            d.invokeFactory('Certificate', certificate_id)
1483        except BadRequest,E:
1484            return '', "%s" % E
[2282]1485        self._v_certificate_list.append(certificate_id)
1486        c = getattr(d,certificate_id)
1487        c.getContent().edit(mapping=mapping)
1488        return certificate_id,''
1489    ###)
1490
1491    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1492    def mass_edit_certificate(self,mapping):
1493        #import pdb;pdb.set_trace()
1494        certificate_id = mapping.get('code')
1495        res = self.portal_catalog(id=certificate_id)
1496        if not res:
[3042]1497            return '', "No Certificate with ID: %s" % certificate_id
[2282]1498        c = res[0].getObject()
1499        c.getContent().edit(mapping=mapping)
1500        return certificate_id,''
1501    ###)
1502
[2520]1503    security.declareProtected(ModifyPortalContent,'mass_create_application') ###(
1504    def mass_create_application(self,mapping):
[2514]1505        #import pdb;pdb.set_trace()
[2547]1506        reg_no = mapping.get('reg_no')
[2514]1507        try:
1508            self.applicants_catalog.addRecord(**mapping)
1509        except ValueError:
[2548]1510            return '', "applicant record with reg_no %s already exists" % reg_no
[2546]1511        return reg_no,''
[2514]1512    ###)
1513
[2520]1514    security.declareProtected(ModifyPortalContent,'mass_edit_application') ###(
1515    def mass_edit_application(self,mapping):
[2514]1516        #import pdb;pdb.set_trace()
1517        reg_no = mapping.get('reg_no')
[2731]1518        status = mapping.get('status')
[2699]1519        res = self.applicants_catalog(reg_no = reg_no)
1520        if len(res):
[2731]1521            if res[0].status == 'created' and status != 'created':
1522                return '', "student object with id %s for %s already created, status cannot be changed" % (res[0].student_id, reg_no)
1523            elif status == 'created' and res[0].status != 'created':
1524                return '', "student object for %s has not yet been created, status cannot be set to 'created'" % (reg_no)
[2699]1525            else:
1526                self.applicants_catalog.modifyRecord(**mapping)
1527                return reg_no,''
1528        else:
[2548]1529            return '', "applicant record with reg_no %s does not exist" % reg_no
[2701]1530
[2514]1531    ###)
1532
[2501]1533    security.declareProtected(ModifyPortalContent,'mass_create_course_result') ###(
1534    def mass_create_course_result(self,mapping):
[2500]1535        #import pdb;pdb.set_trace()
[2747]1536        students_folder = self.portal_url.getPortalObject().campus.students
[2501]1537        if getattr(self,'_v_courses',None) is None:
1538            res = self.courses_catalog()
1539            self._v_courses = {}
1540            for brain in res:
[2520]1541                self._v_courses[brain.code] = brain
[2747]1542        if getattr(self,'_v_level_created',None) is None:
1543            self._v_level_created = []
[2500]1544        course_id = mapping.get('code')
[2501]1545        if course_id not in self._v_courses.keys():
[2754]1546            return '', "No course with ID: %s" % course_id
[2773]1547        id_key = ''
1548        for id_key in ('student_id','matric_no'):
1549            id_field = mapping.get(id_key,None)
1550            if id_field is not None:
1551                student_id = id_field
1552                break
1553        query = Eq(id_key,id_field)
1554        res = self.students_catalog.evalAdvancedQuery(query)
1555        if not res:
[2750]1556            return '', "no student with %(id_key)s %(id_field)s" % vars()
[2773]1557        student_rec = res[0]
[2776]1558        if id_field != "student_id":
1559            mapping['student_id'] = student_rec.id
[2766]1560        student_id = student_rec.id
1561        level_id = mapping['level_id']
1562        code = mapping['code']
[2774]1563        if student_id not in self._v_level_created:
[2747]1564            try:
1565                context = getattr(getattr(students_folder,
[2766]1566                                          "%(student_id)s" % vars()),
[2747]1567                                  'study_course')
1568            except:
[2766]1569                return '', "could not create level %(level_id)s for %(student_id)s" % vars()
1570            if level_id not in context.objectIds():
1571                context.invokeFactory('StudentStudyLevel',"%(level_id)s" % vars())
1572                level = getattr(context,"%(level_id)s" % vars())
[2747]1573                self.portal_workflow.doActionFor(level,'open')
[2754]1574                # the session string must not be copied into the level object
[2775]1575                current_verdict = getattr(student_rec,'current_verdict','')
1576                current_session = getattr(student_rec,'current_session','')
1577                if current_verdict and student_rec.current_level == level_id:
[2771]1578                    level.getContent().edit(mapping={'verdict': "%s" %
[2775]1579                                                     current_verdict,
[2771]1580                                                     'session': "%s" %
[2775]1581                                                     current_session,
[2766]1582                                                    })
1583                    self.portal_workflow.doActionFor(level,'close')
1584            self._v_level_created += student_id,
1585        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
[2746]1586        for k in ('semester','credits',):
[2501]1587            mapping[k] = getattr(self._v_courses[course_id],k)
[2500]1588        try:
[2501]1589            self.course_results.addRecord(**mapping)
1590        except ValueError:
1591            return '', "course result already exists: %s" % key
1592        return key,''
[2500]1593    ###)
1594
1595    security.declareProtected(ModifyPortalContent,'mass_edit_course_result') ###(
1596    def mass_edit_course_result(self,mapping):
[2776]1597        id_key = ''
1598        for id_key in ('student_id','matric_no'):
1599            id_field = mapping.get(id_key,None)
1600            if id_field is not None:
1601                student_id = id_field
1602                break
1603        query = Eq(id_key,id_field)
1604        res = self.students_catalog.evalAdvancedQuery(query)
1605        if not res:
[3053]1606            return '', "No student with %(id_key)s %(id_field)s" % vars()
[2776]1607        if id_field != "student_id":
1608            mapping['student_id'] = res[0].id
1609        if not res:
[3053]1610            return '', "No student with %(id_key)s %(id_field)s" % vars()
[2776]1611        student_rec = res[0]
[2766]1612        student_id = student_rec.id
1613        level_id = mapping['level_id']
1614        code = mapping['code']
1615        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
[2500]1616        try:
1617            self.course_results.modifyRecord(**mapping)
1618        except KeyError:
1619            return '', "No course result to edit: %s" % key
1620        return key,''
1621    ###)
1622
[3057]1623    security.declareProtected(ModifyPortalContent,'mass_delete_course_result') ###(
1624    def mass_delete_course_result(self,mapping):
1625        id_key = ''
1626        for id_key in ('student_id','matric_no'):
1627            id_field = mapping.get(id_key,None)
1628            if id_field is not None:
1629                student_id = id_field
1630                break
1631        query = Eq(id_key,id_field)
1632        res = self.students_catalog.evalAdvancedQuery(query)
1633        if not res:
1634            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1635        if id_field != "student_id":
1636            mapping['student_id'] = res[0].id
1637        if not res:
1638            return '', "no student with %(id_key)s %(id_field)s" % vars()
1639        student_rec = res[0]
1640        student_id = student_rec.id
1641        level_id = mapping['level_id']
1642        code = mapping['code']
1643        key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
1644        # for k in ('semester',):
1645        #     mapping[k] = getattr(self._v_courses[course_id],k)
1646        if self.course_results.getRecordByKey(key) is None:
1647            return '', "no course-result with %(key)s" % vars()
1648        self.course_results.deleteRecord(key)
1649        return key,''
1650    ###)
1651
[2282]1652    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1653    def mass_create_certificate_course(self,mapping):
[2320]1654        if getattr(self,'_v_courses',None) is None:
1655            res = self.courses_catalog()
[2351]1656            self._v_courses= [course.code for course in res]
[2282]1657        if getattr(self,'_v_ceritficates',None) is None:
1658            res = self.portal_catalog(portal_type = "Certificate")
1659            self._v_certificates = {}
1660            for cert in res:
1661                self._v_certificates[cert.getId] = cert.getObject()
[2284]1662        certificate_course_id = mapping.get('code')
[2351]1663        if certificate_course_id not in self._v_courses:
[2284]1664            return '', "No Course with ID: %s" % certificate_course_id
[2282]1665        cert_id = mapping['certificate_code']
1666        cert = self._v_certificates.get(cert_id,None)
1667        if cert is None:
[2284]1668            return '', "No Certificate with ID: %s" % cert_id
[2282]1669        level_id = mapping.get('level')
1670        level = getattr(cert,level_id,None)
1671        if level is None:
1672            cert.invokeFactory('StudyLevel', level_id)
1673            level = getattr(cert,level_id,None)
1674        elif hasattr(level,certificate_course_id):
1675            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1676            (certificate_course_id,cert_id,level_id)
1677        level.invokeFactory('CertificateCourse', certificate_course_id)
1678        c = getattr(level,certificate_course_id)
1679        c.getContent().edit(mapping=mapping)
1680        return certificate_course_id,''
1681    ###)
1682
[2193]1683    field2types_student = {   ###(
[1756]1684                      'StudentApplication':
1685                          {'id': 'application',
1686                           'title': 'Application Data',
[1991]1687                           'wf_transition_return': 'close',
1688                           'wf_transition_admit': 'remain',
[1756]1689                           'fields':
1690                             ('jamb_reg_no',
1691                              'entry_mode',
1692                              'entry_session',
1693                              'jamb_score',
[1786]1694                              'app_email',
[2008]1695                              'jamb_age',
[2428]1696                              'jamb_state',
1697                              'jamb_lga',
[3003]1698                              'jamb_sex',
[1756]1699                              )
1700                              },
[1786]1701                      #'StudentPume':
1702                      #    {'id': 'pume',
1703                      #     'title': 'Pume Data',
[1991]1704                      #     'wf_transition_return': 'close',
1705                      #     'wf_transition_admit': 'close',
[1786]1706                      #     'fields':
1707                      #       ('pume_score',
1708                      #        )
1709                      #        },
[1756]1710                      'StudentClearance':
1711                          {'id': 'clearance',
[2009]1712                           'title': 'Clearance/Eligibility Record',
[1991]1713                           'wf_transition_return': 'close',
1714                           'wf_transition_admit': 'remain',
[1756]1715                           'fields':
1716                             ('matric_no',
1717                              'nationality',
1718                              'lga',
[1804]1719                              'birthday',
[1756]1720                              )
1721                              },
1722                         'StudentPersonal':
1723                          {'id': 'personal',
1724                           'title': 'Personal Data',
[1991]1725                           'wf_transition_return': 'open',
1726                           'wf_transition_admit': 'remain',
[1756]1727                           'fields':
1728                             ('firstname',
1729                              'middlename',
1730                              'lastname',
1731                              'sex',
1732                              'email',
1733                              'phone',
1734                              'perm_address',
1735                              )
1736                              },
1737                         'StudentStudyCourse':
1738                          {'id': 'study_course',
1739                           'title': 'Study Course',
[1991]1740                           'wf_transition_return': 'open',
1741                           'wf_transition_admit': 'remain',
[1756]1742                           'fields':
1743                             ('study_course',
1744                              'current_level',
1745                              'current_session',
1746                              'current_mode',
1747                              'current_verdict',
[2478]1748                              'previous_verdict',
[1756]1749                              )
1750                              },
[2846]1751                         # 'StudentStudyLevel':
1752                         #  {'id': 'current_level',
1753                         #   'title': '',
1754                         #   'wf_transition_return': 'open',
1755                         #   'wf_transition_admit': 'remain',
1756                         #   'fields':
1757                         #     ('verdict',
1758                         #      'session',
1759                         #      )
1760                         #      },
[1898]1761                         'PaymentsFolder':
1762                          {'id': 'payments',
1763                           'title': 'Payments',
[1991]1764                           'wf_transition_return': 'open',
1765                           'wf_transition_admit': 'open',
[1898]1766                           'fields':
1767                             ()
1768                              },
[1756]1769                         }
1770    ###)
1771
[2193]1772    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1773    def mass_create_student(self,mapping):
[3039]1774        "create student records due import"
[2193]1775        logger = logging.getLogger('WAeUPTool.mass_create_student')
[1747]1776        students_folder = self.portal_url.getPortalObject().campus.students
[1818]1777        jamb_reg_no = mapping.get('jamb_reg_no',None)
[1747]1778        if jamb_reg_no:
1779            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1780            if res:
[1749]1781                return '',"jamb_reg_no exists"
[1818]1782        matric_no = mapping.get('matric_no',None)
[1747]1783        if matric_no:
1784            res = self.students_catalog(matric_no = matric_no)
1785            if res:
[1749]1786                return '',"matric_no exists"
[1747]1787        sid = self.waeup_tool.generateStudentId('?')
1788        students_folder.invokeFactory('Student', sid)
1789        student_obj = getattr(students_folder,sid)
[2193]1790        f2t = self.field2types_student
[1772]1791        d = {}
[1990]1792        transition = mapping.get('reg_transition','admit')
1793        if transition not in ('admit','return'):
[2008]1794            return '',"no valid transition provided"
[1747]1795        for pt in f2t.keys():
1796            student_obj.invokeFactory(pt,f2t[pt]['id'])
1797            sub_obj = getattr(student_obj,f2t[pt]['id'])
1798            sub_doc = sub_obj.getContent()
[1772]1799            d['Title'] = f2t[pt]['title']
[1747]1800            for field in f2t[pt]['fields']:
[2702]1801                d[field] = mapping.get(field,'')
[2454]1802
1803            if pt == "StudentApplication":
[3002]1804                #d['jamb_sex']  = 'M'
1805                #if mapping.get('sex'):
1806                #    d['jamb_sex']  = 'F'
[2436]1807                d['jamb_firstname'] = mapping.get('firstname',None)
1808                d['jamb_middlename'] = mapping.get('middlename',None)
1809                d['jamb_lastname'] = mapping.get('lastname',None)
1810
[2433]1811            # if pt == "StudyCourse":
1812            #     for von,zu in (('entry_mode','current_mode'),
1813            #                    ('entry_session','current_session')):
1814            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1815            #             d[zu] = mapping[von]
[1747]1816            sub_doc.edit(mapping = d)
[1990]1817
[1987]1818            #import pdb;pdb.set_trace()
1819            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
[1898]1820            if new_state != "remain":
1821                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
[1990]1822        self.portal_workflow.doActionFor(student_obj,transition)
[1747]1823        student_obj.manage_setLocalRoles(sid, ['Owner',])
1824        return sid,''
1825    ###)
1826
[2193]1827    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1828    def mass_edit_student(self,mapping):
[2754]1829        wftool = self.portal_workflow
[3039]1830        "edit student records due import"
[2193]1831        logger = logging.getLogger('WAeUPTool.mass_edit_student')
[1774]1832        students_folder = self.portal_url.getPortalObject().campus.students
[1818]1833        sid = mapping.get('id',None)
1834        jamb_reg_no = mapping.get('jamb_reg_no',None)
1835        matric_no = mapping.get('matric_no',None)
[1875]1836        editable_keys = mapping.keys()
[1774]1837        if sid:
1838            res = self.students_catalog(id = sid)
1839            if not res:
1840                return '',"no student with id %s" % sid
[2268]1841            if matric_no and res[0].matric_no and\
[1774]1842              matric_no != res[0].matric_no:
[2268]1843                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1844            if jamb_reg_no and res[0].jamb_reg_no and\
[1774]1845              jamb_reg_no != res[0].jamb_reg_no:
[2268]1846                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
[1844]1847        elif jamb_reg_no:
1848            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1849            if not res:
1850                return '',"no student with jamb_reg_no %s" % jamb_reg_no
[1875]1851            editable_keys.remove('jamb_reg_no')
[1774]1852        elif matric_no:
1853            res = self.students_catalog(matric_no = matric_no)
1854            if not res:
1855                return '',"no student with matric_no %s" % matric_no
[1875]1856            editable_keys.remove('matric_no')
[1965]1857
[2268]1858        ## included only to change wf state from admitted to returning
1859        #if res[0].review_state not in ('admitted','objection_raised'):
1860        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1861        ## end inclusion
[1965]1862
[1774]1863        sid = res[0].id
1864        student_obj = getattr(students_folder,sid)
[2193]1865        f2t = self.field2types_student
[1774]1866        d = {}
[2265]1867        #import pdb;pdb.set_trace()
[1875]1868        any_change = False
[2846]1869        #special treatment for StudentStudyLevel
1870        d['verdict']  = mapping.get('current_verdict','')
1871        d['session']  = mapping.get('current_session','')
1872        current_level = mapping.get('current_level','')
1873        while d['session'] and d['verdict'] and current_level:
1874            sub_obj = getattr(student_obj,'study_course',None)
1875            if sub_obj is None:
1876                break
1877            level_obj = getattr(sub_obj,current_level,None)
1878            if  level_obj is None:
1879                break
1880            any_change = True
1881            level_obj.getContent().edit(mapping = d)
1882            try:
1883                wftool.doActionFor(level_obj,'close')
1884            except:
1885                pass
1886            break
[1774]1887        for pt in f2t.keys():
[3002]1888            #if pt == "StudentApplication":
1889            #    d['jamb_sex']  = 'M'
1890            #    if mapping.get('sex'):
1891            #        d['jamb_sex']  = 'F'
[1875]1892            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
[2753]1893            if intersect and pt not in ('StudentStudyLevel',):
1894                object_id = f2t[pt]['id']
1895                sub_obj = getattr(student_obj,object_id,None)
[1875]1896                if sub_obj is None:
1897                    try:
[2753]1898                        student_obj.invokeFactory(pt,object_id)
[1875]1899                    except:
1900                        continue
[2753]1901                    sub_obj = getattr(student_obj,object_id)
1902                    if f2t[pt]['title'] != '':
1903                        d['Title'] = f2t[pt]['title']
[1875]1904                sub_doc = sub_obj.getContent()
1905                for field in intersect:
1906                    changed = False
[2478]1907                    if getattr(sub_doc,field,None) != mapping.get(field,''):
[1875]1908                        any_change = True
1909                        changed = True
1910                        d[field] = mapping.get(field,'')
1911                    if changed:
1912                        sub_doc.edit(mapping = d)
[1904]1913
[1905]1914
[2268]1915        ## included only to change wf state from admitted to returning
1916        #    if res[0].review_state in ('admitted','objection_raised'):
1917        #        new_state = f2t[pt]['wf_transition_return']
1918        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1919        #        if sub_obj and new_state != "remain":
1920        #            try:
1921        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1922        #            except:
1923        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1924        #                pass
1925        #if res[0].review_state in ('admitted','objection_raised'):
1926        #    wfaction = 'return'
1927        #    try:
1928        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1929        #        logger.info('%s, wf state changed' % sid)
1930        #        any_change = True
1931        #    except:
1932        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1933        #        pass
1934        ## end inclusion
[1904]1935
[1905]1936
[1875]1937        if any_change:
1938            return sid,''
1939        else:
1940            return sid,'not modified'
[1774]1941    ###)
[1905]1942
[3033]1943    security.declareProtected(ModifyPortalContent,'mass_edit_verdict') ###(
1944    def mass_edit_verdict(self,mapping):
1945        wftool = self.portal_workflow
[3039]1946        "edit student verdicts"
[3033]1947        logger = logging.getLogger('WAeUPTool.mass_edit_verdict')
1948        students_folder = self.portal_url.getPortalObject().campus.students
1949        student_id = mapping.get('id',None)
1950        matric_no = mapping.get('matric_no',None)
1951        editable_keys = mapping.keys()
1952        if student_id:
[3094]1953            student_record = self.students_catalog.getRecordByKey(student_id)
[3033]1954            if student_record is None:
1955                return '',"no student with id %s" % student_id
1956            if matric_no and student_record.matric_no and\
1957              matric_no != student_record.matric_no:
[3053]1958                return '', 'student %s: matric_no %s does not match %s' % (student_record.id,
[3036]1959                                                                          student_record.matric_no,
1960                                                                          matric_no)
[3033]1961        elif matric_no:
1962            res = self.students_catalog(matric_no = matric_no)
1963            if not res:
1964                return '',"no student with matric_no %s" % matric_no
1965            student_record = res[0]
1966            editable_keys.remove('matric_no')
[3095]1967        else:
1968            return '',"no id or matric_no specified"
[3033]1969        student_id = student_record.id
1970        student_review_state =  student_record.review_state
[3036]1971        if student_review_state not in ('courses_validated','returning'):
[3033]1972            return '',"student %s in wrong review_state %s" % (student_id, student_review_state)
1973        student_obj = getattr(students_folder,student_id)
1974        f2t = self.field2types_student
1975        d = {}
1976        #import pdb;pdb.set_trace()
1977        any_change = False
1978        #special treatment for StudentStudyLevel
[3064]1979        current_session = d['session'] = mapping.get('current_session','')
[3033]1980        if current_session and student_record.session != current_session:
[3053]1981            return '','student %s: imported session %s does not match current_session %s' % (student_id,
[3033]1982                                                                                        current_session,
1983                                                                                        student_record.session)
1984        current_level = mapping.get('current_level','')
1985        if current_level and student_record.level != current_level:
[3053]1986            return '','student %s: imported level %s does not match current_level %s' % (student_id,
[3033]1987                                                                                    current_level,
1988                                                                                    student_record.level)
[3036]1989        study_course_obj = getattr(student_obj,'study_course',None)
1990        if study_course_obj is None:
[3053]1991            return '','student %s: no study_course object' % student_id
[3036]1992        level_obj = getattr(study_course_obj,current_level,None)
[3033]1993        if  level_obj is None:
[3053]1994            return '','student %s: no study_level object for level %s' % (student_id,
[3033]1995                                                                             current_level)
[3036]1996        verdict = d['verdict'] = d['current_verdict']  = mapping.get('current_verdict','')
[3071]1997
[3064]1998        #if verdict == student_record.verdict:
1999        #    return '','student %s: verdict already set to %s' % (student_id,
2000        #                                                            verdict)
[3039]2001
[3033]2002        level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
2003        if level_review_state != "closed":
[3063]2004            wftool.doActionFor(level_obj,'close')
2005            # return '','student %s: level %s is not closed' % (student_id,
2006            #                                                      current_level)
[3039]2007
[3036]2008        study_course_obj.getContent().edit(mapping = d)
[3033]2009        level_obj.getContent().edit(mapping = d)
[3036]2010        if student_review_state != "returning":
2011            wftool.doActionFor(student_obj,'return')
[3063]2012        # try:
2013        #     wftool.doActionFor(level_obj,'close')
2014        # except:
2015        #     pass
[3033]2016        return student_id,''
2017    ###)
2018
[1730]2019    security.declareProtected(ModifyPortalContent,"importData")###(
[2259]2020    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
[1730]2021        """load data from CSV values"""
2022        import transaction
2023        import random
[1775]2024
[1773]2025        pm = self.portal_membership
[1775]2026        member = pm.getAuthenticatedMember()
2027
[1747]2028        logger = logging.getLogger('WAeUPTool.importData')
[1730]2029        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
2030        students_folder = self.portal_url.getPortalObject().campus.students
2031        start = True
[2495]2032        tr_count = 0
[1756]2033        total_imported = 0
2034        total_not_imported = 0
[1730]2035        total = 0
[1749]2036        iname = "import_%s" % name
[2754]2037        if iname in ('import_application','import_course_result',):
[2528]2038            commit_after = 2000
2039        else:
2040            commit_after = 100
[1747]2041        stool = getToolByName(self, 'portal_schemas')
2042        ltool = getToolByName(self, 'portal_layouts')
2043        schema = stool._getOb(iname)
[1730]2044        if schema is None:
[1772]2045            em = 'No such schema %s' % iname
2046            logger.error('No such schema %s' % iname)
[1756]2047            return em
[1747]2048        layout = ltool._getOb(iname)
[1730]2049        if layout is None:
[1772]2050            em = 'No such layout %s' % iname
[1756]2051            logger.error(em)
2052            return em
[1730]2053        validators = {}
2054        for widget in layout.keys():
[1749]2055            validators[widget] = layout[widget].validate
[2289]2056        mode = "create"
[1774]2057        if edit:
[3057]2058            if filename.endswith('_toDelete'):
2059                mode = "delete"
2060            else:
2061                mode = "edit"
[2289]2062        importer_name = "mass_%(mode)s_%(name)s" % vars()
[1772]2063        importer = getattr(self, '%s' % importer_name,None)
2064        if importer is None:
2065            em = 'No importer function %s' % importer_name
[1756]2066            logger.error(em)
2067            return em
[1747]2068        not_imported = []
[1730]2069        imported = []
2070        try:
[1747]2071            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
[1730]2072        except:
[1756]2073            em = 'Error reading %s.csv' % filename
2074            logger.error(em)
2075            return em
[1730]2076        for item in items:
[2704]2077            #import pdb;pdb.set_trace()
[3094]2078            item = dict((k.strip(),l.strip()) for (k,l) in item.items())
[1730]2079            if start:
2080                start = False
[1747]2081                adapters = [MappingStorageAdapter(schema, item)]
[2315]2082                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
[2094]2083                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
[3033]2084                import_keys = [k.strip() for k in attrs if not k.strip().startswith('ignore')]
[1804]2085                diff2schema = set(import_keys).difference(set(schema.keys()))
2086                diff2layout = set(import_keys).difference(set(layout.keys()))
2087                if diff2schema:
[2282]2088                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
[1804]2089                    return em
[2433]2090                if mode == "create":
[2436]2091                    required_keys = [layout.getIdUnprefixed(id)
[2433]2092                                     for id,widget in layout.objectItems()
2093                                     if widget.is_required]
2094                    if not set(required_keys).issubset(set(import_keys)):
2095                        diff2import = set(required_keys).difference(set(import_keys))
2096                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
2097                        return em
[1753]2098                s = ','.join(['"%s"' % fn for fn in import_keys])
[1772]2099                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
2100                s = '"id",' + s
[1756]2101                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
[1730]2102                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
2103                format_error = format + ',"%(Error)s"'
[1756]2104                format = '"%(id)s",'+ format
[2267]2105
[2094]2106            dm = DataModel(item, adapters,context=self)
[1747]2107            ds = DataStructure(data=item,datamodel=dm)
2108            error_string = ""
[2495]2109            total += 1
[2704]2110            error_count = 0
[1730]2111            for k in import_keys:
[2289]2112                if not validators[k](ds,mode=mode):
[2704]2113                    if error_count:
[2710]2114                        error_string += ' ++ '
[2704]2115                    error_string += "%s: %s" % (k,
[2264]2116                                                  self.translation_service(ds.getError(k),
2117                                                                           ds.getErrorMapping(k)))
[2704]2118                    error_count += 1
[1747]2119            if not error_string:
[2433]2120                temp_item = item.copy()
2121                temp_item.update(dm)
[2435]2122                temp_item['id'],error = importer(temp_item)
[1747]2123                if error:
2124                    error_string += error
[2433]2125                else:
2126                    item = temp_item
[2436]2127            if error_string:
[1747]2128                item['Error'] = error_string
2129                not_imported.append(format_error % item)
[1756]2130                total_not_imported += 1
[1747]2131            else:
[1821]2132                em = format % item
2133                imported.append(em)
[1875]2134                tr_count += 1
[1756]2135                total_imported += 1
[3071]2136                logger.info("%(total_imported)d of %(total)d imported in %(mode)s mode, %(em)s" % vars())
[2520]2137
[2528]2138            if total and not total % commit_after:
[1875]2139                transaction.commit()
[1747]2140                if len(not_imported) > 0:
2141                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
2142                             '\n'.join(not_imported) + '\n')
2143                    not_imported = []
2144                if len(imported) > 0:
2145                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
[1772]2146                             '\n'.join(imported) + '\n')
[1747]2147                    imported = []
[1730]2148                em = '%d transactions committed\n' % (tr_count)
2149                regs = []
2150                logger.info(em)
2151                tr_count = 0
[2528]2152                #if total > 100:
2153                #    return
[1756]2154        if len(imported) > 0:
[1747]2155            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
2156                                                '\n'.join(imported))
[1756]2157        if len(not_imported) > 0:
[1747]2158            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
2159                                                '\n'.join(not_imported))
[3071]2160        #if mode.endswith('e'):
2161        #    mode = mode[:-1]
2162        em = "Finished importing in %(mode)s mode from %(filename)s.csv: %(total_imported)d imported, %(total_not_imported)d not imported (of total %(total)d)" % vars()
[2495]2163        logger.info(em)
[1756]2164        return em
[1730]2165    ###)
2166
[2292]2167    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
2168    def moveImagesToFS(self,student_id="O738726"):
2169        "move the images to the filesystem"
[2675]2170        images_dir = getImagesDir(student_id)
2171        #images_dir = os.path.join("%s" % images_base,student_id)
[2292]2172        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
2173        stool = getToolByName(self, 'portal_schemas')
2174        schemas = ['student_application',
2175                   'student_clearance',
2176                   ]
2177        created = False
2178        for schema_id in schemas:
2179            schema = stool._getOb(schema_id)
2180            object = getattr(student_folder,schema_id[len('student_'):],None)
2181            if object is None:
2182                continue
2183            doc = object.getContent()
2184            for key in schema.keys():
2185                if schema[key].meta_type != "CPS Image Field":
2186                    continue
2187                #import pdb;pdb.set_trace()
[2351]2188                image = getattr(doc,key,None)
2189                if not image or not hasattr(image,"data"):
[2292]2190                    continue
2191                if not created:
2192                    if not os.path.exists(images_dir):
2193                        os.mkdir(images_dir)
2194                    created = True
2195                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
2196                open(filename,"wb").write(str(image.data))
[2500]2197    ###)
[2292]2198
[2300]2199    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
2200    def movePassportToFS(self,student_id="O738726"):
2201        "move the passports to the filesystem"
2202        images_dir = os.path.join("%s" % i_home,'passports')
2203        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
2204        stool = getToolByName(self, 'portal_schemas')
2205        schemas = ['student_application',
2206                   #'student_clearance',
2207                   ]
2208        created = False
2209        for schema_id in schemas:
2210            schema = stool._getOb(schema_id)
2211            object = getattr(student_folder,schema_id[len('student_'):],None)
2212            if object is None:
2213                continue
2214            doc = object.getContent()
2215            for key in schema.keys():
2216                if schema[key].meta_type != "CPS Image Field":
2217                    continue
2218                #import pdb;pdb.set_trace()
2219                image = getattr(doc,key)
2220                if not hasattr(image,"data"):
2221                    continue
2222                if not created:
2223                    if not os.path.exists(images_dir):
2224                        os.mkdir(images_dir)
2225                    created = True
2226                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
2227                open(filename,"wb").write(str(image.data))
[2500]2228    ###)
[2300]2229
[828]2230InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.