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

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

Added reinstall profile and removed using content_types_seoprops_enabled propery in seo_properties

  • Property svn:eol-style set to native
File size: 17.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
151        keywords = Set([])
152        if context.hasProperty(prop_name):
153            keywords = Set(context.getProperty(prop_name))
154
155        pprops = getToolByName(context, 'portal_properties')
156        sheet = getattr(pprops, 'seo_properties', None)
157        if sheet and sheet.hasProperty(add_keywords):
158            keywords = keywords | Set(sheet.getProperty(add_keywords))
159
160        if keywords:
161            return keywords
162
163        method = getattr(context, accessor, None)
164        if not callable(method):
165            return None
166
167        # Catch AttributeErrors raised by some AT applications
168        try:
169            value = method()
170        except AttributeError:
171            value = None
172
173        return value
174
175    def seo_canonical( self ):
176        """ Generate canonical URL from SEO properties.
177        """
178        canonical = self.getSEOProperty( 'qSEO_canonical' )
179
180        if not canonical and HAS_CANONICAL_PATH:
181            canpath = queryAdapter(self.context, ICanonicalPath)
182            if canpath:
183                purl = getToolByName(self.context, 'portal_url')()
184                cpath = canpath.canonical_path()
185                canonical = purl + cpath
186
187        return canonical and canonical or self.context.absolute_url()
188
189
190class SEOControlPanel( ControlPanelView ):
191    """ The class with methods configuration Search Engine Optimizer in configlet.
192    """
193    template = ViewPageTemplateFile('templates/seo_controlpanel.pt')
194
195    @property
196    def portal_properties( self ):
197        """
198        """
199        context = aq_inner(self.context)
200        return getToolByName(context, 'portal_properties')
201
202    @property
203    def portal_types( self ):
204        """ Returned a list of portal types.
205        """
206        context = aq_inner(self.context)
207        return getToolByName(context, 'portal_types')
208
209    def hasSEOAction( self, type_info ):
210        """
211        """
212        return filter(lambda x:x.id == 'seo_properties', type_info.listActions())
213
214    def test( self, condition, first, second ):
215        """
216        """
217        return condition and first or second
218
219    def getExposeDCMetaTags( self ):
220        """ Get value from exposeDCMetaTags property in seo_properties.
221        """
222        sp = self.portal_properties.site_properties
223        return sp.getProperty('exposeDCMetaTags')
224
225    def getDefaultCustomMetatags( self ):
226        """ Get values from default_custom_metatags property in seo_properties.
227        """
228        seo = self.portal_properties.seo_properties
229        return seo.getProperty('default_custom_metatags')
230
231    def getMetaTagsOrder( self ):
232        """ Get values from metatags_order property in seo_properties.
233        """
234        seo = self.portal_properties.seo_properties
235        return seo.getProperty('metatags_order')
236
237    def getAdditionalKeywords( self ):
238        """ Get values from additional_keywords property in seo_properties.
239        """
240        seo = self.portal_properties.seo_properties
241        return seo.getProperty('additional_keywords')
242
243    def createMultiColumnList( self ):
244        """
245        """
246        context = aq_inner(self.context)
247        allTypes = self.portal_types.listContentTypes()
248        try:
249            return context.createMultiColumnList(allTypes, sort_on='title_or_id')
250        except AttributeError:
251            return [slist]
252
253    def __call__( self ):
254        """ Perform the update and redirect if necessary, or render the page.
255        """
256        context = aq_inner(self.context)
257        request = self.request
258
259        content_types_seoprops_enabled = request.get( 'contentTypes', [] )
260        exposeDCMetaTags = request.get( 'exposeDCMetaTags', None )
261        additionalKeywords = request.get('additionalKeywords', [])
262        default_custom_metatags = request.get('default_custom_metatags', [])
263        metatags_order = request.get('metatags_order', [])
264
265        site_props = getToolByName(self.portal_properties, 'site_properties')
266        seo_props = getToolByName(self.portal_properties, 'seo_properties')
267
268        form = self.request.form
269        submitted = form.get('form.submitted', False)
270
271        if submitted:
272            site_props.manage_changeProperties(exposeDCMetaTags=exposeDCMetaTags)
273            seo_props.manage_changeProperties(additional_keywords=additionalKeywords)
274            seo_props.manage_changeProperties(default_custom_metatags=default_custom_metatags)
275            seo_props.manage_changeProperties(metatags_order=metatags_order)
276            seo_props.manage_changeProperties(content_types_seoprops_enabled=content_types_seoprops_enabled)
277
278            for ptype in self.portal_types.objectValues():
279                acts = filter(lambda x: x.id == 'seo_properties', ptype.listActions())
280                action = acts and acts[0] or None
281                if ptype.getId() in content_types_seoprops_enabled:
282                    if action is None:
283                        ptype.addAction('seo_properties',
284                                        'SEO Properties',
285                                        'string:${object_url}/@@seo-context-properties',
286                                        "python:exists('portal/@@seo-context-properties')",
287                                        'Modify portal content',
288                                        'object',
289                                        visible=1)
290                else:
291                    if action !=None:
292                        actions = list(ptype.listActions())
293                        ptype.deleteActions([actions.index(a) for a in actions if a.getId()=='seo_properties'])
294            context.plone_utils.addPortalMessage(pmf(u'Changes saved.'))
295            return request.response.redirect('%s/%s'%(self.context.absolute_url(), 'plone_control_panel'))
296        else:
297            return self.template(contentTypes=content_types_seoprops_enabled, exposeDCMetaTags=exposeDCMetaTags)
298
299    def typeInfo( self, type_name ):
300        """ Get info type by type name.
301        """
302        return self.portal_types.getTypeInfo( type_name )
303
304
305class SEOContextPropertiesView( BrowserView ):
306    """ This class contains methods that allows to manage seo properties.
307    """
308    template = ViewPageTemplateFile('templates/seo_context_properties.pt')
309
310    def test( self, condition, first, second ):
311        """
312        """
313        return condition and first or second
314
315    def getMainDomain(self, url):
316        """ Get a main domain.
317        """
318        url = url.split('//')[-1]
319        dompath = url.split(':')[0]
320        dom = dompath.split('/')[0]
321        return '.'.join(dom.split('.')[-2:])
322
323    def validateSEOProperty(self, property, value):
324        """ Validate a seo property.
325        """
326        purl = getToolByName(self.context, 'portal_url')()
327        state = ''
328        if property == PROP_PREFIX+'canonical':
329            # validate seo canonical url property
330            pdomain = self.getMainDomain(purl)
331            if not pdomain == self.getMainDomain(value):
332                state = _('canonical_msg', default=u'Canonical URL mast be in ${pdomain} domain.', mapping={'pdomain': pdomain})
333        return state
334
335    def setProperty(self, property, value, type='string'):
336        """ Add a new property.
337
338        Sets a new property with the given id, value and type or changes it.
339        """
340        context = aq_inner(self.context)
341        state = self.validateSEOProperty(property, value)
342        if not state:
343            if context.hasProperty(property):
344                context.manage_changeProperties({property: value})
345            else:
346                context.manage_addProperty(property, value, type)
347        return state
348
349    def manageSEOProps(self, **kw):
350        """ Manage seo properties.
351        """
352        context = aq_inner(self.context)
353        state = ''
354        delete_list, seo_overrides_keys, seo_keys = [], [], []
355        seo_items = dict([(k[len(SEO_PREFIX):],v) for k,v in kw.items() if k.startswith(SEO_PREFIX)])
356        for key in seo_items.keys():
357            if key.endswith(SUFFIX):
358                seo_overrides_keys.append(key[:-len(SUFFIX)])
359            else:
360                seo_keys.append(key)
361        for seo_key in seo_keys:
362            if seo_key == 'custommetatags':
363                self.manageSEOCustomMetaTagsProperties(**kw)
364            else:
365                if seo_key in seo_overrides_keys and seo_items.get(seo_key+SUFFIX):
366                    seo_value = seo_items[seo_key]
367                    t_value = 'string'
368                    if type(seo_value)==type([]) or type(seo_value)==type(()): t_value = 'lines'
369                    state = self.setProperty(PROP_PREFIX+seo_key, seo_value, type=t_value)
370                    if state:
371                        return state
372                elif context.hasProperty(PROP_PREFIX+seo_key):
373                    delete_list.append(PROP_PREFIX+seo_key)
374        if delete_list:
375            context.manage_delProperties(delete_list)
376        return state
377
378    def setSEOCustomMetaTags(self, custommetatags):
379        """ Set seo custom metatags properties.
380        """
381        context = aq_inner(self.context)
382        for tag in custommetatags:
383            self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, tag['meta_name']), tag['meta_content'])
384
385    def delAllSEOCustomMetaTagsProperties(self):
386        """ Delete all seo custom metatags properties.
387        """
388        context = aq_inner(self.context)
389        delete_list = []
390        for property, value in context.propertyItems():
391            if property.startswith(PROP_CUSTOM_PREFIX)  and not property == PROP_CUSTOM_PREFIX:
392                delete_list.append(property)
393        if delete_list:
394            context.manage_delProperties(delete_list)
395
396    def updateSEOCustomMetaTagsProperties(self, custommetatags):
397        """ Update seo custom metatags properties.
398        """
399        context = aq_inner(self.context)
400        site_properties = getToolByName(context, 'portal_properties')
401        globalCustomMetaTags = []
402        if hasattr(site_properties, 'seo_properties'):
403            custom_meta_tags = getattr(site_properties.seo_properties, 'default_custom_metatags', [])
404            for tag in custom_meta_tags:
405                name_value = tag.split(SEPERATOR)
406                if name_value[0]:
407                    globalCustomMetaTags.append({'meta_name'    : name_value[0],
408                                                 'meta_content' : len(name_value) == 1 and '' or name_value[1]})
409        for tag in custommetatags:
410            meta_name, meta_content = tag['meta_name'], tag['meta_content']
411            if meta_name:
412                if not [gmt for gmt in globalCustomMetaTags if (gmt['meta_name']==meta_name and gmt['meta_content']==meta_content)]:
413                    self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, meta_name), meta_content)
414
415    def manageSEOCustomMetaTagsProperties(self, **kw):
416        """ Update seo custom metatags properties, if enabled checkbox override or delete properties.
417
418        Change object properties by passing either a mapping object
419        of name:value pairs {'foo':6} or passing name=value parameters.
420        """
421        context = aq_inner(self.context)
422        self.delAllSEOCustomMetaTagsProperties()
423        if kw.get('seo_custommetatags_override'):
424            custommetatags = kw.get('seo_custommetatags', {})
425            self.updateSEOCustomMetaTagsProperties(custommetatags)
426
427    def __call__( self ):
428        """ Perform the update seo properties and redirect if necessary, or render the page Call method.
429        """
430        context = aq_inner(self.context)
431        request = self.request
432        form = self.request.form
433        submitted = form.get('form.submitted', False)
434        if submitted:
435            state = self.manageSEOProps(**form)
436            if not state:
437                state = _('seoproperties_saved', default=u'Content SEO properties have been saved.')
438                context.plone_utils.addPortalMessage(state)
439                kwargs = {'modification_date' : DateTime()} 
440                context.plone_utils.contentEdit(context, **kwargs) 
441                return request.response.redirect(self.context.absolute_url())
442            context.plone_utils.addPortalMessage(state, 'error')
443        return self.template()
Note: See TracBrowser for help on using the repository browser.