source: WAeUP_SRP/branches/uli/WAeUPTool.py

Last change on this file was 1653, checked in by uli, 17 years ago

Incorporated changeset 1593:1652 of trunk into uli-branch.

  • Property svn:keywords set to Id
File size: 24.4 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 1653 2007-03-28 02:35:25Z uli $
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
29
30from Products.CMFCore.ActionProviderBase import ActionProviderBase
31from Products.CMFCore.permissions import View
32from Products.ZCatalog.ZCatalog import ZCatalog
33from Products.CMFCore.permissions import ModifyPortalContent
34from Products.CMFCore.utils import UniqueObject
35from Products.CMFCore.URLTool import URLTool
36from Students import makeCertificateCode
37from Globals import package_home,INSTANCE_HOME
38p_home = package_home(globals())
39i_home = INSTANCE_HOME
40import DateTime
41import logging
42import transaction
43import csv,re,os
44
45class WAeUPTool(UniqueObject, SimpleItem, ActionProviderBase):
46    """WAeUP tool"""
47
48    id = 'waeup_tool'
49    meta_type = 'WAeUP Tool'
50    _actions = ()
51
52    security = ClassSecurityInfo()
53    security.declareObjectProtected(View)
54
55    manage_options = ( ActionProviderBase.manage_options
56                     + SimpleItem.manage_options
57                     )
58
59
60    def generateStudentId(self,letter): ###(
61        import random
62        r = random
63        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
64        if letter == '?':
65            letter= r.choice('ABCDEFGHKLMNPQRSTUVWXY')
66        sid = "%c%d" % (letter,r.randint(99999,1000000))
67##        students = self.portal_url.getPortalObject().campus.students
68##        while hasattr(students, sid):
69##            sid = "%c%d" % (letter,r.randint(99999,1000000))
70        while self.students_catalog(id = sid):
71            sid = "%c%d" % (letter,r.randint(99999,1000000))
72        return sid
73    ###)
74
75    def generatePassword(self,s=None): ###(
76        import random
77        r = random
78        ##if letter not in ('ABCDEFGIHKLMNOPQRSTUVWXY'):
79        if s is None:
80            s = 'abcdefghklmnpqrstuvwxy23456789'
81        pw = ''
82        while len(pw) < 6:
83            pw += r.choice(s)
84        return pw
85    ###)
86
87    security.declareProtected(ModifyPortalContent,'getCredential') ###(
88    def getCredential(self,student_id):
89        "return a student password"
90        student_entry = getattr(self.portal_directories.students,student_id,None)
91        if student_entry is None:
92            return None
93        return getattr(student_entry,"password","not set")
94    ###)
95
96    security.declarePublic('checkPassword') ###(
97    def checkPassword(self,student_id,password):
98        "return a student password"
99        student_entry = getattr(self.portal_directories.students,student_id,None)
100        if student_entry is None:
101            return False
102        return getattr(student_entry,"password","not set") == password
103    ###)
104
105    security.declarePublic('editPassword') ###(
106    def editPassword(self,student_id,password):
107        "edit a student password"
108        student_entry = getattr(self.portal_directories.students,student_id,None)
109        if student_entry is None:
110            return
111        setattr(student_entry,'password',password)
112    ###)
113
114    security.declareProtected(View,'doCommit') ###(
115    def doCommit(self,logger=None):
116        "commit some transactions"
117        transaction.commit()
118    ###)
119
120    security.declarePublic('loadStudentFoto') ###(
121    def loadStudentFoto(self,student):
122        "return a student passport picture"
123        app_doc = student.application.getContent()
124        clear = student.clearance
125        clear_doc = clear.getContent()
126        matric_no = clear_doc.matric_no.upper()
127        picture1 ="%s/import/pictures_returning/%s.jpg" % (i_home,matric_no)
128        picture2 ="%s/import/pictures_returning/%s.JPG" % (i_home,matric_no)
129        #import pdb;pdb.set_trace()
130        if os.path.exists(picture1):
131            file = open(picture1)
132        elif os.path.exists(picture2):
133            file = open(picture2)
134        else:
135            return "passport picture not found %s" % picture1
136
137        outfile = file.read()
138        app_doc.manage_addFile('passport',
139                               file=outfile,
140                               title="%s.jpg" % matric_no)
141        return "successfully loaded passport picture"
142    ###)
143
144    security.declareProtected(ModifyPortalContent,'createOne') ###(
145    def createOne(self,students_folder,student_brain,letter,commit=False):
146        sid = self.waeup_tool.generateStudentId(letter)
147        students_folder.invokeFactory('Student', sid)
148        student = getattr(students_folder,sid)
149        self.portal_workflow.doActionFor(student,'return')
150        student.manage_setLocalRoles(sid, ['Owner',])
151        matric_no = student_brain.matric_no
152        jamb_reg_no = student_brain.Entryregno
153        self.students_catalog.addRecord(id = sid,
154                                           matric_no = matric_no,
155                                           jamb_reg_no = jamb_reg_no,
156                                           sex = student_brain.Sex == "F",
157                                           name = "%s %s %s" % (student_brain.Firstname,
158                                                                student_brain.Middlename,
159                                                                student_brain.Lastname)
160                                        )
161        if commit:
162            transaction.commit()
163        return sid,jamb_reg_no
164    ###)
165
166    security.declareProtected(ModifyPortalContent,'createStudent') ###(
167    def createStudent(self,dict):
168        students_folder = self.portal_url.getPortalObject().campus.students
169        sid = self.waeup_tool.generateStudentId('?')
170        students_folder.invokeFactory('Student', sid)
171        student_obj = getattr(students_folder,sid)
172        password = self.generatePassword()
173        self.makeStudentMember(sid,password)
174        status,entry_mode = dict.get('entry_mode').split('_')
175        wfaction = 'return'
176        if status == "NEW":
177            wfaction = 'admit'
178        matric_no = dict.get('matric_no')
179        email = dict.get('email')
180        level = dict.get('level')
181        jamb_reg_no = dict.get('jamb_reg_no')
182        study_course = dict.get('study_course')
183        self.portal_workflow.doActionFor(student_obj,wfaction)
184        student_obj.manage_setLocalRoles(sid, ['Owner',])
185        student_obj.invokeFactory('StudentApplication','application')
186        application = student_obj.application
187        self.portal_workflow.doActionFor(application,'open',dest_container=application)
188        da = {'Title': 'Application Data'}
189        student_obj.invokeFactory('StudentPersonal','personal')
190        da['entry_mode'] = entry_mode
191        personal = student_obj.personal
192        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
193        dp = {'Title': 'Personal Data'}
194        student_obj.invokeFactory('StudentClearance','clearance')
195        clearance = student_obj.clearance
196        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
197        dc = {'Title': 'Clearance/Eligibility Record'}
198        dc['matric_no'] = matric_no
199        da['app_email'] = dp['email'] = email
200        da['jamb_reg_no'] = jamb_reg_no
201        dp['firstname'] = dict.get('firstname')
202        dp['middlename'] = dict.get('middlename')
203        dp['lastname'] = dict.get('lastname')
204        da['jamb_lastname'] = "%(firstname)s %(middlename)s %(lastname)s" % dict
205        sex = dict.get('sex')
206        if sex:
207            da['jamb_sex'] = 'F'
208        else:
209            da['jamb_sex'] = 'M'
210        dp['sex'] = sex
211        application.getContent().edit(mapping=da)
212        self.portal_workflow.doActionFor(application,'close',dest_container=application)
213        personal.getContent().edit(mapping=dp)
214        clearance.getContent().edit(mapping=dc)
215        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
216        catd = {}
217        catd['id'] = sid
218        catd['entry_mode']= entry_mode
219        catd['email'] = email
220        catd['jamb_reg_no'] = jamb_reg_no
221        catd['matric_no'] = matric_no
222        catd['name'] = "%(firstname)s %(middlename)s %(lastname)s" % dp
223        catd['sex'] = dp['sex']
224        catd['level'] = level
225        certificate_brain = self.getCertificateBrain(study_course)
226        if certificate_brain:
227            cpath = certificate_brain.getPath().split('/')
228            catd['faculty'] = cpath[-4]
229            catd['department'] = cpath[-3]
230            catd['course'] = study_course
231        self.students_catalog.addRecord(**catd)
232        #
233        # Study Course
234        #
235        student_obj.invokeFactory('StudentStudyCourse','study_course')
236        sc = student_obj.study_course
237        self.portal_workflow.doActionFor(sc,'open',dest_container=sc)
238        dsc = {}
239        dsc['study_course'] = study_course
240        dsc['current_level'] = level
241        sc.getContent().edit(mapping=dsc)
242
243        return sid,password
244    ###)
245
246    security.declarePublic('getCertificateBrain') ###(
247    def getCertificateBrain(self,cert_id):
248        "do it"
249        res = ZCatalog.searchResults(self.portal_catalog,
250                                {'portal_type':"Certificate",
251                                      'id': cert_id})
252        if res:
253            return res[0]
254        return None
255    ###)
256
257    security.declarePublic('findStudentByMatricelNo') ###(
258    def findStudentByMatricelNo(self,matric_no):
259        "do it"
260        res = ZCatalog.searchResults(self.portal_catalog,
261                                {'portal_type':"StudentClearance",
262                                 'SearchableText': matric_no})
263        if res:
264            return res[0]
265        return None
266    ###)
267
268    security.declarePublic('makeStudentMember') ###(
269    def makeStudentMember(self,sid,password='uNsEt'):
270        """make the student a member"""
271        membership = self.portal_membership
272        membership.addMember(sid,
273                             password ,
274                             roles=('Member',
275                                     'Student',
276                                     ),
277                             domains='',
278                             properties = {'memberareaCreationFlag': False,
279                                           'homeless': True},)
280        member = membership.getMemberById(sid)
281        self.portal_registration.afterAdd(member, sid, password, None)
282        #self.manage_setLocalRoles(sid, ['Owner',])
283    ###)
284
285    security.declarePublic('makeStudentData') ###(
286    def makeStudentData(self,student_id,email=None,phone_nr=None):
287        "create Datastructure for a returning Student"
288        #import pdb;pdb.set_trace()
289        logger = logging.getLogger('WAeUPTool.makeStudentData')
290        students_folder = self.portal_url.getPortalObject().campus.students
291        res = self.students_catalog(id=student_id)
292        if res:
293            st = res[0]
294        res = self.returning_import(matric_no = st.matric_no)
295        if res:
296            student = res[0]
297        logger.info('%s creates data structure' % student_id)
298        s_results = self.results_import(matric_no = st.matric_no)
299        lnr = self.getLevelFromResultsCosCode(s_results)
300        level = "%d00" % lnr
301        verdict,elegible = self.getVerdict(s_results[0].Verdict)
302        if elegible:
303            level = "%d00" % (lnr + 1)
304##        level = s_results[0].Level
305##        for result in s_results:
306##            if level != result.Level:
307##                logger.info('"%s", "Levels differ","%s != %s"' % (student_id,level,result.Level))
308        #student should not be allowed to perform this transition
309        #wftool = self.portal_workflow
310        #wftool.doActionFor(student,'return')
311        certcode_org = student.Coursemajorcode
312        certcode = makeCertificateCode(certcode_org)
313        certificate_brain = self.getCertificateBrain(certcode)
314        if not certificate_brain:
315            em = 'Certificate %s org-code %s not found\n' % (certcode, certcode_org)
316            logger.info(em)
317        matric_no = student.matric_no
318        sid = student_id
319        student_obj = getattr(students_folder,sid)
320        student_obj.invokeFactory('StudentApplication','application')
321        application = student_obj.application
322        self.portal_workflow.doActionFor(application,'open',dest_container=application)
323        da = {'Title': 'Application Data'}
324        student_obj.invokeFactory('StudentPersonal','personal')
325        da['jamb_reg_no'] = student.Entryregno
326        em = self.getEntryMode(student.Entryregno)
327##        em = student.Mode_of_Entry
328##        if em in ('DIRECT', 'DIRECT ENTRY',):
329##            em = 'DE'
330##        elif em in ('U.M.E', 'UNE',):
331##            em = 'UME'
332##        elif not em:
333##            em = "unknown"
334        da['entry_mode'] = em
335        personal = student_obj.personal
336        self.portal_workflow.doActionFor(personal,'open',dest_container=personal)
337        dp = {'Title': 'Personal Data'}
338        student_obj.invokeFactory('StudentClearance','clearance')
339        clearance = student_obj.clearance
340        self.portal_workflow.doActionFor(clearance,'open',dest_container=clearance)
341        dc = {'Title': 'Clearance/Eligibility Record'}
342        dc['matric_no'] = matric_no
343        state = student.State
344        lga = student.LGA
345        if state and lga:
346            lga =  state + ' / ' + lga
347        else:
348            lga = "None"
349        da['jamb_lga'] = dc['lga'] = lga
350        da['app_email'] = dp['email'] = email
351        da['app_mobile'] = dp['phone'] = phone_nr
352        dp['firstname'] = student.Firstname
353        dp['middlename'] = student.Middlename
354        dp['lastname'] = student.Lastname
355        da['jamb_lastname'] = "%s %s %s" % (student.Firstname,student.Middlename,student.Lastname)
356        da['jamb_sex'] = student.Sex
357        dp['sex'] = student.Sex == 'F'
358        dp['perm_address'] = student.Permanent_Address
359        application.getContent().edit(mapping=da)
360        self.portal_workflow.doActionFor(application,'close',dest_container=application)
361        personal.getContent().edit(mapping=dp)
362        clearance.getContent().edit(mapping=dc)
363        self.portal_workflow.doActionFor(clearance,'close',dest_container=clearance)
364        catd = {}
365        catd['id'] = sid
366        catd['entry_mode']= da['entry_mode']
367        catd['matric_no'] = matric_no
368        catd['jamb_reg_no'] = da['jamb_reg_no']
369        catd['name'] = "%(firstname)s %(middlename)s %(lastname)s" % dp
370        catd['sex'] = dp['sex']
371        catd['level'] = level
372        catd['verdict'] = verdict
373        if certificate_brain:
374            cpath = certificate_brain.getPath().split('/')
375            catd['faculty'] = cpath[-4]
376            catd['department'] = cpath[-3]
377            catd['course'] = certcode
378        self.students_catalog.modifyRecord(**catd)
379        #
380        # Study Course
381        #
382        student_obj.invokeFactory('StudentStudyCourse','study_course')
383        studycourse = student_obj.study_course
384        self.portal_workflow.doActionFor(studycourse,'open',dest_container=studycourse)
385        dsc = {}
386        dsc['study_course'] = certcode
387        dsc['current_level'] = level
388        dsc['current_verdict'] = verdict
389        studycourse.getContent().edit(mapping=dsc)
390        #
391        # Level
392        #
393##        l = getattr(studycourse,level,None)
394##        if l is None:
395##            studycourse.invokeFactory('StudentStudyLevel', level)
396##            l = getattr(studycourse, level)
397##            self.portal_workflow.doActionFor(l,'open',dest_container=l)
398##            l.getContent().edit(mapping={'Title': "Level %s" % level})
399###)
400
401    security.declarePublic('makeStudentLevel') ###(
402    def makeStudentLevel(self,student_id):
403        "create the StudyLevel for a returning Student"
404        #import pdb;pdb.set_trace()
405        logger = logging.getLogger('WAeUPTool.makeStudentLevel')
406        students_folder = self.portal_url.getPortalObject().campus.students
407        res = self.students_catalog(id=student_id)
408        if res:
409            st = res[0]
410        course = st.course
411        matric_no = st.matric_no
412        level = st.level
413        res = self.results_import(matric_no = matric_no)
414        if res:
415            results = res
416        logger.info('%s creating Level %s' % (student_id,level))
417        #
418        # Level
419        #
420        student_obj = getattr(self.portal_url.getPortalObject().campus.students,student_id)
421        studycourse = getattr(student_obj,"study_course",None)
422        self.portal_workflow.doActionFor(studycourse,'close_for_edit',dest_container=studycourse)
423        l = getattr(studycourse,level,None)
424        if l is None:
425            studycourse.invokeFactory('StudentStudyLevel', level)
426            l = getattr(studycourse, level)
427            self.portal_workflow.doActionFor(l,'open',dest_container=l)
428            l.getContent().edit(mapping={'Title': "Level %s" % level})
429        ###)
430
431    security.declarePublic('getAccommodationInfo') ###(
432    def getAccommodationInfo(self,bed):
433        """return Accommodation Info"""
434        info = {}
435        hall,block,room,letter = bed.split('_')
436        res = ZCatalog.searchResults(self.portal_catalog,portal_type="AccoHall",id=hall)
437        if res and len(res) == 1:
438            hall_brain = res[0]
439            hall_doc = hall_brain.getObject().getContent()
440        else:
441            return info
442        info['hall_title'] = hall_brain.Title
443        info['maintenance_code'] = hall_doc.maintenance_code
444        res = ZCatalog.searchResults(self.portal_catalog,portal_type="ScratchCardBatch")
445        batch_doc = None
446        for brain in res:
447            if brain.id.startswith(info['maintenance_code']):
448                batch_doc = brain.getObject().getContent()
449                break
450        if batch_doc is None:
451            info['maintenance_fee'] = None
452        else:
453            info['maintenance_fee'] = batch_doc.cost
454        return info
455    ###)
456
457    security.declareProtected(ModifyPortalContent,'deleteAllCourses') ###(
458    def deleteAllCourses(self,department="All"):
459        ''' delete the courses'''
460        pm = self.portal_membership
461        member = pm.getAuthenticatedMember()
462
463        if str(member) not in ("henrik","joachim"):
464            return "not possible"
465        if department == "All":
466            res = self.portal_catalog({'meta_type': 'Department'})
467        if len(res) < 1:
468            return "No Departments found"
469
470        deleted = []
471        for dep in res:
472            cf = dep.getObject().courses
473            if cf:
474                cf.manage_delObjects(ids=cf.objectIds())
475                deleted.append("deleted Courses in %s" % dep.getId)
476        return "\r".join(deleted)
477    ###)
478
479    security.declareProtected(ModifyPortalContent,'getLogfileLines') ###(
480    def getLogfileLines(self,filename="event.log",numlines=20):
481        """Get last NUMLINES lines of logfile FILENAME.
482
483        Return last lines' of a file in the instances logfile directory as
484        a list. The number of returned lines equals `numlines' or less. If
485        less than `numlines' lines are available, the whole file ist
486        returned. If the file can not be opened or some other error
487        occurs, empty list is returend.
488        """
489        result = []
490        lines_hit = 0
491
492        # We only handle files in instances' log directory...
493        logpath = os.path.join(i_home, "log")
494        filename = str(os.path.abspath( os.path.join( logpath, filename )))
495        if not filename.startswith( logpath ):
496            # Attempt to access file outside log-dir...
497            return []
498
499        try:
500            fd = file( filename, "rb" )
501        except IOError:
502            return []
503        if not fd:
504            return []
505
506        if os.linesep == None:
507            linesep = '\n'
508        else:
509            linesep = os.linesep
510
511        # Try to find 'numlines' times a lineseparator, searching from end
512        # and moving to the beginning of file...
513        fd.seek( 0, 2) # Move to end of file...
514        while lines_hit < numlines:
515            if fd.read(1) == linesep[-1]: # This moves filedescriptor
516                                          # one step forward...
517                lines_hit += 1
518            try:
519                fd.seek( -2, 1) # Go two bytes back from current pos...
520            except IOError:
521                # We cannot go back two bytes. Maybe the file is too small...
522                break
523        fd.seek(2,1)
524
525        # Read all lines from current position...
526        result = fd.readlines()
527        # Remove line endings...
528        result = [x.strip() for x in result]
529        fd.close()
530        return result
531    ###)
532
533    security.declareProtected(ModifyPortalContent,"importOnlinePaymentTransactions")###(
534    def importOnlinePaymentTransactions(self):
535        """load Online Payment Transactions from CSV values"""
536        import transaction
537        import random
538        #from pdb import set_trace
539        current = DateTime.DateTime().strftime("%d-%m-%y_%H_%M_%S")
540        opt = self.online_payments_import
541        students_folder = self.portal_url.getPortalObject().campus.students
542        start = True
543        tr_count = 1
544        total = 0
545        #name = 'pume_results'
546        name = 'OnlineTransactions'
547        no_import = []
548        imported = []
549        logger = logging.getLogger('WAeUPTool.importOnlinePaymentTransactions')
550        try:
551            transactions = csv.DictReader(open("%s/import/%s.csv" % (i_home,name),"rb"))
552        except:
553            logger.error('Error reading %s.csv' % name)
554            return
555        for pay_transaction in transactions:
556            if start:
557                start = False
558                logger.info('Start loading from %s.csv' % name)
559                s = ','.join(['"%s"' % fn for fn in pay_transaction.keys()])
560                no_import.append('%s,"Error"' % s)
561                format = ','.join(['"%%(%s)s"' % fn for fn in pay_transaction.keys()])
562                format_error = format + ',"%(Error)s"'
563            data = {}
564
565            # format of the first file sent from Tayo
566            #data['datetime'] = date = DateTime.DateTime(pay_transaction['Date'])
567            #data['student_id'] = student_id = pay_transaction['Payer ID']
568            #data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
569            #data['response_code'] = response_code = pay_transaction['Resp Code']
570            #data['amount'] = amount = pay_transaction['Amount']
571
572            # format of the second file sent from Tayo
573            data['datetime'] = date = 0
574            data['student_id'] = student_id = pay_transaction['Payer ID']
575            data['order_id'] = order_id = pay_transaction['Order ID (Tranx Ref)']
576            data['response_code'] = response_code = '00'
577            data['amount'] = amount = pay_transaction['Amount']
578
579            dup = False
580            if response_code == "12":
581                continue
582            try:
583                opt.addRecord(**data)
584            except ValueError:
585                dup = True
586            #from pdb import set_trace;set_trace()
587            if dup:
588                if response_code == "00":
589                    opt.modifyRecord(**data)
590                else:
591                    pay_transaction['Error'] = "Duplicate order Id"
592                    no_import.append( format_error % pay_transaction)
593                    logger.info("dupplicate order_id %(order_id)s for %(student_id)s %(response_code)s" % data)
594                    continue
595            tr_count += 1
596            if tr_count > 1000:
597                if len(no_import) > 0:
598                    open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
599                             '\n'.join(no_import) + '\n')
600                    no_import = []
601                em = '%d transactions committed\n' % (tr_count)
602                transaction.commit()
603                regs = []
604                logger.info(em)
605                total += tr_count
606                tr_count = 0
607        open("%s/import/%s_not_imported%s.csv" % (i_home,name,current),"a").write(
608                                                '\n'.join(no_import))
609        return self.REQUEST.RESPONSE.redirect("%s" % self.REQUEST.get('URL1'))
610    ###)
611
612InitializeClass(WAeUPTool)
Note: See TracBrowser for help on using the repository browser.