tailbone/tailbone/api/core.py

124 lines
4.4 KiB
Python

# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Tailbone Web API - Core Views
"""
from __future__ import unicode_literals, absolute_import
from rattail.util import load_object
from tailbone.views import View
def api(view_meth):
"""
Common decorator for all API views. Ideally this would not be needed..but
for now, alas, it is.
"""
def wrapped(view, *args, **kwargs):
# TODO: why doesn't this work here...? (instead we have to repeat this
# code in lots of other places)
# if view.request.method == 'OPTIONS':
# return view.request.response
# invoke the view logic first, since presumably it may involve a
# redirect in which case we don't really need to add the CSRF token.
# main known use case for this is the /logout endpoint - if that gets
# hit then the "current" (old) session will be destroyed, in which case
# we can't use the token from that, but instead must generate a new one.
result = view_meth(view, *args, **kwargs)
# explicitly set CSRF token cookie, unless OPTIONS request
# TODO: why doesn't pyramid do this for us again?
if view.request.method != 'OPTIONS':
view.request.response.set_cookie(name='XSRF-TOKEN',
value=view.request.session.get_csrf_token())
return result
return wrapped
class APIView(View):
"""
Base class for all API views.
"""
def pretty_datetime(self, dt):
if not dt:
return ""
return dt.strftime('%Y-%m-%d @ %I:%M %p')
def get_user_info(self, user):
"""
This method is present on *all* API views, and is meant to provide a
single means of obtaining "common" user info, for return to the caller.
Such info may be returned in several places, e.g. upon login but also
in the "check session" call, or e.g. as part of a broader return value
from any other call.
:returns: Dictionary of user info data, ready for JSON serialization.
Note that you should *not* (usually) override this method in any view,
but instead configure a "supplemental" function which can then add or
replace info entries. Config for that looks like e.g.:
.. code-block:: ini
[tailbone.api]
extra_user_info = poser.web.api.util:extra_user_info
Note that the above config assumes a simple *function* defined in your
``util`` module; such a function would look like e.g.::
def extra_user_info(request, user, **info):
# add favorite color
info['favorite_color'] = 'green'
# override display name
info['display_name'] = "TODO"
# remove short_name
info.pop('short_name', None)
return info
"""
# basic / default info
is_admin = user.is_admin()
info = {
'uuid': user.uuid,
'username': user.username,
'display_name': user.display_name,
'short_name': user.get_short_name(),
'is_admin': is_admin,
'is_root': is_admin and self.request.session.get('is_root', False),
}
# maybe get/use "extra" info
extra = self.rattail_config.get('tailbone.api', 'extra_user_info',
usedb=False)
if extra:
extra = load_object(extra)
info = extra(self.request, user, **info)
return info