source: WAeUP_SRP/base/WAeUPTool.py @ 3131

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

fix

  • Property svn:keywords set to Id
File size: 93.1 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 3114 2008-02-05 22:40:23Z henrik $
[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)
[3114]785        if not getattr(student_obj,'application'):
786            student_obj.invokeFactory('StudentApplication','application')
[1151]787        application = student_obj.application
[1169]788        self.portal_workflow.doActionFor(application,'open',dest_container=application)
[1151]789        da = {'Title': 'Application Data'}
790        student_obj.invokeFactory('StudentPersonal','personal')
791        da['jamb_reg_no'] = student.Entryregno
[1462]792        em = self.getEntryMode(student.Entryregno)
[1401]793        da['entry_mode'] = em
[1151]794        personal = student_obj.personal
795        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
796        dp = {'Title': 'Personal Data'}
797        student_obj.invokeFactory('StudentClearance','clearance')
798        clearance = student_obj.clearance
[1169]799        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
[1151]800        dc = {'Title': 'Clearance/Eligibility Record'}
801        dc['matric_no'] = matric_no
802        state = student.State
803        lga = student.LGA
804        if state and lga:
805            lga =  state + ' / ' + lga
806        else:
807            lga = "None"
[1174]808        da['jamb_lga'] = dc['lga'] = lga
[1173]809        da['app_email'] = dp['email'] = email
810        da['app_mobile'] = dp['phone'] = phone_nr
[1411]811        dp['firstname'] = student.Firstname
812        dp['middlename'] = student.Middlename
813        dp['lastname'] = student.Lastname
814        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
[1174]815        da['jamb_sex'] = student.Sex
[1151]816        dp['sex'] = student.Sex == 'F'
817        dp['perm_address'] = student.Permanent_Address
818        application.getContent().edit(mapping=da)
[1169]819        self.portal_workflow.doActionFor(application,'close',dest_container=application)
[1151]820        personal.getContent().edit(mapping=dp)
821        clearance.getContent().edit(mapping=dc)
[1169]822        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
[1151]823        #
824        # Study Course
825        #
826        student_obj.invokeFactory('StudentStudyCourse','study_course')
827        studycourse = student_obj.study_course
828        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
829        dsc = {}
830        dsc['study_course'] = certcode
[1401]831        dsc['current_level'] = level
832        dsc['current_verdict'] = verdict
[1827]833        dsc['current_mode'] = em
[2466]834        dsc['current_session'] = '05'
[1151]835        studycourse.getContent().edit(mapping=dsc)
836        #
837        # Level
838        #
[1198]839##        l = getattr(studycourse,level,None)
840##        if l is None:
841##            studycourse.invokeFactory('StudentStudyLevel', level)
842##            l = getattr(studycourse, level)
843##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
844##            l.getContent().edit(mapping={'Title': "Level %s" % level})
[1194]845###)
[1160]846
[2556]847    security.declareProtected(ModifyPortalContent,'admitOneStudent') ###(
[2576]848    def admitOneStudent(self,brain,entry_session,pin_password):
[2514]849        "create Datastructure for an admitted Student"
850        #import pdb;pdb.set_trace()
[2727]851        if not hasattr(self,"_v_certificates"):
852            self._v_certificates = [entry[0] for entry in self.getCertificatesVoc()]
[2514]853        students_folder = self.portal_url.getPortalObject().campus.students
[2716]854        logger = logging.getLogger('WAeUPTool.admitOneStudent')
[2514]855        if brain.status != "admitted":
856            logger.info('status of %s is %s' % (brain.reg_no,brain.status))
[2540]857            return
[2514]858        pin_parts = brain.pin.split('-')
[2755]859        if pin_parts and len(pin_parts) != 3:
[2695]860            logger.info('invalid pin %s for %s' % (brain.pin,brain.reg_no))
[2540]861            return
[2727]862        if brain.course_admitted not in self._v_certificates:
863            logger.info('certificate %s not found for %s' % (brain.course_admitted,brain.reg_no))
864            return
[2959]865        if brain.sex not in (True,False):
866            logger.info('sex of %s not available' % (brain.reg_no))
[3002]867            return
[2540]868        student_id = self.generateStudentId('?')
[2514]869        students_folder.invokeFactory('Student', student_id)
870        student_object = getattr(students_folder,student_id)
[2576]871        if pin_password:
872            password = pin_parts[2]
873            self.makeStudentMember(student_id,password = password)
[2540]874        student_object.manage_setLocalRoles(student_id, ['Owner',])
875        #logger.info("creating %s reg_no %s" % (student_id,brain.reg_no))
[2514]876        #
877        # application
878        #
[2540]879        student_object.invokeFactory('StudentApplication','application')
880        application = student_object.application
[2575]881        #self.portal_workflow.doActionFor(application,'open',dest_container=application)
[2514]882        da = {'Title': 'Application Data'}
883        da['jamb_reg_no'] = brain.reg_no
[2576]884
[2540]885        sex = 'M'
886        if brain.sex:
887            sex = 'F'
888        da['jamb_sex'] = sex
[2670]889        da['jamb_age'] = brain.jamb_age
[2575]890        #da['app_ac_pin'] = brain.pin
[2670]891        da['jamb_lga'] = brain.jamb_lga
892        da['jamb_state'] = brain.jamb_state
[2575]893        da['jamb_score'] = brain.aggregate
[2514]894        da['app_email'] = brain.email
[2540]895        da['app_mobile'] = brain.phone
[2575]896        if brain.entry_mode:
897            da['entry_mode'] = brain.entry_mode
898        elif brain.screening_type == 'pume':
899            da['entry_mode'] = 'ume_ft'
900        elif brain.screening_type == 'pde':
901            da['entry_mode'] = 'de_ft'
[2950]902        elif brain.screening_type == 'pce':
[2959]903            da['entry_mode'] = 'pce'
[2950]904        elif brain.screening_type == 'prence':
[2959]905            da['entry_mode'] = 'prence'
[2575]906        else:
[2921]907            da['entry_mode'] = ''
[2575]908        da['entry_session'] = entry_session
909        da['jamb_lastname'] = brain.lastname
910        da['jamb_middlename'] = brain.middlenames   # different field names!
[2670]911        da['jamb_firstname'] = brain.firstname
[2575]912        da['screening_application_date'] = brain.application_date
913        da['date_of_birth'] = brain.date_of_birth
914        da['jamb_first_cos'] = brain.course1
915        da['jamb_second_cos'] = brain.course2
916        da['course3'] = brain.course3
917        da['screening_type'] = brain.screening_type
918        da['screening_score'] = brain.screening_score
919        da['screening_date'] = brain.screening_date
920        da['hq_type'] = brain.hq_type
921        da['hq_grade'] = brain.hq_grade
922        da['aos'] = brain.aos
[2576]923
[2514]924        application.getContent().edit(mapping=da)
[2575]925        #self.portal_workflow.doActionFor(application,'close',dest_container=application)
[2514]926        #
927        # personal
928        #
[2540]929        student_object.invokeFactory('StudentPersonal','personal')
930        personal = student_object.personal
[2575]931        #self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
[2514]932        dp = {'Title': 'Personal Data'}
933        dp['sex'] = brain.sex
934        dp['email'] = brain.email
[2540]935        dp['phone'] = brain.phone
[2514]936        dp['lastname'] = brain.lastname
[2575]937        dp['middlename'] = brain.middlenames   # different field names!
[2576]938        dp['firstname'] = brain.firstname
[2514]939        personal.getContent().edit(mapping=dp)
940        #
941        # clearance
942        #
[2540]943        student_object.invokeFactory('StudentClearance','clearance')
944        clearance = student_object.clearance
[2575]945        #self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
[2514]946        dc = {'Title': 'Clearance/Eligibility Record'}
947        dc['lga'] = brain.lga
[2670]948        dc['birthday'] = brain.date_of_birth
[2514]949        clearance.getContent().edit(mapping=dc)
[2575]950        #self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
[2514]951        #
952        # study Course
953        #
[2540]954        student_object.invokeFactory('StudentStudyCourse','study_course')
955        studycourse = student_object.study_course
[2575]956        #self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
[2514]957        dsc = {}
958        dsc['study_course'] = brain.course_admitted
959        dsc['current_verdict'] = ''
[2575]960        dsc['current_mode'] = da['entry_mode']
961        if da['entry_mode'].startswith('de'):
962            dsc['current_level'] = '200'
[3040]963        elif da['entry_mode'].startswith('pre'):
964            dsc['current_level'] = '000'
[2575]965        else:
966            dsc['current_level'] = '100'
967        dsc['current_session'] = entry_session
[2514]968        studycourse.getContent().edit(mapping=dsc)
969        #
970        # payments folder
[2540]971        student_object.invokeFactory('PaymentsFolder','payments')
972        payments = getattr(student_object,'payments')
[2514]973        dpay = {}
974        dpay['Title'] = 'Payments'
975        payments.getContent().edit(mapping=dpay)
[2540]976        self.portal_workflow.doActionFor(payments,'open')
[2580]977        #
978        # passport foto
979        app_picture ="%s/import/images/%s/%s_passport.jpg" % (i_home,
980                                                              brain.screening_type,
981                                                              brain.reg_no)
[2675]982        images_dir = getImagesDir(student_id)
983        #images_dir = os.path.join("%s" % images_base,student_id)
984        letter_dir,student_dir = os.path.split(images_dir)
985        if not os.path.exists(letter_dir):
986            os.mkdir(letter_dir)
[2580]987        if not os.path.exists(images_dir):
988            os.mkdir(images_dir)
989        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
990        if os.path.exists(app_picture):
991            copy2(app_picture,image_name)
992        else:
993            logger.info('passport of %s/%s not found: %s' % (student_id,
994                                                             brain.reg_no,
995                                                             app_picture))
[2656]996
[2514]997        return student_id
998    ###)
999
[2556]1000    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
[1194]1001    def makeStudentLevel(self,student_id):
1002        "create the StudyLevel for a returning Student"
1003        #import pdb;pdb.set_trace()
[1571]1004        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
[1194]1005        students_folder = self.portal_url.getPortalObject().campus.students
1006        res = self.students_catalog(id=student_id)
1007        if res:
1008            st = res[0]
1009        course = st.course
1010        matric_no = st.matric_no
1011        level = st.level
1012        res = self.results_import(matric_no = matric_no)
1013        if res:
1014            results = res
[1571]1015        logger.info('%s creating Level %s' % (student_id,level))
[1194]1016        #
1017        # Level
1018        #
1019        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1020        studycourse = getattr(student_obj,"study_course",None)
1021        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
1022        l = getattr(studycourse,level,None)
1023        if l is None:
1024            studycourse.invokeFactory('StudentStudyLevel', level)
1025            l = getattr(studycourse, level)
1026            self.portal_workflow.doActionFor(l,'open',dest_container=l)
1027            l.getContent().edit(mapping={'Title': "Level %s" % level})
1028        ###)
1029
[2000]1030    security.declarePublic('getHallInfo') ###(
1031    def getHallInfo(self,bed):
1032        """return Hall Info"""
[828]1033        info = {}
1034        hall,block,room,letter = bed.split('_')
[1846]1035        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
[828]1036        if res and len(res) == 1:
1037            hall_brain = res[0]
1038            hall_doc = hall_brain.getObject().getContent()
1039        else:
1040            return info
1041        info['hall_title'] = hall_brain.Title
1042        info['maintenance_code'] = hall_doc.maintenance_code
[1846]1043        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
[828]1044        batch_doc = None
1045        for brain in res:
1046            if brain.id.startswith(info['maintenance_code']):
1047                batch_doc = brain.getObject().getContent()
1048                break
1049        if batch_doc is None:
[2913]1050            info['maintenance_fee'] = ''
[828]1051        else:
1052            info['maintenance_fee'] = batch_doc.cost
1053        return info
[1151]1054    ###)
[828]1055
[2396]1056    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
1057    def removePictureFolder(self,student_id):
1058        """remove picture_folder by renaming it"""
1059        path = 'images'
1060        picture_path = os.path.join(i_home,path,student_id)
1061        if not os.path.exists(picture_path):
1062            return False
1063        os.rename(picture_path,picture_path + "_removed")
1064        return True
1065    ###)
1066
1067    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
1068    def restorePictureFolder(self,student_id):
1069        """restore picture_folder by renaming it"""
1070        path = 'images'
1071        picture_path = os.path.join(i_home,path,student_id)
1072        if not os.path.exists(picture_path + "_removed"):
1073            return False
1074        os.rename(picture_path + "_removed",picture_path)
1075        return True
1076    ###)
1077
[2363]1078    security.declarePublic('picturesExist') ###(
[2420]1079    def picturesExist(self, ids,student_id=None):
[2363]1080        """check if pictures exist in the filesystem"""
[2420]1081        if student_id is None:
1082            student_id = self.getStudentId()
1083        if student_id is None:
1084            return False
[2675]1085        picture_path = getImagesDir(student_id)
1086        #picture_path = os.path.join(images_base,student_id)
[2363]1087        if not os.path.exists(picture_path):
1088            return False
1089        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1090        return set(ids).issubset(set(pictures))
1091    ###)
1092
[2364]1093    security.declarePublic('picturesList') ###(
1094    def picturesList(self):
1095        """check if pictures exist in the filesystem"""
1096        path = 'images'
1097        student_id = self.getStudentId()
[2677]1098        #picture_path = os.path.join(i_home,path,student_id)
1099        picture_path = getImagesDir(student_id)
[2364]1100        if not os.path.exists(picture_path):
1101            return []
1102        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1103    ###)
1104
[2114]1105    security.declarePublic('showFsPicture') ###(
1106    def showFsPicture(self,path):
1107        """return a picture from the filesystem"""
[2675]1108        #picture_path = os.path.join(i_home,path)
1109        picture_path = os.path.join(images_base,path)
[2335]1110        response = self.REQUEST.RESPONSE
[2342]1111        #import pdb;pdb.set_trace()
[2354]1112        registry = getToolByName(self, 'mimetypes_registry')
1113        mimetype = str(registry.lookupExtension(path.lower()) or
1114                    registry.lookupExtension('file.bin'))
[2114]1115        if os.path.exists(picture_path):
[2354]1116            response.setHeader('Content-type',mimetype)
[2114]1117            return open(picture_path).read()
[2335]1118        picture_path = os.path.join(i_home,'import',path)
1119        if os.path.exists(picture_path):
1120            return open(picture_path).read()
[2114]1121    ###)
1122
[1151]1123    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
1124    def deleteAllCourses(self,department="All"):
1125        ''' delete the courses'''
1126        pm = self.portal_membership
1127        member = pm.getAuthenticatedMember()
[1160]1128
[1151]1129        if str(member) not in ("henrik","joachim"):
1130            return "not possible"
1131        if department == "All":
1132            res = self.portal_catalog({'meta_type': 'Department'})
1133        if len(res) < 1:
1134            return "No Departments found"
[1160]1135
[1151]1136        deleted = []
1137        for dep in res:
1138            cf = dep.getObject().courses
1139            if cf:
1140                cf.manage_delObjects(ids=cf.objectIds())
1141                deleted.append("deleted Courses in %s" % dep.getId)
1142        return "\r".join(deleted)
[1160]1143    ###)
[1151]1144
[1572]1145    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
1146    def getLogfileLines(self,filename="event.log",numlines=20):
1147        """Get last NUMLINES lines of logfile FILENAME.
[1160]1148
[1572]1149        Return last lines' of a file in the instances logfile directory as
1150        a list. The number of returned lines equals `numlines' or less. If
1151        less than `numlines' lines are available, the whole file ist
1152        returned. If the file can not be opened or some other error
1153        occurs, empty list is returend.
1154        """
1155        result = []
1156        lines_hit = 0
1157
1158        # We only handle files in instances' log directory...
1159        logpath = os.path.join(i_home, "log")
1160        filename = str(os.path.abspath( os.path.join( logpath, filename )))
1161        if not filename.startswith( logpath ):
1162            # Attempt to access file outside log-dir...
1163            return []
1164
1165        try:
1166            fd = file( filename, "rb" )
1167        except IOError:
1168            return []
1169        if not fd:
1170            return []
1171
1172        if os.linesep == None:
1173            linesep = '\n'
1174        else:
1175            linesep = os.linesep
1176
1177        # Try to find 'numlines' times a lineseparator, searching from end
1178        # and moving to the beginning of file...
1179        fd.seek( 0, 2) # Move to end of file...
1180        while lines_hit < numlines:
1181            if fd.read(1) == linesep[-1]: # This moves filedescriptor
1182                                          # one step forward...
1183                lines_hit += 1
1184            try:
1185                fd.seek( -2, 1) # Go two bytes back from current pos...
1186            except IOError:
1187                # We cannot go back two bytes. Maybe the file is too small...
1188                break
1189        fd.seek(2,1)
1190
1191        # Read all lines from current position...
1192        result = fd.readlines()
1193        # Remove line endings...
1194        result = [x.strip() for x in result]
1195        fd.close()
1196        return result
1197    ###)
1198
[1700]1199    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
[1665]1200    def getCallbacksFromLog(self,filename):
1201        """fix Online Payment Transactions from Z2.log entries"""
1202        import transaction
1203        import random
1204        from cgi import parse_qs
1205        from urlparse import urlparse
1206        #from pdb import set_trace
1207        wftool = self.portal_workflow
1208        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1209        students_folder = self.portal_url.getPortalObject().campus.students
1210        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
1211        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
1212        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
1213        data = re.compile(s)
1214        start = True
1215        tr_count = 1
1216        total = 0
1217        #name = 'pume_results'
1218        #name = 'epaymentsuccessful_z2log2'
1219        name = filename
1220        no_import = []
1221        imported = []
1222        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
1223        try:
1224            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
1225        except:
1226            logger.error('Error reading %s' % name)
1227            return
1228        tas = []
1229        for line in transactions:
1230            dict = {}
1231            items = data.search(line)
1232            dict['idict'] = idict = items.groupdict()
1233            #print idict
1234            #from pdb import set_trace;set_trace()
1235            urlparsed = urlparse(idict['get'][4:])
1236            #print urlparsed
1237            path = urlparsed[2].split('/')
1238            dict['student_id'] = student_id = path[8]
1239            dict['payment_id'] = payment_id = path[10]
1240            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
1241            tas.append(dict)
1242            tr_count += 1
1243        return tas
1244    ###)
1245
[1620]1246    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
1247    def importOnlinePaymentTransactions(self):
1248        """load Online Payment Transactions from CSV values"""
1249        import transaction
1250        import random
1251        #from pdb import set_trace
1252        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
[1625]1253        opt = self.online_payments_import
[1620]1254        students_folder = self.portal_url.getPortalObject().campus.students
1255        start = True
1256        tr_count = 1
1257        total = 0
1258        #name = 'pume_results'
1259        name = 'OnlineTransactions'
1260        no_import = []
1261        imported = []
1262        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
1263        try:
1264            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
1265        except:
1266            logger.error('Error reading %s.csv' % name)
1267            return
1268        for pay_transaction in transactions:
1269            if start:
1270                start = False
1271                logger.info('Start loading from %s.csv' % name)
1272                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
1273                no_import.append('%s,"Error"' % s)
1274                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
1275                format_error = format + ',"%(Error)s"'
1276            data = {}
[1644]1277
[1781]1278            # format of the first file sent by Tayo
[1643]1279            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
1280            #data['student_id'] = student_id = pay_transaction['Payer ID']
1281            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1282            #data['response_code'] = response_code = pay_transaction['Resp Code']
1283            #data['amount'] = amount = pay_transaction['Amount']
[1644]1284
[1781]1285            # format of the second file sent by Tayo
[1798]1286            #data['datetime'] = date = 0
1287            #data['student_id'] = student_id = pay_transaction['Payer ID']
1288            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1289            #data['response_code'] = response_code = '00'
1290            #data['amount'] = amount = pay_transaction['Amount']
[1813]1291
[1798]1292            # format of the third file sent by Kehinde
[1643]1293            data['datetime'] = date = 0
[1798]1294            data['student_id'] = student_id = pay_transaction['customer_id']
1295            data['order_id'] = order_id = pay_transaction['merchant_reference']
[1644]1296            data['response_code'] = response_code = '00'
[1813]1297            data['amount'] = amount = pay_transaction['Amount']
[1644]1298
[1620]1299            dup = False
1300            if response_code == "12":
1301                continue
1302            try:
1303                opt.addRecord(**data)
1304            except ValueError:
1305                dup = True
1306            #from pdb import set_trace;set_trace()
1307            if dup:
1308                if response_code == "00":
[1798]1309                    try:
1310                        opt.modifyRecord(**data)
1311                    except:
1312                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
1313                        continue
[1620]1314                else:
[1674]1315                    pay_transaction['Error'] = "Duplicate order_id"
[1620]1316                    no_import.append( format_error % pay_transaction)
[1674]1317                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
[1620]1318                    continue
1319            tr_count += 1
1320            if tr_count > 1000:
1321                if len(no_import) > 0:
1322                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1323                             '\n'.join(no_import) + '\n')
1324                    no_import = []
[1645]1325                em = '%d transactions committed\n' % (tr_count)
[1620]1326                transaction.commit()
1327                regs = []
1328                logger.info(em)
1329                total += tr_count
1330                tr_count = 0
1331        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1332                                                '\n'.join(no_import))
1333        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
1334    ###)
[2237]1335
[2264]1336    security.declareProtected(ModifyPortalContent,'mass_create_faculty') ###(
1337    def mass_create_faculty(self,mapping):
1338        "create a faculty"
1339        logger = logging.getLogger('WAeUPTool.mass_create_faculty')
1340        academics_folder = self.portal_url.getPortalObject().campus.academics
1341        fid = mapping['code']
1342        if getattr(academics_folder,fid,None) is not None:
1343            return '', "Faculty with ID: %s exists" % fid
[2267]1344        logger.info('Creating Faculty %(code)s, %(title)s' % mapping)
[2283]1345        try:
1346            academics_folder.invokeFactory('Faculty', fid)
1347        except BadRequest,E:
1348            return '', "%s" % E
[2264]1349        f = getattr(academics_folder,fid,None)
1350        f.getContent().edit(mapping=mapping)
1351        return fid,''
1352    ###)
1353
[2288]1354    security.declareProtected(ModifyPortalContent,'mass_edit_faculty') ###(
[2264]1355    def mass_edit_faculty(self,mapping):
1356        "edit a faculty"
1357        logger = logging.getLogger('WAeUPTool.mass_edit_faculty')
1358        academics_folder = self.portal_url.getPortalObject().campus.academics
1359        fid = mapping['code']
1360        f = getattr(academics_folder,fid,None)
1361        if f is None:
1362            return '', "Faculty with ID: %s does not exist" % fid
[2267]1363        logger.info('Editing Faculty %(code)s, %(title)s' % mapping)
[2264]1364        f.getContent().edit(mapping=mapping)
1365        return fid,''
1366    ###)
1367
[2234]1368    security.declareProtected(ModifyPortalContent,'mass_create_department') ###(
[2193]1369    def mass_create_department(self,mapping):
1370        "create a department in the correct faculty"
1371        logger = logging.getLogger('WAeUPTool.mass_create_department')
1372        fid = mapping['faculty_code']
1373        if getattr(self,'_v_faculties',None) is None:
1374            res = self.portal_catalog(portal_type = "Faculty")
1375            self._v_faculties = {}
1376            for f in res:
1377                self._v_faculties[f.getId] = f.getObject()
1378        f = self._v_faculties.get(fid,None)
1379        if f is None:
1380            return '', "No Faculty with ID: %s" % fid
1381        else:
1382            did = mapping.get('code')
1383            d = getattr(f,did,None)
1384            if d is None or d.portal_type == "Faculty":
[2267]1385                logger.info('Creating Department %(code)s, %(title)s' % mapping)
[2283]1386                try:
1387                    f.invokeFactory('Department', did)
1388                except BadRequest,E:
1389                    return '', "%s" % E
[2193]1390                d = getattr(f,did)
1391                d.invokeFactory('CoursesFolder','courses')
1392                courses = getattr(d,'courses')
1393                dict = {'Title': 'Courses'}
1394                courses.getContent().edit(mapping=dict)
1395                d.invokeFactory('CertificatesFolder','certificates')
1396                certificates = getattr(d,'certificates')
1397                dict = {'Title': 'Certificates'}
1398                certificates.getContent().edit(mapping=dict)
1399            d.getContent().edit(mapping=mapping)
1400        return did,''
1401    ###)
[1620]1402
[2234]1403    security.declareProtected(ModifyPortalContent,'mass_edit_department') ###(
[2193]1404    def mass_edit_department(self,mapping):
1405        "create a department in the correct faculty"
1406        logger = logging.getLogger('WAeUPTool.mass_create_department')
1407        academics_folder = self.portal_url.getPortalObject().campus.academics
1408        fid = mapping['faculty_code']
1409        did = mapping.get('code')
1410        try:
1411            d = getattr(getattr(academics_folder,fid),did,None)
1412        except KeyError:
1413            return '', "Department %s or Faculty %s wrong" % (did,fid)
1414        else:
1415            if d is None or d.portal_type == "Faculty":
[2267]1416                logger.info('Editing Department %(code)s, %(title)s' % mapping)
[2193]1417            d.getContent().edit(mapping=mapping)
1418        return did,''
1419    ###)
[1786]1420
[2265]1421    security.declareProtected(ModifyPortalContent,'mass_create_course') ###(
1422    def mass_create_course(self,mapping):
[2315]1423        #import pdb;pdb.set_trace()
[2265]1424        if getattr(self,'_v_course_list',None) is None:
1425            self._v_course_list = []
1426        if getattr(self,'_v_departments',None) is None:
1427            res = self.portal_catalog(portal_type = "Department")
[2313]1428            self._v_department_courses = {}
[2265]1429            for d in res:
[2313]1430                self._v_department_courses[d.getId] = getattr(d.getObject(),"courses",None)
[2265]1431        did = mapping['department_code']
[2313]1432        d = self._v_department_courses.get(did,None)
[2265]1433        if d is None:
[2282]1434            return '', "No Department with ID: %s" % did
[2265]1435        course_id = mapping.get('code')
1436        if course_id in self._v_course_list:
[2313]1437            return '', "Duplicate Course ID: %s" % did
[2265]1438        c = getattr(d,course_id,None)
1439        if c is not None:
[2313]1440            return '', "Duplicate Course ID: %s" % did
[2283]1441        try:
1442            d.invokeFactory('Course', course_id)
1443        except BadRequest,E:
1444            return '', "%s" % E
[2265]1445        self._v_course_list.append(course_id)
1446        c = getattr(d,course_id)
1447        c.getContent().edit(mapping=mapping)
1448        return course_id,''
1449    ###)
1450
[2282]1451    security.declareProtected(ModifyPortalContent,'mass_edit_course') ###(
1452    def mass_edit_course(self,mapping):
1453        #import pdb;pdb.set_trace()
1454        course_id = mapping.get('code')
1455        res = self.portal_catalog(id=course_id)
1456        if not res:
[2289]1457            return '', "No Course with ID: %s" % course_id
[2282]1458        c = res[0].getObject()
1459        c.getContent().edit(mapping=mapping)
1460        return course_id,''
1461    ###)
1462
1463    security.declareProtected(ModifyPortalContent,'mass_create_certificate') ###(
1464    def mass_create_certificate(self,mapping):
1465        if getattr(self,'_v_certificate_list',None) is None:
1466            self._v_certificate_list = []
[2313]1467        if getattr(self,'_v_department_certificates',None) is None:
[2282]1468            res = self.portal_catalog(portal_type = "Department")
[2313]1469            self._v_department_certificates = {}
[2282]1470            for d in res:
[2313]1471                self._v_department_certificates[d.getId] = getattr(d.getObject(),"certificates",None)
[2282]1472        did = mapping['department_code']
[2313]1473        d = self._v_department_certificates.get(did,None)
[2282]1474        if d is None:
1475            return '', "No Department with ID: %s" % did
1476        certificate_id = mapping.get('code')
1477        if certificate_id in self._v_certificate_list:
[2313]1478            return '', "Duplicate Certificate ID: %s" % did
[2282]1479        c = getattr(d,certificate_id,None)
1480        if c is not None:
[2313]1481            return '', "Duplicate Certificate ID: %s" % did
[2283]1482        try:
1483            d.invokeFactory('Certificate', certificate_id)
1484        except BadRequest,E:
1485            return '', "%s" % E
[2282]1486        self._v_certificate_list.append(certificate_id)
1487        c = getattr(d,certificate_id)
1488        c.getContent().edit(mapping=mapping)
1489        return certificate_id,''
1490    ###)
1491
1492    security.declareProtected(ModifyPortalContent,'mass_edit_certificate') ###(
1493    def mass_edit_certificate(self,mapping):
1494        #import pdb;pdb.set_trace()
1495        certificate_id = mapping.get('code')
1496        res = self.portal_catalog(id=certificate_id)
1497        if not res:
[3042]1498            return '', "No Certificate with ID: %s" % certificate_id
[2282]1499        c = res[0].getObject()
1500        c.getContent().edit(mapping=mapping)
1501        return certificate_id,''
1502    ###)
1503
[2520]1504    security.declareProtected(ModifyPortalContent,'mass_create_application') ###(
1505    def mass_create_application(self,mapping):
[2514]1506        #import pdb;pdb.set_trace()
[2547]1507        reg_no = mapping.get('reg_no')
[2514]1508        try:
1509            self.applicants_catalog.addRecord(**mapping)
1510        except ValueError:
[2548]1511            return '', "applicant record with reg_no %s already exists" % reg_no
[2546]1512        return reg_no,''
[2514]1513    ###)
1514
[2520]1515    security.declareProtected(ModifyPortalContent,'mass_edit_application') ###(
1516    def mass_edit_application(self,mapping):
[2514]1517        #import pdb;pdb.set_trace()
1518        reg_no = mapping.get('reg_no')
[2731]1519        status = mapping.get('status')
[2699]1520        res = self.applicants_catalog(reg_no = reg_no)
1521        if len(res):
[2731]1522            if res[0].status == 'created' and status != 'created':
1523                return '', "student object with id %s for %s already created, status cannot be changed" % (res[0].student_id, reg_no)
1524            elif status == 'created' and res[0].status != 'created':
1525                return '', "student object for %s has not yet been created, status cannot be set to 'created'" % (reg_no)
[2699]1526            else:
1527                self.applicants_catalog.modifyRecord(**mapping)
1528                return reg_no,''
1529        else:
[2548]1530            return '', "applicant record with reg_no %s does not exist" % reg_no
[2701]1531
[2514]1532    ###)
1533
[2501]1534    security.declareProtected(ModifyPortalContent,'mass_create_course_result') ###(
1535    def mass_create_course_result(self,mapping):
[2500]1536        #import pdb;pdb.set_trace()
[2747]1537        students_folder = self.portal_url.getPortalObject().campus.students
[2501]1538        if getattr(self,'_v_courses',None) is None:
1539            res = self.courses_catalog()
1540            self._v_courses = {}
1541            for brain in res:
[2520]1542                self._v_courses[brain.code] = brain
[2747]1543        if getattr(self,'_v_level_created',None) is None:
1544            self._v_level_created = []
[2500]1545        course_id = mapping.get('code')
[2501]1546        if course_id not in self._v_courses.keys():
[2754]1547            return '', "No course with ID: %s" % course_id
[2773]1548        id_key = ''
1549        for id_key in ('student_id','matric_no'):
1550            id_field = mapping.get(id_key,None)
1551            if id_field is not None:
1552                student_id = id_field
1553                break
1554        query = Eq(id_key,id_field)
1555        res = self.students_catalog.evalAdvancedQuery(query)
1556        if not res:
[2750]1557            return '', "no student with %(id_key)s %(id_field)s" % vars()
[2773]1558        student_rec = res[0]
[2776]1559        if id_field != "student_id":
1560            mapping['student_id'] = student_rec.id
[2766]1561        student_id = student_rec.id
1562        level_id = mapping['level_id']
1563        code = mapping['code']
[2774]1564        if student_id not in self._v_level_created:
[2747]1565            try:
1566                context = getattr(getattr(students_folder,
[2766]1567                                          "%(student_id)s" % vars()),
[2747]1568                                  'study_course')
1569            except:
[2766]1570                return '', "could not create level %(level_id)s for %(student_id)s" % vars()
1571            if level_id not in context.objectIds():
1572                context.invokeFactory('StudentStudyLevel',"%(level_id)s" % vars())
1573                level = getattr(context,"%(level_id)s" % vars())
[2747]1574                self.portal_workflow.doActionFor(level,'open')
[2754]1575                # the session string must not be copied into the level object
[2775]1576                current_verdict = getattr(student_rec,'current_verdict','')
1577                current_session = getattr(student_rec,'current_session','')
1578                if current_verdict and student_rec.current_level == level_id:
[2771]1579                    level.getContent().edit(mapping={'verdict': "%s" %
[2775]1580                                                     current_verdict,
[2771]1581                                                     'session': "%s" %
[2775]1582                                                     current_session,
[2766]1583                                                    })
1584                    self.portal_workflow.doActionFor(level,'close')
1585            self._v_level_created += student_id,
1586        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
[2746]1587        for k in ('semester','credits',):
[2501]1588            mapping[k] = getattr(self._v_courses[course_id],k)
[2500]1589        try:
[2501]1590            self.course_results.addRecord(**mapping)
1591        except ValueError:
1592            return '', "course result already exists: %s" % key
1593        return key,''
[2500]1594    ###)
1595
1596    security.declareProtected(ModifyPortalContent,'mass_edit_course_result') ###(
1597    def mass_edit_course_result(self,mapping):
[2776]1598        id_key = ''
1599        for id_key in ('student_id','matric_no'):
1600            id_field = mapping.get(id_key,None)
1601            if id_field is not None:
1602                student_id = id_field
1603                break
1604        query = Eq(id_key,id_field)
1605        res = self.students_catalog.evalAdvancedQuery(query)
1606        if not res:
[3053]1607            return '', "No student with %(id_key)s %(id_field)s" % vars()
[2776]1608        if id_field != "student_id":
1609            mapping['student_id'] = res[0].id
1610        if not res:
[3053]1611            return '', "No student with %(id_key)s %(id_field)s" % vars()
[2776]1612        student_rec = res[0]
[2766]1613        student_id = student_rec.id
1614        level_id = mapping['level_id']
1615        code = mapping['code']
1616        mapping['key'] = key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
[2500]1617        try:
1618            self.course_results.modifyRecord(**mapping)
1619        except KeyError:
1620            return '', "No course result to edit: %s" % key
1621        return key,''
1622    ###)
1623
[3057]1624    security.declareProtected(ModifyPortalContent,'mass_delete_course_result') ###(
1625    def mass_delete_course_result(self,mapping):
1626        id_key = ''
1627        for id_key in ('student_id','matric_no'):
1628            id_field = mapping.get(id_key,None)
1629            if id_field is not None:
1630                student_id = id_field
1631                break
1632        query = Eq(id_key,id_field)
1633        res = self.students_catalog.evalAdvancedQuery(query)
1634        if not res:
1635            return '', "No student with %(id_field)s: %(id_key)s" % vars()
1636        if id_field != "student_id":
1637            mapping['student_id'] = res[0].id
1638        if not res:
1639            return '', "no student with %(id_key)s %(id_field)s" % vars()
1640        student_rec = res[0]
1641        student_id = student_rec.id
1642        level_id = mapping['level_id']
1643        code = mapping['code']
1644        key = "%(student_id)s|%(level_id)s|%(code)s" % vars()
1645        # for k in ('semester',):
1646        #     mapping[k] = getattr(self._v_courses[course_id],k)
1647        if self.course_results.getRecordByKey(key) is None:
1648            return '', "no course-result with %(key)s" % vars()
1649        self.course_results.deleteRecord(key)
1650        return key,''
1651    ###)
1652
[2282]1653    security.declareProtected(ModifyPortalContent,'mass_create_certificate_course') ###(
1654    def mass_create_certificate_course(self,mapping):
[2320]1655        if getattr(self,'_v_courses',None) is None:
1656            res = self.courses_catalog()
[2351]1657            self._v_courses= [course.code for course in res]
[2282]1658        if getattr(self,'_v_ceritficates',None) is None:
1659            res = self.portal_catalog(portal_type = "Certificate")
1660            self._v_certificates = {}
1661            for cert in res:
1662                self._v_certificates[cert.getId] = cert.getObject()
[2284]1663        certificate_course_id = mapping.get('code')
[2351]1664        if certificate_course_id not in self._v_courses:
[2284]1665            return '', "No Course with ID: %s" % certificate_course_id
[2282]1666        cert_id = mapping['certificate_code']
1667        cert = self._v_certificates.get(cert_id,None)
1668        if cert is None:
[2284]1669            return '', "No Certificate with ID: %s" % cert_id
[2282]1670        level_id = mapping.get('level')
1671        level = getattr(cert,level_id,None)
1672        if level is None:
1673            cert.invokeFactory('StudyLevel', level_id)
1674            level = getattr(cert,level_id,None)
1675        elif hasattr(level,certificate_course_id):
1676            return '', "Duplicate CertificateCourse ID: %s in %s/ %s" %\
1677            (certificate_course_id,cert_id,level_id)
1678        level.invokeFactory('CertificateCourse', certificate_course_id)
1679        c = getattr(level,certificate_course_id)
1680        c.getContent().edit(mapping=mapping)
1681        return certificate_course_id,''
1682    ###)
1683
[2193]1684    field2types_student = {   ###(
[1756]1685                      'StudentApplication':
1686                          {'id': 'application',
1687                           'title': 'Application Data',
[1991]1688                           'wf_transition_return': 'close',
1689                           'wf_transition_admit': 'remain',
[1756]1690                           'fields':
1691                             ('jamb_reg_no',
1692                              'entry_mode',
1693                              'entry_session',
1694                              'jamb_score',
[1786]1695                              'app_email',
[2008]1696                              'jamb_age',
[2428]1697                              'jamb_state',
1698                              'jamb_lga',
[3003]1699                              'jamb_sex',
[1756]1700                              )
1701                              },
[1786]1702                      #'StudentPume':
1703                      #    {'id': 'pume',
1704                      #     'title': 'Pume Data',
[1991]1705                      #     'wf_transition_return': 'close',
1706                      #     'wf_transition_admit': 'close',
[1786]1707                      #     'fields':
1708                      #       ('pume_score',
1709                      #        )
1710                      #        },
[1756]1711                      'StudentClearance':
1712                          {'id': 'clearance',
[2009]1713                           'title': 'Clearance/Eligibility Record',
[1991]1714                           'wf_transition_return': 'close',
1715                           'wf_transition_admit': 'remain',
[1756]1716                           'fields':
1717                             ('matric_no',
1718                              'nationality',
1719                              'lga',
[1804]1720                              'birthday',
[1756]1721                              )
1722                              },
1723                         'StudentPersonal':
1724                          {'id': 'personal',
1725                           'title': 'Personal Data',
[1991]1726                           'wf_transition_return': 'open',
1727                           'wf_transition_admit': 'remain',
[1756]1728                           'fields':
1729                             ('firstname',
1730                              'middlename',
1731                              'lastname',
1732                              'sex',
1733                              'email',
1734                              'phone',
1735                              'perm_address',
1736                              )
1737                              },
1738                         'StudentStudyCourse':
1739                          {'id': 'study_course',
1740                           'title': 'Study Course',
[1991]1741                           'wf_transition_return': 'open',
1742                           'wf_transition_admit': 'remain',
[1756]1743                           'fields':
1744                             ('study_course',
1745                              'current_level',
1746                              'current_session',
1747                              'current_mode',
1748                              'current_verdict',
[2478]1749                              'previous_verdict',
[1756]1750                              )
1751                              },
[2846]1752                         # 'StudentStudyLevel':
1753                         #  {'id': 'current_level',
1754                         #   'title': '',
1755                         #   'wf_transition_return': 'open',
1756                         #   'wf_transition_admit': 'remain',
1757                         #   'fields':
1758                         #     ('verdict',
1759                         #      'session',
1760                         #      )
1761                         #      },
[1898]1762                         'PaymentsFolder':
1763                          {'id': 'payments',
1764                           'title': 'Payments',
[1991]1765                           'wf_transition_return': 'open',
1766                           'wf_transition_admit': 'open',
[1898]1767                           'fields':
1768                             ()
1769                              },
[1756]1770                         }
1771    ###)
1772
[2193]1773    security.declareProtected(ModifyPortalContent,'mass_create_student') ###(
1774    def mass_create_student(self,mapping):
[3039]1775        "create student records due import"
[2193]1776        logger = logging.getLogger('WAeUPTool.mass_create_student')
[1747]1777        students_folder = self.portal_url.getPortalObject().campus.students
[1818]1778        jamb_reg_no = mapping.get('jamb_reg_no',None)
[1747]1779        if jamb_reg_no:
1780            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1781            if res:
[1749]1782                return '',"jamb_reg_no exists"
[1818]1783        matric_no = mapping.get('matric_no',None)
[1747]1784        if matric_no:
1785            res = self.students_catalog(matric_no = matric_no)
1786            if res:
[1749]1787                return '',"matric_no exists"
[1747]1788        sid = self.waeup_tool.generateStudentId('?')
1789        students_folder.invokeFactory('Student', sid)
1790        student_obj = getattr(students_folder,sid)
[2193]1791        f2t = self.field2types_student
[1772]1792        d = {}
[1990]1793        transition = mapping.get('reg_transition','admit')
1794        if transition not in ('admit','return'):
[2008]1795            return '',"no valid transition provided"
[1747]1796        for pt in f2t.keys():
1797            student_obj.invokeFactory(pt,f2t[pt]['id'])
1798            sub_obj = getattr(student_obj,f2t[pt]['id'])
1799            sub_doc = sub_obj.getContent()
[1772]1800            d['Title'] = f2t[pt]['title']
[1747]1801            for field in f2t[pt]['fields']:
[2702]1802                d[field] = mapping.get(field,'')
[2454]1803
1804            if pt == "StudentApplication":
[3002]1805                #d['jamb_sex']  = 'M'
1806                #if mapping.get('sex'):
1807                #    d['jamb_sex']  = 'F'
[2436]1808                d['jamb_firstname'] = mapping.get('firstname',None)
1809                d['jamb_middlename'] = mapping.get('middlename',None)
1810                d['jamb_lastname'] = mapping.get('lastname',None)
1811
[2433]1812            # if pt == "StudyCourse":
1813            #     for von,zu in (('entry_mode','current_mode'),
1814            #                    ('entry_session','current_session')):
1815            #         if mapping.get(zu,None) is None and mapping.get(von,None) is not None:
1816            #             d[zu] = mapping[von]
[1747]1817            sub_doc.edit(mapping = d)
[1990]1818
[1987]1819            #import pdb;pdb.set_trace()
1820            new_state = f2t[pt]['wf_transition_%(transition)s' % vars()]
[1898]1821            if new_state != "remain":
1822                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
[1990]1823        self.portal_workflow.doActionFor(student_obj,transition)
[1747]1824        student_obj.manage_setLocalRoles(sid, ['Owner',])
1825        return sid,''
1826    ###)
1827
[2193]1828    security.declareProtected(ModifyPortalContent,'mass_edit_student') ###(
1829    def mass_edit_student(self,mapping):
[2754]1830        wftool = self.portal_workflow
[3039]1831        "edit student records due import"
[2193]1832        logger = logging.getLogger('WAeUPTool.mass_edit_student')
[1774]1833        students_folder = self.portal_url.getPortalObject().campus.students
[1818]1834        sid = mapping.get('id',None)
1835        jamb_reg_no = mapping.get('jamb_reg_no',None)
1836        matric_no = mapping.get('matric_no',None)
[1875]1837        editable_keys = mapping.keys()
[1774]1838        if sid:
1839            res = self.students_catalog(id = sid)
1840            if not res:
1841                return '',"no student with id %s" % sid
[2268]1842            if matric_no and res[0].matric_no and\
[1774]1843              matric_no != res[0].matric_no:
[2268]1844                logger.info("%s, old matric_no %s overwritten with %s" % (res[0].id,res[0].matric_no,matric_no))
1845            if jamb_reg_no and res[0].jamb_reg_no and\
[1774]1846              jamb_reg_no != res[0].jamb_reg_no:
[2268]1847                logger.info("%s, old reg_no %s overwritten with %s" % (res[0].id,res[0].jamb_reg_no,jamb_reg_no))
[1844]1848        elif jamb_reg_no:
1849            res = self.students_catalog(jamb_reg_no = jamb_reg_no)
1850            if not res:
1851                return '',"no student with jamb_reg_no %s" % jamb_reg_no
[1875]1852            editable_keys.remove('jamb_reg_no')
[1774]1853        elif matric_no:
1854            res = self.students_catalog(matric_no = matric_no)
1855            if not res:
1856                return '',"no student with matric_no %s" % matric_no
[1875]1857            editable_keys.remove('matric_no')
[1965]1858
[2268]1859        ## included only to change wf state from admitted to returning
1860        #if res[0].review_state not in ('admitted','objection_raised'):
1861        #    return '%s' % res[0].id ,"student is not in state admitted or objection_raised"
1862        ## end inclusion
[1965]1863
[1774]1864        sid = res[0].id
1865        student_obj = getattr(students_folder,sid)
[2193]1866        f2t = self.field2types_student
[1774]1867        d = {}
[2265]1868        #import pdb;pdb.set_trace()
[1875]1869        any_change = False
[2846]1870        #special treatment for StudentStudyLevel
1871        d['verdict']  = mapping.get('current_verdict','')
1872        d['session']  = mapping.get('current_session','')
1873        current_level = mapping.get('current_level','')
1874        while d['session'] and d['verdict'] and current_level:
1875            sub_obj = getattr(student_obj,'study_course',None)
1876            if sub_obj is None:
1877                break
1878            level_obj = getattr(sub_obj,current_level,None)
1879            if  level_obj is None:
1880                break
1881            any_change = True
1882            level_obj.getContent().edit(mapping = d)
1883            try:
1884                wftool.doActionFor(level_obj,'close')
1885            except:
1886                pass
1887            break
[1774]1888        for pt in f2t.keys():
[3002]1889            #if pt == "StudentApplication":
1890            #    d['jamb_sex']  = 'M'
1891            #    if mapping.get('sex'):
1892            #        d['jamb_sex']  = 'F'
[1875]1893            intersect = set(f2t[pt]['fields']).intersection(set(editable_keys))
[2753]1894            if intersect and pt not in ('StudentStudyLevel',):
1895                object_id = f2t[pt]['id']
1896                sub_obj = getattr(student_obj,object_id,None)
[1875]1897                if sub_obj is None:
1898                    try:
[2753]1899                        student_obj.invokeFactory(pt,object_id)
[1875]1900                    except:
1901                        continue
[2753]1902                    sub_obj = getattr(student_obj,object_id)
1903                    if f2t[pt]['title'] != '':
1904                        d['Title'] = f2t[pt]['title']
[1875]1905                sub_doc = sub_obj.getContent()
1906                for field in intersect:
1907                    changed = False
[2478]1908                    if getattr(sub_doc,field,None) != mapping.get(field,''):
[1875]1909                        any_change = True
1910                        changed = True
1911                        d[field] = mapping.get(field,'')
1912                    if changed:
1913                        sub_doc.edit(mapping = d)
[1904]1914
[1905]1915
[2268]1916        ## included only to change wf state from admitted to returning
1917        #    if res[0].review_state in ('admitted','objection_raised'):
1918        #        new_state = f2t[pt]['wf_transition_return']
1919        #        sub_obj = getattr(student_obj,f2t[pt]['id'],None)
1920        #        if sub_obj and new_state != "remain":
1921        #            try:
1922        #                self.portal_workflow.doActionFor(sub_obj,new_state,dest_container=sub_obj)
1923        #            except:
1924        #                #logger.info('%s, wf transition %s of %s failed' % (sid,new_state,sub_obj.id))
1925        #                pass
1926        #if res[0].review_state in ('admitted','objection_raised'):
1927        #    wfaction = 'return'
1928        #    try:
1929        #        self.portal_workflow.doActionFor(student_obj,wfaction)
1930        #        logger.info('%s, wf state changed' % sid)
1931        #        any_change = True
1932        #    except:
1933        #        logger.info('%s, wf transition failed, old state = %s' % (sid,res[0].review_state))
1934        #        pass
1935        ## end inclusion
[1904]1936
[1905]1937
[1875]1938        if any_change:
1939            return sid,''
1940        else:
1941            return sid,'not modified'
[1774]1942    ###)
[1905]1943
[3033]1944    security.declareProtected(ModifyPortalContent,'mass_edit_verdict') ###(
1945    def mass_edit_verdict(self,mapping):
1946        wftool = self.portal_workflow
[3039]1947        "edit student verdicts"
[3033]1948        logger = logging.getLogger('WAeUPTool.mass_edit_verdict')
1949        students_folder = self.portal_url.getPortalObject().campus.students
1950        student_id = mapping.get('id',None)
1951        matric_no = mapping.get('matric_no',None)
1952        editable_keys = mapping.keys()
1953        if student_id:
[3094]1954            student_record = self.students_catalog.getRecordByKey(student_id)
[3033]1955            if student_record is None:
1956                return '',"no student with id %s" % student_id
1957            if matric_no and student_record.matric_no and\
1958              matric_no != student_record.matric_no:
[3053]1959                return '', 'student %s: matric_no %s does not match %s' % (student_record.id,
[3036]1960                                                                          student_record.matric_no,
1961                                                                          matric_no)
[3033]1962        elif matric_no:
1963            res = self.students_catalog(matric_no = matric_no)
1964            if not res:
1965                return '',"no student with matric_no %s" % matric_no
1966            student_record = res[0]
1967            editable_keys.remove('matric_no')
[3095]1968        else:
1969            return '',"no id or matric_no specified"
[3033]1970        student_id = student_record.id
1971        student_review_state =  student_record.review_state
[3036]1972        if student_review_state not in ('courses_validated','returning'):
[3033]1973            return '',"student %s in wrong review_state %s" % (student_id, student_review_state)
1974        student_obj = getattr(students_folder,student_id)
1975        f2t = self.field2types_student
1976        d = {}
1977        #import pdb;pdb.set_trace()
1978        any_change = False
1979        #special treatment for StudentStudyLevel
[3064]1980        current_session = d['session'] = mapping.get('current_session','')
[3033]1981        if current_session and student_record.session != current_session:
[3053]1982            return '','student %s: imported session %s does not match current_session %s' % (student_id,
[3033]1983                                                                                        current_session,
1984                                                                                        student_record.session)
1985        current_level = mapping.get('current_level','')
1986        if current_level and student_record.level != current_level:
[3053]1987            return '','student %s: imported level %s does not match current_level %s' % (student_id,
[3033]1988                                                                                    current_level,
1989                                                                                    student_record.level)
[3036]1990        study_course_obj = getattr(student_obj,'study_course',None)
1991        if study_course_obj is None:
[3053]1992            return '','student %s: no study_course object' % student_id
[3036]1993        level_obj = getattr(study_course_obj,current_level,None)
[3033]1994        if  level_obj is None:
[3053]1995            return '','student %s: no study_level object for level %s' % (student_id,
[3033]1996                                                                             current_level)
[3036]1997        verdict = d['verdict'] = d['current_verdict']  = mapping.get('current_verdict','')
[3071]1998
[3064]1999        #if verdict == student_record.verdict:
2000        #    return '','student %s: verdict already set to %s' % (student_id,
2001        #                                                            verdict)
[3039]2002
[3033]2003        level_review_state = wftool.getInfoFor(level_obj,'review_state',None)
2004        if level_review_state != "closed":
[3063]2005            wftool.doActionFor(level_obj,'close')
2006            # return '','student %s: level %s is not closed' % (student_id,
2007            #                                                      current_level)
[3039]2008
[3036]2009        study_course_obj.getContent().edit(mapping = d)
[3033]2010        level_obj.getContent().edit(mapping = d)
[3036]2011        if student_review_state != "returning":
2012            wftool.doActionFor(student_obj,'return')
[3063]2013        # try:
2014        #     wftool.doActionFor(level_obj,'close')
2015        # except:
2016        #     pass
[3033]2017        return student_id,''
2018    ###)
2019
[1730]2020    security.declareProtected(ModifyPortalContent,"importData")###(
[2259]2021    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
[1730]2022        """load data from CSV values"""
2023        import transaction
2024        import random
[1775]2025
[1773]2026        pm = self.portal_membership
[1775]2027        member = pm.getAuthenticatedMember()
2028
[1747]2029        logger = logging.getLogger('WAeUPTool.importData')
[1730]2030        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
2031        students_folder = self.portal_url.getPortalObject().campus.students
2032        start = True
[2495]2033        tr_count = 0
[1756]2034        total_imported = 0
2035        total_not_imported = 0
[1730]2036        total = 0
[1749]2037        iname = "import_%s" % name
[2754]2038        if iname in ('import_application','import_course_result',):
[2528]2039            commit_after = 2000
2040        else:
2041            commit_after = 100
[1747]2042        stool = getToolByName(self, 'portal_schemas')
2043        ltool = getToolByName(self, 'portal_layouts')
2044        schema = stool._getOb(iname)
[1730]2045        if schema is None:
[1772]2046            em = 'No such schema %s' % iname
2047            logger.error('No such schema %s' % iname)
[1756]2048            return em
[1747]2049        layout = ltool._getOb(iname)
[1730]2050        if layout is None:
[1772]2051            em = 'No such layout %s' % iname
[1756]2052            logger.error(em)
2053            return em
[1730]2054        validators = {}
2055        for widget in layout.keys():
[1749]2056            validators[widget] = layout[widget].validate
[2289]2057        mode = "create"
[1774]2058        if edit:
[3057]2059            if filename.endswith('_toDelete'):
2060                mode = "delete"
2061            else:
2062                mode = "edit"
[2289]2063        importer_name = "mass_%(mode)s_%(name)s" % vars()
[1772]2064        importer = getattr(self, '%s' % importer_name,None)
2065        if importer is None:
2066            em = 'No importer function %s' % importer_name
[1756]2067            logger.error(em)
2068            return em
[1747]2069        not_imported = []
[1730]2070        imported = []
2071        try:
[1747]2072            items = csv.DictReader(open("%s/import/%s.csv" % (i_home,filename),"rb"))
[1730]2073        except:
[1756]2074            em = 'Error reading %s.csv' % filename
2075            logger.error(em)
2076            return em
[1730]2077        for item in items:
[2704]2078            #import pdb;pdb.set_trace()
[3094]2079            item = dict((k.strip(),l.strip()) for (k,l) in item.items())
[1730]2080            if start:
2081                start = False
[1747]2082                adapters = [MappingStorageAdapter(schema, item)]
[2315]2083                logger.info('%s starts import from %s.csv in %s mode with schema and layout %s' % (member,filename,mode,iname))
[2094]2084                attrs = csv.reader(open("%s/import/%s.csv" % (i_home,filename),"rb")).next()
[3033]2085                import_keys = [k.strip() for k in attrs if not k.strip().startswith('ignore')]
[1804]2086                diff2schema = set(import_keys).difference(set(schema.keys()))
2087                diff2layout = set(import_keys).difference(set(layout.keys()))
2088                if diff2schema:
[2282]2089                    em = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
[1804]2090                    return em
[2433]2091                if mode == "create":
[2436]2092                    required_keys = [layout.getIdUnprefixed(id)
[2433]2093                                     for id,widget in layout.objectItems()
2094                                     if widget.is_required]
2095                    if not set(required_keys).issubset(set(import_keys)):
2096                        diff2import = set(required_keys).difference(set(import_keys))
2097                        em = 'required key(s): "%s" not found in heading' % ", ".join(diff2import)
2098                        return em
[1753]2099                s = ','.join(['"%s"' % fn for fn in import_keys])
[1772]2100                open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(s + ',"Error"'+ '\n')
2101                s = '"id",' + s
[1756]2102                open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(s + '\n')
[1730]2103                format = ','.join(['"%%(%s)s"' % fn for fn in import_keys])
2104                format_error = format + ',"%(Error)s"'
[1756]2105                format = '"%(id)s",'+ format
[2267]2106
[2094]2107            dm = DataModel(item, adapters,context=self)
[1747]2108            ds = DataStructure(data=item,datamodel=dm)
2109            error_string = ""
[2495]2110            total += 1
[2704]2111            error_count = 0
[1730]2112            for k in import_keys:
[2289]2113                if not validators[k](ds,mode=mode):
[2704]2114                    if error_count:
[2710]2115                        error_string += ' ++ '
[2704]2116                    error_string += "%s: %s" % (k,
[2264]2117                                                  self.translation_service(ds.getError(k),
2118                                                                           ds.getErrorMapping(k)))
[2704]2119                    error_count += 1
[1747]2120            if not error_string:
[2433]2121                temp_item = item.copy()
2122                temp_item.update(dm)
[2435]2123                temp_item['id'],error = importer(temp_item)
[1747]2124                if error:
2125                    error_string += error
[2433]2126                else:
2127                    item = temp_item
[2436]2128            if error_string:
[1747]2129                item['Error'] = error_string
2130                not_imported.append(format_error % item)
[1756]2131                total_not_imported += 1
[1747]2132            else:
[1821]2133                em = format % item
2134                imported.append(em)
[1875]2135                tr_count += 1
[1756]2136                total_imported += 1
[3071]2137                logger.info("%(total_imported)d of %(total)d imported in %(mode)s mode, %(em)s" % vars())
[2520]2138
[2528]2139            if total and not total % commit_after:
[1875]2140                transaction.commit()
[1747]2141                if len(not_imported) > 0:
2142                    open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
2143                             '\n'.join(not_imported) + '\n')
2144                    not_imported = []
2145                if len(imported) > 0:
2146                    open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
[1772]2147                             '\n'.join(imported) + '\n')
[1747]2148                    imported = []
[1730]2149                em = '%d transactions committed\n' % (tr_count)
2150                regs = []
2151                logger.info(em)
2152                tr_count = 0
[2528]2153                #if total > 100:
2154                #    return
[1756]2155        if len(imported) > 0:
[1747]2156            open("%s/import/%s_imported%s.csv" % (i_home,filename,current),"a").write(
2157                                                '\n'.join(imported))
[1756]2158        if len(not_imported) > 0:
[1747]2159            open("%s/import/%s_not_imported%s.csv" % (i_home,filename,current),"a").write(
2160                                                '\n'.join(not_imported))
[3071]2161        #if mode.endswith('e'):
2162        #    mode = mode[:-1]
2163        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]2164        logger.info(em)
[1756]2165        return em
[1730]2166    ###)
2167
[2292]2168    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
2169    def moveImagesToFS(self,student_id="O738726"):
2170        "move the images to the filesystem"
[2675]2171        images_dir = getImagesDir(student_id)
2172        #images_dir = os.path.join("%s" % images_base,student_id)
[2292]2173        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
2174        stool = getToolByName(self, 'portal_schemas')
2175        schemas = ['student_application',
2176                   'student_clearance',
2177                   ]
2178        created = False
2179        for schema_id in schemas:
2180            schema = stool._getOb(schema_id)
2181            object = getattr(student_folder,schema_id[len('student_'):],None)
2182            if object is None:
2183                continue
2184            doc = object.getContent()
2185            for key in schema.keys():
2186                if schema[key].meta_type != "CPS Image Field":
2187                    continue
2188                #import pdb;pdb.set_trace()
[2351]2189                image = getattr(doc,key,None)
2190                if not image or not hasattr(image,"data"):
[2292]2191                    continue
2192                if not created:
2193                    if not os.path.exists(images_dir):
2194                        os.mkdir(images_dir)
2195                    created = True
2196                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
2197                open(filename,"wb").write(str(image.data))
[2500]2198    ###)
[2292]2199
[2300]2200    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
2201    def movePassportToFS(self,student_id="O738726"):
2202        "move the passports to the filesystem"
2203        images_dir = os.path.join("%s" % i_home,'passports')
2204        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
2205        stool = getToolByName(self, 'portal_schemas')
2206        schemas = ['student_application',
2207                   #'student_clearance',
2208                   ]
2209        created = False
2210        for schema_id in schemas:
2211            schema = stool._getOb(schema_id)
2212            object = getattr(student_folder,schema_id[len('student_'):],None)
2213            if object is None:
2214                continue
2215            doc = object.getContent()
2216            for key in schema.keys():
2217                if schema[key].meta_type != "CPS Image Field":
2218                    continue
2219                #import pdb;pdb.set_trace()
2220                image = getattr(doc,key)
2221                if not hasattr(image,"data"):
2222                    continue
2223                if not created:
2224                    if not os.path.exists(images_dir):
2225                        os.mkdir(images_dir)
2226                    created = True
2227                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
2228                open(filename,"wb").write(str(image.data))
[2500]2229    ###)
[2300]2230
[828]2231InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.