Source code for errbot.core_plugins.wsview

from inspect import getmembers, ismethod
from json import loads
import logging

from bottle import Bottle, request

# noinspection PyUnresolvedReferences
from bottle import jinja2_view as view
# noinspection PyUnresolvedReferences
from bottle import jinja2_template as template

log = logging.getLogger(__name__)


[docs]def strip_path(): # strip the trailing slashes on incoming requests request.environ['PATH_INFO'] = request.environ['PATH_INFO'].rstrip('/')
[docs]class DynamicBottle(Bottle):
[docs] def __init__(self, catchall=True, autojson=True): super().__init__(catchall, autojson) self.add_hook('before_request', strip_path)
[docs] def del_route(self, route_name): deleted_route = None for route_ in self.routes[:]: if route_.name == route_name: self.routes.remove(route_) deleted_route = route_ break if not deleted_route: raise ValueError('Cannot find the route %s to delete' % route_name) del (self.router.rules[deleted_route.rule])
bottle_app = DynamicBottle()
[docs]def try_decode_json(req): data = req.body.read().decode() try: return loads(data) except Exception: return None
[docs]def reset_app(): """Zap everything here, useful for unit tests """ global bottle_app bottle_app = DynamicBottle()
[docs]def route(obj): """Check for functions to route in obj and route them.""" classname = obj.__class__.__name__ log.info("Checking %s for webhooks", classname) for name, func in getmembers(obj, ismethod): if getattr(func, '_err_webhook_uri_rule', False): log.info("Webhook routing %s", func.__name__) for verb in func._err_webhook_methods: wv = WebView(func, func._err_webhook_form_param, func._err_webhook_raw) bottle_app.route(func._err_webhook_uri_rule, verb, callback=wv, name=func.__name__ + '_' + verb)
[docs]class WebView(object):
[docs] def __init__(self, func, form_param, raw): if form_param is not None and raw: raise Exception("Incompatible parameters: form_param cannot be set if raw is True") self.func = func self.raw = raw self.form_param = form_param self.method_filter = lambda obj: ismethod(obj) and self.func.__name__ == obj.__name__
def __call__(self, *args, **kwargs): if self.raw: # override and gives the request directly response = self.func(request, **kwargs) elif self.form_param: content = request.forms.get(self.form_param) if content is None: raise Exception("Received a request on a webhook with a form_param defined, " "but that key ({}) is missing from the request.".format(self.form_param)) try: content = loads(content) except ValueError: log.debug('The form parameter is not JSON, return it as a string') response = self.func(content, **kwargs) else: data = try_decode_json(request) if not data: if hasattr(request, 'forms'): data = dict(request.forms) # form encoded else: data = request.body.read().decode() response = self.func(data, **kwargs) return response if response else '' # assume None as an OK response (simplifies the client side)