source: WAeUP_SRP/base/WAeUPTool.py @ 3033

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

import verdicts mass_edit_verdicts implemented

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