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

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

Added mirgation actions in content type

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