source: products/quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py @ 1580

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

Added radiobuttons in configlet for settings the use Subject, local and global seo keywords

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