Skip to content

Commit

Permalink
Merge beb6199 into 67cb86b
Browse files Browse the repository at this point in the history
  • Loading branch information
claytonc committed Sep 26, 2017
2 parents 67cb86b + beb6199 commit a76645b
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ There's a frood who really knows where his towel is.
- Update Basque translation.
[erral]

- Implement prefetch for Facebook.
[claytonc]


2.12b1 (2017-09-15)
^^^^^^^^^^^^^^^^^^^
Expand Down
14 changes: 14 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ For more information see:

You can disable content validation using an option in the control panel configlet.

Prefetching Facebook
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. note::
This feature is only available for Dexterity-based content types.

Prefetching allows Facebook to download mobile content before someone clicks a link.

Prefetching is especially beneficial for people using Facebook on slow or poor network connections.

According to Facebook's `documentation <https://www.facebook.com/business/help/1514372351922333>`_:

The default is disable, but you can enable prefetch using an option in the control panel configlet.

Canonical URL and migration to HTTPS
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
11 changes: 11 additions & 0 deletions sc/social/like/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class ISocialLikeSettings(model.Schema):
'facebook_app_id',
'fbbuttons',
'fbshowlikes',
'facebook_prefetch_enable'
],
)

Expand Down Expand Up @@ -200,6 +201,16 @@ class ISocialLikeSettings(model.Schema):
default=True,
)

facebook_prefetch_enable = schema.Bool(
title=_(u'Enable Prefetching Facebook?'),
description=_(
u'help_facebook_prefetch_enable',
default=u'If enabled, an event is triggered so that Facebook '
u'downloads mobile content before someone clicks on a link.'
),
default=False,
)

model.fieldset(
'twitter', label=u'Twitter', fields=['twitter_username'])

Expand Down
9 changes: 9 additions & 0 deletions sc/social/like/locales/pt_BR/LC_MESSAGES/sc.social.like.po
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,12 @@ msgstr "Cancelar"
#: sc/social/like/vocabularies.py:36
msgid "vertical"
msgstr "vertical"


#: ./sc/social/like/interfaces.py:220
msgid "Enable Prefetching Facebook?"
msgstr ""

#: ./sc/social/like/interfaces.py:222
msgid "help_facebook_prefetch_enable"
msgstr "Se ativado, um evento é acionado para que o Facebook faça o download de conteúdo móvel antes de alguém clicar em um link."
8 changes: 8 additions & 0 deletions sc/social/like/locales/sc.social.like.pot
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,11 @@ msgstr ""
#: ./sc/social/like/vocabularies.py:36
msgid "vertical"
msgstr ""

#: ./sc/social/like/interfaces.py:220
msgid "Enable Prefetching Facebook?"
msgstr ""

#: ./sc/social/like/interfaces.py:222
msgid "help_facebook_prefetch_enable"
msgstr ""
2 changes: 1 addition & 1 deletion sc/social/like/profiles/default/metadata.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0"?>
<metadata>
<version>3047</version>
<version>3048</version>
</metadata>
27 changes: 27 additions & 0 deletions sc/social/like/subscribers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from zope.component import getUtility
from zope.schema.interfaces import WrongType

import requests
import traceback


Expand Down Expand Up @@ -148,9 +149,35 @@ def check_sharing_best_practices_on_editing(obj, event):
state = api.content.get_state(obj)
if state in ('published', ):
check_sharing_best_practices(obj)
prefetch_facebook(obj)


def check_sharing_best_practices_on_publishing(obj, event):
"""Event subscriber for content being published."""
if event.status['review_state'] in ('published', ):
check_sharing_best_practices(obj)
prefetch_facebook(obj)


def prefetch_facebook(obj):
"""Prefetching in object if enable."""

record = ISocialLikeSettings.__identifier__ + '.facebook_prefetch_enable'
prefetch_enable = api.portal.get_registry_record(record, default=False)

if not prefetch_enable:
return

url = obj.absolute_url()
r = requests.post('https://graph.facebook.com/?id=' + url + '&scrape=true',
timeout=5,
verify=False)

if r.status_code == '200':
prefetch = r.json()
if prefetch.get('og_object', None):
logger.info(u'Prefetching: ' + url)
else:
logger.warn(u'Prefetching failed, page is not accessible by Facebook.')
else:
logger.warn(u'Prefetching failed, invalid HTTP response.')
5 changes: 5 additions & 0 deletions sc/social/like/tests/test_controlpanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def test_twitter_username_record_in_registry(self):
self.assertTrue(hasattr(self.settings, 'twitter_username'))
self.assertEqual(self.settings.twitter_username, '')

def test_facebook_prefetch_enable_record_in_registry(self):
self.assertTrue(hasattr(self.settings, 'facebook_prefetch_enable'))
self.assertEqual(self.settings.facebook_prefetch_enable, False)

def test_records_removed_on_uninstall(self):
qi = self.portal['portal_quickinstaller']

Expand All @@ -126,6 +130,7 @@ def test_records_removed_on_uninstall(self):
ISocialLikeSettings.__identifier__ + '.fbbuttons',
ISocialLikeSettings.__identifier__ + '.fbshowlikes',
ISocialLikeSettings.__identifier__ + '.twitter_username',
ISocialLikeSettings.__identifier__ + '.facebook_prefetch_enable',
]

for r in records:
Expand Down
53 changes: 53 additions & 0 deletions sc/social/like/tests/test_subscribers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
from sc.social.like.utils import MSG_INVALID_OG_DESCRIPTION
from sc.social.like.utils import MSG_INVALID_OG_LEAD_IMAGE_DIMENSIONS
from sc.social.like.utils import MSG_INVALID_OG_TITLE
from testfixtures import LogCapture
from zope import schema
from zope.component import getUtility
from zope.event import notify

