1# Copyright 2015 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""Simple Request handler using Jinja2 templates.""" 6 7import logging 8import os 9 10import jinja2 11import webapp2 12 13from google.appengine.api import users 14 15from dashboard import utils 16from dashboard import xsrf 17 18JINJA2_ENVIRONMENT = jinja2.Environment( 19 loader=jinja2.FileSystemLoader( 20 [os.path.join(os.path.dirname(__file__), 'templates')]), 21 # Security team suggests that autoescaping be enabled. 22 autoescape=True, 23 extensions=['jinja2.ext.autoescape']) 24 25 26class RequestHandler(webapp2.RequestHandler): 27 """Base class for requests. Does common template and error handling tasks.""" 28 29 def RenderHtml(self, template_file, template_values, status=200): 30 """Renders HTML given template and values. 31 32 Args: 33 template_file: string. File name under templates directory. 34 template_values: dict. Mapping of template variables to corresponding. 35 values. 36 status: int. HTTP status code. 37 """ 38 self.response.set_status(status) 39 template = JINJA2_ENVIRONMENT.get_template(template_file) 40 self.GetDynamicVariables(template_values) 41 self.response.out.write(template.render(template_values)) 42 43 def RenderStaticHtml(self, filename): 44 filename = os.path.join(os.path.dirname(__file__), 'static', filename) 45 contents = open(filename, 'r') 46 self.response.out.write(contents.read()) 47 contents.close() 48 49 def GetDynamicVariables(self, template_values, request_path=None): 50 """Gets the values that vary for every page. 51 52 Args: 53 template_values: dict of name/value pairs. 54 request_path: path for login urls, None if using the current path. 55 """ 56 user_info = '' 57 xsrf_token = '' 58 user = users.get_current_user() 59 display_username = 'Sign in' 60 title = 'Sign in to an account' 61 is_admin = False 62 if user: 63 display_username = user.email() 64 title = 'Switch user' 65 xsrf_token = xsrf.GenerateToken(user) 66 is_admin = users.is_current_user_admin() 67 try: 68 login_url = users.create_login_url(request_path or self.request.path_qs) 69 except users.RedirectTooLongError: 70 # On the bug filing pages, the full login URL can be too long. Drop 71 # the correct redirect URL, since the user should already be logged in at 72 # this point anyway. 73 login_url = users.create_login_url('/') 74 user_info = '<a href="%s" title="%s">%s</a>' % ( 75 login_url, title, display_username) 76 template_values['login_url'] = login_url 77 template_values['display_username'] = display_username 78 template_values['user_info'] = user_info 79 template_values['is_admin'] = is_admin 80 template_values['is_internal_user'] = utils.IsInternalUser() 81 template_values['xsrf_token'] = xsrf_token 82 template_values['xsrf_input'] = ( 83 '<input type="hidden" name="xsrf_token" value="%s">' % xsrf_token) 84 template_values['login_url'] = login_url 85 return template_values 86 87 def ReportError(self, error_message, status=500): 88 """Reports the given error to the client and logs the error. 89 90 Args: 91 error_message: The message to log and send to the client. 92 status: The HTTP response code to use. 93 """ 94 logging.error(error_message) 95 self.response.set_status(status) 96 self.response.out.write('%s\nrequest_id:%s\n' % 97 (error_message, utils.GetRequestId())) 98 99 def ReportWarning(self, warning_message, status=200): 100 """Reports a warning to the client and logs the warning. 101 102 Args: 103 warning_message: The warning message to log (as an error). 104 status: The http response code to use. 105 """ 106 logging.warning(warning_message) 107 self.response.set_status(status) 108 self.response.out.write('%s\nrequest_id:%s\n' % 109 (warning_message, utils.GetRequestId())) 110 111 112class InvalidInputError(Exception): 113 """An error class for invalid user input query parameter values.""" 114 pass 115