diff --git a/CHANGES.rst b/CHANGES.rst index b62fb0e4..b17df33f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,6 +6,15 @@ There's a frood who really knows where his towel is. 2.10.2 (unreleased) ^^^^^^^^^^^^^^^^^^^ +- Update Tweet Button code; code clean up and refactor. + [hvelarde] + +- Twitter widgets now respect users' privacy. + [hvelarde] + +- Remove redundant metadata as Twitter can use Open Graph properties as fall back (closes `#112 `_). + [hvelarde] + - Remove useless scale caching on the request as it seems to be causing colateral issues (closes `#109 `_). [rodfersou] diff --git a/sc/social/like/plugins/twitter/browser.py b/sc/social/like/plugins/twitter/browser.py index 7bb8d550..eb7af018 100644 --- a/sc/social/like/plugins/twitter/browser.py +++ b/sc/social/like/plugins/twitter/browser.py @@ -1,83 +1,63 @@ # -*- coding:utf-8 -*- +"""Helper view to generate the Tweet Button widget. + +More information: +* https://dev.twitter.com/web/tweet-button +* https://dev.twitter.com/web/overview/privacy +""" +from Acquisition import aq_inner from plone import api -from plone.api.exc import InvalidParameterError -from Products.CMFPlone.utils import safe_unicode from Products.Five import BrowserView from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile -from Products.PythonScripts.standard import url_quote +from sc.social.like.behaviors import ISocialMedia from sc.social.like.config import IS_PLONE_5 from sc.social.like.interfaces import ISocialLikeSettings -from sc.social.like.utils import get_content_image -from sc.social.like.utils import get_language from urllib import urlencode -from zope.component import getMultiAdapter class PluginView(BrowserView): - - twitter_enabled = False - language = 'en' + """Helper view to generate the Tweet Button widget.""" metadata = ViewPageTemplateFile('templates/metadata.pt') plugin = ViewPageTemplateFile('templates/plugin.pt') link = ViewPageTemplateFile('templates/link.pt') def __init__(self, context, request): - self.context = context - self.title = context.title - self.description = context.Description() + self.context = aq_inner(context) self.request = request - # FIXME: the following could rise unexpected exceptions - # move it to a new setup() method - # see: http://docs.plone.org/develop/plone/views/browserviews.html#creating-a-view - self.portal_state = getMultiAdapter((self.context, self.request), - name=u'plone_portal_state') - self.portal = self.portal_state.portal() - self.site_url = self.portal_state.portal_url() - self.portal_title = self.portal_state.portal_title() - self.url = context.absolute_url() - self.language = get_language(context) - self.image = get_content_image(context) - self.urlnoscript = ( - u'http://twitter.com/home?status=' + - url_quote(u'{0} - {1} via {2}'.format( - safe_unicode(self.context.title), - self.context.absolute_url(), - self.via) - ) - ) @property def is_plone_5(self): return IS_PLONE_5 - @property - def typebutton(self): - record = ISocialLikeSettings.__identifier__ + '.typebutton' - try: - return api.portal.get_registry_record(record) - except InvalidParameterError: - return '' + def portal_url(self): + portal = api.portal.get() + return portal.absolute_url() + + def canonical_url(self): + """Return canonical URL if available; otherwise, context URL.""" + if ISocialMedia.providedBy(self.context): + return self.context.canonical_url + else: + return self.context.absolute_url() - @property def via(self): record = ISocialLikeSettings.__identifier__ + '.twitter_username' - try: - return api.portal.get_registry_record(record) - except InvalidParameterError: - return '' + return api.portal.get_registry_record(record, default='') def share_link(self): - params = dict( - text=safe_unicode(self.context.Title()).encode('utf-8'), - url=self.context.absolute_url(), - ) - if self.via: - params['via'] = self.via + params = { + 'text': self.context.Title(), + 'url': self.context.absolute_url(), + } + + via = self.via() + if via: + params['via'] = via url = 'https://twitter.com/intent/tweet?' + urlencode(params) return url - def image_url(self): - """Return image URL.""" - return self.image.url if self.image else None + def dnt(self): + record = ISocialLikeSettings.__identifier__ + '.do_not_track' + return api.portal.get_registry_record(record, default=False) diff --git a/sc/social/like/plugins/twitter/templates/link.pt b/sc/social/like/plugins/twitter/templates/link.pt index 99f99a6c..8cb43830 100644 --- a/sc/social/like/plugins/twitter/templates/link.pt +++ b/sc/social/like/plugins/twitter/templates/link.pt @@ -1,14 +1,13 @@ - - - - Tweet it! - - + + + Tweet + diff --git a/sc/social/like/plugins/twitter/templates/metadata.pt b/sc/social/like/plugins/twitter/templates/metadata.pt index 9a9949a2..35ed715b 100644 --- a/sc/social/like/plugins/twitter/templates/metadata.pt +++ b/sc/social/like/plugins/twitter/templates/metadata.pt @@ -3,8 +3,6 @@ - - - + diff --git a/sc/social/like/plugins/twitter/templates/plugin.pt b/sc/social/like/plugins/twitter/templates/plugin.pt index f3284851..ba969ef0 100644 --- a/sc/social/like/plugins/twitter/templates/plugin.pt +++ b/sc/social/like/plugins/twitter/templates/plugin.pt @@ -1,14 +1,7 @@ - - - - - - + + + diff --git a/sc/social/like/tests/test_plugin_twitter.py b/sc/social/like/tests/test_plugin_twitter.py index 5ce94072..7633e890 100644 --- a/sc/social/like/tests/test_plugin_twitter.py +++ b/sc/social/like/tests/test_plugin_twitter.py @@ -73,9 +73,10 @@ def setUp(self): def test_plugin_view_metadata(self): def get_meta_content(name): - """Return the content attribute of the meta tag specified by name.""" - return html.find('*/meta[@name="{0}"]'.format(name)).attrib['content'] - + """Return the content attribute of the meta tag specified.""" + meta = html.find('*/meta[@name="{0}"]'.format(name)) + if meta is not None: + return meta.attrib['content'] view = self.newsitem.restrictedTraverse(self.plugin.view()) record = ISocialLikeSettings.__identifier__ + '.twitter_username' api.portal.set_registry_record(record, 'plone') @@ -83,11 +84,13 @@ def get_meta_content(name): from lxml import etree html = etree.HTML(view.metadata()) self.assertEqual(get_meta_content('twitter:card'), 'summary_large_image') - expected = r'http://nohost/plone/lorem-ipsum/@@images/[0-9a-f--]+.png' - self.assertRegexpMatches(get_meta_content('twitter:image'), expected) self.assertEqual(get_meta_content('twitter:site'), '@plone') - self.assertEqual(get_meta_content('twitter:title'), 'Lorem Ipsum') - self.assertEqual(get_meta_content('twitter:description'), 'Neque Porro') + + # privacy settings + self.assertIsNone(get_meta_content('twitter:dnt')) + self.settings.do_not_track = True + html = etree.HTML(view.metadata()) + self.assertEqual(get_meta_content('twitter:dnt'), 'on') def test_plugin_view_html(self): view = self.newsitem.restrictedTraverse(self.plugin.view()) @@ -99,33 +102,13 @@ def test_privacy_plugin_view_html(self): view = self.portal.restrictedTraverse(self.plugin.view()) html = view.link() - self.assertIn('Tweet it!', html) + self.assertIn('Tweet', html) def test_plugin_twitter_username(self): - self.settings.twitter_username = '@simplesconsult' - - view = self.newsitem.restrictedTraverse(self.plugin.view()) - html = view.plugin() - self.assertIn('data-via="@simplesconsult"', html) - - def test_plugin_urlnoscript_encoding(self): - self.newsitem.setTitle(u'Notícia') - self.settings.twitter_username = '@simplesconsult' - - view = self.newsitem.restrictedTraverse(self.plugin.view()) - html = view.plugin() - self.assertIn('%20via%20%40simplesconsult">Tweet', html) - - def test_plugin_language(self): - self.newsitem.setLanguage('pt-br') - view = self.newsitem.restrictedTraverse(self.plugin.view()) - html = view.plugin() - self.assertIn('data-lang="pt-br"', html) - - self.newsitem.setLanguage('en') + self.settings.twitter_username = 'simplesconsult' view = self.newsitem.restrictedTraverse(self.plugin.view()) html = view.plugin() - self.assertIn('data-lang="en"', html) + self.assertIn('data-via="simplesconsult"', html) def test_share_link(self): view = self.newsitem.restrictedTraverse(self.plugin.view())