source: WAeUP_SRP/base/WAeUPTool.py @ 3192

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

first version with import_mode per line, please copy xml files to okene.

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