class PortalTemplate(object): """ Construct the template data needed to render each page, and return the HTTP response and data needed to render the page client-side. """ def __init__(self, portal): """ Initialize the portal template class. """ self.portal = portal # Shared modules self.json = json self.base64 = base64 self.OrderedDict = OrderedDict # Configuration / logger self.conf = config.parse() self.log = logger.create(__name__, self.conf.portal.log) # URL panel self.panel = self.get_query_key('panel') # Threaded API responses self._response = {} # Template data self._tdata = {} # Response filter self.filter = APIFilter() def redirect(self, location): """ Return an HTTPResponseRedirect object. """ return HttpResponseRedirect(location) def get_query_key(self, key): """ Retrieve a key value from the URL query string. """ # Split the query string into an array of key/value pairs query_obj = {} for query_pair in self.portal.request.query.split('&'): if '=' in query_pair: query_set = query_pair.split('=') query_obj[query_set[0]] = query_set[1] else: query_obj[query_pair] = True # If the key is found if key in query_obj: return query_obj[key] # Key not found return False def request_contains(self, req=None, attr=None, values=None): """ Check if the request data contains the specified attribute and values combination. """ if not req or not attr: return False # Check if the request data object contains the specified attribute if hasattr(req, attr): # If testing for supported attributed values if values and isinstance(values, list): if getattr(req, attr) in values: return True return False return True return False def set_template(self, data={}): """ Set the target template file and data. """ self._tdata = self._template_data(data) def set_redirect(self, path): """ Return a template data redirect attribute. """ return { 'redirect': path } def _template_data(self, objs={}): """ Merge base template data and page specific template data. """ # Set the base parameters params = { 'BASE': { # Connection user attributes 'user': { 'is_admin': self.portal.request.is_admin, 'is_authenticated': self.portal.authenticated, 'groups': self.portal.user.get('groups'), 'name': self.portal.user.get('username'), 'email': self.portal.user.get('email') }, # API connection parameters 'api': { 'params': None if not hasattr(self.portal.api, 'params') else self.portal.api.params }, # Request parameters 'request': { 'current': self.portal.request.current, 'path': self.portal.request.path } } } # Replace the API URL with the Socket.IO proxy if params['BASE']['api']['params']: params['BASE']['api']['params']['url'] = '%s://%s:%s' % (self.conf.socket.proto, self.conf.socket.host, self.conf.socket.port) # Merge extra template parameters for k,v in objs.iteritems(): # Do not overwrite the 'BASE' key if k == 'BASE': raise Exception('Template data key [BASE] is reserved for internal use only') # Append the template data key params[k] = v # Return the template data object return params def api_call(self, module, method, data=None): """ Wrapper method for the APIClient class instance. """ # Make sure the base attribute exists if hasattr(self.portal.api.client, module): api_base = getattr(self.portal.api.client, module) # Make sure the method attribute exists if hasattr(api_base, method): api_method = getattr(api_base, method) # Run the API request and return a filtered response return self.filter.object(self.portal.api.response(api_method(data))).map('%s.%s' % (module, method)) # Invalid base/method attribute return False def _api_call_threaded_worker(self, key, base, method, data=None): """ Worker method for handled threaded API calls. """ self._response[key] = self.api_call(base, method, data) def api_call_threaded(self, requests): """ Interface for a multi-threaded API call, to speed up the request/response cycle when calling multiple endpoints when rendering a template. """ # Threads / responses threads = [] # Process each request for key,attr in requests.iteritems(): # Get any request data data = None if (len(attr) == 2) else attr[2] # Create the thread, append, and start thread = Thread(target=self._api_call_threaded_worker, args=[key, attr[0], attr[1], data]) threads.append(thread) thread.start() # Wait for the API calls to complete for thread in threads: thread.join() self.log.info('API_CALL_THREADED: %s' % str(self._response)) # Return the response object return self._response def response(self): """ Construct and return the template response. """ # If redirecting if 'redirect' in self._tdata: return HttpResponseRedirect(self._tdata['redirect']) # Return the template response try: return render(self.portal.request.RAW, 'interface.html', self._tdata) # Failed to render template except Exception as e: # Log the exception self.log.exception('Failed to render application template interface: %s' % str(e)) # Get the exception data e_type, e_info, e_trace = sys.exc_info() # Format the exception message e_msg = '%s: %s' % (e_type.__name__, e_info) # Load the error template t = loader.get_template('core/error/500.html') # Return a server error return HttpResponseServerError(t.render(RequestContext(self.portal.request.RAW, { 'error': 'An error occurred when rendering the requested page.', 'debug': None if self.conf.portal.debug else (e_msg, reversed(traceback.extract_tb(e_trace))) })))
class PortalTemplate(object): """ Construct the template data needed to render each page, and return the HTTP response and data needed to render the page client-side. """ def __init__(self, portal): """ Initialize the portal template class. """ self.portal = portal # Shared modules self.json = json self.base64 = base64 self.OrderedDict = OrderedDict # Configuration / logger self.conf = config.parse() self.log = logger.create(__name__, self.conf.portal.log) # URL panel self.panel = self.get_query_key('panel') # Template data self._tdata = {} # Response filter self.filter = APIFilter() def redirect(self, location): """ Return an HTTPResponseRedirect object. """ return HTTPResponseRedirect(location) def get_query_key(self, key): """ Retrieve a key value from the URL query string. """ # Split the query string into an array of key/value pairs query_obj = {} for query_pair in self.portal.request.query.split('&'): if '=' in query_pair: query_set = query_pair.split('=') query_obj[query_set[0]] = query_set[1] else: query_obj[query_pair] = True # If the key is found if key in query_obj: return query_obj[key] # Key not found return False def request_contains(self, req=None, attr=None, values=None): """ Check if the request data contains the specified attribute and values combination. """ if not req or not attr: return False # Check if the request data object contains the specified attribute if hasattr(req, attr): # If testing for supported attributed values if values and isinstance(values, list): if getattr(req, attr) in values: return True return False return True return False def set_template(self, data={}): """ Set the target template file and data. """ self._tdata = self._template_data(data) def set_redirect(self, path): """ Return a template data redirect attribute. """ return { 'redirect': path } def _template_data(self, objs={}): """ Merge base template data and page specific template data. """ # Set the base parameters base = { 'api_params': None if not hasattr(self.portal.api, 'params') else self.portal.api.params, 'authenticated': self.portal.authenticated, 'request': { 'current': self.portal.request.current } } # Merge extra template parameters for k,v in objs.iteritems(): base[k] = v # Return the template data object return base def api_call(self, base, method, data=None): """ Wrapper method for the APIClient class instance. """ # Make sure the base attribute exists if hasattr(self.portal.api.client, base): api_base = getattr(self.portal.api.client, base) # Make sure the method attribute exists if hasattr(api_base, method): api_method = getattr(api_base, method) # Run the API request and return a filtered response return self.filter.object(self.portal.api.response(api_method(data))).map('%s.%s' % (base, method)) # Invalid base/method attribute return False def response(self): """ Construct and return the template response. """ # If redirecting if 'redirect' in self._tdata: return HttpResponseRedirect(self._tdata['redirect']) # Return the template response try: return render_to_response('interface.html', self._tdata, context_instance=RequestContext(self.portal.request_raw)) # Failed to render template except Exception as e: # Log the exception self.log.exception('Failed to render application template interface: %s' % str(e)) # Load the error template t = loader.get_template('core/error/500.html') # Return a server error return HttpResponseServerError(t.render(RequestContext(self.portal.request_raw, { 'error': 'An error occurred when rendering the requested page.' })))