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

Last change on this file since 1901 was 1900, checked in by mylan, 14 years ago

#166: Force usage ISEOConfigletSchema adapter for getting seo properties

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