Changeset 17

Show
Ignore:
Timestamp:
11/18/08 17:38:53 (7 weeks ago)
Author:
mbertoldi
Message:
 
Location:
gnrpy/gnr/web
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • gnrpy/gnr/web/gnrwebpage_old.py

    r8 r17  
    1 # -*- coding: UTF-8 -*- 
    2 #-------------------------------------------------------------------------- 
    3 # package           : GenroPy web - see LICENSE for details 
    4 # module gnrwebcore : core module for genropy web framework 
    5 # Copyright (c)     : 2004 - 2007 Softwell sas - Milano  
    6 # Written by        : Giovanni Porcari, Francesco Cavazzana 
    7 #                     Saverio Porcari, Francesco Porcari 
    8 #-------------------------------------------------------------------------- 
    9 #This library is free software; you can redistribute it and/or 
    10 #modify it under the terms of the GNU Lesser General Public 
    11 #License as published by the Free Software Foundation; either 
    12 #version 2.1 of the License, or (at your option) any later version. 
     1#try: 
     2#from mod_python import apache 
     3#from gnr.web.apache.gnrwebpage_apache import * 
     4#except ImportError: 
     5#    from gnr.web.wsgi.gnrwebpage_wsgi import * 
     6try: 
     7    from mod_python import apache 
     8    is_apache=True 
     9except ImportError: 
     10    is_apache=False 
    1311 
    14 #This library is distributed in the hope that it will be useful, 
    15 #but WITHOUT ANY WARRANTY; without even the implied warranty of 
    16 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
    17 #Lesser General Public License for more details. 
    18  
    19 #You should have received a copy of the GNU Lesser General Public 
    20 #License along with this library; if not, write to the Free Software 
    21 #Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 
    22  
    23  
    24 """ 
    25 core.py 
    26  
    27 Created by Giovanni Porcari on 2007-03-24. 
    28 Copyright (c) 2007 Softwell. All rights reserved. 
    29 """ 
    30 import md5 
    31 import os, sys 
    32 import re 
    33 import time 
    34 import datetime 
    35 import traceback 
    36 import weakref 
    37 import random 
    38 import itertools 
    39 import urllib 
    40 import zipfile 
    41 import StringIO 
    42 from decimal import Decimal 
    43  
    44 from gnr.core.gnrlog import gnrlogging 
    45 from gnr.core.gnrlang import optArgs 
    46 from gnr.core.gnrlang import gnrImport 
    47  
    48 gnrlogger = gnrlogging.getLogger('gnr.web.gnrwebcore') 
    49  
    50 from mod_python import apache, Session, Cookie 
    51 from mako.template import Template 
    52  
    53 import simplejson as json 
    54  
    55 from mako.lookup import TemplateLookup 
    56  
     12if is_apache: 
     13    from gnr.web.apache.gnrwebpage_apache import * 
     14else: 
     15    from gnr.web.wsgi.gnrwebpage_wsgi import * 
    5716from gnr.core.gnrbag import Bag, DirectoryResolver, TraceBackResolver, TxtDocResolver, UrlResolver, XmlDocResolver, BagFormula 
    5817 
    59 from gnr.core.gnrlang import GnrObject 
    60 from gnr.core import gnrlist 
    61  
    62 from gnr.core.gnrlang import getUuid 
    63 from gnr.core.gnrstring import templateReplace, splitAndStrip, countOf, toText, toJson, concat 
    64 from gnr.core import gnrdate 
    65  
    66 from gnr.web.jsmin import jsmin 
    67  
    68 from gnr.web.gnrwebstruct import GnrDomSrc_dojo_12, GnrDomSrc_dojo_11, GnrGridStruct 
    69 from gnr.web.gnrwebapp import GnrWebApp 
    70  
    71 from gnr.sql.gnrsqldata import SqlRelatedSelectionResolver, SqlRelatedRecordResolver 
    72  
    73 CONNECTION_TIMEOUT = 3600 
    74 CONNECTION_REFRESH = 20 
    75 AUTH_OK=0 
    76 AUTH_NOT_LOGGED=1 
    77 AUTH_FORBIDDEN=-1 
    78  
    79 class GrowlStub(object): 
    80     def notify(self, *args, **kwargs): 
    81         pass 
    82      
    83 class GnrWebClientError(Exception): 
    84     pass 
    85  
    86 class GnrWebServerError(Exception): 
    87     pass 
    88      
    89 class GnrWebPage(GnrObject): 
    90     def __init__(self, req, customclass, filepath, page_id=None, 
    91                  _rpc_resultPath=None, _dk_=None, xxcnt=None, _user_login=None, **kwargs): 
    92         self._rpc_resultPath=_rpc_resultPath 
    93         self.request = req 
    94         req.headers_out["Pragma"] = "no-cache" 
    95          
    96         self.page_id = page_id or getUuid() 
    97         self._dk=_dk_ 
    98         self.filepath = filepath # TOGLIERE ???? 
    99         self._user_login = _user_login 
    100         self.kwargs = kwargs 
    101         self._htmlHeaders=[] 
    102         self._ctxData = Bag() 
    103         self.folders= {'pages':req.hlist.directory, 
    104                        'site':os.path.dirname(req.hlist.directory), 
    105                        'current':os.path.dirname(req.filename), 
    106                        'document_root': self.request.document_root().rstrip('/') # the path may end with / or not depending to httpd.config 
    107                        } 
    108         self.filename = req.filename 
    109         self.pagename = os.path.splitext(os.path.basename(self.filename))[0] 
    110         self.pagepath = self.filename.replace(self.folders['pages'], '') 
    111  
    112         self.theme = getattr(customclass, 'theme', None) or self.config['dojo?theme'] or 'tundra' 
    113         self.dojoversion = getattr(customclass, 'dojoversion', None) or self.config['dojo?version'] or '11' 
    114         self.pagetemplate = getattr(customclass, 'pagetemplate', None) or self.config['dojo?pagetemplate'] 
    115         self.maintable = getattr(customclass, 'maintable', None) 
    116         self.js_requires = splitAndStrip( getattr(customclass, 'js_requires', ''),',') 
    117         self.css_requires = splitAndStrip(getattr(customclass, 'css_requires', ''),',') 
    118         py_requires = splitAndStrip(getattr(customclass, 'py_requires', '') ,',') 
    119         self.eagers = getattr(customclass, 'eagers', {}) 
    120         self._baseMixins() 
    121         self._pyrequiresMixin(py_requires) 
    122         self.mixin(customclass) 
    123         self._customPageMixins() 
    124         self.css_requires.reverse() 
    125          
    126     def getUuid(self): 
    127         return getUuid() 
    128          
    129     def _baseMixins(self): 
    130         pkgId = self.packageId 
    131         pkg=None 
    132         if pkgId: 
    133             pkg = self.application.packages[pkgId] 
    134         if pkg: 
    135             self.mixin(pkg.webPageMixin) # first the package standard 
    136         self.mixin(self.application.webPageCustom) # then the application custom 
    137         if pkg: 
    138             self.mixin(pkg.webPageMixinCustom) # finally the package custom 
    139  
    140     def _customPageMixins(self): 
    141         """Look in the instance custom folder for a file named as the current webpage""" 
    142         if self.packageId: 
    143             filepath = self.pagepath.split('/',1) 
    144             if len(filepath) == 2: #the page is into a package, not root level 
    145                 filepath = filepath[1] 
    146                 customPagePath=os.path.join(self.application.customFolder, self.packageId, 'webpages', filepath) 
    147                 if os.path.isfile(customPagePath): 
    148                     raise self.filename 
    149                     self.mixin('%s:%s' % (customPagePath,'WebPage')) 
    150                  
    151     def _pyrequiresMixin(self, py_requires): 
    152         for mix in py_requires: 
    153             if mix: 
    154                 modName, clsName = mix.split(':') 
    155                 modPathList = self.getResourceList(modName, 'py') or [] 
    156                 if modPathList: 
    157                     modPathList.reverse() 
    158                     for modPath in modPathList: 
    159                         self.mixin('%s:%s' % (modPath, clsName)) 
    160                 else: 
    161                     raise GnrWebServerError('Cannot import component %s' % modName) 
    162  
    163          
    164     def index(self ,**kwargs): 
    165         self.kwargs.update(kwargs) 
    166         self.onInit() 
    167         if self._user_login: 
    168             user=self.user # if we have an embedded login we get the user right now 
    169          
    170         try: 
    171             if 'mako' in self.kwargs: 
    172                 result = self.makoTemplate(path=self.kwargs['mako'], **self.kwargs) 
    173             elif 'method' in self.kwargs: 
    174                 result = self._rpcDispatcher(**self.kwargs) 
    175             else: 
    176                 result = self.indexPage() 
    177                 self.session.loadSessionData() 
    178                 self.session.pagedata['pageArgs'] = self.kwargs 
    179                 self.session.pagedata['page_id'] = self.page_id 
    180                 self.session.pagedata['connection_id'] = self.connection.connection_id 
    181                 self.session.pagedata['pagepath'] = self.pagepath 
    182                 self.session.saveSessionData() 
    183         except: 
    184             self._onEnd() 
    185             raise 
    186         self._onEnd() 
    187         return result 
    188          
    189     def addHtmlHeader(self,tag,innerHtml='',**kwargs): 
    190         attrString=' '.join(['%s="%s"' % (k,str(v)) for k,v in kwargs.items()]) 
    191         self._htmlHeaders.append('<%s %s>%s</%s>'%(tag,attrString,innerHtml,tag)) 
    192          
    193     def _css_dojo_d10(self): 
    194         return ['dojo/resources/dojo.css', 
    195                 'dijit/themes/dijit.css', 
    196                 'dijit/themes/%s/tundra.css' % self.theme, 
    197                 'dojox/grid/_grid/Grid.css', 
    198                 'dojox/grid/_grid/%sGrid.css' % self.theme 
    199                 ] 
    200      
    201     def _gnrjs_d10(self): 
    202         return ['gnrbag','genro', 'genro_widgets', 'genro_rpc',  
    203                                            'genro_dev','genro_dlg','genro_frm','genro_dom','gnrdomsource', 
    204                                            'genro_wdg','genro_src','gnrlang','gnrstores'] 
    205      
    206     def _css_genro_d10(self): 
    207            return {'all': ['gnrbase','gnricons'], 'print':['gnrprint']} 
    208      
    209     def _css_dojo_d11(self): 
    210         return ['dojo/resources/dojo.css', 
    211                 'dijit/themes/dijit.css', 
    212                 'dijit/themes/%s/tundra.css' % self.theme, 
    213                 'dojox/grid/_grid/Grid.css', 
    214                 'dojox/grid/_grid/%sGrid.css' % self.theme 
    215                 ] 
    216      
    217     def _gnrjs_d11(self): 
    218         return ['gnrbag','genro', 'genro_widgets', 'genro_rpc', 'genro_patch', 
    219                                            'genro_dev','genro_dlg','genro_frm','genro_dom','gnrdomsource', 
    220                                            'genro_wdg','genro_src','gnrlang','gnrstores'] 
    221      
    222     def _css_genro_d11(self): 
    223            return {'all': ['gnrbase'], 'print':['gnrprint']} 
    224  
    225     def get_css_genro(self, gnrlibpath): 
    226         css_genro = getattr(self, '_css_genro_d%s' % self.dojoversion)() 
    227         for media in css_genro.keys(): 
    228             css_genro[media] = [self.resolvePathAsUrl('gnrjs',gnrlibpath,'css', '%s.css' % f, folder='*lib') for f in css_genro[media]] 
    229         return css_genro 
    230          
    231     def get_css_requires(self): 
    232         filename = os.path.splitext(os.path.basename(self.filename))[0] 
    233         css_requires=[] 
    234         for css in self.css_requires: 
    235             if css: 
    236                 csslist = self.getResourceList(css,'css') 
    237                 if csslist: 
    238                     csslist.reverse() 
    239                     css_requires.extend( [self.diskPathToUri(css) for css in csslist]) 
    240         if os.path.isfile(self.resolvePath('%s.css' % filename)): 
    241             css_requires.append(self.resolvePathAsUrl('%s.css' % filename))            
    242         return css_requires 
    243  
    244     def get_bodyclasses(self): 
    245         return '%s _common_d%s pkg_%s page_%s' % (self.theme, self.dojoversion, self.packageId, self.pagename) 
    246      
    247     def getPublicMethod(self, prefix, method): 
    248         if '.' in method: 
    249             group, submethod = method.split('.',1) 
    250             handler = getattr(self, group) 
    251             if handler: 
    252                 handler = getattr(handler, '%s_%s' % (prefix,submethod)) 
    253         else: 
    254             handler = getattr(self, '%s_%s' % (prefix,method)) 
    255         return handler 
    256                  
    257     def htmlHeaders(self): 
    258         pass 
    259          
    260     def indexPage(self): 
    261         startArgs = dict(self.kwargs) 
    262         charset='utf-8',  
    263          
    264         filename = os.path.splitext(os.path.basename(self.filename))[0] 
    265         dirname=os.path.dirname(self.filename) 
    266         if not self.pagetemplate: 
    267            tpl = 'standard.tpl' 
    268         else: 
    269            if isinstance(self.pagetemplate, basestring): 
    270                tpl = self.pagetemplate 
    271            else: 
    272                tpl = '%s.%s' % (self.pagename, 'tpl')     
    273         tpldirectories=[os.path.dirname(self.request.filename)]+self.resourceDirs+[self.resolvePath('gnrjs','gnr_d%s' % self.dojoversion,'tpl',folder='*lib')] 
    274         lookup=TemplateLookup(directories=tpldirectories, output_encoding='utf-8', encoding_errors='replace') 
    275         try: 
    276             mytemplate = lookup.get_template(tpl) 
    277         except: 
    278             raise str("No template %s found in %s" % (tpl, str(tpldirectories))) 
    279          
    280          
    281         arg_dict = {} 
    282         self.htmlHeaders() 
    283         arg_dict['customHeaders']=self._htmlHeaders 
    284         arg_dict['charset'] = 'utf-8' 
    285         arg_dict['filename'] = self.pagename 
    286         arg_dict['startArgs'] = toJson(startArgs) 
    287         arg_dict['page_id'] = self.page_id or getUuid() 
    288         arg_dict['bodyclasses'] = self.get_bodyclasses() 
    289         arg_dict['dojolib'] = self.resolvePathAsUrl('dojo/dojo_%s/dojo/dojo.js'%self.dojoversion, folder='*lib') 
    290         arg_dict['djConfig'] = "parseOnLoad: false, isDebug: true, locale: '%s'" % self.locale 
    291         arg_dict['gnrModulePath'] = '../../gnrjs' 
    292  
    293         gnrimports = getattr(self, '_gnrjs_d%s' % self.dojoversion)() 
    294         gnrlibpath='gnr_d%s' % self.dojoversion 
    295          
    296         debug = startArgs.get('jsdebug') 
    297         if True or debug: 
    298             arg_dict['genroJsImport'] = [self.resolvePathAsUrl('gnrjs', gnrlibpath,'js', '%s.js' % f, folder='*lib') for f in gnrimports] 
    299         else: 
    300             jsfiles = [self.resolvePath('gnrjs', gnrlibpath,'js', '%s.js' % f, folder='*lib') for f in gnrimports] 
    301             arg_dict['genroJsImport'] = ['?method=jscompress&mode=text&js=%s' % self._jscompress(jsfiles)] 
    302              
    303          
    304         css_dojo = getattr(self, '_css_dojo_d%s' % self.dojoversion)() 
    305         arg_dict['css_dojo'] = [self.resolvePathAsUrl('dojo/dojo_%s/%s' % (self.dojoversion,f), folder='*lib') for f in css_dojo] 
    306  
    307         arg_dict['css_genro'] = self.get_css_genro(gnrlibpath) 
    308  
    309         js_requires = [x for x in [self.getResourceUri(r,'js') for r in self.js_requires ] if x] 
    310         if os.path.isfile(self.resolvePath('%s.js' % self.pagename)): 
    311            js_requires.append('%s.js' % self.pagename) 
    312         arg_dict['js_requires'] = js_requires 
    313          
    314         arg_dict['css_requires'] = self.get_css_requires() 
    315          
    316         return mytemplate.render(mainpage=self, **arg_dict) 
    317  
    318     def _jscompress(self, jsfiles): 
    319         ts = str(max([os.path.getmtime(fname) for fname in jsfiles])) 
    320         key = '-'.join(jsfiles) 
    321         cpfile = '%s.js' % md5.md5(key).hexdigest() 
    322          
    323         cppath = self.resolvePath('temp','js', cpfile, folder='*data') 
    324          
    325         rebuild = True 
    326         if os.path.isfile(cppath): 
    327             cpf = file(cppath, 'r') 
    328             tsf = cpf.readline() 
    329             cpf.close() 
    330             if ts in tsf: 
    331                 rebuild = False 
    332         if rebuild: 
    333             self.createFolderInData('temp','js') 
    334             cpf = file(cppath, 'w') 
    335             cpf.write('// %s\n' % ts) 
    336             for fname in jsfiles: 
    337                 f = file(fname) 
    338                 js = f.read() 
    339                 f.close() 
    340                 cpf.write(jsmin(js)) 
    341                 cpf.write('\n\n\n\n') 
    342             cpf.close() 
    343         return cpfile 
    344          
    345     def rpc_jscompress(self, js, **kwargs): 
    346         cppath = self.resolvePath('temp','js', js, folder='*data') 
    347         f = file(cppath) 
    348         js = f.read() 
    349         f.close() 
    350         return js 
    351  
    352     def rpc_decodeDatePeriod(self, datestr, workdate=None, locale=None): 
    353         workdate = workdate or self.workdate 
    354         locale = locale or self.locale 
    355         try: 
    356             returnDate = gnrdate.decodeDatePeriod(datestr, workdate=workdate, locale=locale, returnDate=True) 
    357         except: 
    358             returnDate = (None, None) 
    359         result = Bag() 
    360         result['from'] = returnDate[0] 
    361         result['to'] = returnDate[1] 
    362         result['prev_from'] = gnrdate.dateLastYear(returnDate[0]) 
    363         result['prev_to'] = gnrdate.dateLastYear(returnDate[1]) 
    364         return result 
    365          
    366     def rpc_ping(self, **kwargs): 
    367         pass 
    368      
    369     def rpc_setInServer(self, path, value=None, **kwargs): 
    370         self.session.modifyPageData(path, value) 
    371          
    372     #def rpc_eval(self, expr): 
    373     #    if self.request.get_remote_host() == '127.0.0.1': 
    374     #        return eval(expr) 
    375     #    else: 
    376     #        raise apache.SERVER_RETURN, apache.HTTP_UNAUTHORIZED 
    377  
    378     def onEnd(self): 
    379         pass 
    380  
    381     def _onEnd(self): 
    382         if hasattr(self, '_localizer'): 
    383             self.session.loadSessionData() 
    384             localization={} 
    385             localization.update(self.session.pagedata['localization'] or {}) 
    386             localization.update(self.localizer) 
    387             self.session.setInPageData('localization', localization) 
    388             self.session.saveSessionData() 
    389              
    390         if hasattr(self, '_connection'): 
    391             self.connection._finalize() 
    392         if hasattr(self, '_app'): 
    393             self._app._finalize(self) 
    394         self.onEnd() 
    395          
    396     def mixins(self): 
    397         """Implement this method in your page for mixin the page with methods from the local _resources folder 
    398         @return: list of mixin names, moduleName:className""" 
    399         return [] 
    400      
    401     def onInit(self): 
    402         # subclass hook 
    403         pass 
    404          
    405     def requestWrite(self, txt, encoding='utf-8'): 
    406         self.request.write(txt.encode(encoding))  
    407  
    408     def gnotify(self, title, description, always=False): 
    409         if always or self.pageArgs.get('pydebug') : 
    410             self.growl.notify('apache_log', title, description) 
    411          
    412     def _get_growl(self): 
    413         if not hasattr(self, '_growl'): 
    414             try: 
    415                 from Growl import GrowlNotifier 
    416                 self._growl = GrowlNotifier(applicationName='Apache', notifications=['apache_log']) 
    417                 self._growl.register() 
    418             except: 
    419                 self._growl = GrowlStub() 
    420         return self._growl 
    421     growl = property(_get_growl) 
    422      
    423     def log(self, msg): 
    424         if getattr(self, 'debug', False): 
    425             f = file(self.logfile, 'a') 
    426             f.write('%s -- %s\n' % (datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), msg)) 
    427             f.close() 
    428              
    429     def _get_localizer(self):  
    430         if not hasattr(self, '_localizer'): 
    431             self._localizer={} 
    432             self.missingLoc=False 
    433         return self._localizer 
    434     localizer = property(_get_localizer)  
    435      
    436     def isLocalizer(self) : 
    437         return ((self.userTags and ('_TRD_' in self.userTags)) or self.pageArgs.get('_loc_')) 
    438          
    439     def isDeveloper(self) : 
    440         return ((self.userTags and ('_DEV_' in self.userTags)) or self.pageArgs.get('_dev_')) 
    441          
    442     def _get_siteStatus(self): 
    443         if not hasattr(self, '_siteStatus'): 
    444             path = os.path.join(self.siteFolder, 'data', '_siteStatus.xml') 
    445             if os.path.isfile(path): 
    446                 self._siteStatus=Bag(path) 
    447             else: 
    448                 self._siteStatus=Bag() 
    449         return self._siteStatus 
    450     siteStatus = property(_get_siteStatus) 
    451      
    452     def siteStatusSave(self): 
    453         if hasattr(self, '_siteStatus'): 
    454             path = os.path.join(self.siteFolder, 'data', '_siteStatus.xml') 
    455             self._siteStatus.toXml(path) 
    456              
    457     def _get_user(self): 
    458         """Get the user from hidden _user attribute.""" 
    459         if not hasattr(self, '_user'): 
    460             self._user = self.connection.appSlot.get('user') 
    461         return self._user 
    462     user = property(_get_user) 
    463          
    464     def _get_userTags(self): 
    465         return self.connection.appSlot.get('tags') 
    466     userTags = property(_get_userTags) 
    467      
    468     def _get_avatar(self): 
    469         if not hasattr(self, '_avatar'): 
    470             self._avatar = self.application.getAvatar(self.user) 
    471         return self._avatar 
    472     avatar = property(_get_avatar) 
    473      
    474     def updateAvatar(self): 
    475         """Reload the avatar, recalculate tags, and save in cookie""" 
    476         self.connection.updateAvatar(self.avatar) 
    477          
    478     def pageAuthTags(self, method=None, **kwargs): 
    479         return "" 
    480          
    481     def checkPermission(self, pagepath, relative=True): 
    482         if relative: 
    483             pagepath = self.utils.pageFolder(pagepath).replace(self.utils.rootFolder(),'') 
    484         return self.application.checkPagePermission(pagepath, self.userTags) 
    485      
    486     def rpc_doLogin(self, login=None, guestName=None, **kwargs): 
    487         """Service method that set user's avatar into its connection if 
    488         - The user exists and his password is correct. 
    489         - The user is guest 
    490         """ 
    491         if guestName: 
    492             avatar = self.application.getAvatar(guestName) 
    493         else: 
    494             avatar = self.application.getAvatar(login['user'], password=login['password'], authenticate=True) 
    495         if avatar: 
    496             self.connection.updateAvatar(avatar) 
    497             login['message'] = '' 
    498         else: 
    499             login['message'] = 'invalid login' 
    500         return login 
    501      
    502     def _rpcDispatcher(self, method=None, **kwargs):  
    503         if False and method!= 'main': 
    504             if self.session.pagedata['page_id']!=self.page_id : 
    505                 raise apache.SERVER_RETURN, apache.HTTP_UNAUTHORIZED 
    506             if self._dk: 
    507                 cl= ['%s_%s'%(k,v) for k,v in kwargs.items()] 
    508                 cl.append('method_%s'%method) 
    509                 cl.sort() 
    510                 if md5.md5('%s%s%s'%(self.page_id,'_'.join(cl),self.page_id)).hexdigest()!=self._dk: 
    511                     raise apache.SERVER_RETURN, apache.HTTP_UNAUTHORIZED 
    512         parameters = dict(kwargs) 
    513         for k,v in kwargs.items(): 
    514             if isinstance(v, basestring): 
    515                 try: 
    516                     v=self.catalog.fromTypedText(v) 
    517                     if isinstance(v, basestring): 
    518                         v = v.decode('utf-8') 
    519                     parameters[k] = v 
    520                 except Exception, e: 
    521                     raise v 
    522         auth = AUTH_OK 
    523         if not method in ('doLogin', 'jscompress'): 
    524             auth = self._checkAuth(method=method, **parameters) 
    525         return self.rpc(self, method=method, _auth=auth, **parameters) 
    526          
    527     def _checkAuth(self, method=None, **parameters): 
    528         auth = AUTH_OK 
    529         pageTags = self.pageAuthTags(method=method, **parameters) 
    530         if pageTags: 
    531             if not self.user: 
    532                 auth = AUTH_NOT_LOGGED 
    533             elif not self.application.checkResourcePermission(pageTags, self.userTags): 
    534                 auth = AUTH_FORBIDDEN 
    535                  
    536             if auth == AUTH_NOT_LOGGED and method != 'main': 
    537                 if not self.connection.oldcookie: 
    538                     raise apache.SERVER_RETURN, apache.HTTP_UNAUTHORIZED 
    539                 auth = 'EXPIRED' 
    540         elif parameters.get('_loginRequired') == 'y': 
    541             auth = AUTH_NOT_LOGGED 
    542         return auth 
    543          
    544     def pageLocalDocument(self, docname): 
    545         folder = os.path.join(self.connectionFolder, self.page_id) 
    546         if not os.path.isdir(folder): 
    547             os.makedirs(folder) 
    548         return os.path.join(folder, docname) 
    549      
    550     def freezeSelection(self, selection, name): 
    551         selection.freeze(self.pageLocalDocument(name), autocreate=True) 
    552          
    553     def unfreezeSelection(self, dbtable, name): 
    554         if isinstance(dbtable, basestring): 
    555             dbtable = self.db.table(dbtable) 
    556         return dbtable.frozenSelection(self.pageLocalDocument(name)) 
    557  
    558     def _get_connectionFolder(self): 
    559         return self.connection.connectionFolder 
    560     connectionFolder = property(_get_connectionFolder) 
    561      
    562     def _get_connection(self): 
    563         if not hasattr(self, '_connection'): 
    564             self._connection = GnrWebConnection(self) 
    565         return self._connection 
    566     connection = property(_get_connection) 
    567      
    568      
    569      
    570     def _get_utils(self): 
    571         if not hasattr(self, '_utils'): 
    572             self._utils = GnrWebUtils(self) 
    573         return self._utils 
    574     utils = property(_get_utils) 
    575      
    576     def _get_rpc(self): 
    577         if not hasattr(self, '_rpc'): 
    578             self._rpc = GnrWebRpc() 
    579         return self._rpc 
    580     rpc = property(_get_rpc) 
    581      
    582     def _get_html(self): 
    583         if not hasattr(self, '_html'): 
    584             self._html = HtmlFormatter() 
    585         return self._html 
    586     html = property(_get_html) 
    587      
    588     def _get_session(self): 
    589         if not hasattr(self, '_session'): 
    590             self._session = GnrWebSession(self, lock=0) 
    591         return self._session 
    592     session = property(_get_session) 
    593  
    594     def _get_pageArgs(self): 
    595         return self.session.pagedata['pageArgs'] or {} 
    596     pageArgs = property(_get_pageArgs) 
    597      
    598     def rpc_updateSessionContext(self, context, path, evt, value=None, attr=None): 
    599         self.session.loadSessionData() 
    600         self.session.setInPageData('context.%s.%s' % (context, path), value, attr) 
    601         self.session.saveSessionData() 
    602          
    603     def setInClientData(self, _client_path, value, _attributes=None, page_id=None, connection_id=None, fired=False, save=False, **kwargs): 
    604         """@param save: remember to save on the last setInClientData. The first call to setInClientData implicitly lock the session util  
    605                         setInClientData is called with save=True 
    606         """ 
    607         _attributes = dict(_attributes or {}) 
    608         _attributes.update(kwargs) 
    609         _attributes['_client_path'] = _client_path 
    610         if connection_id == None or connection_id==self.connection.connection_id: 
    611             self.session.setInPageData('_clientDataChanges.%s' % _client_path.replace('.','_'),  
    612                                         value, _attributes=_attributes, page_id=page_id) 
    613             if save: self.session.saveSessionData() 
    614         else: 
    615             pass 
    616              
    617     def clientDataChanges(self): 
    618         if self.session.pagedata['_clientDataChanges']: 
    619             self.session.loadSessionData() 
    620             result = self.session.pagedata.pop('_clientDataChanges') or Bag() 
    621             self.session.saveSessionData() 
    622             return result 
    623          
    624  
    625     def _get_catalog(self): 
    626         if not hasattr(self, '_catalog'): 
    627             self._catalog = self.application.catalog 
    628         return self._catalog 
    629     catalog = property(_get_catalog) 
    630      
    631     def _set_locale(self, val): 
    632         self._locale = val 
    633     def _get_locale(self): # TODO IMPLEMENT DEFAULT FROM APP OR AVATAR  
    634         if not hasattr(self, '_locale'): 
    635             self._locale = self.connection.locale or self.request.headers_in.get('Accept-Language', 'en').split(',')[0] or 'en' 
    636         return self._locale 
    637     locale = property(_get_locale, _set_locale) 
    638      
    639     def rpc_changeLocale(self, locale): 
    640         self.connection.locale = locale 
    641          
    642     def translateText(self, txt): 
    643         key='%s|%s' % (self.packageId, txt.lower()) 
    644         localelang = self.locale.split('-')[0] 
    645         loc = self.application.localization.get(key) 
    646         missingLoc=True 
    647         if not loc: 
    648             key=txt 
    649             loc = self.application.localization.get(txt) 
    650         if loc: 
    651             loctxt = loc.get(localelang)  
    652             if loctxt : 
    653                 missingLoc=False 
    654                 txt=loctxt 
    655         else: 
    656             self._translateMissing(txt) 
    657             self.application.localization[key] = {} 
    658         if self.isLocalizer(): 
    659             self.localizer[key]=self.application.localization[key] 
    660             self.missingLoc=self.missingLoc or missingLoc 
    661         return txt 
    662          
    663     def _(self, txt): 
    664         if txt.startswith('!!'): 
    665             txt = self.translateText(txt[2:]) 
    666         return txt 
    667      
    668     def _translateMissing(self, txt): 
    669         if not self.packageId: return 
    670         missingpath = os.path.join(self.siteFolder, 'data', '_missingloc', self.packageId) 
    671         if isinstance(txt, unicode):  
    672             txtmd5 = txt.encode('utf8', 'ignore') 
    673         else: 
    674             txtmd5 = txt 
    675         fname = os.path.join(missingpath, '%s.xml' % md5.md5(txtmd5).hexdigest()) 
    676          
    677         if not os.path.isfile(fname): 
    678             b = Bag() 
    679             b['txt'] = txt 
    680             b['pkg'] = self.packageId 
    681             old_umask = os.umask(2) 
    682             b.toXml(fname, autocreate=True) 
    683             os.umask(old_umask) 
    684          
    685     def toText(self, obj, locale=None, format=None, mask=None, encoding=None, dtype=None): 
    686         locale = locale or self.locale 
    687         return toText(obj, locale=locale, format=format, mask=mask, encoding=encoding) 
    688  
    689     def _get_config(self): 
    690         if not hasattr(self, '_config'): 
    691             self._config = Bag(self.utils.absoluteDiskPath('siteconfig.xml')) 
    692         return self._config 
    693     config = property(_get_config) 
    694      
    695     def _get_siteUri(self): 
    696         path = self.folders['pages'] 
    697         path = path.replace(self.folders['document_root'],'') 
    698         path = os.path.normpath(os.path.join(path, '..')) 
    699         return path 
    700     siteUri = property(_get_siteUri) 
    701      
    702     def getDomainUrl(self, path, **kwargs): 
    703         params = urllib.urlencode(kwargs) 
    704         path = os.path.join(self.folders['pages'].replace(self.folders['document_root'], ''), path) 
    705         if params: 
    706             path = '%s?%s' % (path, params) 
    707         return path 
    708          
    709     def homeUrl(self): 
    710         homeurl = self.config['homeurl'] 
    711         if not homeurl: