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

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

#143: Refactoring 'SEO' tab view for different types

  • Property svn:eol-style set to native
File size: 20.1 KB
Line 
1from sets import Set
2from DateTime import DateTime
3from Acquisition import aq_inner
4from zope.component import queryAdapter
5from plone.app.controlpanel.form import ControlPanelView
6
7from Products.Five.browser import BrowserView
8from Products.CMFCore.utils import getToolByName
9from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
10from Products.CMFPlone import PloneMessageFactory as pmf
11
12from quintagroup.seoptimizer import SeoptimizerMessageFactory as _
13from quintagroup.seoptimizer import interfaces
14
15SEPERATOR = '|'
16SEO_PREFIX = 'seo_'
17PROP_PREFIX = 'qSEO_'
18SUFFIX = '_override'
19PROP_CUSTOM_PREFIX = 'qSEO_custom_'
20
21class SEOContext( BrowserView ):
22    """ This class contains methods that allows to edit html header meta tags.
23    """
24
25    def isSEOTabVisibile(self):
26        context = aq_inner(self.context)
27        portal_properties = getToolByName(context, 'portal_properties')
28        seo_properties = getToolByName(portal_properties, 'seo_properties')
29        content_types_with_seoproperties = seo_properties.getProperty('content_types_with_seoproperties', '')
30        return bool(self.context.portal_type in content_types_with_seoproperties)
31
32    def getSEOProperty( self, property_name, accessor='' ):
33        """ Get value from seo property by property name.
34        """
35        context = aq_inner(self.context)
36
37        if context.hasProperty(property_name):
38            return context.getProperty(property_name)
39
40        if accessor:
41            method = getattr(context, accessor, None)
42            if not callable(method):
43                return None
44
45            # Catch AttributeErrors raised by some AT applications
46            try:
47                value = method()
48            except AttributeError:
49                value = None
50
51            return value
52
53    def seo_title( self ):
54        """ Generate SEO Title from SEO properties.
55        """
56        return self.getSEOProperty( 'qSEO_title', accessor='Title' )
57
58    def seo_robots( self ):
59        """ Generate SEO Robots from SEO properties.
60        """
61        robots = self.getSEOProperty( 'qSEO_robots' )
62        return robots and robots or 'ALL'
63
64    def seo_description( self ):
65        """ Generate Description from SEO properties.
66        """
67
68        return self.getSEOProperty( 'qSEO_description', accessor = 'Description')
69
70    def seo_distribution( self ):
71        """ Generate Distribution from SEO properties.
72        """
73        dist = self.getSEOProperty( 'qSEO_distribution' )
74
75        return dist and dist or 'Global'
76
77    def seo_customMetaTags( self ):
78        """        Returned seo custom metatags from default_custom_metatags property in seo_properties
79        (global seo custom metatags) with update from seo custom metatags properties in context (local seo custom metatags).
80        """
81        tags = self.seo_globalCustomMetaTags()
82        loc = self.seo_localCustomMetaTags()
83        names = [i['meta_name'] for i in tags]
84        add_tags = []
85        for i in loc:
86            if i['meta_name'] in names:
87                for t in tags:
88                    if t['meta_name'] == i['meta_name']:
89                        t['meta_content'] = i['meta_content']
90            else:
91                add_tags.append(i)
92        tags.extend(add_tags)
93        return tags
94
95    def seo_globalWithoutLocalCustomMetaTags( self ):
96        """        Returned seo custom metatags from default_custom_metatags property in seo_properties
97        (global seo custom metatags) without seo custom metatags from properties in context (local seo custom metatags).
98        """
99        glob = self.seo_globalCustomMetaTags()
100        loc = self.seo_localCustomMetaTags()
101        names = [i['meta_name'] for i in loc]
102        tags = []
103        for i in glob:
104            if i['meta_name'] not in names:
105                tags.append(i)
106        return tags
107
108    def seo_localCustomMetaTags( self ):
109        """ Returned seo custom metatags from properties in context (local seo custom metatags).
110        """
111        result = []
112        property_prefix = 'qSEO_custom_'
113        context = aq_inner(self.context)
114        for property, value in context.propertyItems():
115            if property.startswith(property_prefix) and property[len(property_prefix):]:
116                result.append({'meta_name'    : property[len(property_prefix):],
117                               'meta_content' : value})
118        return result
119
120    def seo_globalCustomMetaTags( self ):
121        """ Returned seo custom metatags from default_custom_metatags property in seo_properties.
122        """
123        result = []
124        context = aq_inner(self.context)
125        site_properties = getToolByName(context, 'portal_properties')
126        if hasattr(site_properties, 'seo_properties'):
127            custom_meta_tags = getattr(site_properties.seo_properties, 'default_custom_metatags', [])
128            for tag in custom_meta_tags:
129                name_value = tag.split(SEPERATOR)
130                if name_value[0]:
131                    result.append({'meta_name'    : name_value[0],
132                                   'meta_content' : len(name_value) == 2 and name_value[1] or ''})
133        return result
134
135    def seo_nonEmptylocalMetaTags( self ):
136        """
137        """
138        return bool(self.seo_localCustomMetaTags())
139
140    def seo_html_comment( self ):
141        """ Generate HTML Comments from SEO properties.
142        """
143        html_comment = self.getSEOProperty( 'qSEO_html_comment' )
144        return html_comment and html_comment or '' 
145
146    def meta_keywords( self ):
147        """ Generate Meta Keywords from SEO properties (global and local) with Subject,
148            depending on the options in configlet.
149        """
150        prop_name = 'qSEO_keywords'
151        accessor = 'Subject'
152        context = aq_inner(self.context)
153        keywords = Set([])
154        pprops = getToolByName(context, 'portal_properties')
155        sheet = getattr(pprops, 'seo_properties', None)
156        method = getattr(context, accessor, None)
157        if not callable(method):
158            return None
159
160        # Catch AttributeErrors raised by some AT applications
161        try:
162            subject = Set(method())
163        except AttributeError:
164            subject = keywords
165
166        if sheet:
167          settings_use_keywords_sg = sheet.getProperty('settings_use_keywords_sg')
168          settings_use_keywords_lg = sheet.getProperty('settings_use_keywords_lg')
169          global_keywords = Set(sheet.getProperty('additional_keywords', None))
170          local_keywords = Set(context.getProperty(prop_name, None))
171          # Subject overrides global seo keywords and global overrides local seo keywords
172          if [settings_use_keywords_sg, settings_use_keywords_lg] == [1, 1]:
173              keywords = subject
174          # Subject overrides global seo keywords and merge global and local seo keywords
175          elif [settings_use_keywords_sg, settings_use_keywords_lg] == [1, 2]:
176              keywords = subject | local_keywords
177          # Global seo keywords overrides Subject and global overrides local seo keywords
178          elif [settings_use_keywords_sg, settings_use_keywords_lg] == [2, 1]:
179              keywords = global_keywords
180          # Global seo keywords overrides Subject and merge global and local seo keywords
181          elif [settings_use_keywords_sg, settings_use_keywords_lg] == [2, 2]:
182              keywords = global_keywords | local_keywords
183          # Merge Subject and global seo keywords and global overrides local seo keywords
184          elif [settings_use_keywords_sg, settings_use_keywords_lg] == [3, 1]:
185              keywords = subject | global_keywords
186          # Merge Subject and global seo keywords and merge global and local seo keywords
187          elif [settings_use_keywords_sg, settings_use_keywords_lg] == [3, 2]:
188              keywords = subject | global_keywords | local_keywords
189          else:
190              keywords = subject
191        else:
192            keywords = subject
193
194        return tuple(keywords)
195
196    def seo_keywords( self ):
197        """ Generate SEO Keywords from SEO properties (global merde local).
198        """
199        prop_name = 'qSEO_keywords'
200        context = aq_inner(self.context)
201        keywords = Set([])
202        pprops = getToolByName(context, 'portal_properties')
203        sheet = getattr(pprops, 'seo_properties', None)
204
205        if sheet:
206            settings_use_keywords_sg = sheet.getProperty('settings_use_keywords_sg')
207            settings_use_keywords_lg = sheet.getProperty('settings_use_keywords_lg')
208            global_keywords = Set(sheet.getProperty('additional_keywords', None))
209            local_keywords = Set(context.getProperty(prop_name, None))
210            keywords = global_keywords | local_keywords
211        else:
212            keywords = ''
213        return tuple(keywords)
214
215    def seo_canonical( self ):
216        """ Generate canonical URL from SEO properties.
217        """
218        purl = getToolByName(self.context, 'portal_url')()
219        canpath = queryAdapter(self.context, interfaces.ISEOCanonicalPath)
220        return purl + canpath.canonical_path()
221
222
223class SEOControlPanel( ControlPanelView ):
224    """ The class with methods configuration Search Engine Optimizer in configlet.
225    """
226    template = ViewPageTemplateFile('templates/seo_controlpanel.pt')
227
228    @property
229    def portal_properties( self ):
230        """
231        """
232        context = aq_inner(self.context)
233        return getToolByName(context, 'portal_properties')
234
235    @property
236    def portal_types( self ):
237        """ Returned a list of portal types.
238        """
239        context = aq_inner(self.context)
240        return getToolByName(context, 'portal_types')
241
242    #def hasSEOAction( self, type_info ):
243        #"""
244        #"""
245        #return filter(lambda x:x.id == 'seo_properties', type_info.listActions())
246
247    def test( self, condition, first, second ):
248        """
249        """
250        return condition and first or second
251
252    def getExposeDCMetaTags( self ):
253        """ Get value from exposeDCMetaTags property in seo_properties.
254        """
255        sp = self.portal_properties.site_properties
256        return sp.getProperty('exposeDCMetaTags')
257
258    def getDefaultCustomMetatags( self ):
259        """ Get values from default_custom_metatags property in seo_properties.
260        """
261        seo = self.portal_properties.seo_properties
262        return seo.getProperty('default_custom_metatags')
263
264    def getMetaTagsOrder( self ):
265        """ Get values from metatags_order property in seo_properties.
266        """
267        seo = self.portal_properties.seo_properties
268        return seo.getProperty('metatags_order')
269
270    def getAdditionalKeywords( self ):
271        """ Get values from additional_keywords property in seo_properties.
272        """
273        seo = self.portal_properties.seo_properties
274        return seo.getProperty('additional_keywords')
275
276    def createMultiColumnList( self ):
277        """
278        """
279        context = aq_inner(self.context)
280        allTypes = self.portal_types.listContentTypes()
281        try:
282            return context.createMultiColumnList(allTypes, sort_on='title_or_id')
283        except AttributeError:
284            return [slist]
285
286    def isSEOTabVisibile(self, type):
287        context = aq_inner(self.context)
288        portal_properties = getToolByName(context, 'portal_properties')
289        seo_properties = getToolByName(portal_properties, 'seo_properties')
290        content_types_with_seoproperties = seo_properties.getProperty('content_types_with_seoproperties', '')
291        return bool(type in content_types_with_seoproperties)
292     
293    def __call__( self ):
294        """ Perform the update and redirect if necessary, or render the page.
295        """
296        context = aq_inner(self.context)
297        request = self.request
298
299        exposeDCMetaTags = request.get( 'exposeDCMetaTags', None )
300        additionalKeywords = request.get('additionalKeywords', [])
301        default_custom_metatags = request.get('default_custom_metatags', [])
302        metatags_order = request.get('metatags_order', [])
303        settingsUseKeywordsSG = int(request.get('settingsUseKeywordsSG', 1))
304        settingsUseKeywordsLG = int(request.get('settingsUseKeywordsLG', 1))
305        content_types_with_seoproperties = request.get('contentTypes', [])
306
307        site_props = getToolByName(self.portal_properties, 'site_properties')
308        seo_props = getToolByName(self.portal_properties, 'seo_properties')
309
310        form = self.request.form
311        submitted = form.get('form.submitted', False)
312        if submitted:
313            site_props.manage_changeProperties(exposeDCMetaTags=exposeDCMetaTags)
314            seo_props.manage_changeProperties(additional_keywords=additionalKeywords)
315            seo_props.manage_changeProperties(default_custom_metatags=default_custom_metatags)
316            seo_props.manage_changeProperties(metatags_order=metatags_order)
317            seo_props.manage_changeProperties(settings_use_keywords_sg=settingsUseKeywordsSG)
318            seo_props.manage_changeProperties(settings_use_keywords_lg=settingsUseKeywordsLG)
319            seo_props.manage_changeProperties(content_types_with_seoproperties=content_types_with_seoproperties)
320
321            context.plone_utils.addPortalMessage(pmf(u'Changes saved.'))
322            return request.response.redirect('%s/%s'%(self.context.absolute_url(), 'plone_control_panel'))
323        else:
324            return self.template(contentTypes=content_types_with_seoproperties, exposeDCMetaTags=exposeDCMetaTags)
325
326    def typeInfo( self, type_name ):
327        """ Get info type by type name.
328        """
329        return self.portal_types.getTypeInfo( type_name )
330
331    def select_settings_use_keywords_sg(self):
332        context = aq_inner(self.context)
333        site_properties = getToolByName(context, 'portal_properties')
334        if hasattr(site_properties, 'seo_properties'):
335            settings_use_keywords_sg = getattr(site_properties.seo_properties, 'settings_use_keywords_sg', 0)
336        return settings_use_keywords_sg
337
338    def select_settings_use_keywords_lg(self):
339        context = aq_inner(self.context)
340        site_properties = getToolByName(context, 'portal_properties')
341        if hasattr(site_properties, 'seo_properties'):
342            settings_use_keywords_lg = getattr(site_properties.seo_properties, 'settings_use_keywords_lg', 0)
343        return settings_use_keywords_lg
344
345
346class SEOContextPropertiesView( BrowserView ):
347    """ This class contains methods that allows to manage seo properties.
348    """
349    template = ViewPageTemplateFile('templates/seo_context_properties.pt')
350
351    def test( self, condition, first, second ):
352        """
353        """
354        return condition and first or second
355
356    def getMainDomain(self, url):
357        """ Get a main domain.
358        """
359        url = url.split('//')[-1]
360        dompath = url.split(':')[0]
361        dom = dompath.split('/')[0]
362        return '.'.join(dom.split('.')[-2:])
363
364    def validateSEOProperty(self, property, value):
365        """ Validate a seo property.
366        """
367        purl = getToolByName(self.context, 'portal_url')()
368        state = ''
369        if property == PROP_PREFIX+'canonical':
370            # validate seo canonical url property
371            pdomain = self.getMainDomain(purl)
372            if not pdomain == self.getMainDomain(value):
373                state = _('canonical_msg', default=u'Canonical URL mast be in ${pdomain} domain.', mapping={'pdomain': pdomain})
374        return state
375
376    def setProperty(self, property, value, type='string'):
377        """ Add a new property.
378
379        Sets a new property with the given id, value and type or changes it.
380        """
381        context = aq_inner(self.context)
382        state = self.validateSEOProperty(property, value)
383        if not state:
384            if context.hasProperty(property):
385                context.manage_changeProperties({property: value})
386            else:
387                context.manage_addProperty(property, value, type)
388        return state
389
390    def manageSEOProps(self, **kw):
391        """ Manage seo properties.
392        """
393        context = aq_inner(self.context)
394        state = ''
395        delete_list, seo_overrides_keys, seo_keys = [], [], []
396        seo_items = dict([(k[len(SEO_PREFIX):],v) for k,v in kw.items() if k.startswith(SEO_PREFIX)])
397        for key in seo_items.keys():
398            if key.endswith(SUFFIX):
399                seo_overrides_keys.append(key[:-len(SUFFIX)])
400            else:
401                seo_keys.append(key)
402        for seo_key in seo_keys:
403            if seo_key == 'custommetatags':
404                self.manageSEOCustomMetaTagsProperties(**kw)
405            else:
406                if seo_key in seo_overrides_keys and seo_items.get(seo_key+SUFFIX):
407                    seo_value = seo_items[seo_key]
408                    t_value = 'string'
409                    if type(seo_value)==type([]) or type(seo_value)==type(()): t_value = 'lines'
410                    state = self.setProperty(PROP_PREFIX+seo_key, seo_value, type=t_value)
411                    if state:
412                        return state
413                elif context.hasProperty(PROP_PREFIX+seo_key):
414                    delete_list.append(PROP_PREFIX+seo_key)
415        if delete_list:
416            context.manage_delProperties(delete_list)
417        return state
418
419    def setSEOCustomMetaTags(self, custommetatags):
420        """ Set seo custom metatags properties.
421        """
422        context = aq_inner(self.context)
423        for tag in custommetatags:
424            self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, tag['meta_name']), tag['meta_content'])
425
426    def delAllSEOCustomMetaTagsProperties(self):
427        """ Delete all seo custom metatags properties.
428        """
429        context = aq_inner(self.context)
430        delete_list = []
431        for property, value in context.propertyItems():
432            if property.startswith(PROP_CUSTOM_PREFIX)  and not property == PROP_CUSTOM_PREFIX:
433                delete_list.append(property)
434        if delete_list:
435            context.manage_delProperties(delete_list)
436
437    def updateSEOCustomMetaTagsProperties(self, custommetatags):
438        """ Update seo custom metatags properties.
439        """
440        context = aq_inner(self.context)
441        site_properties = getToolByName(context, 'portal_properties')
442        globalCustomMetaTags = []
443        if hasattr(site_properties, 'seo_properties'):
444            custom_meta_tags = getattr(site_properties.seo_properties, 'default_custom_metatags', [])
445            for tag in custom_meta_tags:
446                name_value = tag.split(SEPERATOR)
447                if name_value[0]:
448                    globalCustomMetaTags.append({'meta_name'    : name_value[0],
449                                                 'meta_content' : len(name_value) == 1 and '' or name_value[1]})
450        for tag in custommetatags:
451            meta_name, meta_content = tag['meta_name'], tag['meta_content']
452            if meta_name:
453                if not [gmt for gmt in globalCustomMetaTags if (gmt['meta_name']==meta_name and gmt['meta_content']==meta_content)]:
454                    self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, meta_name), meta_content)
455
456    def manageSEOCustomMetaTagsProperties(self, **kw):
457        """ Update seo custom metatags properties, if enabled checkbox override or delete properties.
458
459        Change object properties by passing either a mapping object
460        of name:value pairs {'foo':6} or passing name=value parameters.
461        """
462        context = aq_inner(self.context)
463        self.delAllSEOCustomMetaTagsProperties()
464        if kw.get('seo_custommetatags_override'):
465            custommetatags = kw.get('seo_custommetatags', {})
466            self.updateSEOCustomMetaTagsProperties(custommetatags)
467
468    def __call__( self ):
469        """ Perform the update seo properties and redirect if necessary, or render the page Call method.
470        """
471        context = aq_inner(self.context)
472        request = self.request
473        form = self.request.form
474        submitted = form.get('form.submitted', False)
475        if submitted:
476            state = self.manageSEOProps(**form)
477            if not state:
478                state = _('seoproperties_saved', default=u'Content SEO properties have been saved.')
479                context.plone_utils.addPortalMessage(state)
480                kwargs = {'modification_date' : DateTime()} 
481                context.plone_utils.contentEdit(context, **kwargs)
482                return request.response.redirect(self.context.absolute_url())
483            context.plone_utils.addPortalMessage(state, 'error')
484        return self.template()
Note: See TracBrowser for help on using the repository browser.