source: WAeUP_SRP/trunk/WAeUPTool.py @ 5536

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

pd_ft (fceokene) students start at level 500

  • Property svn:keywords set to Id
File size: 84.1 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 5518 2010-09-16 06:42:19Z 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 in ('pume2','pde2'):
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        elif da['entry_mode'].startswith('pde'):
1126            dsc['current_level'] = '500'           
1127        else:
1128            dsc['current_level'] = '100'
1129        dsc['current_session'] = es
1130        studycourse.getContent().edit(mapping=dsc)
1131        self.do_timing()
1132        #
1133        # payments folder
1134        student_object.invokeFactory('PaymentsFolder','payments')
1135        payments = getattr(student_object,'payments')
1136        #self.do_timing()
1137        dpay = {}
1138        dpay['Title'] = 'Payments'
1139        payments.getContent().edit(mapping=dpay)
1140        self.portal_workflow.doActionFor(payments,'open')
1141        self.do_timing()
1142        #
1143        # passport foto
1144        app_picture ="%s/import/images/%s/%s_passport.jpg" % (i_home,
1145                                                              brain.screening_type,
1146                                                              brain.reg_no)
1147        images_dir = getImagesDir(student_id)
1148        #images_dir = os.path.join("%s" % images_base,student_id)
1149        letter_dir,student_dir = os.path.split(images_dir)
1150        if not os.path.exists(letter_dir):
1151            os.mkdir(letter_dir)
1152        if not os.path.exists(images_dir):
1153            os.mkdir(images_dir)
1154        image_name = os.path.join(images_dir,"passport_%(student_id)s.jpg" % vars())
1155        if os.path.exists(app_picture):
1156            copy2(app_picture,image_name)
1157        else:
1158            logger.info('passport of %s/%s not found: %s' % (student_id,
1159                                                             brain.reg_no,
1160                                                             app_picture))
1161
1162        self.do_timing()
1163        self.print_timing()
1164        if with_timing:
1165            self.timer_step = 0
1166            self._v_timer_count += 1
1167            self._v_total += self.total_time
1168        return student_id
1169    ###)
1170
1171    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
1172    def makeStudentLevel(self,student_id):
1173        "create the StudyLevel for a returning Student"
1174        #import pdb;pdb.set_trace()
1175        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
1176        students_folder = self.portal_url.getPortalObject().campus.students
1177        res = self.students_catalog(id=student_id)
1178        if res:
1179            st = res[0]
1180        course = st.course
1181        matric_no = st.matric_no
1182        level = st.level
1183        res = self.results_import(matric_no = matric_no)
1184        if res:
1185            results = res
1186        logger.info('%s creating Level %s' % (student_id,level))
1187        #
1188        # Level
1189        #
1190        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1191        studycourse = getattr(student_obj,"study_course",None)
1192        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
1193        l = getattr(studycourse,level,None)
1194        if l is None:
1195            studycourse.invokeFactory('StudentStudyLevel', level)
1196            l = getattr(studycourse, level)
1197            self.portal_workflow.doActionFor(l,'open',dest_container=l)
1198            l.getContent().edit(mapping={'Title': "Level %s" % level})
1199        ###)
1200       
1201       
1202    security.declareProtected(ModifyPortalContent,'makeStudentLevel') ###(
1203    def exportAllStudyLevels(self,student_id):
1204        "export the StudyLevels for a student"
1205        #import pdb;pdb.set_trace()
1206        logger = logging.getLogger('WAeUPTool.exportAllStudyLevels')
1207        students_folder = self.portal_url.getPortalObject().campus.students
1208        res = self.students_catalog(id=student_id)
1209        if res:
1210            st = res[0]
1211        course = st.course
1212        matric_no = st.matric_no
1213        level = st.level
1214        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1215        studycourse = getattr(student_obj,"study_course",None)
1216        if studycourse:
1217            levels = studycourse.objectIds()
1218        else:
1219            levels = []
1220        stool = getToolByName(self, 'portal_schemas')
1221        schema = stool._getOb('student_study_level')
1222        fields = ['student_id','level']
1223        fields.extend(schema.keys())
1224        format = '"%(' + ')s","%('.join(fields) + ')s"'
1225        export_file = "%s/export/study_levels_removed.csv" % (i_home)
1226       
1227        if not os.path.exists(export_file): 
1228            file_handler = open(export_file,"a")
1229            headline = ','.join(fields)
1230            file_handler.write(headline +'\n')
1231        else:
1232            file_handler = open(export_file,"a")
1233       
1234        for level in levels:
1235            level_object = getattr(studycourse,level)
1236            level_content = level_object.getContent()
1237            d = {'student_id':student_id,'level':level}
1238            for field in schema.keys():
1239                d[field] = getattr(level_content,field,'')   
1240            line = format % d
1241            file_handler.write(line +'\n')               
1242           
1243        ###)       
1244
1245    security.declarePublic('getHallInfo') ###(
1246    def getHallInfo(self,bed):
1247        """return Hall Info"""
1248        info = {}
1249        bedsplit = bed.split('_')
1250        if len(bedsplit) == 4:
1251            hall,block,room,letter = bed.split('_')
1252        else:
1253            info['maintenance_code'] = 'None'
1254            return info
1255        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="AccoHall",id=hall)
1256        if res and len(res) == 1:
1257            hall_brain = res[0]
1258            hall_doc = hall_brain.getObject().getContent()
1259        else:
1260            return info
1261        info['hall_title'] = hall_brain.Title
1262        info['maintenance_code'] = hall_doc.maintenance_code
1263        res = ZCatalog.searchResults(self.portal_catalog_real,portal_type="ScratchCardBatch")
1264        batch_doc = None
1265        # Pick the first pin batch which the right prefix. This may cause problems if old maintenance fee batches exist.
1266        # They must be removed first. 
1267        for brain in res:
1268            if brain.id.startswith(info['maintenance_code']):
1269                batch_doc = brain.getObject().getContent()
1270                break
1271        if batch_doc is None:
1272            info['maintenance_fee'] = ''
1273        else:
1274            info['maintenance_fee'] = batch_doc.cost
1275        return info
1276    ###)
1277
1278    security.declareProtected(ModifyPortalContent,'removePictureFolder') ###(
1279    def removePictureFolder(self,student_id):
1280        """remove picture_folder by renaming it"""
1281        picture_path = getImagesDir(student_id)
1282        dest_path = os.path.join("%s" % images_base,'removed',student_id)
1283        dest_path = dest_path + "_removed"
1284        if os.path.exists(dest_path) or not os.path.exists(picture_path):
1285            return False
1286        os.rename(picture_path,dest_path)
1287        return True
1288    ###)
1289
1290    security.declareProtected(ModifyPortalContent,'restorePictureFolder') ###(
1291    def restorePictureFolder(self,student_id):
1292        """restore picture_folder by renaming it"""
1293        picture_path = getImagesDir(student_id)
1294        orig_path = os.path.join("%s" % images_base,'removed',student_id)
1295        orig_path = orig_path + "_removed"
1296        if os.path.exists(picture_path) or not os.path.exists(orig_path):
1297            return False       
1298        os.rename(orig_path,picture_path)
1299        return True
1300    ###)
1301
1302    security.declarePublic('picturesExist') ###(
1303    def picturesExist(self, ids,student_id=None):
1304        """check if pictures exist in the filesystem"""
1305        if student_id is None:
1306            student_id = self.getStudentId()
1307        if student_id is None:
1308            return False
1309        picture_path = getImagesDir(student_id)
1310        #picture_path = os.path.join(images_base,student_id)
1311        if not os.path.exists(picture_path):
1312            return False
1313        pictures  = [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1314        return set(ids).issubset(set(pictures))
1315    ###)
1316   
1317        security.declarePublic('picturePathExists') ###(
1318    def picturePathExists(self, student_id=None):
1319        """check if picture path exists in the filesystem"""
1320        if student_id is None:
1321            student_id = self.getStudentId()
1322        if student_id is None:
1323            return False
1324        picture_path = getImagesDir(student_id)
1325        if os.path.exists(picture_path):
1326            return True
1327        return False
1328    ###)
1329   
1330   
1331    security.declareProtected(ModifyPortalContent,'removeUnusedImageFolders') ###(
1332    def removeUnusedImageFolders(self):
1333        """check if an unused image folders exists in the filesystem"""
1334        mtool = self.portal_membership
1335        member = mtool.getAuthenticatedMember()
1336        member_id = str(member)
1337        logger = logging.getLogger('WAeUPTool.removeUnusedImageFolders')
1338        abc = os.listdir(images_base)
1339        ifolders = []
1340        for i in abc:
1341            picture_path = os.path.join(images_base,i)
1342            ifolders.extend(os.listdir(picture_path))
1343        unused_ids = []
1344        for id in ifolders:
1345            res = self.students_catalog(id=id)
1346            if not res:
1347                unused_ids.append(id)
1348                #import pdb;pdb.set_trace()   
1349                if not id.endswith('removed'):
1350                    removed = self.waeup_tool.removePictureFolder(id) 
1351                    if removed:
1352                        logger.info('%s: image folder %s successfully removed' % (member_id,id))
1353                    else:
1354                        logger.info('%s: image folder %s could not be removed' % (member_id,id))
1355        return
1356       
1357    ###)   
1358
1359    security.declarePublic('picturesList') ###(
1360    def picturesList(self):
1361        """check if pictures exist in the filesystem"""
1362        path = 'images'
1363        student_id = self.getStudentId()
1364        #picture_path = os.path.join(i_home,path,student_id)
1365        picture_path = getImagesDir(student_id)
1366        if not os.path.exists(picture_path):
1367            return []
1368        return [picture[:picture.rfind('_')] for picture in os.listdir(picture_path)]
1369    ###)
1370
1371    security.declarePublic('showFsPicture') ###(
1372    def showFsPicture(self,path):
1373        """return a picture from the filesystem"""
1374        #picture_path = os.path.join(i_home,path)
1375        picture_path = os.path.join(images_base,path)
1376        response = self.REQUEST.RESPONSE
1377        #import pdb;pdb.set_trace()
1378        registry = getToolByName(self, 'mimetypes_registry')
1379        mimetype = str(registry.lookupExtension(path.lower()) or
1380                    registry.lookupExtension('file.bin'))
1381        if os.path.exists(picture_path):
1382            response.setHeader('Content-type',mimetype)
1383            return open(picture_path).read()
1384        picture_path = os.path.join(i_home,'import',path)
1385        if os.path.exists(picture_path):
1386            return open(picture_path).read()
1387    ###)
1388
1389    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
1390    def deleteAllCourses(self,department="All"):
1391        ''' delete the courses'''
1392        pm = self.portal_membership
1393        member = pm.getAuthenticatedMember()
1394
1395        if str(member) not in ("henrik","joachim"):
1396            return "not possible"
1397        if department == "All":
1398            res = self.portal_catalog({'meta_type': 'Department'})
1399        if len(res) < 1:
1400            return "No Departments found"
1401
1402        deleted = []
1403        for dep in res:
1404            cf = dep.getObject().courses
1405            if cf:
1406                cf.manage_delObjects(ids=cf.objectIds())
1407                deleted.append("deleted Courses in %s" % dep.getId)
1408        return "\r".join(deleted)
1409    ###)
1410
1411    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
1412    def getLogfileLines(self,filename="event.log",numlines=20):
1413        """Get last NUMLINES lines of logfile FILENAME.
1414
1415        Return last lines' of a file in the instances logfile directory as
1416        a list. The number of returned lines equals `numlines' or less. If
1417        less than `numlines' lines are available, the whole file ist
1418        returned. If the file can not be opened or some other error
1419        occurs, empty list is returend.
1420        """
1421        result = []
1422        lines_hit = 0
1423
1424        # We only handle files in instances' log directory...
1425        logpath = os.path.join(i_home, "log")
1426        filename = str(os.path.abspath( os.path.join( logpath, filename )))
1427        if not filename.startswith( logpath ):
1428            # Attempt to access file outside log-dir...
1429            return []
1430
1431        try:
1432            fd = file( filename, "rb" )
1433        except IOError:
1434            return []
1435        if not fd:
1436            return []
1437
1438        if os.linesep == None:
1439            linesep = '\n'
1440        else:
1441            linesep = os.linesep
1442
1443        # Try to find 'numlines' times a lineseparator, searching from end
1444        # and moving to the beginning of file...
1445        fd.seek( 0, 2) # Move to end of file...
1446        while lines_hit < numlines:
1447            if fd.read(1) == linesep[-1]: # This moves filedescriptor
1448                                          # one step forward...
1449                lines_hit += 1
1450            try:
1451                fd.seek( -2, 1) # Go two bytes back from current pos...
1452            except IOError:
1453                # We cannot go back two bytes. Maybe the file is too small...
1454                break
1455        fd.seek(2,1)
1456
1457        # Read all lines from current position...
1458        result = fd.readlines()
1459        # Remove line endings...
1460        result = [x.strip() for x in result]
1461        fd.close()
1462        return result
1463    ###)
1464
1465    security.declareProtected(ModifyPortalContent,"getCallbacksFromLog")###(
1466    def getCallbacksFromLog(self,filename):
1467        """fix Online Payment Transactions from Z2.log entries"""
1468        import transaction
1469        import random
1470        from cgi import parse_qs
1471        from urlparse import urlparse
1472        #from pdb import set_trace
1473        wftool = self.portal_workflow
1474        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1475        students_folder = self.portal_url.getPortalObject().campus.students
1476        s = r'(?P<client_ip>\S+) - (?P<member_id>\S+) \['
1477        s += r'(?P<date>.*)\] "(?P<get>.*)" (?P<codes>\d+ \d+) "'
1478        s += r'(?P<intersw>.*)" "(?P<agent>.*)"'
1479        data = re.compile(s)
1480        start = True
1481        tr_count = 1
1482        total = 0
1483        #name = 'pume_results'
1484        #name = 'epaymentsuccessful_z2log2'
1485        name = filename
1486        no_import = []
1487        imported = []
1488        logger = logging.getLogger('WAeUPTool.getFailedTransactions')
1489        try:
1490            transactions = open("%s/import/%s" % (i_home,name),"rb").readlines()
1491        except:
1492            logger.error('Error reading %s' % name)
1493            return
1494        tas = []
1495        for line in transactions:
1496            dict = {}
1497            items = data.search(line)
1498            dict['idict'] = idict = items.groupdict()
1499            #print idict
1500            #from pdb import set_trace;set_trace()
1501            urlparsed = urlparse(idict['get'][4:])
1502            #print urlparsed
1503            path = urlparsed[2].split('/')
1504            dict['student_id'] = student_id = path[8]
1505            dict['payment_id'] = payment_id = path[10]
1506            dict['qs_dict'] = qs_dict = parse_qs(urlparsed[4])
1507            tas.append(dict)
1508            tr_count += 1
1509        return tas
1510    ###)
1511
1512    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
1513    def importOnlinePaymentTransactions(self):
1514        """load Online Payment Transactions from CSV values"""
1515        import transaction
1516        import random
1517        #from pdb import set_trace
1518        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
1519        opt = self.online_payments_import
1520        students_folder = self.portal_url.getPortalObject().campus.students
1521        start = True
1522        tr_count = 1
1523        total = 0
1524        #name = 'pume_results'
1525        name = 'OnlineTransactions'
1526        no_import = []
1527        imported = []
1528        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
1529        try:
1530            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
1531        except:
1532            logger.error('Error reading %s.csv' % name)
1533            return
1534        for pay_transaction in transactions:
1535            if start:
1536                start = False
1537                logger.info('Start loading from %s.csv' % name)
1538                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
1539                no_import.append('%s,"Error"' % s)
1540                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
1541                format_error = format + ',"%(Error)s"'
1542            data = {}
1543
1544            # format of the first file sent by Tayo
1545            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
1546            #data['student_id'] = student_id = pay_transaction['Payer ID']
1547            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1548            #data['response_code'] = response_code = pay_transaction['Resp Code']
1549            #data['amount'] = amount = pay_transaction['Amount']
1550
1551            # format of the second file sent by Tayo
1552            #data['datetime'] = date = 0
1553            #data['student_id'] = student_id = pay_transaction['Payer ID']
1554            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
1555            #data['response_code'] = response_code = '00'
1556            #data['amount'] = amount = pay_transaction['Amount']
1557
1558            # format of the third file sent by Kehinde
1559            data['datetime'] = date = 0
1560            data['student_id'] = student_id = pay_transaction['customer_id']
1561            data['order_id'] = order_id = pay_transaction['merchant_reference']
1562            data['response_code'] = response_code = '00'
1563            data['amount'] = amount = pay_transaction['Amount']
1564
1565            dup = False
1566            if response_code == "12":
1567                continue
1568            try:
1569                opt.addRecord(**data)
1570            except ValueError:
1571                dup = True
1572            #from pdb import set_trace;set_trace()
1573            if dup:
1574                if response_code == "00":
1575                    try:
1576                        opt.modifyRecord(**data)
1577                    except:
1578                        logger.info("duplicate uid, order_id %(order_id)s, student_id %(student_id)s, response_code %(response_code)s" % data)
1579                        continue
1580                else:
1581                    pay_transaction['Error'] = "Duplicate order_id"
1582                    no_import.append( format_error % pay_transaction)
1583                    logger.info("duplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
1584                    continue
1585            tr_count += 1
1586            if tr_count > 1000:
1587                if len(no_import) > 0:
1588                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1589                             '\n'.join(no_import) + '\n')
1590                    no_import = []
1591                em = '%d transactions committed\n' % (tr_count)
1592                transaction.commit()
1593                regs = []
1594                logger.info(em)
1595                total += tr_count
1596                tr_count = 0
1597        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
1598                                                '\n'.join(no_import))
1599        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
1600    ###)
1601
1602    security.declareProtected(ModifyPortalContent,"importData")###(
1603    def importData(self,filename,name,edit=False,bypass_queue_catalog=False):
1604        """load data from CSV values"""
1605        import transaction
1606        import random
1607        students_folder = self.portal_url.getPortalObject().campus.students
1608        uploads_folder = self.portal_url.getPortalObject().campus.uploads
1609        pending_only = False
1610        pend_str = '--'
1611        elapse = time.time()
1612        #
1613        # preparations
1614        #
1615        if filename == pend_str:
1616            pending_only = True
1617        importer_name = ''.join([part.capitalize() for part in name.split('_')])
1618        importer = eval("%sImport" % importer_name)(self)
1619        logger = importer.logger
1620        if importer.init_errors:
1621            logger.info(importer.init_errors)
1622            return importer.init_errors
1623        member = importer.member
1624        #current = importer.current
1625        import_date = importer.import_date
1626        #
1627        # not_imported
1628        #
1629        info = importer.info
1630        data_keys = importer.data_keys
1631        csv_keys = importer.csv_keys
1632        #csv_keys.extend(info.keys())
1633        headline_mapping = dict((k,k) for k in csv_keys)
1634        #
1635        # pending
1636        #
1637        pending_path = importer.pending_path
1638        pending_tmp = importer.pending_tmp
1639        pending_backup = importer.pending_backup
1640        pending_fn = importer.pending_fn
1641        imported_path = importer.imported_path
1642        imported_fn = importer.imported_fn
1643        commit_after = importer.commit_after
1644        pending = []
1645        pending_digests = []
1646        #total_added_to_pending = 0
1647        if not pending_only:
1648            pending,pending_digests = importer.makeIdLists()
1649            pending_at_start = len(pending)
1650        datafile = open(pending_tmp,"w")
1651        pending_csv_writer = csv.DictWriter(datafile,
1652                                                    csv_keys,
1653                                                    extrasaction='ignore')
1654        pending_csv_writer.writerow(headline_mapping)
1655        datafile.close()
1656        #
1657        # imported
1658        #
1659        if not os.path.exists(imported_path):
1660            datafile = open(imported_path,"w")
1661            imported_csv_writer = csv.DictWriter(datafile,
1662                                                 csv_keys,
1663                                                 extrasaction='ignore')
1664            imported_csv_writer.writerow(headline_mapping)
1665            datafile.close()
1666        start = True
1667        tr_count = 0
1668        total = 0
1669        total_added_to_imported = 0
1670        total_pending = 0
1671        import_source_done = ""
1672        if pending_only:
1673            import_source_path = pending_path
1674        else:
1675            import_source_path = "%s/import/%s.csv" % (i_home,filename)
1676            import_source_done = "%s/import/%s.done" % (i_home,filename)
1677        if not os.path.exists(import_source_path):
1678            fn = os.path.split(import_source_path)[1]
1679            em = 'no import file %(fn)s' % vars()
1680            return em
1681        import_source_fn = os.path.split(import_source_path)[1]
1682        if not pending_only:
1683            info['imported_from'] = import_source_fn
1684        headline = csv.reader(open(import_source_path,"rb")).next()
1685        if "import_mode" not in headline:
1686            msg = 'import_mode must be in heading'
1687            return msg
1688        invalid_keys = importer.checkHeadline(headline)
1689        if invalid_keys:
1690            return 'not ignorable key(s): "%s" found in heading' % ", ".join(invalid_keys)
1691
1692        import_keys = [k.strip() for k in headline if not (k.strip().startswith('ignore')
1693                                                         or k.strip() in info.keys())]
1694        # diff2schema = set(import_keys).difference(set(importer.schema.keys()))
1695        # diff2layout = set(import_keys).difference(set(importer.layout.keys()))
1696        # if diff2schema and diff2schema != set(['id',]):
1697        #     msg = 'not ignorable key(s): "%s" found in heading' % ", ".join(diff2schema)
1698        #     return msg
1699        #
1700        # start importing
1701        #
1702        try:
1703            reader = csv.DictReader(open(import_source_path,"rb"))
1704        except:
1705            msg = 'Error reading %s.csv' % filename
1706            logger.error(msg)
1707            return msg
1708        items = [item for item in reader]
1709        total_to_import = len(items)
1710        tti_float = float(total_to_import)
1711        if pending_only:
1712            pending_at_start = total_to_import
1713        count = 0
1714        imported = []
1715        old_commit_count = 0
1716        error_count = imported_count = 0
1717        already_in = 0
1718        for record in items:
1719            item = {}
1720            empty_value_keys = []
1721            for k,v in record.items():
1722                if k is None:
1723                    continue
1724                if v:
1725                    if v == EMPTY:
1726                        empty_value_keys += k,
1727                        v = ''
1728                    item[k.strip()] = v.strip()
1729            count += 1
1730            if start:
1731                start = False
1732                adapters = [MappingStorageAdapter(importer.schema, item)]
1733                logger.info('%(member)s starts import from %(import_source_fn)s' % vars())
1734            dm = DataModel(item, adapters,context=self)
1735            ds = DataStructure(data=item,datamodel=dm)
1736            error_string = ""
1737            total += 1
1738            import_mode = item.get('import_mode','')
1739            import_method = getattr(importer, '%(import_mode)s' % vars(),None )
1740            if import_method is None:
1741                error_string += "import_mode '%(import_mode)s' is invalid" % vars()
1742            elif (import_mode in importer.required_modes and
1743                not set(importer.required_keys[import_mode]).issubset(set(item.keys()))):
1744                diff2import = set(importer.required_keys[import_mode]).difference(set(item.keys()))
1745                error_string += 'required key(s): "%s" not found in record' % ", ".join(diff2import)
1746            else:
1747                for k in import_keys:
1748                    if k not in item.keys() or k not in importer.validators.keys():
1749                        continue
1750                    if not importer.validators[k](ds,mode=import_mode):
1751                        error_string += ' ++ '
1752                        error_string += "%s: %s" % (k,self.translation_service(ds.getError(k),
1753                                                                           ds.getErrorMapping(k)))
1754            if error_string:
1755                error = error_string
1756                id = ''
1757                mapping = item
1758            else:
1759                temp_item = item.copy()
1760                temp_item.update(dm)
1761                results = import_method(temp_item)
1762                id = results[0]
1763                error = results[1]
1764                mapping = results[2]
1765            #
1766            # restore some values
1767            #
1768            for k in empty_value_keys:
1769                mapping[k] = EMPTY
1770            if mapping.has_key('sex'):
1771                #import pdb;pdb.set_trace()
1772                if mapping['sex'] == True:
1773                    mapping['sex'] = 'F'
1774                elif mapping['sex'] == False:
1775                    mapping['sex'] = 'M'
1776            if pending_only:
1777                info['imported_from'] = item['imported_from']
1778            data_string = ", ".join("%s: %s" % (k,v) for k,v in mapping.items())
1779            info['error'] = error
1780            info['import_record_no'] = count + 1
1781            mapping.update(info)
1782            log_list = []
1783            if error:
1784                error_count += 1
1785                digest = makeDigest(mapping,data_keys)
1786                if digest not in pending_digests:
1787                    pending_digests += digest,
1788                    pending.append(mapping)
1789                    if not pending_only:
1790                        log_list += "record from %(import_source_fn)s added to %(pending_fn)s, %(data_string)s, %(error)s" % vars(),
1791                else:
1792                    already_in += 1
1793                    pass
1794            else:
1795                imported_count += 1
1796                imported += mapping,
1797                log_list += "record imported and added to %(imported_fn)s from %(import_source_fn)s, %(data_string)s" % vars(),
1798            if log_list:
1799                time_till_now = time.time() - elapse
1800                percent_finished = (error_count + imported_count)/tti_float*100
1801                log_list.insert(0,("%(percent_finished)6.3f %% done in %(time_till_now)3.2fs," % vars()),)
1802                logger.info(' '.join(log_list))
1803            finished = count > total_to_import - 1
1804            must_commit = (imported_count != old_commit_count) and (not imported_count % commit_after)
1805            if must_commit:
1806                old_commit_count = imported_count
1807
1808            if must_commit or finished:
1809                if len(imported):
1810                    transaction.commit()
1811                    datafile = open(imported_path,"a")
1812                    writer = csv.DictWriter(datafile,
1813                                            csv_keys,
1814                                            extrasaction='ignore')
1815                    writer.writerows(imported)
1816                    datafile.close()
1817                    total_added_to_imported += len(imported)
1818                    imported = []
1819                if len(pending) > 0:
1820                    datafile = open(pending_tmp,"a")
1821                    writer = csv.DictWriter(datafile,
1822                                            csv_keys,
1823                                            extrasaction='ignore')
1824                    writer.writerows(pending)
1825                    datafile.close()
1826                    total_pending += len(pending)
1827                    #total_added_to_pending += len(pending)
1828                    pending = []
1829                if not finished:
1830                    msg = '%(commit_after)d records imported and committed of total %(total_added_to_imported)d\n' % vars()
1831                    logger.info(msg)
1832        elapse = time.time() - elapse
1833        if os.path.exists(pending_path):
1834            copy2(pending_path,pending_backup)
1835        copy2(pending_tmp,pending_path)
1836        msg = "finished importing from %(import_source_fn)s in %(elapse).2f seconds, " % vars()
1837        msg += "%(count)d records totally read, %(total_added_to_imported)d added to %(imported_fn)s, " % vars()
1838        if pending_only:
1839            removed_pending = pending_at_start - total_pending
1840            msg += "%(removed_pending)d removed from %(pending_fn)s" % vars()
1841        else:
1842            added_pending = total_pending - pending_at_start
1843            msg += "%(added_pending)d added to %(pending_fn)s, %(already_in)s already in %(pending_fn)s" % vars()
1844        #msg += "%(total_pending)d totally written" % vars()    # this line does not make any sense
1845        logger.info(msg)
1846        if import_source_done:
1847            copy(import_source_path,import_source_done)
1848            os.remove(import_source_path)
1849            upload = getattr(uploads_folder,os.path.split(import_source_path)[1],None)
1850            if upload is not None:
1851                upload_doc = upload.getContent()
1852                mapping = {}
1853                #mapping['import_date'] = DateTime.DateTime()
1854                mapping['import_date'] = import_date
1855                mapping['imported_by'] = importer.imported_by
1856                mapping['import_message'] = msg
1857                upload_doc.edit(mapping = mapping)
1858        os.remove(pending_tmp)
1859        return msg
1860    ###)
1861
1862    security.declareProtected(ModifyPortalContent,"moveImagesToFS")###(
1863    def moveImagesToFS(self,student_id="O738726"):
1864        "move the images to the filesystem"
1865        images_dir = getImagesDir(student_id)
1866        #images_dir = os.path.join("%s" % images_base,student_id)
1867        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1868        stool = getToolByName(self, 'portal_schemas')
1869        schemas = ['student_application',
1870                   'student_clearance',
1871                   ]
1872        created = False
1873        for schema_id in schemas:
1874            schema = stool._getOb(schema_id)
1875            object = getattr(student_folder,schema_id[len('student_'):],None)
1876            if object is None:
1877                continue
1878            doc = object.getContent()
1879            for key in schema.keys():
1880                if schema[key].meta_type != "CPS Image Field":
1881                    continue
1882                #import pdb;pdb.set_trace()
1883                image = getattr(doc,key,None)
1884                if not image or not hasattr(image,"data"):
1885                    continue
1886                if not created:
1887                    if not os.path.exists(images_dir):
1888                        os.mkdir(images_dir)
1889                    created = True
1890                filename = os.path.join(images_dir,"%(key)s_%(student_id)s.jpg" % vars())
1891                open(filename,"wb").write(str(image.data))
1892    ###)
1893
1894    security.declareProtected(ModifyPortalContent,"movePassportToFS")###(
1895    def movePassportToFS(self,student_id="O738726"):
1896        "move the passports to the filesystem"
1897        images_dir = os.path.join("%s" % i_home,'passports')
1898        student_folder = getattr(self.portal_url.getPortalObject().campus.students,student_id)
1899        stool = getToolByName(self, 'portal_schemas')
1900        schemas = ['student_application',
1901                   #'student_clearance',
1902                   ]
1903        created = False
1904        for schema_id in schemas:
1905            schema = stool._getOb(schema_id)
1906            object = getattr(student_folder,schema_id[len('student_'):],None)
1907            if object is None:
1908                continue
1909            doc = object.getContent()
1910            for key in schema.keys():
1911                if schema[key].meta_type != "CPS Image Field":
1912                    continue
1913                #import pdb;pdb.set_trace()
1914                image = getattr(doc,key)
1915                if not hasattr(image,"data"):
1916                    continue
1917                if not created:
1918                    if not os.path.exists(images_dir):
1919                        os.mkdir(images_dir)
1920                    created = True
1921                filename = os.path.join(images_dir,"%(student_id)s.jpg" % vars())
1922                open(filename,"wb").write(str(image.data))
1923    ###)
1924   
1925   
1926    security.declarePublic('getConfigParams')
1927    def getConfigParams(self,conf_id="configuration"):
1928        conf = getattr(self.portal_url.getPortalObject().campus,conf_id)
1929        conf_obj = conf.getContent()
1930        stool = getToolByName(self, 'portal_schemas')
1931        schema = stool._getOb('configuration')
1932        d = {}
1933        for key in schema.keys():
1934            d[key] = getattr(conf_obj,key,None)
1935        return d
1936
1937
1938    security.declarePublic("changeWorkflowState")
1939    def changeWorkflowState(self, content, state_id, acquire_permissions=False,
1940                            portal_workflow=None, **kw):
1941        #Change the workflow state of an object
1942        #@param content: Content obj which state will be changed
1943        #@param state_id: name of the state to put on content
1944        #@param acquire_permissions: True->All permissions unchecked and on riles and
1945        #                            acquired
1946        #                            False->Applies new state security map
1947        #@param portal_workflow: Provide workflow tool (optimisation) if known
1948        #@param kw: change the values of same name of the state mapping
1949        #@return: None
1950       
1951   
1952        if portal_workflow is None:
1953            portal_workflow = getToolByName(content, 'portal_workflow')
1954   
1955        # Might raise IndexError if no workflow is associated to this type
1956
1957        wf_def = portal_workflow.getWorkflowsFor(content)[0]
1958        wf_id= wf_def.getId()
1959   
1960        wf_state = {
1961            'action': None,
1962            'actor': None,
1963            'comments': "Setting state to %s" % state_id,
1964            'review_state': state_id,
1965            'time': DateTime.DateTime(),
1966            }
1967   
1968        # Updating wf_state from keyword args
1969        for k in kw.keys():
1970            # Remove unknown items
1971            if not wf_state.has_key(k):
1972                del kw[k]
1973        if kw.has_key('review_state'):
1974            del kw['review_state']
1975        wf_state.update(kw)
1976   
1977        portal_workflow.setStatusOf(wf_id, content, wf_state)
1978   
1979        if acquire_permissions:
1980            # Acquire all permissions
1981            for permission in content.possible_permissions():
1982                content.manage_permission(permission, acquire=1)
1983        else:
1984            # Setting new state permissions
1985            wf_def.updateRoleMappingsFor(content)
1986   
1987        # Map changes to the catalogs
1988        content.reindexObject(idxs=['allowedRolesAndUsers', 'review_state'])
1989        return
1990       
1991       
1992       
1993    security.declareProtected(ModifyPortalContent,"changeStudentState")
1994    def changeStudentState(self, content, state_id, acquire_permissions=False,
1995                            portal_workflow=None, **kw):
1996        """Change the student state of an object
1997       
1998        ChangeWorkflowState + indexing students_catalog and check for registration state
1999
2000        """
2001   
2002        if portal_workflow is None:
2003            portal_workflow = getToolByName(content, 'portal_workflow')
2004   
2005        # Might raise IndexError if no workflow is associated to this type
2006
2007        wf_def = portal_workflow.getWorkflowsFor(content)[0]
2008        wf_id= wf_def.getId()
2009        wf = portal_workflow.getWorkflowById(wf_id)
2010
2011        if not wf.states.get(state_id):
2012            return 'reg state does not exist'
2013       
2014        wf_state = {
2015            'action': None,
2016            'actor': None,
2017            'comments': "Setting state to %s" % state_id,
2018            'review_state': state_id,
2019            'time': DateTime.DateTime(),
2020            }
2021   
2022        # Updating wf_state from keyword args
2023        for k in kw.keys():
2024            # Remove unknown items
2025            if not wf_state.has_key(k):
2026                del kw[k]
2027        if kw.has_key('review_state'):
2028            del kw['review_state']
2029        wf_state.update(kw)
2030       
2031        portal_workflow.setStatusOf(wf_id, content, wf_state)
2032   
2033        if acquire_permissions:
2034            # Acquire all permissions
2035            for permission in content.possible_permissions():
2036                content.manage_permission(permission, acquire=1)
2037        else:
2038            # Setting new state permissions
2039            wf_def.updateRoleMappingsFor(content)
2040   
2041        # Map changes to the catalogs
2042        content.reindexObject(idxs=['allowedRolesAndUsers', 'review_state'])
2043        data = {}
2044        #import pdb;pdb.set_trace()
2045        student_id = content.getId()
2046        res = self.students_catalog(id=student_id)
2047        data['id'] = student_id
2048        data['review_state'] = state_id
2049        self.students_catalog.modifyRecord(**data)       
2050       
2051        return       
2052
2053
2054    security.declarePublic('web_sniffer') ###(
2055    def web_sniffer(self,domain=None,params=None):
2056        "web sniffer based on http://python-dev.blogspot.com/2008/06/python-websniffer.html"
2057   
2058        import httplib
2059        import string
2060        import os
2061       
2062        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"}
2063       
2064        path = '/'
2065        method = 'GET'
2066        profile = opera
2067        #import pdb;pdb.set_trace()
2068        conn = httplib.HTTPSConnection(domain)
2069        conn.request(method, path, params, profile)
2070        stat = conn.getresponse()
2071        headers = stat.getheaders()
2072        version = stat.version
2073        status = stat.status
2074        reason = stat.reason
2075        data = stat.read()
2076        conn.close()
2077       
2078        #file_name = domain.replace(".", "-")
2079        #file_object = open(file_name, "w")
2080        #file_object.write(data)
2081        #file_object.close()
2082       
2083        print "\n"
2084        print "WEBSNIFFER 0.1"
2085        print "+++++++++++++++++"
2086        print "\n"
2087        print "Header (Client)"
2088        print "-----------------"
2089        for key, value in profile.iteritems():
2090            print "%s \t %s" % (key, value)
2091        print "-----------------"
2092        print "\n"
2093        print "Header (Server)"
2094        print "-----------------"
2095        print "HTTP \t %s" % (version)
2096        print "Status \t %s (%s)" % (status, reason)
2097        for key, value in headers:
2098            print "%s \t %s" % (key, value)
2099        print "-----------------"
2100        print "\n"
2101        #print "Quelltext"
2102        #print "-----------------"
2103        #print "Quelltext geschrieben in File:"
2104        #print file_name
2105        #print "-----------------"
2106        #print "\n"
2107
2108
2109
2110InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.