Changeset 4809
- Timestamp:
- 06/24/08 11:52:44 (5 months ago)
- Files:
-
- trunk/tg/controllers.py (modified) (26 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/tg/controllers.py
r4761 r4809 3 3 4 4 DecoratedController allows the decorators in tg.decorators to work 5 5 6 6 ObjectDispatchController is a specialised form of DecoratedController that 7 7 converts URL portions into traversing Python objects. This controller is 8 8 usable in plain pylons if you route to it's "routes_placeholder" method 9 9 10 10 TGController is a specialised form of ObjectDispatchController that forms the 11 11 basis of standard TurboGears controllers. The "Root" controller of a standard … … 20 20 import pylons 21 21 from pylons.controllers import WSGIController 22 23 22 from pylons.controllers.util import abort 24 23 25 from tg.exceptions import HTTPFound, HTTPNotFound, HTTPException 24 from tg.exceptions import HTTPFound, HTTPNotFound, HTTPException, HTTPClientError 26 25 from tw.api import Widget 26 from webob.exc import HTTPForbidden 27 27 28 28 log = logging.getLogger(__name__) … … 45 45 The decorators in tg.decorators create an attribute named 'decoration' on 46 46 the controller method, creating rules as to: 47 47 48 48 1) how to validate the request, 49 49 2) how to render the response, 50 50 3) allowing hooks to be registered to happen: 51 51 52 52 a) before validation 53 53 b) before the controller method is called … … 71 71 72 72 The before_render hook provides a place for functions that are called 73 before the template is rendered. For example, you could use it to 73 before the template is rendered. For example, you could use it to 74 74 add and remove from the dictionary returned by the controller method, 75 75 before it is passed to rendering. … … 78 78 rendering. 79 79 """ 80 80 81 81 self._initialize_validation_context() 82 82 … … 100 100 101 101 except formencode.api.Invalid, inv: 102 controller, output = self._handle_validation_errors(controller, 102 controller, output = self._handle_validation_errors(controller, 103 103 remainder, 104 104 params, inv) … … 135 135 if validation is None: 136 136 return params 137 137 138 138 #Initialize new_params -- if it never gets updated just return params 139 139 new_params = {} 140 140 141 141 # The validator may be a dictionary, a FormEncode Schema object, or any 142 142 # object with a "validate" method. … … 166 166 formencode.schema.format_compound_error(errors), 167 167 params, None, error_dict=errors) 168 168 169 169 elif isinstance(validation.validators, formencode.Schema): 170 170 # A FormEncode Schema object - to_python converts the incoming 171 171 # parameters to sanitized Python values 172 172 new_params = validation.validators.to_python(params) 173 173 174 174 elif hasattr(validation.validators, 'validate'): 175 175 # An object with a "validate" method - call it with the parameters 176 176 new_params = validation.validators.validate(params) 177 177 178 178 # Theoretically this should not happen... 179 179 if new_params is None: 180 180 return params 181 181 182 182 return new_params 183 183 … … 204 204 205 205 # Always set content type 206 pylons.response.headers['Content-Type'] = content_type 206 pylons.response.headers['Content-Type'] = content_type 207 207 req = pylons.request 208 208 … … 218 218 warnings.warn(msg, DeprecationWarning) 219 219 setattr(pylons.c.w, key, item) 220 220 221 221 # Prepare the engine, if it's not already been prepared. 222 222 if engine_name not in _configured_engines(): … … 228 228 #if there is an identity, push it to the pylons template context 229 229 pylons.tmpl_context.identity = pylons.request.environ.get('repoze.who.identity') 230 230 231 231 # Setup the template namespace, removing anything that the user 232 232 # has marked to be excluded. … … 262 262 263 263 pylons.c.validation_exception = exception 264 pylons.c.form_errors = {} 265 264 pylons.c.form_errors = {} 265 266 266 # Most Invalid objects come back with a list of errors in the format: 267 267 #"fieldname1: error\nfieldname2: error" … … 272 272 field_value = error.split(':') 273 273 274 #if the error has no field associated with it, 274 #if the error has no field associated with it, 275 275 #return the error as a global form error 276 276 if len(field_value) == 1: … … 279 279 280 280 pylons.c.form_errors[field_value[0]] = field_value[1].strip() 281 281 282 282 pylons.c.form_values = exception.value 283 283 … … 292 292 293 293 return error_handler, output 294 294 295 295 def _initialize_validation_context(self): 296 296 pylons.c.form_errors = {} … … 349 349 url_path = pylons.request.path.split('/')[1:] 350 350 else: 351 url_path = url.split('/') 352 351 url_path = url.split('/') 352 353 353 controller, remainder = _object_dispatch(self, url_path) 354 354 # XXX Place controller url at context temporarily... we should be … … 364 364 def _perform_call(self, func, args): 365 365 controller, remainder, params = self._get_routing_info(args.get('url')) 366 return DecoratedController._perform_call( self, controller, params,367 remainder=remainder)368 369 def routes_placeholder(self, url='/', start_response=None, **kwargs): 366 return DecoratedController._perform_call( 367 self, controller, params, remainder=remainder) 368 369 def routes_placeholder(self, url='/', start_response=None, **kwargs): 370 370 """ 371 371 This function does not do anything. It is a placeholder that allows … … 383 383 obj, remainder = _find_object(obj, remainder, notfound_handlers) 384 384 return obj, remainder 385 386 # identity error should be treated separatly from "not found" errors 387 except HTTPForbidden, httpe: 388 log.debug("a 403 error occured for obj: %s" % obj) 389 raise 390 385 391 except HTTPException: 386 392 if not notfound_handlers: 387 393 raise HTTPNotFound().exception 394 388 395 name, obj, remainder = notfound_handlers.pop() 389 396 if name == 'default': 390 397 return obj, remainder 398 391 399 else: 392 400 obj, remainder = obj(*remainder) … … 397 405 if obj is None: 398 406 raise HTTPNotFound().exception 407 408 _check_security(obj) 409 399 410 if _iscontroller(obj): 400 411 return obj, remainder … … 415 426 if not remainder: 416 427 raise HTTPNotFound().exception 428 417 429 obj = getattr(obj, remainder[0], None) 418 430 remainder = remainder[1:] 431 432 def _check_security(obj): 433 """this function checks if a controller has a 'require' attribute and if 434 it is the case, test that this require predicate can be evaled to True. 435 It will raise a Forbidden exception if the predicate is not valid. 436 """ 437 if hasattr(obj, "im_self"): 438 klass_instance = obj.im_self 439 else: 440 klass_instance = obj 441 442 if hasattr(klass_instance, "check_security"): 443 if not klass_instance.check_security(): 444 raise HTTPForbidden().exception 445 #abort(403) 419 446 420 447 def _iscontroller(obj): … … 429 456 An ObjectDispatchController-derived class for stock-standard TurboGears 430 457 controllers. 431 432 This controller can be used as a baseclass for anything in the 458 459 This controller can be used as a baseclass for anything in the 433 460 object dispatch tree, but it MUST be used in the Root controller 434 a d any controller which you intend to do object dispatch from461 and any controller which you intend to do object dispatch from 435 462 using Routes. 436 463 """ 437 464 438 465 def _perform_call(self, func, args): 439 466 setup_i18n() 440 467 routingArgs = None 441 468 442 469 if isinstance(args, dict) and 'url' in args: 443 470 routingArgs = args['url'] 444 471 445 472 try: 446 473 controller, remainder, params = self._get_routing_info(routingArgs) 447 474 result = DecoratedController._perform_call( 448 475 self, controller, params, remainder=remainder) 476 449 477 except HTTPException, httpe: 450 478 result = httpe … … 467 495 if not params: 468 496 params = {} 469 497 470 498 curent_url = pylons.request.url 471 499 url = urlparse.urljoin(curent_url, url) … … 476 504 url = url.encode('utf8') 477 505 found = HTTPFound(location=url).exception 478 506 479 507 #TODO: Make this work with WebOb 480 508 481 509 ## Merging cookies and headers from global response into redirect 482 510 #for header in pylons.response.headerlist: … … 495 523 app_root = pylons.request.application_url[len(pylons.request.host_url):] 496 524 tgpath = app_root + tgpath 497 tgpath = pylons.config.get("server.webpath", "") + tgpath 525 tgpath = pylons.config.get("server.webpath", "") + tgpath 498 526 result = tgpath 499 527 else: 500 result = tgpath 528 result = tgpath 501 529 502 530 if tgparams is None: … … 525 553 result += "?" + "&".join(args) 526 554 return result 527 555 528 556 529 557 def setup_i18n(): … … 543 571 set_lang(languages[0]) 544 572 log.info("Set request language to %s", languages[0]) 545 __all__ = [ 546 "DecoratedController", "ObjectDispatchController", "TGController", 573 __all__ = [ 574 "DecoratedController", "ObjectDispatchController", "TGController", 547 575 "url", "redirect" 548 576 ]