Skip to content

Commit

Permalink
Merge pull request #253 from gbin/rawwebhooks
Browse files Browse the repository at this point in the history
Added a raw option for the webhook API.
  • Loading branch information
gbin committed Jun 21, 2014
2 parents 36272a7 + d337cd7 commit ce3b7b0
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 4 deletions.
9 changes: 7 additions & 2 deletions errbot/builtins/wsview.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ def reset_app():
bottle_app = DynamicBottle()

class WebView(object):
def __init__(self, func, form_param):
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 object: ismethod(object) and self.func.__name__ == object.__name__

Expand All @@ -55,7 +58,9 @@ def __call__(self, *args, **kwargs):
logging.debug('Matching members %s -> %s' % (obj, matching_members))
if matching_members:
name, func = matching_members[0]
if self.form_param:
if self.raw: # override and gives the request directly
response = 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, "
Expand Down
8 changes: 6 additions & 2 deletions errbot/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ def webhook(*args, **kwargs):
:param form_param: The key who's contents will be passed to your method's `payload`
parameter. This is used for example when using the `application/x-www-form-urlencoded`
mimetype.
:param raw: Boolean to overrides the request decoding (including form_param) and
passes the raw http request to your method's `payload`.
The passed type in payload will provide the BaseRequest interface as defined here :
http://bottlepy.org/docs/dev/api.html#bottle.BaseRequest
This decorator should be applied to methods of :class:`~errbot.botplugin.BotPlugin`
classes to turn them into webhooks which can be reached on Err's built-in webserver.
Expand All @@ -123,11 +127,11 @@ def a_webhook(self, payload):
pass
"""

def decorate(func, uri_rule, methods=('POST', 'GET'), form_param=None):
def decorate(func, uri_rule, methods=('POST', 'GET'), form_param=None, raw=False):
logging.info("webhooks: Bind %s to %s" % (uri_rule, func.__name__))

for verb in methods:
bottle_app.route(uri_rule, verb, callback=WebView(func, form_param), name=func.__name__ + '_' + verb)
bottle_app.route(uri_rule, verb, callback=WebView(func, form_param, raw), name=func.__name__ + '_' + verb)
return func

if isinstance(args[0], str) or (PY2 and isinstance(args[0], basestring)):
Expand Down
4 changes: 4 additions & 0 deletions tests/webhooks_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ def test_webhooks_with_form_parameter_on_custom_url_decode_json_automatically(se
form = {'form': JSONOBJECT}
self.assertEquals(requests.post('http://localhost:3141/custom_form/', data=form).text, repr(json.loads(JSONOBJECT)))

def test_webhooks_with_raw_request(self):
form = {'form': JSONOBJECT}
self.assertEquals(requests.post('http://localhost:3141/raw/', data=form).text, "<class 'bottle.LocalRequest'>")

def test_generate_certificate_creates_usable_cert(self):
key_path = os.sep.join((BOT_DATA_DIR, "webserver_key.pem"))
cert_path = os.sep.join((BOT_DATA_DIR, "webserver_certificate.pem"))
Expand Down
5 changes: 5 additions & 0 deletions tests/webhooks_tests/webtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ def webhook3(self, payload):
def webhook4(self, payload):
logging.debug(str(payload))
return str(payload)

@webhook(r'/raw/', raw=True)
def webhook5(self, payload):
logging.debug(str(payload))
return str(type(payload))

0 comments on commit ce3b7b0

Please sign in to comment.