source: indico/indico/MaKaC/webinterface/rh/base.py @ a9444c

burotelhello-world-walkthroughipv6v0.98-seriesv0.98.2v0.98.3v0.98b1v0.98b2v0.99v1.0v1.1
Last change on this file since a9444c was a9444c, checked in by Pedro Ferreira <jose.pedro.ferreira@…>, 22 months ago

[FIX] Getting rid of old URL reconstruction func

  • Was causing problems with port numbers;
  • Property mode set to 100644
File size: 31.8 KB
Line 
1# -*- coding: utf-8 -*-
2##
3##
4## This file is part of CDS Indico.
5## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
6##
7## CDS Indico is free software; you can redistribute it and/or
8## modify it under the terms of the GNU General Public License as
9## published by the Free Software Foundation; either version 2 of the
10## License, or (at your option) any later version.
11##
12## CDS Indico is distributed in the hope that it will be useful, but
13## WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15## General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
19## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20
21"""Base definitions for the request handlers (rh). A rh is a class which
22complies to a well defined interface and which from a mod_python request knows
23which action to carry out in order to handle the request made. This means that
24each of the possible HTTP ports of the system will have a rh which will know
25what to do depending on the parameter values received, etc.
26"""
27import copy, time, os, sys, random, re
28import StringIO
29from datetime import datetime, timedelta
30
31try:
32    from indico.web.wsgi.indico_wsgi_handler_utils import Field
33    from indico.web.wsgi import webinterface_handler_config as apache
34except ImportError:
35    pass
36from ZODB.POSException import ConflictError, POSKeyError
37from ZEO.Exceptions import ClientDisconnected
38
39from MaKaC.common import fossilize
40from MaKaC.webinterface.pages.conferences import WPConferenceModificationClosed
41from MaKaC.common.TemplateExec import escapeHTMLForJS
42
43import MaKaC.webinterface.session as session
44import MaKaC.webinterface.urlHandlers as urlHandlers
45import MaKaC.webinterface.pages.errors as errors
46from MaKaC.common.general import *
47
48from MaKaC.accessControl import AccessWrapper
49from MaKaC.common import DBMgr, Config, security
50from MaKaC.errors import MaKaCError, ModificationError, AccessError, TimingError, ParentTimingError, EntryTimingError, FormValuesError, NoReportError, NotFoundError, HtmlScriptError, HtmlForbiddenTag, ConferenceClosedError, HostnameResolveError
51from MaKaC.webinterface.mail import GenericMailer, GenericNotification
52from xml.sax.saxutils import escape
53
54from MaKaC.common.utils import truncate
55from MaKaC.common.logger import Logger
56from MaKaC.common.contextManager import ContextManager
57from MaKaC.i18n import _, langList
58
59from MaKaC.plugins import PluginsHolder
60from MaKaC.user import Group, Avatar
61from MaKaC.accessControl import AdminList
62
63from MaKaC.plugins.base import OldObservable
64
65
66class RequestHandlerBase(OldObservable):
67
68    _uh = None
69    _currentRH = None
70
71    def __init__(self, req):
72
73        # attention: not thread-safe
74        RequestHandlerBase._currentRH = self
75
76        if req == None:
77            raise Exception("Request object not initialised")
78        self._req = req
79
80    def _checkProtection( self ):
81        """
82        """
83        pass
84
85    def getAW( self ):
86        """
87        Returns the access wrapper related to this session/user
88        """
89        return self._aw
90
91    def _getUser(self):
92        """
93        Returns the current user
94        """
95        return self._aw.getUser()
96
97    def _setUser(self, newUser=None):
98        """
99        Sets the current user
100        """
101        self._aw.setUser(newUser)
102
103    def getCurrentURL( self ):
104        """
105        Gets the "current URL", through the URL handler
106        """
107        if self._uh == None:
108            return ""
109        return self._uh.getURL( self._target )
110
111    def _setLang(self, params=None):
112
113        # allow to choose the lang from params
114        if params and 'lang' in params:
115            newLang = params.get('lang', '')
116            for lang in langList():
117                if newLang.lower() == lang[0].lower():
118                    self._websession.setLang(lang[0])
119                    break
120
121        lang=self._websession.getLang()
122        Logger.get('i18n').debug("lang:%s"%lang)
123        if lang is None:
124            lang = "en_US"
125        from MaKaC import i18n
126        i18n.install('messages', lang, unicode=True)
127
128    def getHostIP(self):
129        import socket
130
131        host = str(self._req.get_remote_host(apache.REMOTE_NOLOOKUP))
132
133        try:
134            hostIP = socket.gethostbyname(host)
135            minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
136            if minfo.useProxy():
137                # if we're behind a proxy, use X-Forwarded-For
138                xff = self._req.headers_in.get("X-Forwarded-For",hostIP).split(", ")[-1]
139                return socket.gethostbyname(xff)
140            else:
141                return hostIP
142        except socket.gaierror, e:
143            # in case host resolution fails
144            raise HostnameResolveError("Error resolving host '%s' : %s" % (host, e))
145
146
147
148
149    accessWrapper = property( getAW )
150
151
152class RH(RequestHandlerBase):
153    """This class is the base for request handlers of the application. A request
154        handler will be instantiated when a web request arrives to mod_python;
155        the mp layer will forward the request to the corresponding request
156        handler which will know which action has to be performed (displaying a
157        web page or performing some operation and redirecting to another page).
158        Request handlers will be responsible for parsing the parameters coming
159        from a mod_python request, handle the errors which occurred during the
160        action to perform, managing the sessions, checking security for each
161        operation (thus they implement the access control system of the web
162        interface).
163        It is important to encapsulate all this here as in case of changing
164        the web application framework we'll just need to adapt this layer (the
165        rest of the system wouldn't need any change).
166
167        Attributes:
168            _uh - (URLHandler) Associated URLHandler which points to the
169                current rh.
170            _req - (mod_python.Request) mod_python request received for the
171                current rh.
172            _requestStarted - (bool) Flag which tells whether a DB transaction
173                has been started or not.
174            _websession - ( webinterface.session.sessionManagement.PSession )
175                Web session associated to the HTTP request.
176            _aw - (AccessWrapper) Current access information for the rh.
177            _target - (Locable) Reference to an object which is the destination
178                of the operations needed to carry out the rh. If set it must
179                provide (through the standard Locable interface) the methods
180                to get the url parameters in order to reproduce the access to
181                the rh.
182            _reqParams - (dict) Dictionary containing the received HTTP
183                 parameters (independently of the method) transformed into
184                 python data types. The key is the parameter name while the
185                 value should be the received paramter value (or values).
186    """
187    _tohttps = False
188    _doNotSanitizeFields = []
189
190    def __init__( self, req ):
191        """Constructor. Initialises the rh setting up basic attributes so it is
192            able to process the request.
193
194            Parameters:
195                req - (mod_python.Request) mod_python request received for the
196                    current rh.
197        """
198        RequestHandlerBase.__init__(self, req)
199        self._requestStarted = False
200        self._websession = None
201        self._aw = AccessWrapper()  #Fill in the aw instance with the current information
202        self._target = None
203        self._reqParams = {}
204        self._startTime = None
205        self._endTime = None
206        self._tempFilesToDelete = []
207        self._doProcess = True  #Flag which indicates whether the RH process
208                                #   must be carried out; this is useful for
209                                #   the checkProtection methods when they
210                                #   detect that an inmediate redirection is
211                                #   needed
212
213    # Methods =============================================================
214
215    def getTarget( self ):
216        return self._target
217
218    def _setSession( self ):
219        """Sets up a reference to the corresponding web session. It uses the
220            session manager to retrieve the session corresponding to the
221            received request and makes sure it is a valid one. In case of having
222            an invalid session it reset client settings and creates a new one.
223       """
224        if not self._websession:
225            sm = session.getSessionManager()
226            try:
227                self._websession = sm.get_session( self._req )
228            except session.SessionError, e:
229                sm.revoke_session_cookie( self._req )
230                self._websession = sm.get_session( self._req )
231            sm.maintain_session( self._req, self._websession )
232
233    def _getSession( self ):
234        """Returns the web session associated to the received mod_python
235            request.
236        """
237        if not self._websession:
238            self._setSession()
239        return self._websession
240
241    def _setSessionUser( self ):
242        """
243        """
244        self._aw.setUser( self._getSession().getUser() )
245
246    def _getRequestParams( self ):
247        return self._reqParams
248
249    def getRequestParams( self ):
250        return self._getRequestParams()
251
252    def getRequestHTTPHeaders( self ):
253        return self._req.headers_in
254
255    def _disableCaching(self):
256        """
257        Disables caching, i.e. for materials
258        """
259
260        # IE doesn't seem to like 'no-cache' Cache-Control headers...
261        if (re.match(r'.*MSIE.*', self._req.headers_in.get("User-Agent",""))):
262            # actually, the only way to safely disable caching seems to be this one
263            self._req.headers_out["Cache-Control"] = "private"
264            self._req.headers_out["Expires"] = "-1"
265        else:
266            self._req.headers_out["Cache-Control"] = "no-store, no-cache, must-revalidate"
267            self._req.headers_out["Pragma"] = "no-cache"
268
269    def _redirect( self, targetURL, noCache=False ):
270        """Utility for redirecting the client web browser to the specified
271            URL.
272            Params:
273                newURL - Target URL of the redirection
274        """
275        #check if there is no \r\n character to avoid http header injection
276
277        if str(targetURL):
278            if "\r" in str(targetURL) or "\n" in str(targetURL):
279                raise MaKaCError(_("http header CRLF injection detected"))
280        self._req.headers_out["Location"] = str(targetURL)
281
282        if noCache:
283            self._disableCaching()
284        try:
285            self._req.status = apache.HTTP_SEE_OTHER
286        except NameError:
287            pass
288
289    def _checkHttpsRedirect(self):
290        if self._tohttps and not self._req.is_https():
291            current_url = self._req.construct_url(self._req.unparsed_uri)
292            self._redirect(urlHandlers.setSSLPort(current_url.replace("http://", "https://")))
293            return True
294        else:
295            return False
296
297    def _normaliseListParam( self, param ):
298        if not isinstance(param, list):
299                return [ param ]
300        return param
301
302    def _processError( self, ex ):
303        """
304        """
305        raise
306
307    def _checkParams( self, params ):
308        """
309        """
310        pass
311
312    def _process( self ):
313        """
314        """
315        pass
316
317    def _processGeneralError(self,e):
318        """Treats general errors occured during the process of a RH.
319        """
320
321        Logger.get('requestHandler').info('Request %s finished with: "%s"' % (id(self._req), e))
322
323        p=errors.WPGenericError(self)
324        return p.display()
325
326
327    def _getTruncatedParams(self):
328        """ Truncates params, so that file objects do not show up in the logs """
329
330        params = {}
331
332        for key,value in self._reqParams.iteritems():
333            if isinstance(value, Field):
334                params[key] = "<FILE>"
335            elif type(value) == str:
336                params[key] = truncate(value, 1024)
337            else:
338                params[key] = value
339
340        return params
341
342    def _processUnexpectedError(self,e):
343        """Unexpected errors
344        """
345
346        Logger.get('requestHandler').exception('Request %s failed: "%s"\n\nurl: %s\n\nparameters: %s\n\n' % (id(self._req), e,self.getRequestURL(), self._getTruncatedParams()))
347        p=errors.WPUnexpectedError(self)
348        return p.display()
349
350    def _processHostnameResolveError(self,e):
351        """Unexpected errors
352        """
353
354        Logger.get('requestHandler').exception('Request %s failed: "%s"\n\nurl: %s\n\nparameters: %s\n\n' % (id(self._req), e,self.getRequestURL(), self._getTruncatedParams()))
355        p=errors.WPHostnameResolveError(self)
356        return p.display()
357
358
359    def _processAccessError(self,e):
360        """Treats access errors occured during the process of a RH.
361        """
362        Logger.get('requestHandler').info('Request %s finished with AccessError: "%s"' % (id(self._req), e))
363
364        self._req.status = apache.HTTP_FORBIDDEN
365        p=errors.WPAccessError(self)
366        return p.display()
367
368    def _processModificationError(self,e):
369        """Treats modification errors occured during the process of a RH.
370        """
371
372        Logger.get('requestHandler').info('Request %s finished with ModificationError: "%s"' % (id(self._req), e))
373
374        p=errors.WPModificationError(self)
375        return p.display()
376
377    def _processConferenceClosedError(self,e):
378        """Treats access to modification pages for conferences when they are closed.
379        """
380        p = WPConferenceModificationClosed( self, e._conf )
381        return p.display()
382
383    def _processTimingError(self,e):
384        """Treats timing errors occured during the process of a RH.
385        """
386
387        Logger.get('requestHandler').info('Request %s finished with TimingError: "%s"' % (id(self._req), e))
388
389        p=errors.WPTimingError(self,e)
390        return p.display()
391
392    def _processNoReportError(self,e):
393        """Process errors without reporting
394        """
395
396        Logger.get('requestHandler').info('Request %s finished with NoReportError: "%s"' % (id(self._req), e))
397
398        p=errors.WPNoReportError(self,e)
399        return p.display()
400
401    def _processNotFoundError(self,e):
402        """Process not found error; uses NoReportError template
403        """
404
405        Logger.get('requestHandler').info('Request %s finished with NotFoundError: "%s"' % (id(self._req), e))
406
407        try:
408            self._req.status = apache.HTTP_NOT_FOUND
409        except NameError:
410            pass
411
412        p=errors.WPNoReportError(self,e)
413        return p.display()
414
415    def _processParentTimingError(self,e):
416        """Treats timing errors occured during the process of a RH.
417        """
418
419        Logger.get('requestHandler').info('Request %s finished with ParentTimingError: "%s"' % (id(self._req), e))
420
421        p=errors.WPParentTimingError(self,e)
422        return p.display()
423
424    def _processEntryTimingError(self,e):
425        """Treats timing errors occured during the process of a RH.
426        """
427
428        Logger.get('requestHandler').info('Request %s finished with EntryTimingError: "%s"' % (id(self._req), e))
429
430        p=errors.WPEntryTimingError(self,e)
431        return p.display()
432
433    def _processFormValuesError(self,e):
434        """Treats user input related errors occured during the process of a RH.
435        """
436
437        Logger.get('requestHandler').info('Request %s finished with FormValuesError: "%s"' % (id(self._req), e))
438
439        p=errors.WPFormValuesError(self,e)
440        return p.display()
441
442    def _processHtmlScriptError(self, e):
443
444        Logger.get('requestHandler').info('Request %s finished with ProcessHtmlScriptError: "%s"' % (id(self._req), e))
445
446        p=errors.WPHtmlScriptError(self, escape(str(e)))
447        return p.display()
448
449    def _processRestrictedHTML(self, e):
450
451        Logger.get('requestHandler').info('Request %s finished with ProcessRestrictedHTMLError: "%s"' % (id(self._req), e))
452
453        p=errors.WPRestrictedHTML(self, escape(str(e)))
454        return p.display()
455
456    def process( self, params ):
457        """
458        """
459        profile = Config.getInstance().getProfile()
460        proffilename = ""
461        res = ""
462        retry = 10
463        textLog = []
464        self._startTime = datetime.now()
465
466        # create the context
467        ContextManager.create()
468
469        #redirect to https if necessary
470        if self._checkHttpsRedirect():
471            return res
472
473        DBMgr.getInstance().startRequest()
474        self._startRequestSpecific2RH()     # I.e. implemented by Room Booking request handlers
475        textLog.append("%s : Database request started"%(datetime.now() - self._startTime))
476        Logger.get('requestHandler').info('[pid=%s] Request %s started (%s)' % (os.getpid(),id(self._req), self._req.unparsed_uri))
477
478        # notify components that the request has started
479        self._notify('requestStarted', self._req)
480
481        try:
482            while retry>0:
483
484                if retry < 10:
485                    # notify components that the request is being retried
486                    self._notify('requestRetry', self._req, 10 - retry)
487
488                try:
489                    Logger.get('requestHandler').info('\t[pid=%s] from host %s' % (os.getpid(), self.getHostIP()))
490                    try:
491                        # clear the fossile cache at the start of each request
492                        fossilize.clearCache()
493
494                        DBMgr.getInstance().sync()
495                        # keep a link to the web session in the access wrapper
496                        # this is used for checking access/modification key existence
497                        # in the user session
498                        self._aw.setIP( self.getHostIP() )
499                        self._aw.setSession(self._getSession())
500                        #raise(str(dir(self._websession)))
501                        self._setSessionUser()
502                        self._setLang(params)
503
504                        if self._getUser():
505                            Logger.get('requestHandler').info('Request %s identified with user %s (%s)' % (id(self._req), self._getUser().getFullName(), self._getUser().getId()))
506                            if not self._tohttps and Config.getInstance().getAuthenticatedEnforceSecure():
507                                self._tohttps = True
508                                if self._checkHttpsRedirect():
509                                    return res
510
511                        #if self._getUser() != None and self._getUser().getId() == "893":
512                        #    profile = True
513                        self._reqParams = copy.copy( params )
514                        self._checkParams( self._reqParams )
515
516                        self._checkProtection()
517                        security.Sanitization.sanitizationCheck(self._target,
518                                               self._reqParams,
519                                               self._aw, self._doNotSanitizeFields)
520                        if self._doProcess:
521                            if profile:
522                                import profile, pstats
523                                proffilename = os.path.join(Config.getInstance().getTempDir(), "stone%s.prof" % str(random.random()))
524                                result = [None]
525                                profile.runctx("result[0] = self._process()", globals(), locals(), proffilename)
526                                res = result[0]
527                            else:
528                                res = self._process()
529
530                        # notify components that the request has finished
531                        self._notify('requestFinished', self._req)
532
533                        self._endRequestSpecific2RH( True ) # I.e. implemented by Room Booking request handlers
534
535                        DBMgr.getInstance().endRequest( True )
536                        Logger.get('requestHandler').info('Request %s successful' % (id(self._req)))
537
538                        #request succesfull, now, doing tas that must be done only once
539                        try:
540                            self._sendEmails()
541                            self._deleteTempFiles()
542                        except:
543                            pass
544                        break
545                    except MaKaCError, e:
546                        #DBMgr.getInstance().endRequest(False)
547                        res = self._processError(e)
548                except (ConflictError, POSKeyError):
549                    import traceback
550                    Logger.get('requestHandler').warning('Conflict in Database! (Request %s)\n%s' % (id(self._req), traceback.format_exc()))
551                    self._abortSpecific2RH()
552                    DBMgr.getInstance().abort()
553                    retry -= 1
554                    continue
555                except ClientDisconnected:
556                    Logger.get('requestHandler').warning('Client Disconnected! (Request %s)' % id(self._req) )
557                    self._abortSpecific2RH()
558                    DBMgr.getInstance().abort()
559                    retry -= 1
560                    time.sleep(10-retry)
561                    continue
562        except AccessError, e:
563            #Access error treatment
564            res = self._processAccessError( e )
565            self._endRequestSpecific2RH( False )
566            DBMgr.getInstance().endRequest(False)
567        except HostnameResolveError, e:
568            res = self._processHostnameResolveError( e )
569            self._endRequestSpecific2RH( False )
570            DBMgr.getInstance().endRequest(False)
571        except ModificationError, e:
572            #Modification error treatment
573            res = self._processModificationError( e )
574            self._endRequestSpecific2RH( False )
575            DBMgr.getInstance().endRequest(False)
576        except ParentTimingError, e:
577            #Modification error treatment
578            res = self._processParentTimingError( e )
579            self._endRequestSpecific2RH( False )
580            DBMgr.getInstance().endRequest(False)
581        except EntryTimingError, e:
582            #Modification error treatment
583            res = self._processEntryTimingError( e )
584            self._endRequestSpecific2RH( False )
585            DBMgr.getInstance().endRequest(False)
586        except TimingError, e:
587            #Modification error treatment
588            res = self._processTimingError( e )
589            self._endRequestSpecific2RH( False )
590            DBMgr.getInstance().endRequest(False)
591        except FormValuesError, e:
592            #Error filling the values of a form
593            res = self._processFormValuesError( e )
594            self._endRequestSpecific2RH( False )
595            DBMgr.getInstance().endRequest(False)
596        except ConferenceClosedError, e:
597            #Modification error treatment
598            res = self._processConferenceClosedError( e )
599            self._endRequestSpecific2RH( False )
600            DBMgr.getInstance().endRequest(False)
601        except NoReportError, e:
602            #Error without report option
603            res = self._processNoReportError( e )
604            DBMgr.getInstance().endRequest(False)
605        except NotFoundError, e:
606            #File not fond error
607            res = self._processNotFoundError( e )
608            DBMgr.getInstance().endRequest(False)
609        except HtmlScriptError,e:
610            res = self._processHtmlScriptError(e)
611            DBMgr.getInstance().endRequest(False)
612        except HtmlForbiddenTag,e:
613            res = self._processRestrictedHTML(e)
614            DBMgr.getInstance().endRequest(False)
615        except MaKaCError, e:
616            res = self._processGeneralError( e )
617            DBMgr.getInstance().endRequest(False)
618        except ValueError, e:
619            res = self._processGeneralError( e )
620            DBMgr.getInstance().endRequest(False)
621        except Exception, e: #Generic error treatment
622            res = self._processUnexpectedError( e )
623            #DBMgr.getInstance().endRequest(False)
624            #self._endRequestSpecific2RH( False )
625
626            #cancels any redirection
627            try:
628                del self._req.headers_out["Location"]
629            except AttributeError:
630                pass
631            try:
632                self._req.status=apache.HTTP_INTERNAL_SERVER_ERROR
633            except NameError:
634                pass
635
636
637        # destroy the context
638        ContextManager.destroy()
639
640        totalTime = (datetime.now() - self._startTime)
641        textLog.append("%s : Request ended"%totalTime)
642
643        # log request timing
644        if profile and totalTime > timedelta(0, 1) and os.path.isfile(proffilename):
645            rep = Config.getInstance().getTempDir()
646            stats = pstats.Stats(proffilename)
647            stats.strip_dirs()
648            stats.sort_stats('cumulative', 'time', 'calls')
649            stats.dump_stats(os.path.join(rep, "IndicoRequestProfile.log"))
650            output = StringIO.StringIO()
651            sys.stdout = output
652            stats.print_stats(100)
653            sys.stdout = sys.__stdout__
654            s = output.getvalue()
655            f = file(os.path.join(rep, "IndicoRequest.log"), 'a+')
656            f.write("--------------------------------\n")
657            f.write("URL     : " + self._req.construct_url(self._req.unparsed_uri) + "\n")
658            f.write("%s : start request\n"%self._startTime)
659            f.write("params:%s"%params)
660            f.write("\n".join(textLog))
661            f.write("\n")
662            f.write("retried : %d\n"%(10-retry))
663            f.write(s)
664            f.write("--------------------------------\n\n")
665            f.close()
666        if profile and proffilename != "" and os.path.exists(proffilename):
667            os.remove(proffilename)
668
669        # In case of no process needed, we should return empty string to avoid erroneous ouput
670        # specially with getVars breaking the JS files.
671        if not self._doProcess:
672            return ""
673
674        if res == "" or res == None:
675            return "[done]"
676
677        return res
678
679    def _sendEmails( self ):
680        if hasattr( self, "_emailsToBeSent" ):
681            for email in self._emailsToBeSent:
682                GenericMailer.send(GenericNotification(email))
683
684    def _deleteTempFiles( self ):
685        if len(self._tempFilesToDelete) > 0:
686            for file in self._tempFilesToDelete:
687                os.remove(file)
688
689    def getRequestURL( self ):
690        """
691        Reconstructs the request URL
692        """
693        return self._req.construct_url(self._req.unparsed_uri)
694
695    def _startRequestSpecific2RH( self ):
696        """
697        Works like DBMgr.getInstance().startRequest() but is specific to
698        request handler. It is used to connect to other database only
699        in choosen request handlers.
700
701        I.e. all Room Booking request handlers override this
702        method to connect to Room Booking backend.
703        """
704        pass
705
706    def _endRequestSpecific2RH( self, commit ):
707        """
708        Works like DBMgr.getInstance().endRequest() but is specific to
709        request handler. It is used to disconnect from other database only
710        in choosen request handlers.
711
712        I.e. all Room Booking request handlers override this
713        method to disconnect from Room Booking backend.
714        """
715        pass
716
717    def _syncSpecific2RH( self ):
718        """
719        Works like DBMgr.getInstance().sync() but is specific to
720        request handler. It is used to connect to other database only
721        in choosen request handlers.
722
723        I.e. all Room Booking request handlers override this
724        method to sync backend.
725        """
726        pass
727
728    def _abortSpecific2RH( self ):
729        """
730        Works like DBMgr.getInstance().abort() but is specific to
731        request handler. It is used to abort transactions of other database
732        only in choosen request handlers.
733
734        I.e. all Room Booking request handlers override this method.
735        """
736        pass
737
738    # Properties =============================================================
739
740    requestURL = property( getRequestURL )
741    relativeURL = None
742
743
744from MaKaC.rb_location import CrossLocationDB
745import MaKaC.common.info as info
746
747class RoomBookingDBMixin:     # It's _not_ RH
748    """
749    Goal:
750    Only _some_ Request Handlers should connect to
751    room booking database.
752
753    Mix in this class into all Request Handlers,
754    which must use Room Booking backend.
755
756    Usage:
757
758    class RHExample( RoomBookingDBMixin, RHProtected ):
759        pass
760
761    NOTE: it is important to put RoomBookingDBMixin as first
762    base class.
763    """
764
765    def _startRequestSpecific2RH( self ):
766        minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
767        if minfo.getRoomBookingModuleActive():
768            CrossLocationDB.connect()
769
770    def _endRequestSpecific2RH( self, commit = True ):
771        minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
772        if minfo.getRoomBookingModuleActive():
773            if commit: CrossLocationDB.commit()
774            else: CrossLocationDB.rollback()
775            CrossLocationDB.disconnect()
776
777    def _syncSpecific2RH( self ):
778        minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
779        if minfo.getRoomBookingModuleActive():
780            CrossLocationDB.sync()
781
782    def _abortSpecific2RH( self ):
783        minfo = info.HelperMaKaCInfo.getMaKaCInfoInstance()
784        if minfo.getRoomBookingModuleActive():
785            CrossLocationDB.rollback()
786
787
788class RHProtected( RH ):
789
790    def _getLoginURL( self ):
791        return urlHandlers.UHSignIn.getURL(self.getRequestURL())
792
793    def _checkSessionUser( self ):
794        """
795        """
796
797        if self._getUser() == None:
798            self._redirect( self._getLoginURL() )
799            self._doProcess = False
800
801    def _checkProtection( self ):
802        self._checkSessionUser()
803
804
805class RHRoomBookingProtected( RHProtected ):
806
807    def _checkSessionUser( self ):
808        user = self._getUser()
809        if user == None:
810            self._redirect( self._getLoginURL() )
811            self._doProcess = False
812        else:
813            try:
814                if PluginsHolder().getPluginType("RoomBooking").isActive():
815                    if not AdminList.getInstance().isAdmin(user) and PluginsHolder().getPluginType("RoomBooking").getOption("AuthorisedUsersGroups").getValue() != []:
816                        authenticatedUser = False
817                        for entity in PluginsHolder().getPluginType("RoomBooking").getOption("AuthorisedUsersGroups").getValue():
818                            if isinstance(entity, Group) and entity.containsUser(user) or \
819                               isinstance(entity, Avatar) and entity == user:
820                                    authenticatedUser = True
821                                    break
822                        if not authenticatedUser:
823                            raise AccessError()
824            except KeyError:
825                pass
826
827class RHDisplayBaseProtected( RHProtected ):
828
829    def _checkProtection( self ):
830        if not self._target.canAccess( self.getAW() ):
831            from MaKaC.conference import Link, LocalFile, Category
832            if isinstance(self._target,Link) or isinstance(self._target,LocalFile):
833                target = self._target.getOwner()
834            else:
835                target = self._target
836            if not isinstance(self._target, Category):
837                if target.getAccessKey() != "" or target.getConference() and target.getConference().getAccessKey() != "":
838                    raise AccessError()
839            if self._getUser() == None:
840                self._checkSessionUser()
841            else:
842                raise AccessError()
843
844
845class RHModificationBaseProtected( RHProtected ):
846
847    _allowClosed = False
848
849    def _checkProtection( self ):
850        if not self._target.canModify( self.getAW() ):
851            if self._target.getModifKey() != "":
852                raise ModificationError()
853            if self._getUser() == None:
854                self._checkSessionUser()
855            else:
856                raise ModificationError()
857        if hasattr(self._target, "getConference") and not self._allowClosed:
858            if self._target.getConference().isClosed():
859                raise ConferenceClosedError(self._target.getConference())
860
Note: See TracBrowser for help on using the repository browser.