controllers.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  2. import json
  3. import logging
  4. import werkzeug
  5. from psycopg2.errorcodes import SERIALIZATION_FAILURE
  6. from psycopg2 import OperationalError
  7. from odoo import http
  8. from odoo.exceptions import AccessError, UserError
  9. from odoo.http import request
  10. from odoo.tools import replace_exceptions
  11. from odoo.addons.web.controllers.utils import ensure_db
  12. _logger = logging.getLogger(__name__)
  13. CT_JSON = {'Content-Type': 'application/json; charset=utf-8'}
  14. WSGI_SAFE_KEYS = {'PATH_INFO', 'QUERY_STRING', 'RAW_URI', 'SCRIPT_NAME', 'wsgi.url_scheme'}
  15. # Force serialization errors. Patched in some tests.
  16. should_fail = None
  17. class SerializationFailureError(OperationalError):
  18. pgcode = SERIALIZATION_FAILURE
  19. class TestHttp(http.Controller):
  20. # =====================================================
  21. # Greeting
  22. # =====================================================
  23. @http.route(['/test_http/greeting', '/test_http/greeting-none'], type='http', auth='none')
  24. def greeting_none(self):
  25. return "Tek'ma'te"
  26. @http.route('/test_http/greeting-public', type='http', auth='public')
  27. def greeting_public(self):
  28. assert request.env.user, "ORM should be initialized"
  29. return "Tek'ma'te"
  30. @http.route('/test_http/greeting-user', type='http', auth='user')
  31. def greeting_user(self):
  32. assert request.env.user, "ORM should be initialized"
  33. return "Tek'ma'te"
  34. @http.route('/test_http/wsgi_environ', type='http', auth='none')
  35. def wsgi_environ(self):
  36. environ = {
  37. key: val for key, val in request.httprequest.environ.items()
  38. if (key.startswith('HTTP_') # headers
  39. or key.startswith('REMOTE_')
  40. or key.startswith('REQUEST_')
  41. or key.startswith('SERVER_')
  42. or key.startswith('werkzeug.proxy_fix.')
  43. or key in WSGI_SAFE_KEYS)
  44. }
  45. return request.make_response(
  46. json.dumps(environ, indent=4),
  47. headers=list(CT_JSON.items())
  48. )
  49. # =====================================================
  50. # Echo-Reply
  51. # =====================================================
  52. @http.route('/test_http/echo-http-get', type='http', auth='none', methods=['GET'])
  53. def echo_http_get(self, **kwargs):
  54. return str(kwargs)
  55. @http.route('/test_http/echo-http-post', type='http', auth='none', methods=['POST'], csrf=False)
  56. def echo_http_post(self, **kwargs):
  57. return str(kwargs)
  58. @http.route('/test_http/echo-http-csrf', type='http', auth='none', methods=['POST'], csrf=True)
  59. def echo_http_csrf(self, **kwargs):
  60. return str(kwargs)
  61. @http.route('/test_http/echo-http-context-lang', type='http', auth='public', methods=['GET'], csrf=False)
  62. def echo_http_context_lang(self, **kwargs):
  63. return request.env.context.get('lang', '')
  64. @http.route('/test_http/echo-json', type='json', auth='none', methods=['POST'], csrf=False)
  65. def echo_json(self, **kwargs):
  66. return kwargs
  67. @http.route('/test_http/echo-json-context', type='json', auth='user', methods=['POST'], csrf=False)
  68. def echo_json_context(self, **kwargs):
  69. return request.env.context
  70. @http.route('/test_http/echo-json-over-http', type='http', auth='none', methods=['POST'], csrf=False)
  71. def echo_json_over_http(self):
  72. try:
  73. data = request.get_json_data()
  74. except ValueError as exc:
  75. raise werkzeug.exceptions.BadRequest("Invalid JSON data") from exc
  76. return request.make_json_response(data)
  77. # =====================================================
  78. # Models
  79. # =====================================================
  80. @http.route('/test_http/<model("test_http.galaxy"):galaxy>', auth='public')
  81. def galaxy(self, galaxy):
  82. if not galaxy.exists():
  83. raise UserError('The Ancients did not settle there.')
  84. return http.request.render('test_http.tmpl_galaxy', {
  85. 'galaxy': galaxy,
  86. 'stargates': http.request.env['test_http.stargate'].search([
  87. ('galaxy_id', '=', galaxy.id)
  88. ]),
  89. })
  90. @http.route('/test_http/<model("test_http.galaxy"):galaxy>/<model("test_http.stargate"):gate>', auth='user')
  91. def stargate(self, galaxy, gate):
  92. if not gate.exists():
  93. raise UserError("The goa'uld destroyed the gate")
  94. return http.request.render('test_http.tmpl_stargate', {
  95. 'gate': gate
  96. })
  97. # =====================================================
  98. # Cors
  99. # =====================================================
  100. @http.route('/test_http/cors_http_default', type='http', auth='none', cors='*')
  101. def cors_http(self):
  102. return "Hello"
  103. @http.route('/test_http/cors_http_methods', type='http', auth='none', methods=['GET', 'PUT'], cors='*')
  104. def cors_http_verbs(self, **kwargs):
  105. return "Hello"
  106. @http.route('/test_http/cors_json', type='json', auth='none', cors='*')
  107. def cors_json(self, **kwargs):
  108. return {}
  109. # =====================================================
  110. # Dual nodb/db
  111. # =====================================================
  112. @http.route('/test_http/ensure_db', type='http', auth='none')
  113. def ensure_db_endpoint(self, db=None):
  114. ensure_db()
  115. assert request.db, "There should be a database"
  116. return request.db
  117. # =====================================================
  118. # Session
  119. # =====================================================
  120. @http.route('/test_http/geoip', type='http', auth='none')
  121. def geoip(self):
  122. return str(request.geoip)
  123. @http.route('/test_http/save_session', type='http', auth='none')
  124. def touch(self):
  125. request.session.touch()
  126. return ''
  127. # =====================================================
  128. # Errors
  129. # =====================================================
  130. @http.route('/test_http/json_value_error', type='json', auth='none')
  131. def json_value_error(self):
  132. raise ValueError('Unknown destination')
  133. @http.route('/test_http/hide_errors/decorator', type='http', auth='none')
  134. @replace_exceptions(AccessError, by=werkzeug.exceptions.NotFound())
  135. def hide_errors_decorator(self, error):
  136. if error == 'AccessError':
  137. raise AccessError("Wrong iris code")
  138. if error == 'UserError':
  139. raise UserError("Walter is AFK")
  140. @http.route('/test_http/hide_errors/context-manager', type='http', auth='none')
  141. def hide_errors_context_manager(self, error):
  142. with replace_exceptions(AccessError, by=werkzeug.exceptions.NotFound()):
  143. if error == 'AccessError':
  144. raise AccessError("Wrong iris code")
  145. if error == 'UserError':
  146. raise UserError("Walter is AFK")
  147. @http.route("/test_http/upload_file", methods=["POST"], type="http", auth="none", csrf=False)
  148. def upload_file_retry(self, ufile):
  149. global should_fail # pylint: disable=W0603
  150. if should_fail is None:
  151. raise ValueError("should_fail should be set.")
  152. data = ufile.read()
  153. if should_fail:
  154. should_fail = False # Fail once
  155. raise SerializationFailureError()
  156. return data.decode()