source: WAeUP_SRP/trunk/WAeUPTool.py @ 5437

Last change on this file since 5437 was 5373, checked in by Henrik Bettermann, 14 years ago

use jamb_reg_no if provided

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