diff --git a/rest_hooks/migrations/0001_initial.py b/rest_hooks/migrations/0001_initial.py index d21317a..0ac085d 100644 --- a/rest_hooks/migrations/0001_initial.py +++ b/rest_hooks/migrations/0001_initial.py @@ -21,6 +21,8 @@ class Migration(migrations.Migration): ('event', models.CharField(max_length=64, verbose_name=b'Event', db_index=True)), ('target', models.URLField(max_length=255, verbose_name=b'Target URL')), ('user', models.ForeignKey(related_name='hooks', to=settings.AUTH_USER_MODEL)), + ('authorization', models.CharField(max_length=200, verbose_name=b'Authorization', null=True, blank=True)), + ], options={ }, diff --git a/rest_hooks/models.py b/rest_hooks/models.py index df88720..195d12a 100644 --- a/rest_hooks/models.py +++ b/rest_hooks/models.py @@ -43,6 +43,8 @@ class Hook(models.Model): db_index=True, choices=[(e, e) for e in HOOK_EVENTS.keys()]) target = models.URLField('Target URL', max_length=255) + authorization = models.CharField('Authorization', max_length=200, + null=True, blank=True) def dict(self): return { @@ -87,10 +89,13 @@ def deliver_hook(self, instance, payload_override=None): deliverer = get_module(settings.HOOK_DELIVERER) deliverer(self.target, payload, instance=instance, hook=self) else: + headers = {'Content-Type': 'application/json'} + if self.authorization is not None: + headers["Authorization"] = self.authorization client.post( url=self.target, data=json.dumps(payload, cls=serializers.json.DjangoJSONEncoder), - headers={'Content-Type': 'application/json'} + headers=headers ) signals.hook_sent_event.send_robust(sender=self.__class__, payload=payload, instance=instance, hook=self) diff --git a/rest_hooks/south_migrations/0001_initial.py b/rest_hooks/south_migrations/0001_initial.py index cfcc7c9..8d890b0 100644 --- a/rest_hooks/south_migrations/0001_initial.py +++ b/rest_hooks/south_migrations/0001_initial.py @@ -16,6 +16,7 @@ def forwards(self, orm): ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='hooks', to=orm['auth.User'])), ('event', self.gf('django.db.models.fields.CharField')(max_length=64, db_index=True)), ('target', self.gf('django.db.models.fields.URLField')(max_length=255)), + ('authorization', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True, null=True)), )) db.send_create_signal('rest_hooks', ['Hook']) @@ -69,8 +70,9 @@ def backwards(self, orm): 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'target': ('django.db.models.fields.URLField', [], {'max_length': '255'}), 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hooks'", 'to': "orm['auth.User']"}) + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hooks'", 'to': "orm['auth.User']"}), + 'authorization': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True', 'null': 'True'}) } } - complete_apps = ['rest_hooks'] \ No newline at end of file + complete_apps = ['rest_hooks'] diff --git a/rest_hooks/tasks.py b/rest_hooks/tasks.py index cb84e61..ba332f7 100644 --- a/rest_hooks/tasks.py +++ b/rest_hooks/tasks.py @@ -9,13 +9,17 @@ class DeliverHook(Task): - def run(self, target, payload, instance=None, hook_id=None, **kwargs): + def run(self, target, payload, instance=None, hook_id=None, + authorization=None, **kwargs): """ target: the url to receive the payload. payload: a python primitive data structure instance: a possibly null "trigger" instance hook: the defining Hook object (useful for removing) """ + headers = {'Content-Type': 'application/json'} + if authorization is not None: + headers["Authorization"] = authorization response = requests.post( url=target, data=json.dumps(payload, cls=DjangoJSONEncoder), @@ -28,6 +32,7 @@ def run(self, target, payload, instance=None, hook_id=None, **kwargs): # would be nice to log this, at least for a little while... + def deliver_hook_wrapper(target, payload, instance=None, hook=None, **kwargs): if hook: kwargs['hook_id'] = hook.id diff --git a/rest_hooks/tests.py b/rest_hooks/tests.py index a1ac0df..bcea697 100644 --- a/rest_hooks/tests.py +++ b/rest_hooks/tests.py @@ -67,6 +67,14 @@ def make_hook(self, event, target): target=target ) + def make_hook_with_auth(self, event, target, authorization): + return Hook.objects.create( + user=self.user, + event=event, + target=target, + authorization=authorization + ) + ############# ### TESTS ### ############# @@ -100,6 +108,24 @@ def perform_create_request_cycle(self, method_mock): return hook, comment, json.loads(method_mock.call_args_list[0][1]['data']) + @patch('requests.post', autospec=True) + def perform_create_request_cycle_authorized(self, method_mock): + method_mock.return_value = None + + target = 'http://example.com/perform_create_request_cycle' + auth = 'Token 0639e26b-a9df-4fb7-9c40-10d7f62e6e06' + hook = self.make_hook_with_auth('comment.added', target, auth) + + comment = Comment.objects.create( + site=self.site, + content_object=self.user, + user=self.user, + comment='Hello world!' + ) + # time.sleep(1) # should change a setting to turn off async + + return hook, comment, json.loads(method_mock.call_args_list[0][1]['data']) + def test_simple_comment_hook(self): """ Uses the default serializer. @@ -114,6 +140,20 @@ def test_simple_comment_hook(self): self.assertEquals('Hello world!', payload['data']['fields']['comment']) self.assertEquals(comment.user.id, payload['data']['fields']['user']) + def test_simple_comment_hook_authorized(self): + """ + Uses the default serializer. + """ + hook, comment, payload = self.perform_create_request_cycle_authorized() + + self.assertEquals(hook.id, payload['hook']['id']) + self.assertEquals('comment.added', payload['hook']['event']) + self.assertEquals(hook.target, payload['hook']['target']) + + self.assertEquals(comment.id, payload['data']['pk']) + self.assertEquals('Hello world!', payload['data']['fields']['comment']) + self.assertEquals(comment.user.id, payload['data']['fields']['user']) + def test_comment_hook_serializer_method(self): """ Use custom serialize_hook on the Comment model.