diff --git a/app.yaml b/app.yaml index 33f7cf7e..5f5237c6 100644 --- a/app.yaml +++ b/app.yaml @@ -68,7 +68,7 @@ handlers: script: facebook.application secure: always -- url: /flickr/(start|add|delete)(/.*)? +- url: /flickr/(start|add|delete|publish)(/.*)? script: flickr.application secure: always diff --git a/flickr.py b/flickr.py index 4091d965..3eb01fa7 100644 --- a/flickr.py +++ b/flickr.py @@ -87,6 +87,19 @@ def canonicalize_syndication_url(self, url, **kwargs): return url +class StartHandler(util.Handler): + """Custom handler that sets OAuth scopes based on the requested + feature(s) + """ + def post(self): + features = self.request.get('feature') + features = features.split(',') if features else [] + starter = util.oauth_starter(oauth_flickr.StartHandler).to( + '/flickr/add', + scopes='write' if 'publish' in features else 'read') + starter(self.request, self.response).post() + + class AddFlickr(oauth_flickr.CallbackHandler, util.Handler): def finish(self, auth_entity, state=None): logging.debug('finish with %s, %s', auth_entity, state) @@ -94,7 +107,10 @@ def finish(self, auth_entity, state=None): application = webapp2.WSGIApplication([ - ('/flickr/start', util.oauth_starter(oauth_flickr.StartHandler).to('/flickr/add')), + ('/flickr/start', StartHandler), ('/flickr/add', AddFlickr), - ('/flickr/delete/finish', oauth_flickr.CallbackHandler.to('/delete/finish')), + ('/flickr/delete/finish', + oauth_flickr.CallbackHandler.to('/delete/finish')), + ('/flickr/publish/start', + oauth_flickr.StartHandler.to('/publish/flickr/finish')), ], debug=appengine_config.DEBUG) diff --git a/publish.py b/publish.py index 3c0f4ab3..09b96f56 100644 --- a/publish.py +++ b/publish.py @@ -38,19 +38,21 @@ from appengine_config import HTTP_TIMEOUT from bs4 import BeautifulSoup +from facebook import FacebookPage +from flickr import Flickr +from googleplus import GooglePlusPage from granary import microformats2 from granary import source as gr_source +from instagram import Instagram +from models import Publish, PublishedPage from oauth_dropins import facebook as oauth_facebook +from oauth_dropins import flickr as oauth_flickr from oauth_dropins import instagram as oauth_instagram from oauth_dropins import twitter as oauth_twitter -from facebook import FacebookPage -from googleplus import GooglePlusPage +from twitter import Twitter import html2text -from instagram import Instagram import models -from models import Publish, PublishedPage import requests -from twitter import Twitter import util import webapp2 import webmention @@ -58,12 +60,9 @@ from google.appengine.ext import ndb from google.appengine.ext.webapp import template -SOURCE_NAMES = { - cls.SHORT_NAME: cls for cls in - (FacebookPage, Twitter, Instagram, GooglePlusPage)} -SOURCE_DOMAINS = { - cls.GR_CLASS.DOMAIN: cls for cls in - (FacebookPage, Twitter, Instagram, GooglePlusPage)} +SOURCES = (FacebookPage, Flickr, Twitter, Instagram, GooglePlusPage) +SOURCE_NAMES = {cls.SHORT_NAME: cls for cls in SOURCES} +SOURCE_DOMAINS = {cls.GR_CLASS.DOMAIN: cls for cls in SOURCES} class Handler(webmention.WebmentionHandler): @@ -120,7 +119,8 @@ def _run(self): source_cls = SOURCE_NAMES.get(path_parts[-1]) if (domain not in ('brid.gy', 'www.brid.gy', 'localhost:8080') or len(path_parts) != 2 or path_parts[0] != '/publish' or not source_cls): - return self.error('Target must be brid.gy/publish/{facebook,twitter,instagram}') + return self.error( + 'Target must be brid.gy/publish/{facebook,flickr,twitter,instagram}') elif source_cls == GooglePlusPage: return self.error('Sorry, %s is not yet supported.' % source_cls.GR_CLASS.NAME) @@ -539,14 +539,20 @@ def error(self, error, html=None, status=400, data=None, mail=False): self.mail_me(error) -# We want CallbackHandler.get() and SendHandler.finish(), so put CallbackHandler -# first and override finish. +# We want CallbackHandler.get() and SendHandler.finish(), so put +# CallbackHandler first and override finish. class FacebookSendHandler(oauth_facebook.CallbackHandler, SendHandler): finish = SendHandler.finish + +class FlickrSendHandler(oauth_flickr.CallbackHandler, SendHandler): + finish = SendHandler.finish + + class TwitterSendHandler(oauth_twitter.CallbackHandler, SendHandler): finish = SendHandler.finish + # Instagram only allows a single OAuth callback URL, so that's handled in # instagram.py and it redirects here for publishes. class InstagramSendHandler(SendHandler): @@ -590,6 +596,7 @@ def authorize(self): ('/publish/webmention', WebmentionHandler), ('/publish/(facebook|twitter|instagram)', webmention.WebmentionGetHandler), ('/publish/facebook/finish', FacebookSendHandler), + ('/publish/flickr/finish', FlickrSendHandler), ('/publish/instagram/finish', InstagramSendHandler), ('/publish/twitter/finish', TwitterSendHandler), ], diff --git a/templates/flickr_user.html b/templates/flickr_user.html index 544b9c90..54ba4292 100644 --- a/templates/flickr_user.html +++ b/templates/flickr_user.html @@ -10,3 +10,13 @@ enter it in the Website field, then click here: {% include "flickr_signup.html" %} {% endblock %} + + +{% block publish-signup %} +Click to enable publishing: +
+ + +
+{% endblock %} diff --git a/templates/social_user.html b/templates/social_user.html index 363589cc..674af685 100644 --- a/templates/social_user.html +++ b/templates/social_user.html @@ -48,7 +48,7 @@
-
+
{% if "listen" in source.features and source.status != "disabled" %} diff --git a/util.py b/util.py index 53b92898..0829642f 100644 --- a/util.py +++ b/util.py @@ -25,7 +25,7 @@ from google.appengine.ext import ndb # when running in dev_appserver, replace these domains in links with localhost -LOCALHOST_TEST_DOMAINS = frozenset(('kylewm.com', 'snarfed.org')) +LOCALHOST_TEST_DOMAINS = frozenset(('snarfed.org',)) EPOCH = datetime.datetime.utcfromtimestamp(0) POLL_TASK_DATETIME_FORMAT = '%Y-%m-%d-%H-%M-%S'