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

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

added escaping meta tag content values

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1from cgi import escape
2from DateTime import DateTime
3from Acquisition import aq_inner
4
5from zope.component import queryAdapter
6from zope.component import queryMultiAdapter
7from zope.component import getMultiAdapter
8from plone.app.layout.viewlets.common import ViewletBase
9
10from Products.CMFPlone.utils import safe_unicode, getSiteEncoding
11
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
17from Products.CMFPlone.PloneTool import FLOOR_DATE, CEILING_DATE
18
19
20class SEOTagsViewlet(ViewletBase):
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)
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()])
30
31    def listMetaTags(self):
32        """Calculate list metatags"""
33
34        result = SortedDict()
35        pps = queryMultiAdapter((self.context, self.request),
36                                name="plone_portal_state")
37        seo_global = queryAdapter(pps.portal(), ISEOConfigletSchema)
38        seo_context = queryMultiAdapter((self.context, self.request),
39                                        name='seo_context')
40
41        use_all = seo_global.exposeDCMetaTags
42        adapter = IMappingMetaTags(self.context, None)
43        mapping_metadata = adapter and adapter.getMappingMetaTags() \
44                           or SortedDict()
45
46        if not use_all:
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:
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
65            if accessor in seo_context._seotags:
66                value = seo_context._seotags.get(accessor, None)
67            else:
68                method = getattr(seo_context, accessor, None)
69                if method is None:
70                    method = getattr(aq_inner(self.context).aq_explicit,
71                                     accessor, None)
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
93            if accessor == 'Description' and \
94               not 'description' in metadata_names:
95                result['description'] = escape(value)
96            elif accessor == 'Subject' and \
97                 not 'keywords' in metadata_names:
98                result['keywords'] = escape(value)
99
100            if accessor not in ('Description', 'Subject'):
101                result[key] = escape(value)
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
142        custom_meta_tags = seo_context and \
143                           seo_context['seo_customMetaTags'] or []
144        for tag in custom_meta_tags:
145            if tag['meta_content']:
146                result[tag['meta_name']] = escape(tag['meta_content'])
147
148        return result
149
150
151class TitleCommentViewlet(ViewletBase):
152    """ Simple viewlet for custom title rendering.
153    """
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')
160        self.seo_context = getMultiAdapter((self.context, self.request),
161                                             name=u'seo_context')
162
163        self.override_title = self.seo_context['has_seo_title']
164        self.has_comments = self.seo_context['has_html_comment']
165
166    def std_title(self):
167        page_title = safe_unicode(self.context_state.object_title())
168        portal_title = safe_unicode(self.portal_state.portal_title())
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
176    def render(self):
177        if self.override_title:
178            qseo_title = u"<title>%s</title>" % escape(safe_unicode(
179                self.seo_context["seo_title"]))
180        else:
181            qseo_title = self.std_title()
182
183        comments = ""
184        if self.has_comments:
185            comments = u"\n<!--%s-->" % escape(safe_unicode(
186                self.seo_context["seo_html_comment"]))
187
188        return qseo_title + comments
189
190
191class CustomScriptViewlet(ViewletBase):
192    """ Simple viewlet for custom script rendering.
193    """
194    def getCustomScript(self):
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 ''
201
202    def render(self):
203        return safe_unicode("""%s""" % self.getCustomScript())
204
205
206class CanonicalUrlViewlet(ViewletBase):
207    """ Simple viewlet for canonical url link rendering.
208    """
209    def render(self):
210        seoc = getMultiAdapter((self.context, self.request),
211                               name=u'seo_context')
212        if seoc['seo_canonical']:
213            return """<link rel="canonical" href="%s" />""" \
214                   % seoc['seo_canonical']
215        return ""
Note: See TracBrowser for help on using the repository browser.