Commit 7fbde6a9 authored by Romain Courteaud's avatar Romain Courteaud

XXXXXXXX Revert "erp5_api_style: rewrite most of `jIOWebSection`"

This reverts commit bc17aafd.

Check if it fixes tests.
parent 7187b0de
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
############################################################################## ##############################################################################
# #
# Copyright (c) 2024 Nexedi SA and Contributors. All Rights Reserved. # Copyright (c) 2016 Nexedi SA and Contributors. All Rights Reserved.
# Cédric Le Ninivin <cedric.leninivin@nexedi.com>
# #
# WARNING: This program as such is intended to be used by professional # WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential # programmers who take the whole responsability of assessing all potential
...@@ -27,118 +28,140 @@ ...@@ -27,118 +28,140 @@
############################################################################## ##############################################################################
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from AccessControl import Unauthorized
from Acquisition import aq_inner from Acquisition import aq_inner
from OFS.Traversable import NotFound
from zExceptions import NotFound, Unauthorized
from Products.ERP5Type import Permissions
from erp5.component.mixin.DocumentExtensibleTraversableMixin import DocumentExtensibleTraversableMixin
from erp5.component.document.WebSection import WebSection from erp5.component.document.WebSection import WebSection
from Products.ERP5Type import Permissions
from zExceptions import HTTPClientError
from zLOG import LOG, INFO
MARKER = [] MARKER = []
ALLOWED_MODES = ["put", "get", "post", "allDocs"]
class jIOAPITraverseErrorWrapper(object): # Redefine an Unauthorized error to avoid Zope redirecting the user to the main ERP5 login form
""" class jIOUnauthorized(HTTPClientError):
JSON error object, to avoid ERP5 default error pages. errmsg = 'Unauthorized'
Publishable but non-Persistent and without Acquisition. status = 401
"""
def __init__(self, error_context, portal): def __init__(self, underlyingError):
self.error_context = error_context HTTPClientError.__init__(self)
self.portal = portal self.underlyingError = underlyingError
# Used for debugging, especially in tests
def __str__(self): def __str__(self):
return str(self.error_context) return str(self.underlyingError)
def __call__(self):
portal = self.portal
# Skin used to allow replacement and because Manager proxy role is needed
portal.ERP5Site_logApiErrorAndReturn(**self.error_context)
def __bytes__(self):
return bytes(self.underlyingError)
class jIOMethod(object): def convertTojIOAPICall(function):
""" """
Represents one of the four possible jIO methods. Wrap the method to create a log entry for each invocation to the zope logger
Publishable but non-Persistent and without Acquisition.
XXX: Acquisition might be suitable here
""" """
def wrapper(self, *args, **kwd):
def __init__(self, mode_name, web_section): """
super(jIOMethod, self).__init__() Log the call, and the result of the call
self.mode_name = mode_name """
self.web_section = web_section assert(self.REQUEST.REQUEST_METHOD == "POST")
def __call__(self):
self.web_section.REQUEST.response.setHeader("Content-Type", "application/json")
try: try:
return self.web_section.ERP5Site_asjIOStyle( self.REQUEST.response.setHeader("Content-Type", "application/json")
mode=self.mode_name, retval = function(self, *args, **kwd)
text_content=self.web_section.REQUEST.get("BODY"), except Unauthorized, e:
data_dict=None, body = self.ERP5Site_logApiErrorAndReturn(
error_code="401",
error_message=str(e),
error_name="Unauthorized"
)
self.REQUEST.response.setBody(body, lock=True)
raise jIOUnauthorized(e)
except NotFound, e:
LOG('jIOWebSection', INFO, 'Converting NotFound to NotFound error mesage in JSON,',
error=True)
body = self.ERP5Site_logApiErrorAndReturn(
error_code="404",
error_message=str(e),
error_name="NotFound"
)
self.REQUEST.response.setBody(body, lock=True)
raise
except:
LOG('jIOWebSection', INFO, 'Converting Error to InternalError message in JSON,',
error=True)
body = self.ERP5Site_logApiErrorAndReturn(
error_code="500",
error_message="Internal Server Error",
error_name="InternalError"
) )
except Exception as e: self.REQUEST.response.setBody(body, lock=True)
error_context = { raise
"error_code": 500,
"error_name": "API-INTERNAL-ERROR", return '%s' % retval
"error_message": str(e) wrapper.__doc__ = function.__doc__
} return wrapper
# This NotFound catches instance of objects not found inside API call
if isinstance(e, NotFound):
error_context["error_code"] = 404
error_context["error_name"] = "API-NOT-FOUND"
elif isinstance(e, Unauthorized):
error_context["error_code"] = 403
error_context["error_name"] = "API-UNAUTHORIZED"
# Avoid information leak when Unauthorized
del error_context["error_message"]
# Skin used to allow replacement and because Manager proxy role is needed
self.web_section.ERP5Site_logApiErrorAndReturn(**error_context)
class jIOWebSection(WebSection): class jIOWebSection(WebSection):
portal_type = "jIO Web Section" """
This Web Section is a wrapper to jIO to pass content in the body
"""
# Declarative security portal_type = 'jIO Web Section'
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
security.declareProtected(Permissions.AccessContentsInformation, "getLayoutProperty") security.declareProtected(Permissions.AccessContentsInformation, 'getLayoutProperty')
def getLayoutProperty(self, key, default=None): def getLayoutProperty(self, key, default=None):
""" """
A simple method to get a property of the current by A simple method to get a property of the current by
acquiring it from the current section or its parents. acquiring it from the current section or its parents.
""" """
section = aq_inner(self) section = aq_inner(self)
while section.getPortalType() in ("Web Section", "Web Site", "Static Web Section", "Static Web Site", "jIO Web Section"): while section.getPortalType() in ('Web Section', 'Web Site', 'Static Web Section', 'Static Web Site',
'jIO Web Section'):
result = section.getProperty(key, MARKER) result = section.getProperty(key, MARKER)
if result not in (MARKER, None): if result not in (MARKER, None):
return result return result
section = section.aq_parent section = section.aq_parent
return default return default
security.declareProtected(Permissions.View, "_bobo_traverse__") @convertTojIOAPICall
def __bobo_traverse__(self, request, name): def _asjIOStyle(self, mode, text_content="", data_dict=None):
if name in ALLOWED_MODES: return self.ERP5Site_asjIOStyle(
return jIOMethod(name, self) mode=mode,
text_content=text_content,
data_dict=data_dict,
)
document = None security.declareProtected(Permissions.View, 'get')
try: def get(self): #pylint:disable=arguments-differ
# Inheritance as follows: jIOWebSection <| WebSection <| (Domain, DocumentExtensibleTraversableMixin) """
# Use DocumentExtensibleTraversableMixin traversal to avoid ERP5 HTML 404 page. Taken from WebSection Bobo Traverse, the difference is that
document = DocumentExtensibleTraversableMixin.__bobo_traverse__(self, request, name) __bobo_traverse__ from DocumentExtensibleTraversableMixin is not called
# This NotFound catches objects not found during traversal """
except NotFound as e: # Register current web site physical path for later URL generation
error_context = { return self._asjIOStyle(mode="get", text_content=self.REQUEST.get('BODY'))
"error_code": 404,
"error_message": str(e), security.declareProtected(Permissions.View, 'post')
"error_name": "NotFound", def post(self):
"text_content": request.get("BODY") """
} Taken from WebSection Bobo Traverse, the difference is that
document = jIOAPITraverseErrorWrapper(error_context, self.getPortalObject()) __bobo_traverse__ from DocumentExtensibleTraversableMixin is not called
"""
return document # Register current web site physical path for later URL generation
return self._asjIOStyle(mode="post", text_content=self.REQUEST.get('BODY'))
security.declareProtected(Permissions.View, 'put')
def put(self):
"""
Taken from WebSection Bobo Traverse, the difference is that
__bobo_traverse__ from DocumentExtensibleTraversableMixin is not called
"""
# Register current web site physical path for later URL generation
return self._asjIOStyle(mode="put", text_content=self.REQUEST.get('BODY'))
security.declareProtected(Permissions.View, 'allDocs')
def allDocs(self):
"""
Taken from WebSection Bobo Traverse, the difference is that
__bobo_traverse__ from DocumentExtensibleTraversableMixin is not called
"""
# Register current web site physical path for later URL generation
return self._asjIOStyle(mode="allDocs", text_content=self.REQUEST.get('BODY'))
...@@ -7,6 +7,7 @@ error = context.getPortalObject().error_record_module.newContent( ...@@ -7,6 +7,7 @@ error = context.getPortalObject().error_record_module.newContent(
description=str(error_message), description=str(error_message),
text_content=str(text_content) text_content=str(text_content)
) )
container.REQUEST.RESPONSE.setStatus(error_code, lock=True)
# We follow here Paypal api guideline # We follow here Paypal api guideline
# https://github.com/paypal/api-standards/blob/master/api-style-guide.md#error-schema # https://github.com/paypal/api-standards/blob/master/api-style-guide.md#error-schema
error_dict = { error_dict = {
...@@ -23,10 +24,4 @@ if error_link: ...@@ -23,10 +24,4 @@ if error_link:
if detail_list: if detail_list:
error_dict["details"] = detail_list error_dict["details"] = detail_list
error.setDescription(str(error_message) + "\n".join([str(x) for x in detail_list])) error.setDescription(str(error_message) + "\n".join([str(x) for x in detail_list]))
return json.dumps(error_dict, indent=2)
serialized_error = json.dumps(error_dict, indent=2)
context.REQUEST.response.setHeader("Content-Type", "application/json")
context.REQUEST.response.setStatus(error_code, lock=True)
context.REQUEST.response.setBody(serialized_error, lock=True)
return serialized_error
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment