Skip to content

Commit

Permalink
request: headers and url parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
jlmadurga committed Mar 10, 2016
1 parent 08a33e9 commit a972494
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 32 deletions.
44 changes: 44 additions & 0 deletions microbot/migrations/0003_auto_20160310_0941.py
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('microbot', '0002_environmentvar'),
]

operations = [
migrations.CreateModel(
name='HeaderParam',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('key', models.CharField(max_length=255, verbose_name='Key')),
('value_template', models.CharField(max_length=255, verbose_name='Value template')),
('request', models.ForeignKey(related_name='header_parameters', verbose_name='Request', to='microbot.Bot')),
],
options={
'verbose_name': 'Header Parameter',
'verbose_name_plural': 'Header Parameters',
},
),
migrations.CreateModel(
name='UrlParam',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('key', models.CharField(max_length=255, verbose_name='Key')),
('value_template', models.CharField(max_length=255, verbose_name='Value template')),
('request', models.ForeignKey(related_name='url_parameters', verbose_name='Request', to='microbot.Bot')),
],
options={
'verbose_name': 'Url Parameter',
'verbose_name_plural': 'Url Parameters',
},
),
migrations.RemoveField(
model_name='request',
name='content_type',
),
]
2 changes: 1 addition & 1 deletion microbot/models/__init__.py
@@ -1,4 +1,4 @@
from microbot.models.telegram_api import (User, Chat, Message, Update) # NOQA
from microbot.models.bot import Bot # NOQA
from microbot.models.handler import Handler, Request # NOQA
from microbot.models.handler import Handler, Request, UrlParam, HeaderParam # NOQA
from microbot.models.environment_vars import EnvironmentVar # NOQA
61 changes: 53 additions & 8 deletions microbot/models/handler.py
Expand Up @@ -11,6 +11,23 @@

logger = logging.getLogger(__name__)


class AbstractParam(models.Model):
key = models.CharField(_('Key'), max_length=255)
value_template = models.CharField(_('Value template'), max_length=255)

class Meta:
abstract = True
verbose_name = _('Parameter')
verbose_name_plural = _('Parameters')

def __str__(self):
return "(%s, %s)" % (self.key, self.value_template)

def process(self, **context):
value_template = Template(self.value_template)
return value_template.render(**context)

@python_2_unicode_compatible
class Request(models.Model):
url_template = models.CharField(_('Url template'), max_length=255)
Expand All @@ -22,7 +39,6 @@ class Request(models.Model):
(DELETE, _("Delete")),
)
method = models.CharField(_("Method"), max_length=128, default=GET, choices=METHOD_CHOICES)
content_type = models.CharField(_('Content type'), max_length=255, null=True, blank=True)
data = models.TextField(null=True, blank=True, verbose_name=_("Data of the request"))

class Meta:
Expand All @@ -32,21 +48,50 @@ class Meta:
def __str__(self):
return "%s(%s)" % (self.method, self.url_template)

def _url_params(self, **context):
params = {}
for param in self.url_parameters.all():
params[param.key] = param.process(**context)
return params

def _header_params(self, **context):
headers = {}
for header in self.header_parameters.all():
headers[header.key] = header.process(**context)
return headers

def process(self, **context):
url_template = Template(self.url_template)
url = url_template.render(**context)
logger.debug("Request %s generates url %s" % (self, url))
logger.debug("Request %s generates url %s" % (self, url))
params = self._url_params(**context)
logger.debug("Request %s generates params %s" % (self, params))
headers = self._header_params(**context)
logger.debug("Request %s generates header %s" % (self, headers))

if self.method == self.GET:
r = requests.get(url)
r = requests.get(url, headers=headers, params=params)
elif self.method == self.POST:
headers = {'content_type': self.content_type}
r = requests.post(url, json.loads(self.data), headers=headers)
r = requests.post(url, data=json.loads(self.data), headers=headers, params=params)
elif self.method == self.PUT:
headers = {'content_type': self.content_type}
r = requests.put(url, json.loads(self.data), headers=headers)
r = requests.put(url, data=json.loads(self.data), headers=headers, params=params)
else:
r = requests.delete(url)
r = requests.delete(url, headers=headers, params=params)
return r

class UrlParam(AbstractParam):
request = models.ForeignKey(Request, verbose_name=_('Request'), related_name="url_parameters")

class Meta:
verbose_name = _("Url Parameter")
verbose_name_plural = _("Url Parameters")

class HeaderParam(AbstractParam):
request = models.ForeignKey(Request, verbose_name=_('Request'), related_name="header_parameters")

class Meta:
verbose_name = _("Header Parameter")
verbose_name_plural = _("Header Parameters")


@python_2_unicode_compatible
Expand Down
2 changes: 1 addition & 1 deletion microbot/test/factories/__init__.py
@@ -1,4 +1,4 @@
from microbot.test.factories.bot import BotFactory # noqa
from microbot.test.factories.telegram_lib import (UserLibFactory, ChatLibFactory, # noqa
MessageLibFactory, UpdateLibFactory) # noqa
from microbot.test.factories.handler import HandlerFactory, RequestFactory # noqa
from microbot.test.factories.handler import HandlerFactory, RequestFactory, UrlParamFactory, HeaderParamFactory # noqa
18 changes: 16 additions & 2 deletions microbot/test/factories/handler.py
@@ -1,6 +1,6 @@
# coding=utf-8
from factory import DjangoModelFactory, SubFactory
from microbot.models import Handler, Request
from factory import DjangoModelFactory, SubFactory, Sequence
from microbot.models import Handler, Request, UrlParam, HeaderParam
from microbot.test.factories import BotFactory


Expand All @@ -9,6 +9,20 @@ class Meta:
model = Request
url_template = "https://api.github.com/users/jlmadurga"
method = Request.GET

class UrlParamFactory(DjangoModelFactory):
class Meta:
model = UrlParam
key = Sequence(lambda n: 'key%d' % n)
value_template = Sequence(lambda n: '{{value%d}}' % n)
request = SubFactory(RequestFactory)

class HeaderParamFactory(DjangoModelFactory):
class Meta:
model = HeaderParam
key = Sequence(lambda n: 'key%d' % n)
value_template = Sequence(lambda n: '{{value%d}}' % n)
request = SubFactory(RequestFactory)


class HandlerFactory(DjangoModelFactory):
Expand Down
3 changes: 2 additions & 1 deletion requirements/test.txt
Expand Up @@ -3,4 +3,5 @@ coverage
mock==1.3.0
flake8>=2.1.0
tox>=1.7.0
factory-boy==2.6.1
factory-boy==2.6.1
django-filter==0.12.0
77 changes: 61 additions & 16 deletions tests/test_microbot.py
Expand Up @@ -11,9 +11,8 @@
except ImportError:
import mock # noqa


class TestBot(testcases.BaseTestBot):

def test_enable_webhook(self):
self.assertTrue(self.bot.enabled)
with mock.patch("telegram.bot.Bot.setWebhook", callable=mock.MagicMock()) as mock_setwebhook:
Expand All @@ -22,34 +21,34 @@ def test_enable_webhook(self):
self.assertEqual(1, mock_setwebhook.call_count)
self.assertIn(reverse('microbot:telegrambot', kwargs={'token': self.bot.token}),
kwargs['webhook_url'])

def test_disable_webhook(self):
self.bot.enabled = False
with mock.patch("telegram.bot.Bot.setWebhook", callable=mock.MagicMock()) as mock_setwebhook:
self.bot.save()
args, kwargs = mock_setwebhook.call_args
self.assertEqual(1, mock_setwebhook.call_count)
self.assertEqual(None, kwargs['webhook_url'])

def test_bot_user_api(self):
with mock.patch("telegram.bot.Bot.setWebhook", callable=mock.MagicMock()):
self.bot.user_api = None
self.bot.save()
self.assertEqual(self.bot.user_api.first_name, u'Microbot_test')
self.assertEqual(self.bot.user_api.username, u'Microbot_test_bot')

def test_no_bot_associated(self):
Bot.objects.all().delete()
self.assertEqual(0, Bot.objects.count())
response = self.client.post(self.webhook_url, self.update.to_json(), **self.kwargs)
self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code)

def test_bot_disabled(self):
self.bot.enabled = False
self.bot.save()
response = self.client.post(self.webhook_url, self.update.to_json(), **self.kwargs)
self.assertEqual(status.HTTP_404_NOT_FOUND, response.status_code)

def test_not_valid_update(self):
del self.update.message
response = self.client.post(self.webhook_url, self.update.to_json(), **self.kwargs)
Expand Down Expand Up @@ -123,6 +122,20 @@ class TestRequests(LiveServerTestCase, testcases.BaseTestBot):
}
}

author_get_with_url_parameters = {'in': '/authors_name@author1',
'out': {'parse_mode': 'HTML',
'reply_markup': '',
'text': '<b>author1</b>'
}
}

author_post_header_error = {'in': '/authors',
'out': {'parse_mode': 'HTML',
'reply_markup': '',
'text': 'not created'
}
}

def test_get_request(self):
Author.objects.create(name="author1")
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/',
Expand All @@ -133,7 +146,7 @@ def test_get_request(self):
response_text_template='{% for author in response.list %}<b>{{author.name}}</b>{% endfor %}',
response_keyboard_template='')
self._test_message(self.author_get)

def test_get_pattern_command(self):
Author.objects.create(name="author1")
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/{{url.id}}/',
Expand All @@ -144,7 +157,7 @@ def test_get_pattern_command(self):
response_keyboard_template='',
request=self.request)
self._test_message(self.author_get_pattern)

def test_get_request_with_keyboard(self):
Author.objects.create(name="author1")
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/',
Expand All @@ -155,11 +168,10 @@ def test_get_request_with_keyboard(self):
response_text_template='{% for author in response.list %}<b>{{author.name}}</b>{% endfor %}',
response_keyboard_template='[[{% for author in response.list %}"{{author.name}}"{% endfor %}]]')
self._test_message(self.author_get_keyboard)

def test_post_request(self):
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/',
method=Request.POST,
content_type="application/json",
data='{"name": "author1"}')
self.handler = factories.HandlerFactory(bot=self.bot,
pattern='/authors',
Expand All @@ -170,12 +182,11 @@ def test_post_request(self):
self.assertEqual(Author.objects.count(), 1)
author = Author.objects.all()[0]
self.assertEqual(author.name, "author1")

def test_put_request(self):
author = Author.objects.create(name="author1")
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/{{url.id}}/',
method=Request.PUT,
content_type="application/json",
data='{"name": "author2"}')
self.handler = factories.HandlerFactory(bot=self.bot,
pattern='/authors@(?P<id>\d+)',
Expand All @@ -186,7 +197,7 @@ def test_put_request(self):
self.assertEqual(Author.objects.count(), 1)
author = Author.objects.all()[0]
self.assertEqual(author.name, "author2")

def test_delete_request(self):
Author.objects.create(name="author1")
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/{{url.id}}/',
Expand All @@ -198,7 +209,7 @@ def test_delete_request(self):
response_keyboard_template='')
self._test_message(self.author_delete_pattern)
self.assertEqual(Author.objects.count(), 0)

def test_environment_vars(self):
EnvironmentVar.objects.create(bot=self.bot,
key="shop",
Expand All @@ -211,4 +222,38 @@ def test_environment_vars(self):
request=self.request,
response_text_template='{{env.shop}}:{% for author in response.list %}<b>{{author.name}}</b>{% endfor %}',
response_keyboard_template='')
self._test_message(self.author_get_with_environment_var)
self._test_message(self.author_get_with_environment_var)

def test_url_parameters(self):
Author.objects.create(name="author1")
Author.objects.create(name="author2")
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/',
method=Request.GET)
self.url_param = factories.UrlParamFactory(request=self.request,
key='name',
value_template='{{url.name}}')
self.handler = factories.HandlerFactory(bot=self.bot,
pattern='/authors_name@(?P<name>\w+)',
request=self.request,
response_text_template='{% for author in response.list %}<b>{{author.name}}</b>{% endfor %}',
response_keyboard_template='')
self._test_message(self.author_get_with_url_parameters)

def test_header_parameters(self):
# Unsupported media type 415. Author not created
EnvironmentVar.objects.create(bot=self.bot,
key="content_type",
value="application/xml")
self.request = factories.RequestFactory(url_template=self.live_server_url + '/api/authors/',
method=Request.POST,
data='{"name": "author1"}')
self.header_param = factories.HeaderParamFactory(request=self.request,
key='Content-Type',
value_template='{{env.content_type}}')
self.handler = factories.HandlerFactory(bot=self.bot,
pattern='/authors',
request=self.request,
response_text_template='{% if response.name %}<b>{{response.name}}</b> created{% else %}not created{% endif %}',
response_keyboard_template='')
self._test_message(self.author_post_header_error)
self.assertEqual(Author.objects.count(), 0)
8 changes: 5 additions & 3 deletions tests/views.py
@@ -1,10 +1,12 @@
from rest_framework import viewsets
from rest_framework import viewsets, filters
from tests.serializers import AuthorSerializer
from tests.models import Author

class AuthorViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
API endpoint that allows authors to be viewed or edited.
"""
queryset = Author.objects.all()
serializer_class = AuthorSerializer
serializer_class = AuthorSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('name', 'id')

0 comments on commit a972494

Please sign in to comment.