Source code for worldline.acquiring.sdk.communication.metadata_provider

import platform
import re
from base64 import b64encode
from typing import Optional, Sequence

from .request_header import RequestHeader

from worldline.acquiring.sdk.domain.data_object import DataObject
from worldline.acquiring.sdk.domain.shopping_cart_extension import ShoppingCartExtension
from worldline.acquiring.sdk.json.default_marshaller import DefaultMarshaller


class IterProperty(object):
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        return self.func(owner)


[docs] class MetadataProvider(object): """ Provides meta info about the server. """ __sdk_version = "0.1.0" __server_meta_info_header = "X-WL-ServerMetaInfo" __prohibited_headers = tuple(sorted([__server_meta_info_header, "Date", "Content-Type", "Authorization"], key=str.lower)) __metadata_headers: Sequence[RequestHeader] = None class ServerMetaInfo(DataObject): platform_identifier = None sdk_identifier = None sdk_creator = None integrator = None shopping_cart_extension = None def to_dictionary(self) -> dict: dictionary = super(MetadataProvider.ServerMetaInfo, self).to_dictionary() if self.platform_identifier is not None: dictionary['platformIdentifier'] = self.platform_identifier if self.sdk_identifier is not None: dictionary['sdkIdentifier'] = self.sdk_identifier if self.sdk_creator is not None: dictionary['sdkCreator'] = self.sdk_creator if self.integrator is not None: dictionary['integrator'] = self.integrator if self.shopping_cart_extension is not None: dictionary['shoppingCartExtension'] = self.shopping_cart_extension.to_dictionary() return dictionary def from_dictionary(self, dictionary: dict) -> 'MetadataProvider.ServerMetaInfo': super(MetadataProvider.ServerMetaInfo, self).from_dictionary(dictionary) if 'platformIdentifier' in dictionary: self.platform_identifier = dictionary['platformIdentifier'] if 'sdkIdentifier' in dictionary: self.sdk_identifier = dictionary['sdkIdentifier'] if 'sdkCreator' in dictionary: self.sdk_creator = dictionary['sdkCreator'] if 'integrator' in dictionary: self.integrator = dictionary['integrator'] if 'shoppingCartExtension' in dictionary: if not isinstance(dictionary['shoppingCartExtension'], dict): raise TypeError('value \'{}\' is not a dictionary'.format(dictionary['shoppingCartExtension'])) self.shopping_cart_extension = ShoppingCartExtension.create_from_dictionary(dictionary['shoppingCartExtension']) return self def __init__(self, integrator: Optional[str], shopping_cart_extension: Optional[ShoppingCartExtension] = None, additional_request_headers: Optional[Sequence[RequestHeader]] = ()): if integrator is None or not integrator.strip(): raise ValueError("integrator is required") MetadataProvider.__validate_additional_request_headers(additional_request_headers) def subber(name_or_value): return re.sub(r'\r?\n(?:(?![\r\n])\s)*', " ", name_or_value).strip() additional_request_headers = [RequestHeader(subber(header.name), subber(header.value)) for header in additional_request_headers] server_meta_info = self.ServerMetaInfo() server_meta_info.platform_identifier = self._platform_identifier server_meta_info.sdk_identifier = self._sdk_identifier server_meta_info.sdk_creator = "Worldline" server_meta_info.integrator = integrator server_meta_info.shopping_cart_extension = shopping_cart_extension server_meta_info_string = DefaultMarshaller.instance().marshal(server_meta_info) server_meta_info_header = RequestHeader(self.__server_meta_info_header, b64encode(server_meta_info_string.encode('utf-8')).decode('utf-8')) if not additional_request_headers: self.__metadata_headers = tuple([server_meta_info_header]) else: request_headers = [server_meta_info_header] request_headers.extend(additional_request_headers) self.__metadata_headers = tuple(request_headers) @staticmethod def __validate_additional_request_headers(additional_request_headers: Optional[Sequence[RequestHeader]]) -> None: if additional_request_headers is not None: for additional_request_header in additional_request_headers: MetadataProvider.__validate_additional_request_header(additional_request_header) @staticmethod def __validate_additional_request_header(additional_request_header: RequestHeader) -> None: try: if additional_request_header.name in MetadataProvider.__prohibited_headers: raise ValueError("request header not allowed: " + str(additional_request_header)) except AttributeError: raise AttributeError("Each request header should have an attribute 'name' and an attribute 'value'") @IterProperty def prohibited_headers(self) -> Sequence[str]: return self.__prohibited_headers @property def metadata_headers(self) -> Sequence[RequestHeader]: """ :return: The server related headers containing the metadata to be associated with the request (if any). This will always contain at least an automatically generated header X-WL-ServerMetaInfo. """ return self.__metadata_headers @property def _platform_identifier(self) -> str: return platform.system() + " " + platform.release() + "/" + \ platform.version() + " Python/" + platform.python_version() + \ " (" + platform.python_implementation() + "; " + \ str(platform.python_compiler()) + ")" @property def _sdk_identifier(self) -> str: return "PythonServerSDK/v" + self.__sdk_version