##// END OF EJS Templates
fix(caching): fixed problems with Cache query for users....
fix(caching): fixed problems with Cache query for users. The old way of querying caused the user get query to be always cached, and returning old results even in 2fa forms. The new limited query doesn't cache the user object resolving issues

File last commit:

r5114:6bd1539d default
r5365:ae8a165b default
Show More
adapters.py
280 lines | 6.4 KiB | text/x-python | PythonLexer
"""
Adapters
--------
.. contents::
:backlinks: none
The :func:`authomatic.login` function needs access to functionality like
getting the **URL** of the handler where it is being called, getting the
**request params** and **cookies** and **writing the body**, **headers**
and **status** to the response.
Since implementation of these features varies across Python web frameworks,
the Authomatic library uses **adapters** to unify these differences into a
single interface.
Available Adapters
^^^^^^^^^^^^^^^^^^
If you are missing an adapter for the framework of your choice, please
open an `enhancement issue <https://github.com/authomatic/authomatic/issues>`_
or consider a contribution to this module by
:ref:`implementing <implement_adapters>` one by yourself.
Its very easy and shouldn't take you more than a few minutes.
.. autoclass:: DjangoAdapter
:members:
.. autoclass:: Webapp2Adapter
:members:
.. autoclass:: WebObAdapter
:members:
.. autoclass:: WerkzeugAdapter
:members:
.. _implement_adapters:
Implementing an Adapter
^^^^^^^^^^^^^^^^^^^^^^^
Implementing an adapter for a Python web framework is pretty easy.
Do it by subclassing the :class:`.BaseAdapter` abstract class.
There are only **six** members that you need to implement.
Moreover if your framework is based on the |webob|_ or |werkzeug|_ package
you can subclass the :class:`.WebObAdapter` or :class:`.WerkzeugAdapter`
respectively.
.. autoclass:: BaseAdapter
:members:
"""
import abc
from authomatic.core import Response
class BaseAdapter(object, metaclass=abc.ABCMeta):
"""
Base class for platform adapters.
Defines common interface for WSGI framework specific functionality.
"""
@abc.abstractproperty
def params(self):
"""
Must return a :class:`dict` of all request parameters of any HTTP
method.
:returns:
:class:`dict`
"""
@abc.abstractproperty
def url(self):
"""
Must return the url of the actual request including path but without
query and fragment.
:returns:
:class:`str`
"""
@abc.abstractproperty
def cookies(self):
"""
Must return cookies as a :class:`dict`.
:returns:
:class:`dict`
"""
@abc.abstractmethod
def write(self, value):
"""
Must write specified value to response.
:param str value:
String to be written to response.
"""
@abc.abstractmethod
def set_header(self, key, value):
"""
Must set response headers to ``Key: value``.
:param str key:
Header name.
:param str value:
Header value.
"""
@abc.abstractmethod
def set_status(self, status):
"""
Must set the response status e.g. ``'302 Found'``.
:param str status:
The HTTP response status.
"""
class DjangoAdapter(BaseAdapter):
"""
Adapter for the |django|_ framework.
"""
def __init__(self, request, response):
"""
:param request:
An instance of the :class:`django.http.HttpRequest` class.
:param response:
An instance of the :class:`django.http.HttpResponse` class.
"""
self.request = request
self.response = response
@property
def params(self):
params = {}
params.update(self.request.GET.dict())
params.update(self.request.POST.dict())
return params
@property
def url(self):
return self.request.build_absolute_uri(self.request.path)
@property
def cookies(self):
return dict(self.request.COOKIES)
def write(self, value):
self.response.write(value)
def set_header(self, key, value):
self.response[key] = value
def set_status(self, status):
status_code, reason = status.split(' ', 1)
self.response.status_code = int(status_code)
class WebObAdapter(BaseAdapter):
"""
Adapter for the |webob|_ package.
"""
def __init__(self, request, response):
"""
:param request:
A |webob|_ :class:`Request` instance.
:param response:
A |webob|_ :class:`Response` instance.
"""
self.request = request
self.response = response
# =========================================================================
# Request
# =========================================================================
@property
def url(self):
return self.request.path_url
@property
def params(self):
return dict(self.request.params)
@property
def cookies(self):
return dict(self.request.cookies)
# =========================================================================
# Response
# =========================================================================
def write(self, value):
self.response.write(value)
def set_header(self, key, value):
self.response.headers[key] = str(value)
def set_status(self, status):
self.response.status = status
class Webapp2Adapter(WebObAdapter):
"""
Adapter for the |webapp2|_ framework.
Inherits from the :class:`.WebObAdapter`.
"""
def __init__(self, handler):
"""
:param handler:
A :class:`webapp2.RequestHandler` instance.
"""
self.request = handler.request
self.response = handler.response
class WerkzeugAdapter(BaseAdapter):
"""
Adapter for |flask|_ and other |werkzeug|_ based frameworks.
Thanks to `Mark Steve Samson <http://marksteve.com>`_.
"""
@property
def params(self):
return self.request.args
@property
def url(self):
return self.request.base_url
@property
def cookies(self):
return self.request.cookies
def __init__(self, request, response):
"""
:param request:
Instance of the :class:`werkzeug.wrappers.Request` class.
:param response:
Instance of the :class:`werkzeug.wrappers.Response` class.
"""
self.request = request
self.response = response
def write(self, value):
self.response.data = self.response.data.decode('utf-8') + value
def set_header(self, key, value):
self.response.headers[key] = value
def set_status(self, status):
self.response.status = status