def _dispatch(self, state, remainder=None): """ This method defines how the object dispatch mechanism works, including checking for security along the way. """ if state.dispatcher is None: state.dispatcher = self state.add_controller('/', self) if remainder is None: remainder = state.path current_controller = state.controller #skip any empty urls if remainder and not (remainder[0]): return self._dispatch(state, remainder[1:]) self._enter_controller(state, remainder) #we are plumb out of path, check for index if not remainder: if self._is_exposed(current_controller, 'index') and \ method_matches_args(current_controller.index, state.params, remainder, self._use_lax_params): state.add_method(current_controller.index, remainder) return state #if there is no index, head up the tree #to see if there is a default or lookup method we can use return self._dispatch_first_found_default_or_lookup( state, remainder) current_path = state.path_translator(remainder[0]) current_args = remainder[1:] #an exposed method matching the path is found if self._is_exposed(current_controller, current_path): #check to see if the argspec jives controller = getattr(current_controller, current_path) if method_matches_args(controller, state.params, current_args, self._use_lax_params): state.add_method(controller, current_args) return state #another controller is found current_controller = getattr(current_controller, current_path, None) if current_controller is not None: return self._dispatch_controller(current_path, current_controller, state, current_args) #dispatch not found return self._dispatch_first_found_default_or_lookup(state, remainder)
def _dispatch(self, state, remainder=None): """ This method defines how the object dispatch mechanism works, including checking for security along the way. """ if state.dispatcher is None: state.dispatcher = self state.add_controller('/', self) if remainder is None: remainder = state.path current_controller = state.controller #skip any empty urls if remainder and not(remainder[0]): return self._dispatch(state, remainder[1:]) self._enter_controller(state, remainder) #we are plumb out of path, check for index if not remainder: if self._is_exposed(current_controller, 'index') and \ method_matches_args(current_controller.index, state.params, remainder, self._use_lax_params): state.add_method(current_controller.index, remainder) return state #if there is no index, head up the tree #to see if there is a default or lookup method we can use return self._dispatch_first_found_default_or_lookup(state, remainder) current_path = state.path_translator(remainder[0]) current_args = remainder[1:] #an exposed method matching the path is found if self._is_exposed(current_controller, current_path): #check to see if the argspec jives controller = getattr(current_controller, current_path) if method_matches_args(controller, state.params, current_args, self._use_lax_params): state.add_method(controller, current_args) return state #another controller is found current_controller = getattr(current_controller, current_path, None) if current_controller is not None: return self._dispatch_controller(current_path, current_controller, state, current_args) #dispatch not found return self._dispatch_first_found_default_or_lookup(state, remainder)
def _dispatch_first_found_default_or_lookup(self, state, remainder): """ When the dispatch has reached the end of the tree but not found an applicable method, so therefore we head back up the branches of the tree until we found a method which matches with a default or lookup method. """ if not state._notfound_stack: if self._use_index_fallback: #see if there is an index current_controller = state.controller method = getattr(current_controller, 'index', None) if method: if method_matches_args(method, state.params, remainder, self._use_lax_params): state.add_method(current_controller.index, remainder) return state raise HTTPNotFound else: m_type, meth, m_remainder, warning = state._notfound_stack.pop() if m_type == 'lookup': new_controller, new_remainder = meth(*m_remainder) state.add_controller(new_controller.__class__.__name__, new_controller) dispatcher = getattr(new_controller, '_dispatch', self._dispatch) r = dispatcher(state, new_remainder) return r elif m_type == 'default': state.add_method(meth, m_remainder) state.dispatcher = self return state
def _handle_custom_method(self, method, state, remainder): current_controller = state.controller method_name = method http_method = state.request.method method = self._find_first_exposed( current_controller, ('%s_%s' % (http_method, method_name), method_name, 'post_%s' % method_name)) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state # there might be a sub-controller with a custom method, let's go see if remainder: sub_controller = getattr(current_controller, remainder[0], None) if sub_controller: current = remainder[0] remainder = remainder[1:] r = self._dispatch_controller(current, sub_controller, state, remainder) if r: return r return self._dispatch_first_found_default_or_lookup(state, remainder)
def _handle_delete(self, http_method, state, remainder): current_controller = state.controller method = self._find_first_exposed(current_controller, ('post_delete', 'delete')) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.add_method(method, remainder) return state #you may not send a delete request to a non-delete function if remainder and self._is_exposed(current_controller, remainder[0]): raise HTTPMethodNotAllowed # there might be a sub-controller with a delete method, let's go see if remainder: sub_controller = getattr(current_controller, remainder[0], None) if sub_controller: remainder = remainder[1:] state.current_controller = sub_controller state.path = remainder r = self._dispatch_controller(remainder[0], sub_controller, state, remainder) if r: return r return self._dispatch_first_found_default_or_lookup(state, remainder)
def _handle_get(self, method, state, remainder): current_controller = state.controller if not remainder: method = self._find_first_exposed(current_controller, ('get_all', 'get')) if method: state.set_action(method, remainder) return state if self._is_exposed(current_controller, 'get_one'): method = current_controller.get_one if method and method_matches_args( method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state return self._dispatch_first_found_default_or_lookup( state, remainder) #test for "delete", "edit" or "new" r = self._handle_delete_edit_or_new(state, remainder) if r is not None: return r #test for custom REST-like attribute r = self._handle_custom_get(state, remainder) if r is not None: return r current_path = state.translate_path_piece(remainder[0]) if self._is_exposed(current_controller, current_path): state.set_action(getattr(current_controller, current_path), remainder[1:]) return state if self._is_controller(current_controller, current_path): current_controller = getattr(current_controller, current_path) return self._dispatch_controller(current_path, current_controller, state, remainder[1:]) method = self._find_first_exposed(current_controller, ('get_one', 'get')) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder)
def _handle_custom_get(self, state, remainder): controller = state.controller method_name = remainder[-1] current_controller = state.controller get_method = self._find_first_exposed(current_controller, ("get_%s" % method_name, method_name)) if get_method: new_remainder = remainder[:-1] if method_matches_args(get_method, state.params, new_remainder, self._use_lax_params): state.set_action(get_method, new_remainder) return state
def _handle_custom_get(self, state, remainder): controller = state.controller method_name = remainder[-1] current_controller = state.controller get_method = self._find_first_exposed(current_controller, ('get_%s' % method_name, method_name)) if get_method: new_remainder = remainder[:-1] if method_matches_args(get_method, state.params, new_remainder, self._use_lax_params): state.add_method(get_method, new_remainder) return state
def _handle_get(self, method, state, remainder): current_controller = state.controller if not remainder: method = self._find_first_exposed(current_controller, ("get_all", "get")) if method: state.set_action(method, remainder) return state if self._is_exposed(current_controller, "get_one"): method = current_controller.get_one if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder) # test for "delete", "edit" or "new" r = self._handle_delete_edit_or_new(state, remainder) if r is not None: return r # test for custom REST-like attribute r = self._handle_custom_get(state, remainder) if r is not None: return r current_path = state.translate_path_piece(remainder[0]) if self._is_exposed(current_controller, current_path): state.set_action(getattr(current_controller, current_path), remainder[1:]) return state if self._is_controller(current_controller, current_path): current_controller = getattr(current_controller, current_path) return self._dispatch_controller(current_path, current_controller, state, remainder[1:]) method = self._find_first_exposed(current_controller, ("get_one", "get")) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder)
def _handle_delete_edit_or_new(self, state, remainder): method_name = remainder[-1] if method_name not in ('new', 'edit', 'delete'): return if method_name == 'delete': method_name = 'get_delete' current_controller = state.controller if self._is_exposed(current_controller, method_name): method = getattr(current_controller, method_name) new_remainder = remainder[:-1] if method and method_matches_args(method, state.params, new_remainder, self._use_lax_params): state.add_method(method, new_remainder) return state
def _handle_delete_edit_or_new(self, state, remainder): method_name = remainder[-1] if method_name not in ("new", "edit", "delete"): return if method_name == "delete": method_name = "get_delete" current_controller = state.controller if self._is_exposed(current_controller, method_name): method = getattr(current_controller, method_name) new_remainder = remainder[:-1] if method and method_matches_args(method, state.params, new_remainder, self._use_lax_params): state.set_action(method, new_remainder) return state
def _handle_put_or_post(self, http_method, state, remainder): current_controller = state.controller if remainder: current_path = remainder[0] if self._is_exposed(current_controller, current_path): state.set_action(getattr(current_controller, current_path), remainder[1:]) return state if self._is_controller(current_controller, current_path): current_controller = getattr(current_controller, current_path) return self._dispatch_controller(current_path, current_controller, state, remainder[1:]) method = self._find_first_exposed(current_controller, [http_method]) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder)
def _handle_put_or_post(self, method, state, remainder): current_controller = state.controller if remainder: current_path = remainder[0] if self._is_exposed(current_controller, current_path): state.add_method(getattr(current_controller, current_path), remainder[1:]) return state if self._is_controller(current_controller, current_path): current_controller = getattr(current_controller, current_path) return self._dispatch_controller(current_path, current_controller, state, remainder[1:]) method_name = method method = self._find_first_exposed(current_controller, [method,]) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.add_method(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder)
def _handle_delete(self, http_method, state, remainder): current_controller = state.controller method = self._find_first_exposed(current_controller, ("post_delete", "delete")) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state # you may not send a delete request to a non-delete function if remainder and self._is_exposed(current_controller, remainder[0]): raise HTTPMethodNotAllowed # there might be a sub-controller with a delete method, let's go see if remainder: sub_controller = getattr(current_controller, remainder[0], None) if sub_controller: remainder = remainder[1:] r = self._dispatch_controller(remainder[0], sub_controller, state, remainder) if r: return r return self._dispatch_first_found_default_or_lookup(state, remainder)
def _handle_custom_method(self, method, state, remainder): current_controller = state.controller method_name = method http_method = state.request.method method = self._find_first_exposed( current_controller, ("%s_%s" % (http_method, method_name), method_name, "post_%s" % method_name) ) if method and method_matches_args(method, state.params, remainder, self._use_lax_params): state.set_action(method, remainder) return state # there might be a sub-controller with a custom method, let's go see if remainder: sub_controller = getattr(current_controller, remainder[0], None) if sub_controller: current = remainder[0] remainder = remainder[1:] r = self._dispatch_controller(current, sub_controller, state, remainder) if r: return r return self._dispatch_first_found_default_or_lookup(state, remainder)