source: products/quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/viewlets.py @ 3330

Last change on this file since 3330 was 3330, checked in by vmaksymiv, 13 years ago

added escaping meta tag content values

  • Property svn:eol-style set to native
File size: 7.8 KB
RevLine 
[1052]1from cgi import escape
[2139]2from DateTime import DateTime
3from Acquisition import aq_inner
4
5from zope.component import queryAdapter
6from zope.component import queryMultiAdapter
[387]7from zope.component import getMultiAdapter
8from plone.app.layout.viewlets.common import ViewletBase
9
[2139]10from Products.CMFPlone.utils import safe_unicode, getSiteEncoding
[1313]11
[2139]12from quintagroup.seoptimizer.util import SortedDict
13from quintagroup.seoptimizer.interfaces import IMetaKeywords
14from quintagroup.seoptimizer.interfaces import IMappingMetaTags
15from quintagroup.seoptimizer.browser.seo_configlet import ISEOConfigletSchema
16
[3141]17from Products.CMFPlone.PloneTool import FLOOR_DATE, CEILING_DATE
[2139]18
[3134]19
20class SEOTagsViewlet(ViewletBase):
[2139]21    """ Simple viewlet for custom title rendering.
22    """
23
24    def render(self):
25        TEMPLATE = '<meta name="%s" content="%s"/>'
26        enc = getSiteEncoding(self.context)
[3134]27        sfuncd = lambda x, enc=enc: safe_unicode(x, enc)
28        return u'\n'.join([TEMPLATE % tuple(map(sfuncd, (k, v))) \
29                           for k, v in self.listMetaTags().items()])
[2139]30
31    def listMetaTags(self):
32        """Calculate list metatags"""
33
34        result = SortedDict()
[3134]35        pps = queryMultiAdapter((self.context, self.request),
36                                name="plone_portal_state")
[2139]37        seo_global = queryAdapter(pps.portal(), ISEOConfigletSchema)
[3134]38        seo_context = queryMultiAdapter((self.context, self.request),
39                                        name='seo_context')
[2139]40
41        use_all = seo_global.exposeDCMetaTags
42        adapter = IMappingMetaTags(self.context, None)
[3134]43        mapping_metadata = adapter and adapter.getMappingMetaTags() \
44                           or SortedDict()
[2139]45
46        if not use_all:
[3134]47            metadata_names = 'DC.description' in mapping_metadata and \
48                {'DC.description': mapping_metadata['DC.description']} \
49                or SortedDict()
50            if 'description' in mapping_metadata:
[2139]51                metadata_names['description'] = mapping_metadata['description']
52        else:
53            metadata_names = mapping_metadata
54
55        for key, accessor in metadata_names.items():
56            if accessor == 'meta_keywords':
57                # Render all the existing keywords for the current content type
58                adapter = IMetaKeywords(self.context, None)
59                if adapter is not None:
60                    keywords = adapter.getMetaKeywords()
61                    if keywords:
62                        result['keywords'] = keywords
63                continue
64
[3134]65            if accessor in seo_context._seotags:
[2139]66                value = seo_context._seotags.get(accessor, None)
67            else:
68                method = getattr(seo_context, accessor, None)
69                if method is None:
[3134]70                    method = getattr(aq_inner(self.context).aq_explicit,
71                                     accessor, None)
[2139]72
73                if not callable(method):
74                    continue
75
76                # Catch AttributeErrors raised by some AT applications
77                try:
78                    value = method()
79                except AttributeError:
80                    value = None
81
82            if not value:
83                # No data
84                continue
85            if accessor == 'Publisher' and value == 'No publisher':
86                # No publisher is hardcoded (TODO: still?)
87                continue
88            if isinstance(value, (list, tuple)):
89                # convert a list to a string
90                value = ', '.join(value)
91
92            # Special cases
[3134]93            if accessor == 'Description' and \
94               not 'description' in metadata_names:
[3330]95                result['description'] = escape(value)
[3134]96            elif accessor == 'Subject' and \
97                 not 'keywords' in metadata_names:
[3330]98                result['keywords'] = escape(value)
[2139]99
100            if accessor not in ('Description', 'Subject'):
[3330]101                result[key] = escape(value)
[2139]102
103        if use_all:
104            created = self.context.CreationDate()
105
106            try:
107                effective = self.context.EffectiveDate()
108                if effective == 'None':
109                    effective = None
110                if effective:
111                    effective = DateTime(effective)
112            except AttributeError:
113                effective = None
114
115            try:
116                expires = self.context.ExpirationDate()
117                if expires == 'None':
118                    expires = None
119                if expires:
120                    expires = DateTime(expires)
121            except AttributeError:
122                expires = None
123
124            # Filter out DWIMish artifacts on effective / expiration dates
125            if effective is not None and \
126               effective > FLOOR_DATE and \
127               effective != created:
128                eff_str = effective.Date()
129            else:
130                eff_str = ''
131
132            if expires is not None and expires < CEILING_DATE:
133                exp_str = expires.Date()
134            else:
135                exp_str = ''
136
137            if exp_str or exp_str:
138                result['DC.date.valid_range'] = '%s - %s' % (eff_str, exp_str)
139
140        # add custom meta tags (added from qseo tab by user)
141        # for given context and default from configlet
[3134]142        custom_meta_tags = seo_context and \
143                           seo_context['seo_customMetaTags'] or []
[2139]144        for tag in custom_meta_tags:
145            if tag['meta_content']:
[3330]146                result[tag['meta_name']] = escape(tag['meta_content'])
[2139]147
148        return result
149
150
[387]151class TitleCommentViewlet(ViewletBase):
[1509]152    """ Simple viewlet for custom title rendering.
153    """
[387]154
155    def update(self):
156        self.portal_state = getMultiAdapter((self.context, self.request),
157                                            name=u'plone_portal_state')
158        self.context_state = getMultiAdapter((self.context, self.request),
159                                             name=u'plone_context_state')
[2139]160        self.seo_context = getMultiAdapter((self.context, self.request),
161                                             name=u'seo_context')
[387]162
[2139]163        self.override_title = self.seo_context['has_seo_title']
[3135]164        self.has_comments = self.seo_context['has_html_comment']
[387]165
[1052]166    def std_title(self):
[2205]167        page_title = safe_unicode(self.context_state.object_title())
168        portal_title = safe_unicode(self.portal_state.portal_title())
[1052]169        if page_title == portal_title:
170            return u"<title>%s</title>" % (escape(portal_title))
171        else:
172            return u"<title>%s &mdash; %s</title>" % (
173                escape(safe_unicode(page_title)),
174                escape(safe_unicode(portal_title)))
175
[387]176    def render(self):
[3135]177        if self.override_title:
178            qseo_title = u"<title>%s</title>" % escape(safe_unicode(
179                self.seo_context["seo_title"]))
[387]180        else:
[3135]181            qseo_title = self.std_title()
[387]182
[3135]183        comments = ""
184        if self.has_comments:
185            comments = u"\n<!--%s-->" % escape(safe_unicode(
186                self.seo_context["seo_html_comment"]))
[387]187
[3140]188        return qseo_title + comments
[3135]189
190
[3134]191class CustomScriptViewlet(ViewletBase):
[1509]192    """ Simple viewlet for custom script rendering.
193    """
[3134]194    def getCustomScript(self):
[2139]195        pps = queryMultiAdapter((self.context, self.request),
196                                name="plone_portal_state")
197        gseo = queryAdapter(pps.portal(), ISEOConfigletSchema)
198        if gseo:
199            return gseo.custom_script
200        return ''
[869]201
[3134]202    def render(self):
203        return safe_unicode("""%s""" % self.getCustomScript())
[869]204
[896]205
[3134]206class CanonicalUrlViewlet(ViewletBase):
[1509]207    """ Simple viewlet for canonical url link rendering.
[896]208    """
[3134]209    def render(self):
210        seoc = getMultiAdapter((self.context, self.request),
211                               name=u'seo_context')
[2237]212        if seoc['seo_canonical']:
[3134]213            return """<link rel="canonical" href="%s" />""" \
214                   % seoc['seo_canonical']
[2237]215        return ""
Note: See TracBrowser for help on using the repository browser.