Source code for errbot.core_plugins.wsview
import logging
from inspect import getmembers, ismethod
from json import loads
from flask import request
from flask.app import Flask
from flask.views import View
import errbot.core_plugins
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]def try_decode_json(req):
data = req.data.decode()
try:
return loads(data)
except Exception:
return None
[docs]def reset_app():
"""Zap everything here, useful for unit tests"""
errbot.core_plugins.flask_app = Flask(__name__)
[docs]def route(obj):
"""Check for functions to route in obj and route them."""
flask_app = errbot.core_plugins.flask_app
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__)
form_param = func._err_webhook_form_param
uri_rule = func._err_webhook_uri_rule
verbs = func._err_webhook_methods
raw = func._err_webhook_raw
callable_view = WebView.as_view(
func.__name__ + "_" + "_".join(verbs), func, form_param, raw
)
# Change existing rule.
for rule in flask_app.url_map._rules:
if rule.rule == uri_rule:
flask_app.view_functions[rule.endpoint] = callable_view
return
# Add a new rule
flask_app.add_url_rule(
uri_rule, view_func=callable_view, methods=verbs, strict_slashes=False
)
[docs]class WebView(View):
[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__
)
[docs] def dispatch_request(self, *args, **kwargs):
if self.raw: # override and gives the request directly
response = self.func(request, **kwargs)
elif self.form_param:
content = request.form.get(self.form_param)
if content is None:
raise Exception(
"Received a request on a webhook with a form_param defined, "
"but that key (%s) is missing from the request.",
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.data.decode()
response = self.func(data, **kwargs)
return (
response if response else ""
) # assume None as an OK response (simplifies the client side)