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

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

Added portal message in configlet

  • Property svn:eol-style set to native
File size: 14.9 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    """
28    """
29    def getSEOProperty( self, property_name, accessor='' ):
30        """
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        """
52        """
53        return self.getSEOProperty( 'qSEO_title', accessor='Title' )
54
55    def seo_robots( self ):
56        """
57        """
58        robots = self.getSEOProperty( 'qSEO_robots' )
59        return robots and robots or 'ALL'
60
61    def seo_description( self ):
62        """
63            Generate Description from SEO properties
64        """
65
66        return self.getSEOProperty( 'qSEO_description', accessor = 'Description')
67
68    def seo_distribution( self ):
69        """
70           Generate Description from SEO properties
71        """
72        dist = self.getSEOProperty( 'qSEO_distribution' )
73
74        return dist and dist or 'Global'
75
76    def seo_customMetaTags( self ):
77        """
78        """
79        tags = self.seo_globalCustomMetaTags()
80        loc = self.seo_localCustomMetaTags()
81        names = [i['meta_name'] for i in tags]
82        add_tags = []
83        for i in loc:
84            if i['meta_name'] in names:
85                for t in tags:
86                    if t['meta_name'] == i['meta_name']:
87                        t['meta_content'] = i['meta_content']
88            else:
89                add_tags.append(i)
90        tags.extend(add_tags)
91        return tags
92
93    def seo_globalWithoutLocalCustomMetaTags( self ):
94        """
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        """
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        """
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        """
139        """
140        html_comment = self.getSEOProperty( 'qSEO_html_comment' )
141        return html_comment and html_comment or '' 
142
143    def seo_keywords( self ):
144        """
145           Generate Keywords from SEO properties
146        """
147
148        prop_name = 'qSEO_keywords'
149        add_keywords = 'additional_keywords'
150        accessor = 'Subject'
151        context = aq_inner(self.context)
152
153        keywords = Set([])
154        if context.hasProperty(prop_name):
155            keywords = Set(context.getProperty(prop_name))
156
157        pprops = getToolByName(context, 'portal_properties')
158        sheet = getattr(pprops, 'seo_properties', None)
159        if sheet and sheet.hasProperty(add_keywords):
160            keywords = keywords | Set(sheet.getProperty(add_keywords))
161
162        if keywords:
163            return keywords
164
165        method = getattr(context, accessor, None)
166        if not callable(method):
167            return None
168
169        # Catch AttributeErrors raised by some AT applications
170        try:
171            value = method()
172        except AttributeError:
173            value = None
174
175        return value
176
177    def seo_canonical( self ):
178        """
179           Get canonical URL
180        """
181        canonical = self.getSEOProperty( 'qSEO_canonical' )
182
183        if not canonical and HAS_CANONICAL_PATH:
184            canpath = queryAdapter(self.context, ICanonicalPath)
185            if canpath:
186                purl = getToolByName(self.context, 'portal_url')()
187                cpath = canpath.canonical_path()
188                canonical = purl + cpath
189
190        return canonical and canonical or self.context.absolute_url()
191
192
193class SEOControlPanel( ControlPanelView ):
194    """
195    """
196    template = ViewPageTemplateFile('templates/seo_controlpanel.pt')
197
198    @property
199    def portal_properties( self ):
200        """
201        """
202        context = aq_inner(self.context)
203        return getToolByName(context, 'portal_properties')
204
205    @property
206    def portal_types( self ):
207        """
208        """
209        context = aq_inner(self.context)
210        return getToolByName(context, 'portal_types')
211
212    def hasSEOAction( self, type_info ):
213        """
214        """
215        return filter(lambda x:x.id == 'seo_properties', type_info.listActions())
216
217    def test( self, condition, first, second ):
218        """
219        """
220        return condition and first or second
221
222    def getExposeDCMetaTags( self ):
223        """
224        """
225        sp = self.portal_properties.site_properties
226        return sp.getProperty('exposeDCMetaTags')
227
228    def getDefaultCustomMetatags( self ):
229        """
230        """
231        seo = self.portal_properties.seo_properties
232        return seo.getProperty('default_custom_metatags')
233
234    def getMetaTagsOrder( self ):
235        """
236        """
237        seo = self.portal_properties.seo_properties
238        return seo.getProperty('metatags_order')
239
240    def getAdditionalKeywords( self ):
241        """
242        """
243        seo = self.portal_properties.seo_properties
244        return seo.getProperty('additional_keywords')
245
246    def createMultiColumnList( self ):
247        """
248        """
249        context = aq_inner(self.context)
250        allTypes = self.portal_types.listContentTypes()
251        try:
252            return context.createMultiColumnList(allTypes, sort_on='title_or_id')
253        except AttributeError:
254            return [slist]
255
256    def __call__( self ):
257        """
258        """
259        context = aq_inner(self.context)
260        request = self.request
261
262        portalTypes=request.get( 'portalTypes', [] )
263        exposeDCMetaTags=request.get( 'exposeDCMetaTags', None )
264        additionalKeywords=request.get('additionalKeywords', [])
265        default_custom_metatags=request.get('default_custom_metatags', [])
266        metatags_order=request.get('metatags_order', [])
267
268        site_props = getToolByName(self.portal_properties, 'site_properties')
269        seo_props = getToolByName(self.portal_properties, 'seo_properties')
270
271        form = self.request.form
272        submitted = form.get('form.submitted', False)
273
274        if submitted:
275            site_props.manage_changeProperties(exposeDCMetaTags=exposeDCMetaTags)
276            seo_props.manage_changeProperties(additional_keywords=additionalKeywords)
277            seo_props.manage_changeProperties(default_custom_metatags=default_custom_metatags)
278            seo_props.manage_changeProperties(metatags_order=metatags_order)
279
280            for ptype in self.portal_types.objectValues():
281                acts = filter(lambda x: x.id == 'seo_properties', ptype.listActions())
282                action = acts and acts[0] or None
283                if ptype.getId() in portalTypes:
284                    if action is None:
285                        ptype.addAction('seo_properties',
286                                        'SEO Properties',
287                                        'string:${object_url}/@@seo-context-properties',
288                                        '',
289                                        'Modify portal content',
290                                        'object',
291                                        visible=1)
292                else:
293                    if action !=None:
294                        actions = list(ptype.listActions())
295                        ptype.deleteActions([actions.index(a) for a in actions if a.getId()=='seo_properties'])
296            context.plone_utils.addPortalMessage(pmf(u'Changes saved.'))
297            return request.response.redirect('%s/%s'%(self.context.absolute_url(), 'plone_control_panel'))
298        else:
299            return self.template(portalTypes=portalTypes, exposeDCMetaTags=exposeDCMetaTags)
300
301    def typeInfo( self, type_name ):
302        """
303        """
304        return self.portal_types.getTypeInfo( type_name )
305
306
307class SEOContextPropertiesView( BrowserView ):
308    """
309    """
310    template = ViewPageTemplateFile('templates/seo_context_properties.pt')
311
312    def test( self, condition, first, second ):
313        """
314        """
315        return condition and first or second
316
317    def getMainDomain(self, url):
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        purl = getToolByName(self.context, 'portal_url')()
325        state = ''
326        if property == PROP_PREFIX+'canonical':
327            pdomain = self.getMainDomain(purl)
328            if not pdomain == self.getMainDomain(value):
329                state = _('canonical_msg', default=u'Canonical URL mast be in ${pdomain} domain.', mapping={'pdomain': pdomain})
330        return state
331
332    def setProperty(self, property, value, type='string'):
333        context = aq_inner(self.context)
334        state = self.validateSEOProperty(property, value)
335        if not state:
336            if context.hasProperty(property):
337                context.manage_changeProperties({property: value})
338            else:
339                context.manage_addProperty(property, value, type)
340        return state
341
342    def manageSEOProps(self, **kw):
343        context = aq_inner(self.context)
344        state = ''
345        delete_list, seo_overrides_keys, seo_keys = [], [], []
346        seo_items = dict([(k[len(SEO_PREFIX):],v) for k,v in kw.items() if k.startswith(SEO_PREFIX)])
347        for key in seo_items.keys():
348            if key.endswith(SUFFIX):
349                seo_overrides_keys.append(key[:-len(SUFFIX)])
350            else:
351                seo_keys.append(key)
352        for seo_key in seo_keys:
353            if seo_key == 'custommetatags':
354                self.manageSEOCustomMetaTagsProperties(**kw)
355            else:
356                if seo_key in seo_overrides_keys and seo_items.get(seo_key+SUFFIX):
357                    seo_value = seo_items[seo_key]
358                    t_value = 'string'
359                    if type(seo_value)==type([]) or type(seo_value)==type(()): t_value = 'lines'
360                    state = self.setProperty(PROP_PREFIX+seo_key, seo_value, type=t_value)
361                    if state:
362                        return state
363                elif context.hasProperty(PROP_PREFIX+seo_key):
364                    delete_list.append(PROP_PREFIX+seo_key)
365        if delete_list:
366            context.manage_delProperties(delete_list)
367        return state
368
369    def setSEOCustomMetaTags(self, custommetatags):
370        context = aq_inner(self.context)
371        for tag in custommetatags:
372            self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, tag['meta_name']), tag['meta_content'])
373
374    def delAllSEOCustomMetaTagsProperties(self):
375        context = aq_inner(self.context)
376        delete_list = []
377        for property, value in context.propertyItems():
378            if property.startswith(PROP_CUSTOM_PREFIX)  and not property == PROP_CUSTOM_PREFIX:
379                delete_list.append(property)
380        if delete_list:
381            context.manage_delProperties(delete_list)
382
383    def updateSEOCustomMetaTagsProperties(self, custommetatags):
384        context = aq_inner(self.context)
385        site_properties = getToolByName(context, 'portal_properties')
386        globalCustomMetaTags = []
387        if hasattr(site_properties, 'seo_properties'):
388            custom_meta_tags = getattr(site_properties.seo_properties, 'default_custom_metatags', [])
389            for tag in custom_meta_tags:
390                name_value = tag.split(SEPERATOR)
391                if name_value[0]:
392                    globalCustomMetaTags.append({'meta_name'    : name_value[0],
393                                                 'meta_content' : len(name_value) == 1 and '' or name_value[1]})
394        for tag in custommetatags:
395            meta_name, meta_content = tag['meta_name'], tag['meta_content']
396            if meta_name:
397                if not [gmt for gmt in globalCustomMetaTags if (gmt['meta_name']==meta_name and gmt['meta_content']==meta_content)]:
398                    self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, meta_name), meta_content)
399
400    def manageSEOCustomMetaTagsProperties(self, **kw):
401        context = aq_inner(self.context)
402        self.delAllSEOCustomMetaTagsProperties()
403        if kw.get('seo_custommetatags_override'):
404            custommetatags = kw.get('seo_custommetatags', {})
405            self.updateSEOCustomMetaTagsProperties(custommetatags)
406
407    def __call__( self ):
408        """
409        """
410        context = aq_inner(self.context)
411        request = self.request
412        form = self.request.form
413        submitted = form.get('form.submitted', False)
414        if submitted:
415            state = self.manageSEOProps(**form)
416            if not state:
417                state = _('seoproperties_saved', default=u'Content SEO properties have been saved.')
418                context.plone_utils.addPortalMessage(state)
419                kwargs = {'modification_date' : DateTime()} 
420                context.plone_utils.contentEdit(context, **kwargs) 
421                return request.response.redirect(self.context.absolute_url())
422            context.plone_utils.addPortalMessage(state, 'error')
423        return self.template()
Note: See TracBrowser for help on using the repository browser.