avoid conflict when confirming pubsub sbuscription
[mygpo.git] / mygpo / pubsub / views.py
blob6858211ca9d8dcde9bdbc1650e796b11b1db64a7
1 # -*- coding: utf-8 -*-
3 # PubSubHubbub subscriber for mygpo
7 import logging
9 from django.http import HttpResponseNotFound, HttpResponse
10 from django.views.generic.base import View
11 from django.views.decorators.csrf import csrf_exempt
13 from couchdbkit.ext.django import *
15 from feedservice import urlstore
16 from mygpo.pubsub.models import SubscriptionError, Subscription
17 from mygpo.pubsub.signals import subscription_updated
18 from mygpo.db.couchdb.pubsub import subscription_for_topic, \
19 set_subscription_verified
21 logger = logging.getLogger(__name__)
24 class SubscribeView(View):
25 """ Endpoint for Pubsubhubbub subscriptions """
27 @csrf_exempt
28 def dispatch(self, *args, **kwargs):
29 return super(SubscribeView, self).dispatch(*args, **kwargs)
31 def get(self, request):
32 """ Callback used by the Hub to verify the subscription request """
34 # received arguments: hub.mode, hub.topic, hub.challenge,
35 # hub.lease_seconds, hub.verify_token
36 mode = request.GET.get('hub.mode')
37 feed_url = request.GET.get('hub.topic')
38 challenge = request.GET.get('hub.challenge')
39 lease_seconds = request.GET.get('hub.lease_seconds')
40 verify_token = request.GET.get('hub.verify_token')
42 logger.debug(('received subscription-parameters: mode: %(mode)s, ' +
43 'topic: %(topic)s, challenge: %(challenge)s, lease_seconds: ' +
44 '%(lease_seconds)s, verify_token: %(verify_token)s') % \
45 dict(mode=mode, topic=feed_url, challenge=challenge,
46 lease_seconds=lease_seconds, verify_token=verify_token))
48 subscription = subscription_for_topic(feed_url)
50 if subscription is None:
51 logger.warn('subscription does not exist')
52 return HttpResponseNotFound()
54 if subscription.mode != mode:
55 logger.warn('invalid mode, %s expected' % subscription.mode)
56 return HttpResponseNotFound()
58 if subscription.verify_token != verify_token:
59 logger.warn('invalid verify_token, %s expected' %
60 subscribe.verify_token)
61 return HttpResponseNotFound()
63 set_subscription_verified(subscription)
65 logger.info('subscription confirmed')
66 return HttpResponse(challenge)
69 def post(self, request):
70 """ Callback to notify about a feed update """
72 feed_url = request.GET.get('url')
74 if not feed_url:
75 logger.info('received notification without url')
76 return HttpResponse(status=400)
78 logger.info('received notification for %s' % feed_url)
80 subscription = subscription_for_topic(feed_url)
82 if subscription is None:
83 logger.warn('no subscription for this URL')
84 return HttpResponse(status=400)
86 if subscription.mode != 'subscribe':
87 logger.warn('invalid subscription mode: %s' % subscription.mode)
88 return HttpResponse(status=400)
90 if not subscription.verified:
91 logger.warn('the subscription has not yet been verified')
92 return HttpResponse(status=400)
94 subscription_updated.send(sender=feed_url)
96 return HttpResponse(status=200)