diff --git a/sc/social/like/configure.zcml b/sc/social/like/configure.zcml index 7dfbb6b8..204881ca 100644 --- a/sc/social/like/configure.zcml +++ b/sc/social/like/configure.zcml @@ -34,6 +34,34 @@ handler=".subscribers.assign_canonical_url" /> + + + + + + + + diff --git a/sc/social/like/subscribers.py b/sc/social/like/subscribers.py index d81ad7d9..ec238b9c 100644 --- a/sc/social/like/subscribers.py +++ b/sc/social/like/subscribers.py @@ -15,10 +15,15 @@ """ from plone import api from plone.registry.interfaces import IRegistry +from Products.CMFCore.WorkflowCore import WorkflowException from sc.social.like.config import IS_PLONE_5 from sc.social.like.config import PROJECTNAME from sc.social.like.interfaces import ISocialLikeSettings from sc.social.like.logger import logger +from utils import get_content_image +from utils import validate_description_social +from utils import validate_image_social +from utils import validate_title_social from zope.component import getUtility from zope.schema.interfaces import WrongType @@ -107,3 +112,44 @@ def assign_canonical_url(obj, event): 'Canonical domain not set in Social Media configlet; ' "Facebook's Open Graph canonical URL (og:orl) will not be available" ) + + +def social_content_check(obj, event): + + request = obj.REQUEST + verify_state = 'published' + + if getattr(event, 'status', None): + state = event.status['review_state'] + else: + try: + state = api.content.get_state(obj) + except WorkflowException: + state = '' + verify_state = '' + + if obj.restrictedTraverse('@@social_likes_view').enabled \ + and state == verify_state: + + title = getattr(obj, 'title', None) + v_title = validate_title_social(title) + if title and v_title: + msg = v_title + api.portal.show_message(message=msg, request=request, type='warning') + + try: + description = obj.Description() + v_description = validate_description_social(description) + if description and v_description: + msg = v_description + api.portal.show_message(message=msg, request=request, type='warning') + except AttributeError: + pass + + image = get_content_image(obj) + if image: + v_image = validate_image_social(image) + if v_image: + msg = v_image + logger.info(msg) + api.portal.show_message(message=msg, request=request, type='warning') diff --git a/sc/social/like/tests/images/imgtest_1024x768.bmp b/sc/social/like/tests/images/imgtest_1024x768.bmp new file mode 100755 index 00000000..e45d0690 Binary files /dev/null and b/sc/social/like/tests/images/imgtest_1024x768.bmp differ diff --git a/sc/social/like/tests/images/imgtest_200x200.png b/sc/social/like/tests/images/imgtest_200x200.png new file mode 100755 index 00000000..13355708 Binary files /dev/null and b/sc/social/like/tests/images/imgtest_200x200.png differ diff --git a/sc/social/like/tests/test_utils.py b/sc/social/like/tests/test_utils.py index 91b67c59..c244c2b8 100644 --- a/sc/social/like/tests/test_utils.py +++ b/sc/social/like/tests/test_utils.py @@ -1,5 +1,13 @@ # -*- coding: utf-8 -*- +from plone import api +from sc.social.like.testing import INTEGRATION_TESTING +from sc.social.like.testing import load_image +from sc.social.like.tests.api_hacks import set_image_field +from sc.social.like.utils import get_content_image from sc.social.like.utils import validate_canonical_domain +from sc.social.like.utils import validate_description_social +from sc.social.like.utils import validate_image_social +from sc.social.like.utils import validate_title_social from zope.interface import Invalid import unittest @@ -7,6 +15,25 @@ class UtilsTestCase(unittest.TestCase): + layer = INTEGRATION_TESTING + + def setUp(self): + self.portal = self.layer['portal'] + self.request = self.layer['request'] + + with api.env.adopt_roles(['Manager']): + self.obj = api.content.create( + self.portal, type='News Item', id='foo') + set_image_field(self.obj, load_image(1024, 768), 'image/png') + + self.obj2 = api.content.create( + self.portal, type='News Item', id='foo2') + set_image_field(self.obj2, load_image(200, 200), 'image/png') + + self.obj3 = api.content.create( + self.portal, type='News Item', id='foo3') + set_image_field(self.obj3, load_image(200, 200), 'image/bmp') + def test_validate_canonical_domain_valid(self): self.assertTrue(validate_canonical_domain('http://example.org')) self.assertTrue(validate_canonical_domain('https://example.org')) @@ -20,3 +47,33 @@ def test_validate_canonical_domain_invalid(self): validate_canonical_domain('https://example.org?foo') # query with self.assertRaises(Invalid): validate_canonical_domain('https://example.org#bar') # fragment + + def test_validate_title_social_valid(self): + self.assertFalse(validate_title_social('Lorem ipsum dolor sit amet, ' + 'consectetur adipiscing elit.')) + + def test_validate_title_social_invalid(self): + self.assertTrue(validate_title_social('Integer molestie massa auctor diam ' + 'volutpat, et sodales lectus pulvinar.')) + + def test_validate_description_social_valid(self): + self.assertFalse(validate_title_social('Lorem ipsum dolor sit amet, ' + 'consectetur adipiscing elit.')) + + def test_validate_description_social_invalid(self): + self.assertTrue(validate_description_social('Integer molestie massa auctor diam ' + 'volutpat, et sodales lectus pulvinar.')) + + self.assertTrue(validate_description_social('Sed pellentesque quam tincidunt neque imperdiet porta. ' + 'Fusce nec vestibulum felis, ut faucibus odio. Maecenas sit ' + 'amet dapibus diam.')) + + def test_validate_image_social_valid(self): + image = get_content_image(self.obj) + self.assertFalse(validate_image_social(image)) + + def test_validate_image_social_invalid(self): + image = get_content_image(self.obj2) + self.assertTrue(validate_image_social(image)) + image = get_content_image(self.obj3) + self.assertTrue(validate_image_social(image)) diff --git a/sc/social/like/utils.py b/sc/social/like/utils.py index 042f5fb0..a1e86753 100644 --- a/sc/social/like/utils.py +++ b/sc/social/like/utils.py @@ -112,3 +112,65 @@ def get_valid_objects(brains): logger.warn(msg.format(b.getPath())) continue yield obj + + +def validate_title_social(value): + """Check if title field have more than 70 characters.""" + if len(value) > 70: + msg = u'Title have more than 70 characters.' + logger.info(msg) + return msg + return + + +def validate_description_social(value): + """Check if description field have more than 200 characters.""" + + if value and len(value) > 200: + msg = u'Description have more than 200 characters.' + logger.info(msg) + return msg + + elif value and (value.count('.') < 2 or value.count('.') > 2): + msg = u'Description should contain at least 2 phrases.' + logger.info(msg) + return msg + + return + + +def validate_image_social(value): + """Check if image be in formats mime type, dimensions and size.""" + + list_mimetypes = ['image/jpeg', 'image/png', 'image/gif', ' image/webp'] + + type = getattr(value, 'mimetype', None) + if type not in list_mimetypes: + msg = u'Image mime type not supported: {0}' + logger.info(msg.format(type)) + return msg.format(type) + + size = value.size + if size > 5242880: + msg = u'Image size should be less than 5MB.' + logger.info(msg) + return msg + + width, height = (value.width, value.height) + if width < 600 and height < 315: + msg = u'Image dimensions should be at least 600 x 315.' + logger.info(msg) + return msg + + if get_ratio(width, height) < 1.33: + msg = u'Image aspect ratio should be 1.33:1 at least.' + logger.info(msg) + return msg + + +def get_ratio(w, h): + """Calculate aspect ratio.""" + w = float(w) + h = float(h) + r = w % h or w + return '%s' % float((w / r) / (h / r))