source: products/quintagroup.seoptimizer/branches/refactoring2.3.0/quintagroup/seoptimizer/browser/views.py

Last change on this file was 1958, checked in by liebster, 14 years ago

Clean-up code http://codereview.corp.quintagroup.com/40241/show

  • Property svn:eol-style set to native
File size: 13.4 KB
RevLine 
[1908]1from time import time
[1958]2from DateTime import DateTime
[401]3from Acquisition import aq_inner
[896]4from zope.component import queryAdapter
[1824]5from zope.component import queryMultiAdapter
[1935]6from zope.schema.interfaces import InvalidValue
7
[1908]8from plone.memoize import view, ram
[392]9
[408]10from Products.Five.browser import BrowserView
[1958]11from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
[1918]12from Products.CMFPlone.utils import getSiteEncoding
[401]13
[1931]14from quintagroup.canonicalpath.interfaces import ICanonicalLink
15from quintagroup.canonicalpath.adapters import PROPERTY_LINK as CANONICAL_PROPERTY
16
[1821]17from quintagroup.seoptimizer.browser.seo_configlet import ISEOConfigletSchema
[1824]18from quintagroup.seoptimizer import SeoptimizerMessageFactory as _
[1463]19
[1183]20SEPERATOR = '|'
[1460]21SEO_PREFIX = 'seo_'
22PROP_PREFIX = 'qSEO_'
23SUFFIX = '_override'
[1461]24PROP_CUSTOM_PREFIX = 'qSEO_custom_'
25
[1908]26# Ram cache function, which depends on plone instance and time
27def plone_instance_time(method, self, *args, **kwargs):
28    return (self.pps.portal(), time() // (60 * 60))
29
[408]30class SEOContext( BrowserView ):
[1506]31    """ This class contains methods that allows to edit html header meta tags.
[408]32    """
[1782]33
[1815]34    def __init__(self, *args, **kwargs):
35        super(SEOContext, self).__init__(*args, **kwargs)
[1831]36        self.pps = queryMultiAdapter((self.context, self.request), name="plone_portal_state")
37        self.pcs = queryMultiAdapter((self.context, self.request), name="plone_context_state")
38        self.gseo = queryAdapter(self.pps.portal(), ISEOConfigletSchema)
[1815]39        self._seotags = self._getSEOTags()
[1782]40
[1815]41    def __getitem__(self, key):
42        return self._seotags.get(key, '')
43
44    @view.memoize
45    def _getSEOTags(self):
46        seotags = {
[1831]47            "seo_title": self.getSEOProperty( 'qSEO_title', default=self.pcs.object_title() ),
[1815]48            "seo_robots": self.getSEOProperty( 'qSEO_robots', default='ALL'),
49            "seo_description": self.getSEOProperty( 'qSEO_description', accessor='Description' ),
50            "seo_distribution": self.getSEOProperty( 'qSEO_distribution', default="Global"),
51            "seo_customMetaTags": self.seo_customMetaTags(),
[1908]52            # "seo_localCustomMetaTags": self.seo_localCustomMetaTags(),
53            # "seo_globalCustomMetaTags": self.seo_globalCustomMetaTags(),
[1815]54            "seo_html_comment": self.getSEOProperty( 'qSEO_html_comment', default='' ),
[1824]55            "meta_keywords": self.getSEOProperty('qSEO_keywords', 'Subject', ()),
56            "seo_keywords": self.getSEOProperty('qSEO_keywords', default=()),
[1931]57            "seo_canonical": ICanonicalLink(self.context).canonical_link,
[1815]58            # Add test properties
59            "has_seo_title": self.context.hasProperty('qSEO_title'),
60            "has_seo_robots": self.context.hasProperty('qSEO_robots'),
61            "has_seo_description": self.context.hasProperty( 'qSEO_description'),
62            "has_seo_distribution": self.context.hasProperty( 'qSEO_distribution'),
63            "has_html_comment": self.context.hasProperty('qSEO_html_comment'),
64            "has_seo_keywords": self.context.hasProperty('qSEO_keywords'),
[1931]65            "has_seo_canonical": self.context.hasProperty(CANONICAL_PROPERTY),
[1815]66            }
[1908]67        #seotags["seo_nonEmptylocalMetaTags"] = bool(seotags["seo_localCustomMetaTags"])
[1815]68        return seotags
69
70    def getSEOProperty( self, property_name, accessor='', default=None ):
[1506]71        """ Get value from seo property by property name.
[408]72        """
[413]73        context = aq_inner(self.context)
74
75        if context.hasProperty(property_name):
[1815]76            return context.getProperty(property_name, default)
[1475]77
[413]78        if accessor:
[1815]79            method = getattr(context, accessor, default)
[413]80            if not callable(method):
[1815]81                return default
[408]82
[413]83            # Catch AttributeErrors raised by some AT applications
84            try:
85                value = method()
86            except AttributeError:
[1815]87                value = default
[1475]88
[413]89            return value
[1824]90        return default
[408]91
92    def seo_customMetaTags( self ):
[1819]93        """Returned seo custom metatags from default_custom_metatags property in seo_properties
[1958]94           (global seo custom metatags) with update from seo custom metatags properties
95           in context (local seo custom metatags).
[408]96        """
[1824]97        glob, loc = self.seo_globalCustomMetaTags(), self.seo_localCustomMetaTags()
98        gnames = set(map(lambda x: x['meta_name'], glob))
99        lnames = set(map(lambda x: x['meta_name'], loc))
100        # Get untouch global, override global in custom and new custom meta tags
101        untouchglob = [t for t in glob if t['meta_name'] in list(gnames - lnames)]
102        return untouchglob + loc
[1265]103
104    def seo_globalWithoutLocalCustomMetaTags( self ):
[1819]105        """Returned seo custom metatags from default_custom_metatags property in seo_properties
[1958]106           (global seo custom metatags) without seo custom metatags from properties
107           in context (local seo custom metatags).
[1265]108        """
[1824]109        glob, loc = self.seo_globalCustomMetaTags(), self.seo_localCustomMetaTags()
110        gnames = set(map(lambda x: x['meta_name'], glob))
111        lnames = set(map(lambda x: x['meta_name'], loc))
112        return [t for t in glob if t['meta_name'] in list(gnames - lnames)]
[1265]113
114    def seo_localCustomMetaTags( self ):
[1506]115        """ Returned seo custom metatags from properties in context (local seo custom metatags).
[1265]116        """
[408]117        result = []
118        property_prefix = 'qSEO_custom_'
119        context = aq_inner(self.context)
120        for property, value in context.propertyItems():
[1265]121            if property.startswith(property_prefix) and property[len(property_prefix):]:
[408]122                result.append({'meta_name'    : property[len(property_prefix):],
123                               'meta_content' : value})
[1265]124        return result
[408]125
[1908]126    @ram.cache(plone_instance_time)
[1265]127    def seo_globalCustomMetaTags( self ):
[1506]128        """ Returned seo custom metatags from default_custom_metatags property in seo_properties.
[1265]129        """
130        result = []
[1824]131        if self.gseo:
[1900]132            for tag in self.gseo.default_custom_metatags:
[1183]133                name_value = tag.split(SEPERATOR)
[1265]134                if name_value[0]:
135                    result.append({'meta_name'    : name_value[0],
[1309]136                                   'meta_content' : len(name_value) == 2 and name_value[1] or ''})
[408]137        return result
[1265]138
[896]139
[1460]140class SEOContextPropertiesView( BrowserView ):
[1506]141    """ This class contains methods that allows to manage seo properties.
[1460]142    """
143    template = ViewPageTemplateFile('templates/seo_context_properties.pt')
144
[1900]145    def __init__(self, *args, **kwargs):
146        super(SEOContextPropertiesView, self).__init__(*args, **kwargs)
147        self.pps = queryMultiAdapter((self.context, self.request),
148                                     name="plone_portal_state")
149        self.gseo = queryAdapter(self.pps.portal(), ISEOConfigletSchema)
150
151
[1461]152    def test( self, condition, first, second ):
153        """
154        """
[1958]155        return condition and first or second
[1466]156
157    def validateSEOProperty(self, property, value):
[1506]158        """ Validate a seo property.
159        """
[1931]160        return ''
[1466]161
[1462]162    def setProperty(self, property, value, type='string'):
[1506]163        """ Add a new property.
164
[1958]165            Sets a new property with the given id, value and type or changes it.
[1506]166        """
[1958]167        context = aq_inner(self.context)
[1466]168        state = self.validateSEOProperty(property, value)
169        if not state:
170            if context.hasProperty(property):
171                context.manage_changeProperties({property: value})
172            else:
173                context.manage_addProperty(property, value, type)
174        return state
[1461]175
176    def manageSEOProps(self, **kw):
[1506]177        """ Manage seo properties.
178        """
[1461]179        context = aq_inner(self.context)
[1466]180        state = ''
[1468]181        delete_list, seo_overrides_keys, seo_keys = [], [], []
[1460]182        seo_items = dict([(k[len(SEO_PREFIX):],v) for k,v in kw.items() if k.startswith(SEO_PREFIX)])
183        for key in seo_items.keys():
184            if key.endswith(SUFFIX):
[1468]185                seo_overrides_keys.append(key[:-len(SUFFIX)])
[1460]186            else:
[1468]187                seo_keys.append(key)
188        for seo_key in seo_keys:
189            if seo_key == 'custommetatags':
190                self.manageSEOCustomMetaTagsProperties(**kw)
191            else:
192                if seo_key in seo_overrides_keys and seo_items.get(seo_key+SUFFIX):
193                    seo_value = seo_items[seo_key]
[1935]194                    if seo_key == 'canonical':
195                        try:
196                            ICanonicalLink(self.context).canonical_link = seo_value
197                        except InvalidValue, e:
198                            state = "'%s' - wrong canonical url" % str(e)
199                    else:
200                        t_value = 'string'
201                        if type(seo_value)==type([]) or type(seo_value)==type(()): t_value = 'lines'
202                        state = self.setProperty(PROP_PREFIX+seo_key, seo_value, type=t_value)
[1468]203                    if state:
204                        return state
[1935]205                elif seo_key == 'canonical':
206                    del ICanonicalLink(self.context).canonical_link
[1468]207                elif context.hasProperty(PROP_PREFIX+seo_key):
208                    delete_list.append(PROP_PREFIX+seo_key)
[1466]209        if delete_list:
210            context.manage_delProperties(delete_list)
211        return state
[1461]212
[1462]213    def setSEOCustomMetaTags(self, custommetatags):
[1506]214        """ Set seo custom metatags properties.
215        """
[1462]216        context = aq_inner(self.context)
[1463]217        for tag in custommetatags:
218            self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, tag['meta_name']), tag['meta_content'])
[1462]219
[1466]220    def delAllSEOCustomMetaTagsProperties(self):
[1506]221        """ Delete all seo custom metatags properties.
222        """
[1466]223        context = aq_inner(self.context)
[1461]224        delete_list = []
225        for property, value in context.propertyItems():
[1466]226            if property.startswith(PROP_CUSTOM_PREFIX)  and not property == PROP_CUSTOM_PREFIX:
[1461]227                delete_list.append(property)
[1466]228        if delete_list:
229            context.manage_delProperties(delete_list)
[1461]230
[1466]231    def updateSEOCustomMetaTagsProperties(self, custommetatags):
[1506]232        """ Update seo custom metatags properties.
233        """
[1461]234        globalCustomMetaTags = []
[1900]235        if self.gseo:
236            custom_meta_tags = self.gseo.default_custom_metatags
[1461]237            for tag in custom_meta_tags:
238                name_value = tag.split(SEPERATOR)
239                if name_value[0]:
[1900]240                    globalCustomMetaTags.append(
241                        {'meta_name' : name_value[0],
242                         'meta_content' : len(name_value) == 1 and '' or name_value[1]})
[1461]243        for tag in custommetatags:
244            meta_name, meta_content = tag['meta_name'], tag['meta_content']
245            if meta_name:
[1900]246                if not [gmt for gmt in globalCustomMetaTags \
247                        if (gmt['meta_name']==meta_name and gmt['meta_content']==meta_content)]:
[1466]248                    self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, meta_name), meta_content)
249
250    def manageSEOCustomMetaTagsProperties(self, **kw):
[1506]251        """ Update seo custom metatags properties, if enabled checkbox override or delete properties.
252
[1958]253            Change object properties by passing either a mapping object
254            of name:value pairs {'foo':6} or passing name=value parameters.
[1506]255        """
[1461]256        context = aq_inner(self.context)
[1466]257        self.delAllSEOCustomMetaTagsProperties()
258        if kw.get('seo_custommetatags_override'):
259            custommetatags = kw.get('seo_custommetatags', {})
260            self.updateSEOCustomMetaTagsProperties(custommetatags)
[1460]261
[1918]262    def getPropertyStopWords(self):
263        """ Get property 'stop_words' from SEO Properties tool.
264        """
265        enc = getSiteEncoding(self.context)
266        # self.gseo.stop_words return list of unicode objects,
267        # and may contains stop words in different languages.
268        # So we must return encoded strings.
269        sw = map(lambda x:unicode.encode(x, enc), self.gseo.stop_words)
270        return str(sw)
271
272    def getPropertyFields(self):
273        """ Get property 'fields' from SEO Properties tool.
274        """
275        # self.gseo.fields return list of unicode objects,
276        # so *str* use as encoding function from unicode to latin-1 string.
277        fields_id = map(str, self.gseo.fields)
278        return str(fields_id)
279
[1460]280    def __call__( self ):
[1958]281        """ Perform the update seo properties and redirect if necessary,
282            or render the page Call method.
[1460]283        """
284        context = aq_inner(self.context)
285        request = self.request
286        form = self.request.form
287        submitted = form.get('form.submitted', False)
288        if submitted:
[1466]289            state = self.manageSEOProps(**form)
290            if not state:
291                state = _('seoproperties_saved', default=u'Content SEO properties have been saved.')
292                context.plone_utils.addPortalMessage(state)
[1475]293                kwargs = {'modification_date' : DateTime()} 
[1675]294                context.plone_utils.contentEdit(context, **kwargs)
[1466]295                return request.response.redirect(self.context.absolute_url())
296            context.plone_utils.addPortalMessage(state, 'error')
297        return self.template()
[1821]298
299
300class VisibilityCheckerView( BrowserView ):
301    """ This class contains methods that visibility checker.
302    """
303
304    def checkVisibilitySEOAction(self):
305        """ Checks visibility 'SEO Properties' action for content
306        """
307        context = aq_inner(self.context)
[1824]308        plone = queryMultiAdapter((self, self.request),name="plone_portal_state").portal()
[1821]309        adapter = ISEOConfigletSchema(plone)
310        return bool(self.context.portal_type in adapter.types_seo_enabled)
Note: See TracBrowser for help on using the repository browser.