import requests_mock
import unittest


Expand Down Expand Up @@ -200,6 +202,57 @@ def test_validate_with_package_uninstalled(self):
# should not raise exceptions on editing
notify(EditFinishedEvent(self.news_item))

@requests_mock.mock()
def test_validate_facebook_prefetch_valid(self, m):
RESPONSE_VALID = """{"share":{"comment_count":0,"share_count":4},
"og_object":{"id":"442171799221474","description":"Plone","title":"Lorem ipsum","type":"website",
"updated_time":"2013-10-31T12:59:59+0000"},"id":"http:\/\/nohost/plone/\/news-item"}"""
url = self.news_item.absolute_url()
m.post('https://graph.facebook.com/?id=' + url + '&scrape=true', text=RESPONSE_VALID, status_code='200')
api.portal.set_registry_record('facebook_prefetch_enable', True, interface=ISocialLikeSettings)

# testing log
expected = ('sc.social.like', 'INFO', u'Prefetching: http://nohost/plone/lorem-ipsum')
log = LogCapture(PROJECTNAME)

with api.env.adopt_roles(['Manager']):
api.content.transition(self.news_item, 'publish')

log.check(expected)

@requests_mock.mock()
def test_validate_facebook_prefetch_invalid(self, m):
RESPONSE_INVALID = """{"share":{"comment_count":0,"share_count":4},"id":"http:\/\/nohost/plone/\/news-item"}"""
url = self.news_item.absolute_url()
m.post('https://graph.facebook.com/?id=' + url + '&scrape=true', text=RESPONSE_INVALID, status_code='200')
api.portal.set_registry_record('facebook_prefetch_enable', True, interface=ISocialLikeSettings)

# testing log
expected = ('sc.social.like', 'WARNING', u'Prefetching failed, page is not accessible by Facebook.')
log = LogCapture(PROJECTNAME)

with api.env.adopt_roles(['Manager']):
api.content.transition(self.news_item, 'publish')

log.check(expected)

@requests_mock.mock()
def test_validate_facebook_prefetch_response_invalid(self, m):
RESPONSE_INVALID = """{"error":{"message":"Application request limit reached","type":"ThrottlingException",
"is_transient":true,"code":4,"fbtrace_id":"C+fZI9UDOoi"}}"""
url = self.news_item.absolute_url()
m.post('https://graph.facebook.com/?id=' + url + '&scrape=true', text=RESPONSE_INVALID, status_code='403')
api.portal.set_registry_record('facebook_prefetch_enable', True, interface=ISocialLikeSettings)

# testing log
expected = ('sc.social.like', 'WARNING', u'Prefetching failed, invalid HTTP response.')
log = LogCapture(PROJECTNAME)

with api.env.adopt_roles(['Manager']):
api.content.transition(self.news_item, 'publish')

log.check(expected)


def load_tests(loader, tests, pattern):
from sc.social.like.testing import HAS_DEXTERITY
Expand Down
33 changes: 33 additions & 0 deletions sc/social/like/tests/test_upgrades.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,3 +357,36 @@ def test_add_validation_enabled_record(self):
# Test if our setting is there and set
settings = registry.forInterface(ISocialLikeSettings)
self.assertEqual(settings.validation_enabled, True)


class To3048TestCase(UpgradeTestCaseBase):

def setUp(self):
UpgradeTestCaseBase.setUp(self, u'3047', u'3048')

def test_registrations(self):
version = self.setup.getLastVersionForProfile(self.profile_id)[0]
self.assertGreaterEqual(int(version), int(self.to_version))
self.assertEqual(self.total_steps, 1)

def test_add_validation_enabled_record(self):
title = u'Enable prefetch for Facebook'
step = self.get_upgrade_step(title)
self.assertIsNotNone(step)

# simulate state on previous version
from plone.registry.interfaces import IRegistry
registry = getUtility(IRegistry)
record = ISocialLikeSettings.__identifier__ + '.facebook_prefetch_enable'
del registry.records[record]
self.assertNotIn(record, registry)

with self.assertRaises(KeyError):
registry.forInterface(ISocialLikeSettings)

# run the upgrade step to validate the update
self.execute_upgrade_step(step)

# Test if our setting is there and set
settings = registry.forInterface(ISocialLikeSettings)
self.assertEqual(settings.facebook_prefetch_enable, False)
1 change: 1 addition & 0 deletions sc/social/like/upgrades/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
<include package=".v3045" />
<include package=".v3046" />
<include package=".v3047" />
<include package=".v3048" />

</configure>
Empty file.
18 changes: 18 additions & 0 deletions sc/social/like/upgrades/v3048/configure.zcml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:genericsetup="http://namespaces.zope.org/genericsetup">

<genericsetup:upgradeSteps
source="3047"
destination="3048"
profile="sc.social.like:default">

<genericsetup:upgradeDepends
title="Enable prefetch for Facebook"
description="Adds new field to the control panel configlet."
import_steps="plone.app.registry"
/>

</genericsetup:upgradeSteps>

</configure>
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
'Products.CMFPlone >=4.3',
'Products.CMFQuickInstallerTool',
'Products.GenericSetup',
'requests',
'setuptools',
'zope.component',
'zope.i18nmessageid',
Expand All @@ -68,8 +69,10 @@
'plone.browserlayer',
'plone.namedfile',
'plone.testing',
'requests-mock',
'Products.statusmessages',
'profilehooks',
'testfixtures',
'robotsuite',
'zope.event',
],
Expand Down

0 comments on commit a76645b

Please sign in to comment.