Changeset 3134 in products
- Timestamp:
- Apr 18, 2011 2:32:21 PM (13 years ago)
- Location:
- quintagroup.seoptimizer/trunk
- Files:
-
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/Extensions/Install.py
r2139 r3134 11 11 UNINSTALL = 'profile-%s:uninstall' % PROJECT_NAME 12 12 13 13 14 def install(portal, reinstall=False): 14 15 """ (Re)Install this product. 15 16 16 This external method is need, because portal_quickinstaller doens't know17 what GenericProfile profile to apply when reinstalling a product.17 This external method is need, because portal_quickinstaller doens't 18 know what GenericProfile profile to apply when reinstalling a product. 18 19 """ 19 20 setup_tool = getToolByName(portal, 'portal_setup') … … 21 22 step = None 22 23 profile_id = 'quintagroup.seoptimizer:default' 23 steps_to_run = [s['id'] for s in setup_tool.listUpgrades(profile_id, show_old=False)] 24 steps_to_run = [s['id'] for s in \ 25 setup_tool.listUpgrades(profile_id, show_old=False)] 24 26 for step_id in steps_to_run: 25 27 step = _upgrade_registry.getUpgradeStep(profile_id, step_id) 26 28 step.doStep(setup_tool) 27 msg = "Ran upgrade step %s for profile %s" % (step.title, profile_id) 29 msg = "Ran upgrade step %s for profile %s" \ 30 % (step.title, profile_id) 28 31 logger.log(logging.INFO, msg) 29 32 # We update the profile version to the last one we have reached 30 33 # with running an upgrade step. 31 34 if step and step.dest is not None and step.checker is None: 32 setup_tool.setLastVersionForProfile(profile_id, step.dest)35 setup_tool.setLastVersionForProfile(profile_id, step.dest) 33 36 return "Ran all reinstall steps." 34 37 else: … … 36 39 return "Ran all install steps." 37 40 41 38 42 def uninstall(portal, reinstall=False): 39 43 """ Uninstall this product. 40 44 41 This external method is need, because portal_quickinstaller doens't know42 what GenericProfile profile to apply when uninstalling a product.45 This external method is need, because portal_quickinstaller doens't 46 know what GenericProfile profile to apply when uninstalling a product. 43 47 """ 44 48 setup_tool = getToolByName(portal, 'portal_setup') -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/adapters.py
r2139 r3134 26 26 ("robots", "seo_robots"), 27 27 ("distribution", "seo_distribution")]) 28 28 29 29 30 class MetaKeywordsAdapter(object): … … 59 60 if self.gseo: 60 61 for mt in self.gseo.metatags_order: 61 if METADATA_MAPS.has_key(mt):62 if mt in METADATA_MAPS: 62 63 metadata_name[mt] = METADATA_MAPS[mt] 63 64 return metadata_name -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/interfaces.py
r2139 r3134 1 1 from zope.interface import Interface 2 2 from plone.theme.interfaces import IDefaultPloneLayer 3 3 4 4 5 class IPloneSEOLayer(IDefaultPloneLayer): … … 6 7 Selection in portal_skins. 7 8 """ 9 8 10 9 11 class IValidateSEOKeywordsView(Interface): -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/keywords.py
r2933 r3134 1 import re, sys, urllib2 1 import re 2 import sys 3 import urllib2 2 4 from xml.dom import Node 3 5 … … 17 19 from quintagroup.seoptimizer.browser.seo_configlet import ISEOConfigletSchema 18 20 21 19 22 class ValidateSEOKeywordsView(BrowserView): 20 23 … … 27 30 transforms = getUtility(IPortalTransformsTool) 28 31 portal = getToolByName(self.context, 'portal_url').getPortalObject() 29 isExternal = queryAdapter(portal, ISEOConfigletSchema).external_keywords_test 32 query_adapter = queryAdapter(portal, ISEOConfigletSchema) 33 isExternal = query_adapter.external_keywords_test 30 34 # extract keywords from text 31 35 enc = getSiteEncoding(self.context) … … 42 46 # Not pass timeout option because: 43 47 # 1. its value get from the global default timeout settings. 44 # 2. timeout option added in python 2.6 (so acceptable only in plone4+) 48 # 2. timeout option added in python 2.6 49 # (so acceptable only in plone4+) 45 50 try: 46 51 resp = urllib2.urlopen(self.context.absolute_url()) … … 50 55 resp.close() 51 56 except (urllib2.URLError, urllib2.HTTPError), e: 52 # In case of exceed timeout period or other URL connection errors. 53 # Get nearest to context error_log object (stolen from Zope2/App/startup.py) 57 # In case of exceed timeout period or 58 # other URL connection errors. 59 # Get nearest to context error_log object 60 # (stolen from Zope2/App/startup.py) 54 61 html = None 55 62 info = sys.exc_info() … … 59 66 html = unicode(self.context()).encode(enc) 60 67 61 # If no html - information about problem with page retrieval should be returned 68 # If no html - information about problem with page retrieval 69 # should be returned 62 70 result = [] 63 71 if html is None: … … 69 77 # check every keyword on appearing in body of html page 70 78 for keyword in keywords: 71 keyword_on_page = unicode(len(re.findall(u'\\b%s\\b' % keyword, page_text, re.I|re.U))) 79 keyword_on_page = unicode(len(re.findall(u'\\b%s\\b' % keyword, 80 page_text, re.I | re.U))) 72 81 result.append(' - '.join((keyword, keyword_on_page))) 73 82 74 83 return ts.utranslate(domain='quintagroup.seoptimizer', 75 84 msgid=_(u'number_keywords', 76 default=u'Number of keywords at page:\n${result}', 77 mapping={'result':'\n'.join(result)}), 85 default=u'Number of keywords at page:\n' 86 '${result}', 87 mapping={'result': '\n'.join(result)}), 78 88 context=self.context) -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/seo_configlet.py
r2889 r3134 27 27 exposeDCMetaTags = Bool( 28 28 title=_("label_exposeDCMetaTags", 29 default='Expose <abbr title="Dublin Core">DC</abbr> meta tags'), 29 default='Expose <abbr title="Dublin Core">DC</abbr> ' \ 30 'meta tags'), 30 31 description=_("description_seo_dc_metatags", 31 default='Controls if <abbr title="Dublin Core">DC</abbr>'32 'metatags are exposed to page header. They include '33 'DC.description, DC.type, DC.format, DC.creator and '34 'others.'),32 default='Controls if <abbr title="Dublin Core">DC</abbr>' 33 ' metatags are exposed to page header. They include ' 34 'DC.description, DC.type, DC.format, DC.creator and ' 35 'others.'), 35 36 default=True, 36 37 required=False) … … 40 41 default='Meta tags order in the page.'), 41 42 description=_("help_metatags_order", 42 default='Fill in meta tags (one per line) in the order in which'43 ' they will appear on site source pages. Example:'44 '"metaname accessor".'),43 default='Fill in meta tags (one per line) in the order ' 44 'in which they will appear on site source pages. ' 45 'Example: "metaname accessor".'), 45 46 required=False) 46 47 … … 56 57 57 58 default_custom_metatags = List( 58 title=_("label_default_custom_metatags", default='Default custom metatags.'), 59 title=_("label_default_custom_metatags", 60 default='Default custom metatags.'), 59 61 description=_("help_default_custom_metatags", 60 default='Fill in custom metatag names (one per line) which will ' 61 'appear on qseo_properties edit tab. Example: ' 62 '"metaname|metacontent" or "metaname".'), 63 required=False) 64 62 default='Fill in custom metatag names (one per line) ' \ 63 'which will appear on qseo_properties edit tab. ' \ 64 'Example: "metaname|metacontent" or "metaname".'), 65 required=False) 65 66 66 67 … … 75 76 76 77 fields = List( 77 title=_("label_fields", default='Fields for keywords statistic calculation.'), 78 description=_("help_fields", 79 default='Fill in filds (one per line) which statistics of keywords usage ' 80 'should be calculated for.'), 78 title=_("label_fields", default='Fields for keywords statistic ' 79 'calculation.'), 80 description=_("help_fields", default='Fill in filds (one per line)' 81 'which statistics of keywords usage should ' 82 'be calculated for.'), 81 83 required=False) 82 84 83 85 stop_words = List( 84 86 title=_("label_stop_words", default='Stop words.'), 85 description=_("help_stop_words", 86 default='Fill in stop words (one per line) which will'87 'be excluded from kewordsstatistics calculation.'),87 description=_("help_stop_words", default='Fill in stop words ' 88 '(one per line) which will be excluded from kewords ' 89 'statistics calculation.'), 88 90 required=False) 89 91 … … 120 122 self.encoding = pprop.site_properties.default_charset 121 123 122 123 124 def getExposeDC(self): 124 125 return self.siteprops.getProperty('exposeDCMetaTags') … … 146 147 147 148 exposeDCMetaTags = property(getExposeDC, setExposeDC) 148 default_custom_metatags = ProxyFieldProperty(ISEOConfigletSchema['default_custom_metatags']) 149 seo_default_custom_metatag = ISEOConfigletSchema['default_custom_metatags'] 150 default_custom_metatags = ProxyFieldProperty(seo_default_custom_metatag) 149 151 metatags_order = ProxyFieldProperty(ISEOConfigletSchema['metatags_order']) 150 152 types_seo_enabled = property(getTypesSEOEnabled, setTypesSEOEnabled) … … 152 154 fields = ProxyFieldProperty(ISEOConfigletSchema['fields']) 153 155 stop_words = ProxyFieldProperty(ISEOConfigletSchema['stop_words']) 154 external_keywords_test = ProxyFieldProperty(ISEOConfigletSchema['external_keywords_test']) 156 seo_external_keywords_test = ISEOConfigletSchema['external_keywords_test'] 157 external_keywords_test = ProxyFieldProperty(seo_external_keywords_test) 155 158 156 159 157 160 class Text2ListWidget(TextAreaWidget): 158 161 height = 5 159 splitter = re.compile(u'\\r?\\n', re.S |re.U)162 splitter = re.compile(u'\\r?\\n', re.S | re.U) 160 163 161 164 def _toFieldValue(self, input): … … 166 169 167 170 def _toFormValue(self, value): 168 if value == self.context.missing_value or value == self.context._type(): 171 if value == self.context.missing_value or \ 172 value == self.context._type(): 169 173 return self._missing 170 174 else: … … 181 185 advancedset.label = _(u'label_seoadvanced', default=u'Advanced') 182 186 187 183 188 class SEOConfiglet(ControlPanelForm): 184 189 185 190 form_fields = FormFieldsets(baseset, advancedset) 191 type_seo_enabled = MultiCheckBoxThreeColumnWidget 186 192 187 193 form_fields['default_custom_metatags'].custom_widget = Text2ListWidget 188 194 form_fields['metatags_order'].custom_widget = Text2ListWidget 189 form_fields['types_seo_enabled'].custom_widget = MultiCheckBoxThreeColumnWidget190 form_fields['types_seo_enabled'].custom_widget.cssClass ='label'195 form_fields['types_seo_enabled'].custom_widget = type_seo_enabled 196 form_fields['types_seo_enabled'].custom_widget.cssClass = 'label' 191 197 form_fields['fields'].custom_widget = Text2ListWidget 192 198 form_fields['stop_words'].custom_widget = Text2ListWidget … … 195 201 description = _("seo_configlet_description", default="You can select what " 196 202 "content types are qSEOptimizer-enabled, and control if " 197 "Dublin Core metatags are exposed in the header of content 198 " pages.")203 "Dublin Core metatags are exposed in the header of content" 204 " pages.") 199 205 form_name = _("") -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/viewlets.py
r2237 r3134 17 17 from Products.CMFPlone.PloneTool import * 18 18 19 class SEOTagsViewlet( ViewletBase ): 19 20 class SEOTagsViewlet(ViewletBase): 20 21 """ Simple viewlet for custom title rendering. 21 22 """ … … 24 25 TEMPLATE = '<meta name="%s" content="%s"/>' 25 26 enc = getSiteEncoding(self.context) 26 sfuncd = lambda x, enc=enc: safe_unicode(x, enc)27 return u'\n'.join([TEMPLATE % tuple(map(sfuncd, (k, v))) \28 for k, v in self.listMetaTags().items()])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()]) 29 30 30 31 def listMetaTags(self): … … 32 33 33 34 result = SortedDict() 34 pps = queryMultiAdapter((self.context, self.request), name="plone_portal_state") 35 pps = queryMultiAdapter((self.context, self.request), 36 name="plone_portal_state") 35 37 seo_global = queryAdapter(pps.portal(), ISEOConfigletSchema) 36 seo_context = queryMultiAdapter((self.context, self.request), name='seo_context') 38 seo_context = queryMultiAdapter((self.context, self.request), 39 name='seo_context') 37 40 38 41 use_all = seo_global.exposeDCMetaTags 39 42 adapter = IMappingMetaTags(self.context, None) 40 mapping_metadata = adapter and adapter.getMappingMetaTags() or SortedDict() 43 mapping_metadata = adapter and adapter.getMappingMetaTags() \ 44 or SortedDict() 41 45 42 46 if not use_all: 43 metadata_names = mapping_metadata.has_key('DC.description')\44 and{'DC.description': mapping_metadata['DC.description']} \45 46 if mapping_metadata.has_key('description'):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: 47 51 metadata_names['description'] = mapping_metadata['description'] 48 52 else: … … 59 63 continue 60 64 61 if seo_context._seotags.has_key(accessor):65 if accessor in seo_context._seotags: 62 66 value = seo_context._seotags.get(accessor, None) 63 67 else: 64 68 method = getattr(seo_context, accessor, None) 65 69 if method is None: 66 method = getattr(aq_inner(self.context).aq_explicit, accessor, None) 70 method = getattr(aq_inner(self.context).aq_explicit, 71 accessor, None) 67 72 68 73 if not callable(method): … … 86 91 87 92 # Special cases 88 if accessor == 'Description' and not metadata_names.has_key('description'): 93 if accessor == 'Description' and \ 94 not 'description' in metadata_names: 89 95 result['description'] = value 90 elif accessor == 'Subject' and not metadata_names.has_key('keywords'): 96 elif accessor == 'Subject' and \ 97 not 'keywords' in metadata_names: 91 98 result['keywords'] = value 92 99 … … 133 140 # add custom meta tags (added from qseo tab by user) 134 141 # for given context and default from configlet 135 custom_meta_tags = seo_context and seo_context['seo_customMetaTags'] or [] 142 custom_meta_tags = seo_context and \ 143 seo_context['seo_customMetaTags'] or [] 136 144 for tag in custom_meta_tags: 137 145 if tag['meta_content']: … … 139 147 140 148 return result 141 142 149 143 150 … … 175 182 qseo_comments = u"<!--%s-->" % safe_unicode( 176 183 self.seo_context["seo_html_comment"]) 177 return u"%s\n%s" %(std_title, qseo_comments)184 return u"%s\n%s" % (std_title, qseo_comments) 178 185 else: 179 186 qseo_title = u"<title>%s</title>" % safe_unicode( … … 184 191 qseo_comments = u"<!--%s-->" % safe_unicode( 185 192 self.seo_context["seo_html_comment"]) 186 return u"%s\n%s" %(qseo_title, qseo_comments)187 188 189 class CustomScriptViewlet( ViewletBase):193 return u"%s\n%s" % (qseo_title, qseo_comments) 194 195 196 class CustomScriptViewlet(ViewletBase): 190 197 """ Simple viewlet for custom script rendering. 191 198 """ 192 def getCustomScript( self):199 def getCustomScript(self): 193 200 pps = queryMultiAdapter((self.context, self.request), 194 201 name="plone_portal_state") … … 198 205 return '' 199 206 200 def render( self):201 return safe_unicode("""%s""" % self.getCustomScript())202 203 204 class CanonicalUrlViewlet( ViewletBase):207 def render(self): 208 return safe_unicode("""%s""" % self.getCustomScript()) 209 210 211 class CanonicalUrlViewlet(ViewletBase): 205 212 """ Simple viewlet for canonical url link rendering. 206 213 """ 207 def render( self ): 208 seoc = getMultiAdapter((self.context, self.request), name=u'seo_context') 214 def render(self): 215 seoc = getMultiAdapter((self.context, self.request), 216 name=u'seo_context') 209 217 if seoc['seo_canonical']: 210 return """<link rel="canonical" href="%s" />""" % seoc['seo_canonical'] 218 return """<link rel="canonical" href="%s" />""" \ 219 % seoc['seo_canonical'] 211 220 return "" -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/browser/views.py
r3007 r3134 13 13 14 14 from quintagroup.canonicalpath.interfaces import ICanonicalLink 15 from quintagroup.canonicalpath.adapters import PROPERTY_LINK as CANONICAL_PROPERTY 15 from quintagroup.canonicalpath.adapters import PROPERTY_LINK \ 16 as CANONICAL_PROPERTY 16 17 17 18 from quintagroup.seoptimizer.browser.seo_configlet import ISEOConfigletSchema … … 24 25 PROP_CUSTOM_PREFIX = 'qSEO_custom_' 25 26 27 26 28 # Ram cache function, which depends on plone instance and time 27 29 def plone_instance_time(method, self, *args, **kwargs): 28 30 return (self.pps.portal(), time() // (60 * 60)) 29 31 30 class SEOContext( BrowserView ): 32 33 class SEOContext(BrowserView): 31 34 """ This class contains methods that allows to edit html header meta tags. 32 35 """ … … 34 37 def __init__(self, *args, **kwargs): 35 38 super(SEOContext, self).__init__(*args, **kwargs) 36 self.pps = queryMultiAdapter((self.context, self.request), name="plone_portal_state") 37 self.pcs = queryMultiAdapter((self.context, self.request), name="plone_context_state") 39 self.pps = queryMultiAdapter((self.context, self.request), 40 name="plone_portal_state") 41 self.pcs = queryMultiAdapter((self.context, self.request), 42 name="plone_context_state") 38 43 self.gseo = queryAdapter(self.pps.portal(), ISEOConfigletSchema) 39 44 self._seotags = self._getSEOTags() … … 45 50 def _getSEOTags(self): 46 51 seotags = { 47 "seo_title": self.getSEOProperty( 'qSEO_title', default=self.pcs.object_title() ), 48 "seo_robots": self.getSEOProperty( 'qSEO_robots', default='ALL'), 49 "seo_description": self.getSEOProperty( 'qSEO_description', accessor='Description' ), 50 "seo_distribution": self.getSEOProperty( 'qSEO_distribution', default="Global"), 52 "seo_title": self.getSEOProperty('qSEO_title', 53 default=self.pcs.object_title()), 54 "seo_robots": self.getSEOProperty('qSEO_robots', default='ALL'), 55 "seo_description": self.getSEOProperty('qSEO_description', 56 accessor='Description'), 57 "seo_distribution": self.getSEOProperty('qSEO_distribution', 58 default="Global"), 51 59 "seo_customMetaTags": self.seo_customMetaTags(), 52 60 # "seo_localCustomMetaTags": self.seo_localCustomMetaTags(), 53 61 # "seo_globalCustomMetaTags": self.seo_globalCustomMetaTags(), 54 "seo_html_comment": self.getSEOProperty( 'qSEO_html_comment', default='' ), 55 "meta_keywords": self.getSEOProperty('qSEO_keywords', 'Subject', ()), 62 "seo_html_comment": self.getSEOProperty('qSEO_html_comment', 63 default=''), 64 "meta_keywords": self.getSEOProperty('qSEO_keywords', 65 'Subject', ()), 56 66 "seo_keywords": self.getSEOProperty('qSEO_keywords', default=()), 57 67 "seo_canonical": self.getCanonical(), … … 59 69 "has_seo_title": self.context.hasProperty('qSEO_title'), 60 70 "has_seo_robots": self.context.hasProperty('qSEO_robots'), 61 "has_seo_description": self.context.hasProperty( 'qSEO_description'), 62 "has_seo_distribution": self.context.hasProperty( 'qSEO_distribution'), 71 "has_seo_description": \ 72 self.context.hasProperty('qSEO_description'), 73 "has_seo_distribution": \ 74 self.context.hasProperty('qSEO_distribution'), 63 75 "has_html_comment": self.context.hasProperty('qSEO_html_comment'), 64 76 "has_seo_keywords": self.context.hasProperty('qSEO_keywords'), 65 77 "has_seo_canonical": self.context.hasProperty(CANONICAL_PROPERTY), 66 78 } 67 #seotags["seo_nonEmptylocalMetaTags"] = bool(seotags["seo_localCustomMetaTags"]) 79 #seotags["seo_nonEmptylocalMetaTags"] = \ 80 # bool(seotags["seo_localCustomMetaTags"]) 68 81 return seotags 69 82 70 def getSEOProperty( self, property_name, accessor='', default=None):83 def getSEOProperty(self, property_name, accessor='', default=None): 71 84 """ Get value from seo property by property name. 72 85 """ … … 90 103 return default 91 104 92 def seo_customMetaTags( self ): 93 """Returned seo custom metatags from default_custom_metatags property in seo_properties 94 (global seo custom metatags) with update from seo custom metatags properties 95 in context (local seo custom metatags). 96 """ 97 glob, loc = self.seo_globalCustomMetaTags(), self.seo_localCustomMetaTags() 105 def seo_customMetaTags(self): 106 """Returned seo custom metatags from default_custom_metatags property 107 in seo_properties (global seo custom metatags) with update from seo 108 custom metatags properties in context (local seo custom metatags). 109 """ 110 glob = self.seo_globalCustomMetaTags() 111 loc = self.seo_localCustomMetaTags() 98 112 gnames = set(map(lambda x: x['meta_name'], glob)) 99 113 lnames = set(map(lambda x: x['meta_name'], loc)) 100 # Get untouch global, override global in custom and new custom meta tags 101 untouchglob = [t for t in glob if t['meta_name'] in list(gnames - lnames)] 114 # Get untouch global, override global in custom 115 # and new custom meta tags 116 untouchglob = [t for t in glob \ 117 if t['meta_name'] in list(gnames - lnames)] 102 118 return untouchglob + loc 103 119 104 def seo_globalWithoutLocalCustomMetaTags( self ): 105 """Returned seo custom metatags from default_custom_metatags property in seo_properties 106 (global seo custom metatags) without seo custom metatags from properties 107 in context (local seo custom metatags). 108 """ 109 glob, loc = self.seo_globalCustomMetaTags(), self.seo_localCustomMetaTags() 120 def seo_globalWithoutLocalCustomMetaTags(self): 121 """Returned seo custom metatags from default_custom_metatags property 122 in seo_properties (global seo custom metatags) without seo custom 123 metatags from properties in context (local seo custom metatags). 124 """ 125 glob = self.seo_globalCustomMetaTags() 126 loc = self.seo_localCustomMetaTags() 110 127 gnames = set(map(lambda x: x['meta_name'], glob)) 111 128 lnames = set(map(lambda x: x['meta_name'], loc)) 112 129 return [t for t in glob if t['meta_name'] in list(gnames - lnames)] 113 130 114 def seo_localCustomMetaTags( self ): 115 """ Returned seo custom metatags from properties in context (local seo custom metatags). 131 def seo_localCustomMetaTags(self): 132 """ Returned seo custom metatags from properties in 133 context (local seo custom metatags). 116 134 """ 117 135 result = [] … … 119 137 context = aq_inner(self.context) 120 138 for property, value in context.propertyItems(): 121 if property.startswith(property_prefix) and property[len(property_prefix):]: 122 result.append({'meta_name' : property[len(property_prefix):], 123 'meta_content' : value}) 139 if property.startswith(property_prefix) and \ 140 property[len(property_prefix):]: 141 result.append({'meta_name': property[len(property_prefix):], 142 'meta_content': value}) 124 143 return result 125 144 126 145 @ram.cache(plone_instance_time) 127 def seo_globalCustomMetaTags( self ): 128 """ Returned seo custom metatags from default_custom_metatags property in seo_properties. 146 def seo_globalCustomMetaTags(self): 147 """ Returned seo custom metatags from default_custom_metatags property 148 in seo_properties. 129 149 """ 130 150 result = [] … … 133 153 name_value = tag.split(SEPERATOR) 134 154 if name_value[0]: 135 result.append({'meta_name' : name_value[0], 136 'meta_content' : len(name_value) == 2 and name_value[1] or ''}) 155 result.append({'meta_name': name_value[0], 156 'meta_content': len(name_value) == 2 and \ 157 name_value[1] or ''}) 137 158 return result 138 159 … … 142 163 143 164 144 class SEOContextPropertiesView( BrowserView):165 class SEOContextPropertiesView(BrowserView): 145 166 """ This class contains methods that allows to manage seo properties. 146 167 """ … … 153 174 self.gseo = queryAdapter(self.pps.portal(), ISEOConfigletSchema) 154 175 155 156 def test( self, condition, first, second ): 176 def test(self, condition, first, second): 157 177 """ 158 178 """ … … 167 187 """ Add a new property. 168 188 169 Sets a new property with the given id, value and type or changes it. 189 Sets a new property with the given id, value and type or 190 changes it. 170 191 """ 171 192 context = aq_inner(self.context) … … 184 205 state = '' 185 206 delete_list, seo_overrides_keys, seo_keys = [], [], [] 186 seo_items = dict([(k[len(SEO_PREFIX):],v) for k,v in kw.items() if k.startswith(SEO_PREFIX)]) 207 seo_items = dict([(k[len(SEO_PREFIX):], v) \ 208 for k, v in kw.items() if k.startswith(SEO_PREFIX)]) 187 209 for key in seo_items.keys(): 188 210 if key.endswith(SUFFIX): … … 194 216 self.manageSEOCustomMetaTagsProperties(**kw) 195 217 else: 196 if seo_key in seo_overrides_keys and seo_items.get(seo_key+SUFFIX): 218 if seo_key in seo_overrides_keys and \ 219 seo_items.get(seo_key + SUFFIX): 197 220 seo_value = seo_items[seo_key] 198 221 if seo_key == 'canonical': 199 222 try: 200 ICanonicalLink(self.context).canonical_link = seo_value 223 i_canonical_link = ICanonicalLink(self.context) 224 i_canonical_link.canonical_link = seo_value 201 225 except InvalidValue, e: 202 226 state = "'%s' - wrong canonical url" % str(e) 203 227 else: 204 228 t_value = 'string' 205 if type(seo_value)==type([]) or type(seo_value)==type(()): t_value = 'lines' 206 state = self.setProperty(PROP_PREFIX+seo_key, seo_value, type=t_value) 229 if type(seo_value) == type([]) or \ 230 type(seo_value) == type(()): 231 t_value = 'lines' 232 state = self.setProperty(PROP_PREFIX + seo_key, 233 seo_value, type=t_value) 207 234 if state: 208 235 return state 209 236 elif seo_key == 'canonical': 210 237 del ICanonicalLink(self.context).canonical_link 211 elif context.hasProperty(PROP_PREFIX +seo_key):212 delete_list.append(PROP_PREFIX +seo_key)238 elif context.hasProperty(PROP_PREFIX + seo_key): 239 delete_list.append(PROP_PREFIX + seo_key) 213 240 if delete_list: 214 241 context.manage_delProperties(delete_list) … … 220 247 context = aq_inner(self.context) 221 248 for tag in custommetatags: 222 self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, tag['meta_name']), tag['meta_content']) 249 self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, tag['meta_name']), 250 tag['meta_content']) 223 251 224 252 def delAllSEOCustomMetaTagsProperties(self): … … 228 256 delete_list = [] 229 257 for property, value in context.propertyItems(): 230 if property.startswith(PROP_CUSTOM_PREFIX) and not property == PROP_CUSTOM_PREFIX: 258 if property.startswith(PROP_CUSTOM_PREFIX) and \ 259 not property == PROP_CUSTOM_PREFIX: 231 260 delete_list.append(property) 232 261 if delete_list: … … 243 272 if name_value[0]: 244 273 globalCustomMetaTags.append( 245 {'meta_name' : name_value[0], 246 'meta_content' : len(name_value) > 1 and name_value[1] or ''}) 274 {'meta_name': name_value[0], 275 'meta_content': len(name_value) > 1 and \ 276 name_value[1] or ''}) 247 277 for tag in custommetatags: 248 278 meta_name, meta_content = tag['meta_name'], tag['meta_content'] 249 279 if meta_name: 250 280 if not [gmt for gmt in globalCustomMetaTags \ 251 if (gmt['meta_name']==meta_name and gmt['meta_content']==meta_content)]: 252 self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, meta_name), meta_content) 281 if (gmt['meta_name'] == meta_name and \ 282 gmt['meta_content'] == meta_content)]: 283 self.setProperty('%s%s' % (PROP_CUSTOM_PREFIX, meta_name), 284 meta_content) 253 285 254 286 def manageSEOCustomMetaTagsProperties(self, **kw): 255 """ Update seo custom metatags properties, if enabled checkbox override or delete properties. 287 """ Update seo custom metatags properties, if enabled checkbox override 288 or delete properties. 256 289 257 290 Change object properties by passing either a mapping object … … 271 304 # and may contains stop words in different languages. 272 305 # So we must return encoded strings. 273 sw = map(lambda x: unicode.encode(x, enc), self.gseo.stop_words)306 sw = map(lambda x: unicode.encode(x, enc), self.gseo.stop_words) 274 307 return str(sw) 275 308 … … 282 315 return str(fields_id) 283 316 284 def __call__( self):317 def __call__(self): 285 318 """ Perform the update seo properties and redirect if necessary, 286 319 or render the page Call method. … … 290 323 form = self.request.form 291 324 submitted = form.get('form.submitted', False) 292 #import pdb;pdb.set_trace()293 325 if submitted: 294 326 msgtype = "info" … … 299 331 msg = _('seoproperties_saved', 300 332 default=u'Content SEO properties have been saved.') 301 kwargs = {'modification_date' : DateTime()}333 kwargs = {'modification_date': DateTime()} 302 334 context.plone_utils.contentEdit(context, **kwargs) 303 335 else: … … 305 337 else: 306 338 # Cancel 307 msg = _('seoproperties_canceled', 308 default=u'No content SEOproperties have been changed.')339 msg = _('seoproperties_canceled', default=u'No content SEO ' \ 340 'properties have been changed.') 309 341 310 342 context.plone_utils.addPortalMessage(msg, msgtype) … … 315 347 316 348 317 class VisibilityCheckerView( BrowserView):349 class VisibilityCheckerView(BrowserView): 318 350 """ This class contains methods that visibility checker. 319 351 """ … … 323 355 """ 324 356 context = aq_inner(self.context) 325 plone = queryMultiAdapter((self, self.request),name="plone_portal_state").portal() 357 plone = queryMultiAdapter((self, self.request), 358 name="plone_portal_state").portal() 326 359 adapter = ISEOConfigletSchema(plone) 327 360 return bool(self.context.portal_type in adapter.types_seo_enabled) 328 -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/interfaces.py
r2139 r3134 1 1 from zope.interface import Interface 2 2 3 3 4 class IMetaKeywords(Interface): … … 8 9 """ 9 10 11 10 12 class IMappingMetaTags(Interface): 11 13 """ -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/listMetaTags.py
r2139 r3134 2 2 3 3 originalListMetaTags = PloneTool.listMetaTags 4 4 5 5 6 def qsListMetaTags(self, context): … … 11 12 return {} 12 13 14 13 15 def qsListMetaTagsOriginal(self, context): 14 16 """ Returned original method listMetaTags -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/setuphandlers.py
r2139 r3134 4 4 5 5 from config import SUPPORT_BLAYER 6 6 7 7 from Products.CMFCore.utils import getToolByName 8 8 9 9 logger = logging.getLogger('quintagroup.seoptimizer') 10 10 11 11 12 def removeActions(site): … … 18 19 if idxs: 19 20 ptype.deleteActions(idxs) 20 logger.log(logging.INFO, "Deleted \"SEO Properties\" action for %s type." % ptype.id) 21 msg_delete = "Deleted \"SEO Properties\" action for %s type." 22 logger.log(logging.INFO, msg_delete % ptype.id) 23 21 24 22 25 def removeConfiglet(site): … … 29 32 logger.log(logging.INFO, "Unregistered \"%s\" configlet." % conf_id) 30 33 34 31 35 def removeBrowserLayer(site): 32 36 """ Remove browser layer. … … 38 42 from plone.browserlayer.interfaces import ILocalBrowserLayerType 39 43 40 name ="qSEOptimizer"44 name = "qSEOptimizer" 41 45 site = getSiteManager(site) 42 46 registeredLayers = [r.name for r in site.registeredUtilities() … … 45 49 unregister_layer(name, site_manager=site) 46 50 logger.log(logging.INFO, "Unregistered \"%s\" browser layer." % name) 51 47 52 48 53 def uninstall(context): -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/base.py
r3011 r3134 38 38 ptc.setupPloneSite() 39 39 40 40 41 class NotInstalled(PloneSite): 41 42 """ Only package register, without installation into portal … … 71 72 def tearDown(cls): 72 73 ptc_setup._placefulTearDown() 73 74 74 75 75 76 class MixinTestCase: … … 81 82 authenticator = self.portal.restrictedTraverse("@@authenticator") 82 83 except: 83 handle 84 handle = "" 84 85 else: 85 86 html = authenticator.authenticator() … … 99 100 layer = Installed 100 101 102 101 103 class TestCaseNotInstalled(MixinTestCase, ptc.PloneTestCase): 102 104 layer = NotInstalled … … 109 111 self.installBrowserLayer() 110 112 113 111 114 class FunctionalTestCaseNotInstalled(MixinTestCase, ptc.FunctionalTestCase): 112 115 layer = NotInstalled -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testBugs.py
r3125 r3134 22 22 23 23 def afterSetUp(self): 24 self.basic_auth = ':'.join((portal_owner, default_password))24 self.basic_auth = ':'.join((portal_owner, default_password)) 25 25 self.loginAsPortalOwner() 26 26 # prepare test document … … 37 37 38 38 md_before = self.my_doc.modification_date 39 self.publish(path=self.mydoc_path +'/@@seo-context-properties',39 self.publish(path=self.mydoc_path + '/@@seo-context-properties', 40 40 basic=self.basic_auth, request_method='POST', 41 41 stdin=StringIO(urllib.urlencode(form_data))) … … 73 73 """ 74 74 curl = re.compile('<link\srel\s*=\s*"canonical"\s+' \ 75 '[^>]*href\s*=\s*\"([^\"]*)\"[^>]*>', re.S|re.M) 76 # When adapter registered for the object - canoncal link present on the page 77 self.assertNotEqual( queryAdapter(self.my_doc, ICanonicalLink), None) 75 '[^>]*href\s*=\s*\"([^\"]*)\"[^>]*>', re.S | re.M) 76 # When adapter registered for the object - canoncal link 77 # present on the page 78 self.assertNotEqual(queryAdapter(self.my_doc, ICanonicalLink), None) 78 79 79 80 res = self.publish(path=self.mydoc_path, basic=self.basic_auth) … … 84 85 # - canonical link will be absent on the page 85 86 gsm = getGlobalSiteManager() 86 gsm.unregisterAdapter(DefaultCanonicalLinkAdapter, [ITraversable, ],87 gsm.unregisterAdapter(DefaultCanonicalLinkAdapter, [ITraversable, ], 87 88 ICanonicalLink) 88 self.assertEqual( 89 self.assertEqual(queryAdapter(self.my_doc, ICanonicalLink), None) 89 90 90 91 res = self.publish(path=self.mydoc_path, basic=self.basic_auth) … … 92 93 93 94 # register adapter back in the global site manager 94 gsm.registerAdapter(DefaultCanonicalLinkAdapter, [ITraversable, ],95 gsm.registerAdapter(DefaultCanonicalLinkAdapter, [ITraversable, ], 95 96 ICanonicalLink) 96 97 … … 104 105 105 106 def test_escape_characters_title(self): 106 """Change escape characters in title of SEO properties 107 Bug url http://plone.org/products/plone-seo/issues/31 108 """ 107 """Change escape characters in title of SEO properties 108 Bug url http://plone.org/products/plone-seo/issues/31 109 """ 109 110 from cgi import escape 110 111 title = 'New <i>Title</i>' … … 113 114 'form.button.Save': "Save", 114 115 'form.submitted:int': 1} 115 116 res = self.publish(path=self.mydoc_path +'/@@seo-context-properties',116 117 res = self.publish(path=self.mydoc_path + '/@@seo-context-properties', 117 118 basic=self.basic_auth, request_method='POST', 118 119 stdin=StringIO(urllib.urlencode(form_data))) 119 120 html = self.publish(self.mydoc_path, self.basic_auth).getBody() 120 m = re.match('.*<title>\\s*%s\\s*</title>' % escape(title), html, re.S|re.M) 121 self.assert_(m, 'Title is not escaped properly.') 121 m = re.match('.*<title>\\s*%s\\s*</title>' % escape(title), html, 122 re.S | re.M) 123 self.assert_(m, 'Title is not escaped properly.') 122 124 123 125 def test_escape_characters_comment(self): 124 """Change escape characters in comment of SEO properties 125 """ 126 """Change escape characters in comment of SEO properties 127 """ 126 128 from cgi import escape 127 129 comment = 'New <i>comment</i>' … … 132 134 'form.button.Save': "Save", 133 135 'form.submitted:int': 1} 134 135 res = self.publish(path=self.mydoc_path +'/@@seo-context-properties',136 basic=self.basic_auth, request_method='POST',137 stdin=StringIO(urllib.urlencode(form_data)))136 137 res = self.publish(path=self.mydoc_path + '/@@seo-context-properties', 138 basic=self.basic_auth, request_method='POST', 139 stdin=StringIO(urllib.urlencode(form_data))) 138 140 html = self.publish(self.mydoc_path, self.basic_auth).getBody() 139 m = re.match('.*<!--\\s*%s\\s*-->' % escape(comment), html, re.S|re.M) 140 self.assert_(m, 'Comment is not escaped properly.') 141 m = re.match('.*<!--\\s*%s\\s*-->' % escape(comment), html, 142 re.S | re.M) 143 self.assert_(m, 'Comment is not escaped properly.') 141 144 142 145 def test_bug_custom_metatags_update(self): … … 145 148 request = self.portal.REQUEST 146 149 directlyProvides(request, IPloneSEOLayer) 147 seo_context_props = getMultiAdapter((page, request), name="seo-context-properties") 150 seo_context_props = getMultiAdapter((page, request), 151 name="seo-context-properties") 148 152 # Set default custom meta tag without default value (tag name only) 149 153 self.gseo = queryAdapter(self.portal, ISEOConfigletSchema) 150 self.gseo.default_custom_metatags = ["test_tag", ]154 self.gseo.default_custom_metatags = ["test_tag", ] 151 155 try: 152 # Breakage on updating custom metatag with seo-context-properties view 156 # Breakage on updating custom metatag 157 # with seo-context-properties view 153 158 seo_context_props.updateSEOCustomMetaTagsProperties([]) 154 159 except IndexError: 155 self.fail("Error in calculating of default tag value, when only tag name set "\ 156 "in default_custom_metatags property of the configlet.") 160 self.fail("Error in calculating of default tag value, when only "\ 161 "tag name set in default_custom_metatags property of "\ 162 "the configlet.") 157 163 158 164 … … 168 174 ['Member'], []) 169 175 uf.userFolderAddUser(editor_id, test_pswd, 170 ['Member', 'Editor'], [])171 172 self.member_auth = '%s:%s' %(member_id, test_pswd)173 self.editor_auth = '%s:%s' %(editor_id, test_pswd)176 ['Member', 'Editor'], []) 177 178 self.member_auth = '%s:%s' % (member_id, test_pswd) 179 self.editor_auth = '%s:%s' % (editor_id, test_pswd) 174 180 self.portal_url = '/'.join(self.portal.getPhysicalPath()) 175 181 … … 190 196 rexp = re.compile('<a\s+[^>]*' \ 191 197 'href="[a-zA-Z0-9\:\/_-]*/@@seo-context-properties"[^>]*>'\ 192 '\s*SEO Properties\s*</a>', re.I |re.S)198 '\s*SEO Properties\s*</a>', re.I | re.S) 193 199 # Anonymous: NO SEO Properties link 194 200 res = self.publish(path=self.portal_url).getBody() 195 201 self.assertEqual(rexp.search(res), None) 196 202 # Member: NO 'SEO Properties' link 197 res = self.publish(path=self.portal_url, basic=self.member_auth).getBody() 203 res = self.publish(path=self.portal_url, 204 basic=self.member_auth).getBody() 198 205 self.assertEqual(rexp.search(res), None) 199 206 # Editor: PRESENT 'SEO Properties' link 200 res = self.publish(path=self.portal_url, basic=self.editor_auth).getBody() 207 res = self.publish(path=self.portal_url, 208 basic=self.editor_auth).getBody() 201 209 self.assertNotEqual(rexp.search(res), None) 202 210 … … 206 214 # Anonymous: can NOT ACCESS 207 215 headers = self.publish(path=test_url).headers 208 self.assertEqual( headers.get('bobo-exception-type',""), 'Unauthorized', 209 "No 'Unauthorized' exception rised for Anonymous on '@@seo-context-properties' view") 216 self.assertEqual(headers.get('bobo-exception-type', ""), 217 'Unauthorized', "No 'Unauthorized' exception rised " \ 218 "for Anonymous on '@@seo-context-properties' view") 210 219 # Member: can NOT ACCESS 211 220 status = self.publish(path=test_url, basic=self.member_auth).headers 212 self.assertEqual( headers.get('bobo-exception-type',""), 'Unauthorized', 213 "No 'Unauthorized' exception rised for Member on '@@seo-context-properties' view") 221 self.assertEqual(headers.get('bobo-exception-type', ""), 222 'Unauthorized', "No 'Unauthorized' exception rised " \ 223 "for Member on '@@seo-context-properties' view") 214 224 # Editor: CAN Access 215 225 res = self.publish(path=test_url, basic=self.editor_auth) 216 226 self.assertEqual(res.status, 200) 217 218 227 219 228 def test_tab_edit(self): … … 224 233 'form.submitted:int': 1} 225 234 res = self.publish(path=test_url, basic=self.editor_auth, 226 request_method='POST', stdin=StringIO(urllib.urlencode(form_data))) 235 request_method='POST', 236 stdin=StringIO(urllib.urlencode(form_data))) 227 237 self.assertNotEqual(res.status, 200) 228 238 … … 234 244 suite.addTest(makeSuite(TestBug24AtPloneOrg)) 235 245 return suite 236 -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testCanonicalURL.py
r3012 r3134 1 1 from quintagroup.canonicalpath.interfaces import ICanonicalLink 2 2 from base import * 3 3 4 4 5 class TestCanonicalURL(FunctionalTestCase): 5 6 6 7 def afterSetUp(self): 7 self.basic_auth = ':'.join((portal_owner, default_password))8 self.basic_auth = ':'.join((portal_owner, default_password)) 8 9 self.loginAsPortalOwner() 9 10 # Preparation for functional testing … … 12 13 self.mydoc_path = "/%s" % self.mydoc.absolute_url(1) 13 14 self.curl = re.compile('<link\srel\s*=\s*"canonical"\s+' \ 14 '[^>]*href\s*=\s*\"([^\"]*)\"[^>]*>', re.S|re.M) 15 '[^>]*href\s*=\s*\"([^\"]*)\"[^>]*>', 16 re.S | re.M) 15 17 16 18 def test_CanonicalURL(self): … … 19 21 mydoc_url = self.mydoc.absolute_url() 20 22 21 self.assertTrue([1 for curl in foundcurls if curl ==mydoc_url],23 self.assertTrue([1 for curl in foundcurls if curl == mydoc_url], 22 24 "Wrong CANONICAL URL for document: %s, all must be: %s" % ( 23 25 foundcurls, mydoc_url)) … … 27 29 # Update canonical url property 28 30 self.publish(self.mydoc_path + '/@@seo-context-properties?' \ 29 'seo_canonical_override=checked&seo_canonical=%s&' \ 30 'form.submitted=1&form.button.Save=Save' % mydoc_url_new, self.basic_auth) 31 'seo_canonical_override=checked&seo_canonical=%s&' \ 32 'form.submitted=1&form.button.Save=Save' % mydoc_url_new, 33 self.basic_auth) 31 34 # Test updated canonical url 32 35 html = self.publish(self.mydoc_path, self.basic_auth).getBody() … … 35 38 qseo_url = ICanonicalLink(self.mydoc).canonical_link 36 39 self.assertTrue(qseo_url == mydoc_url_new, 37 "Not set 'qSEO_canonical' property")38 self.assertTrue([1 for curl in foundcurls if curl ==mydoc_url_new],39 "Wrong CANONICAL URL for document: %s, all must be: %s" % (40 foundcurls, mydoc_url_new))40 "Not set 'qSEO_canonical' property") 41 self.assertTrue([1 for curl in foundcurls if curl == mydoc_url_new], 42 "Wrong CANONICAL URL for document: %s, all must be: %s" 43 % (foundcurls, mydoc_url_new)) 41 44 42 45 def test_defaultCanonical(self): … … 66 69 mydoc_catalog_canonical = catalog(id="mydoc")[0].canonical_link 67 70 self.assertTrue(newcpath == mydoc_catalog_canonical, 68 "canonical path get by adapter: '%s' not equals to cataloged one: '%s'" % ( 69 newcpath, mydoc_catalog_canonical)) 71 "canonical path get by adapter: '%s' not equals to "\ 72 "cataloged one: '%s'" % (newcpath, 73 mydoc_catalog_canonical)) 70 74 71 75 def test_canonicalValidation(self): … … 73 77 # Update canonical url property 74 78 html = self.publish(self.mydoc_path + '/@@seo-context-properties?' \ 75 'seo_canonical_override=checked&seo_canonical=%s&' \ 76 'form.submitted=1&form.button.Save=Save' % wrong_canonical, self.basic_auth).getBody() 79 'seo_canonical_override=checked&seo_canonical=%s&'\ 80 'form.submitted=1&form.button.Save=Save' 81 % wrong_canonical, self.basic_auth).getBody() 77 82 self.assertTrue("wrong canonical url" in html, 78 83 "Canonical url not validated") … … 86 91 # remove canonical url customization 87 92 self.publish(self.mydoc_path + '/@@seo-context-properties?' \ 88 'seo_canonical=%s&seo_canonical_override=&form.submitted=1&form.button.Save=Save' % newcanonical, 89 self.basic_auth) 93 'seo_canonical=%s&seo_canonical_override=&'\ 94 'form.submitted=1&form.button.Save=Save' % newcanonical, 95 self.basic_auth) 90 96 91 97 mydoc_canonical = ICanonicalLink(self.mydoc).canonical_link -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testConfiglet.py
r2888 r3134 5 5 from quintagroup.seoptimizer.browser.seo_configlet import ISEOConfigletSchema 6 6 7 7 8 class TestConfiglet(FunctionalTestCase): 8 9 … … 10 11 self.sp = self.portal.portal_properties.site_properties 11 12 self.seo = self.portal.portal_properties.seo_properties 12 self.basic_auth = ':'.join((portal_owner, default_password))13 self.basic_auth = ':'.join((portal_owner, default_password)) 13 14 self.loginAsPortalOwner() 14 self.save_url = self.portal.id+'/@@seo-controlpanel?form.actions.save=1' \ 15 '&_authenticator=%s' % self._getauth() 15 self.save_url = self.portal.id + '/@@seo-controlpanel?' \ 16 'form.actions.save=1&_authenticator=%s' \ 17 % self._getauth() 16 18 17 19 def test_exposeDCMetaTags_On(self): … … 28 30 expect = ('test', 'custom', 'metatags') 29 31 formdata = "\n".join(expect) 30 self.publish(self.save_url + '&form.default_custom_metatags=%s' %formdata,31 self.basic_auth)32 self.publish(self.save_url + '&form.default_custom_metatags=%s' 33 % formdata, self.basic_auth) 32 34 33 35 dcm = self.seo.getProperty("default_custom_metatags", ()) 34 36 self.assertTrue(dcm == expect, '"default_custom_metatags" property ' \ 35 'contains: "%s", must: "%s"' % (dcm, expect))37 'contains: "%s", must: "%s"' % (dcm, expect)) 36 38 37 39 def test_defaultCustomMetatags_Off(self): … … 39 41 self.seo._updateProperty("default_custom_metatags", data) 40 42 self.publish(self.save_url + '&form.default_custom_metatags=', 41 self.basic_auth)43 self.basic_auth) 42 44 43 45 dcm = self.seo.getProperty("default_custom_metatags", ()) 44 46 self.assertTrue(dcm == (), '"default_custom_metatags" property ' \ 45 'contains: "%s", must be empty"' % str(dcm))47 'contains: "%s", must be empty"' % str(dcm)) 46 48 47 49 def test_metatagsOrder_On(self): 48 50 expect = ('test', 'metatags', 'order') 49 51 formdata = "\n".join(expect) 50 self.publish(self.save_url + '&form.metatags_order=%s' %formdata,51 self.basic_auth)52 self.publish(self.save_url + '&form.metatags_order=%s' % formdata, 53 self.basic_auth) 52 54 53 55 mo = self.seo.getProperty("metatags_order", ()) 54 56 self.assertTrue(mo == expect, '"metatags_order" property ' \ 55 'contains: "%s", must: "%s"' % (mo, expect))57 'contains: "%s", must: "%s"' % (mo, expect)) 56 58 57 59 def test_metatagsOrder_Off(self): … … 59 61 self.seo._updateProperty("metatags_order", data) 60 62 self.publish(self.save_url + '&form.metatags_order=', 61 self.basic_auth)63 self.basic_auth) 62 64 63 65 mo = self.seo.getProperty("metatags_order", ()) 64 66 self.assertTrue(mo == (), '"metatags_order" property ' \ 65 'contains: "%s", must be empty"' % str(mo))67 'contains: "%s", must be empty"' % str(mo)) 66 68 67 69 def test_typesSEOEnabled_On(self): 68 70 expect = 'Event' 69 self.publish(self.save_url + "&form.types_seo_enabled=%s" % expect, self.basic_auth) 71 self.publish(self.save_url + "&form.types_seo_enabled=%s" % expect, 72 self.basic_auth) 70 73 tse = self.seo.getProperty("content_types_with_seoproperties", ()) 71 74 self.assertTrue(tse == (expect,), 72 '"content_types_with_seoproperties" property contains:' \73 '"%s", must: "%s"' % (tse, expect))75 '"content_types_with_seoproperties" property ' \ 76 'contains:" %s", must: "%s"' % (tse, expect)) 74 77 75 78 def test_typesSEOEnabled_Off(self): … … 78 81 79 82 tse = self.seo.getProperty("content_types_with_seoproperties", ()) 80 self.assertTrue(tse == (), '"content_types_with_seoproperties" property' \81 'contains: "%s", must be empty"' % str(tse))83 self.assertTrue(tse == (), '"content_types_with_seoproperties" ' \ 84 'property contains: "%s", must be empty"' % str(tse)) 82 85 83 86 def test_CustomScriptAdd(self): … … 102 105 expect = ('field1', 'field2') 103 106 formdata = "\n".join(expect) 104 self.publish(self.save_url + '&form.fields=%s' %formdata,105 self.basic_auth)107 self.publish(self.save_url + '&form.fields=%s' % formdata, 108 self.basic_auth) 106 109 107 110 f = self.seo.getProperty("fields", ()) … … 113 116 self.seo._updateProperty("fields", data) 114 117 self.publish(self.save_url + '&form.fields=', 115 self.basic_auth)118 self.basic_auth) 116 119 117 120 f = self.seo.getProperty("fields", ()) 118 121 self.assertTrue(f == (), '"fields" property ' \ 119 'contains: "%s", must be empty"' % str(f))122 'contains: "%s", must be empty"' % str(f)) 120 123 121 124 def test_stopWordsAdd(self): 122 125 expect = ('sw1', 'sw2', 'sw3') 123 126 formdata = "\n".join(expect) 124 self.publish(self.save_url + '&form.stop_words=%s' %formdata,125 self.basic_auth)127 self.publish(self.save_url + '&form.stop_words=%s' % formdata, 128 self.basic_auth) 126 129 127 130 f = self.seo.getProperty("stop_words", ()) 128 131 self.assertTrue(f == expect, '"stop_words" property ' \ 129 'contains: "%s", must: "%s"' % (f, expect))132 'contains: "%s", must: "%s"' % (f, expect)) 130 133 131 134 def test_stopWordsDel(self): … … 133 136 self.seo._updateProperty("stop_words", data) 134 137 self.publish(self.save_url + '&form.stop_words=', 135 self.basic_auth)138 self.basic_auth) 136 139 137 140 f = self.seo.getProperty("stop_words", ()) 138 141 self.assertTrue(f == (), '"stop_words" property ' \ 139 'contains: "%s", must be empty"' % str(f))142 'contains: "%s", must be empty"' % str(f)) 140 143 141 144 def test_externalKeywordTest(self): 142 145 fields = FormFields(ISEOConfigletSchema) 143 146 ffield = fields.get("external_keywords_test") 144 self.assertTrue(ffield is not None, 'Not found "external_keywords_test" '\ 145 'field in ISEOConfigletSchema interface') 147 self.assertTrue(ffield is not None, 148 'Not found "external_keywords_test" field in ' \ 149 'ISEOConfigletSchema interface') 146 150 self.assertTrue(IBool.providedBy(ffield.field), 147 '"external_keywords_test" is not boolean type field')151 '"external_keywords_test" is not boolean type field') 148 152 self.assertTrue(ffield.field.default == False, 149 '"external_keywords_test" field default value is not set to False') 153 '"external_keywords_test" field default value ' \ 154 'is not set to False') 150 155 151 156 def test_externalKeyword_On(self): -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testContextForm.py
r3012 r3134 35 35 METATAG = '.*(<meta\s+(?:(?:name="%s"\s*)|(?:content="%s"\s*)){2}/>)' 36 36 37 37 38 class TestContextForm(FunctionalTestCase): 38 39 … … 42 43 self.wf = self.portal.portal_workflow 43 44 44 self.basic_auth = ':'.join((portal_owner, default_password))45 self.basic_auth = ':'.join((portal_owner, default_password)) 45 46 self.loginAsPortalOwner() 46 47 … … 51 52 self.abs_path = "/%s" % my_doc.absolute_url(1) 52 53 # prepare seo context form data 53 self.sp.manage_changeProperties( 54 default_custom_metatags = 'metatag1|global_metatag1value\n' \55 'metatag4|global_metatag4value')54 self.sp.manage_changeProperties(default_custom_metatags='metatag1|' \ 55 'global_metatag1value\nmetatag4|' \ 56 'global_metatag4value') 56 57 st = '' 57 58 for d in CUSTOM_METATAGS: 58 59 st += '&seo_custommetatags.meta_name:records=%s' % d['meta_name'] 59 st += '&seo_custommetatags.meta_content:records=%s' % d['meta_content'] 60 st += '&seo_custommetatags.meta_content:records=%s' \ 61 % d['meta_content'] 60 62 # update seo properties for the test document and publish it 61 self.publish(path=self.abs_path +'/@@seo-context-properties',63 self.publish(path=self.abs_path + '/@@seo-context-properties', 62 64 basic=self.basic_auth, request_method='POST', 63 stdin=StringIO(urllib.urlencode(FORM) +st))65 stdin=StringIO(urllib.urlencode(FORM) + st)) 64 66 self.wf.doActionFor(my_doc, 'publish') 65 67 # get html view of test document 66 68 self.html = self.publish(self.abs_path, self.basic_auth).getBody() 67 69 68 69 70 def testTitle(self): 70 m = re.match('.*<title>\\s*hello world\\s*</title>', self.html, re.S|re.M) 71 m = re.match('.*<title>\\s*hello world\\s*</title>', self.html, 72 re.S | re.M) 71 73 self.assert_(m, 'Title not set in') 72 74 73 75 def testTitleDuplication(self): 74 """If we are not overriding page title and current page title equals title of the plone site 75 then there should be no concatenation of both titles. Only one should be displayed. 76 """If we are not overriding page title and current page title equals 77 title of the plone site then there should be no concatenation of 78 both titles. Only one should be displayed. 76 79 """ 77 80 # setup page with title equal to plone site's title … … 80 83 my_doc2 = self.portal['my_doc2'] 81 84 self.wf.doActionFor(my_doc2, 'publish') 82 html2 = self.publish('/'+my_doc2.absolute_url(1), self.basic_auth).getBody() 85 html2 = self.publish('/' + my_doc2.absolute_url(1), 86 self.basic_auth).getBody() 83 87 84 m = re.match('.*<title>\\s*%s\\s*</title>' % self.portal.Title(), html2, re.S|re.M) 85 self.assert_(m, 'Title is not set correctly, perhaps it is duplicated with plone site title') 88 m = re.match('.*<title>\\s*%s\\s*</title>' % self.portal.Title(), 89 html2, re.S | re.M) 90 self.assert_(m, 'Title is not set correctly, perhaps it is ' \ 91 'duplicated with plone site title') 86 92 87 93 def testDescription(self): 88 m = re.match(METATAG % ("description", FORM['seo_description']), self.html, re.S|re.M) 94 m = re.match(METATAG % ("description", FORM['seo_description']), 95 self.html, re.S | re.M) 89 96 self.assert_(m, 'Description not set in') 90 97 91 98 def testRobots(self): 92 m = re.match(METATAG % ("robots", FORM['seo_robots']), self.html, re.S|re.M) 99 m = re.match(METATAG % ("robots", FORM['seo_robots']), self.html, 100 re.S | re.M) 93 101 self.assert_(m, 'Robots not set in') 94 102 95 103 def testDistribution(self): 96 m = re.match(METATAG % ("distribution", FORM['seo_distribution']), self.html, re.S|re.M) 104 m = re.match(METATAG % ("distribution", FORM['seo_distribution']), 105 self.html, re.S | re.M) 97 106 self.assert_(m, 'Distribution not set in') 98 107 99 108 def testHTMLComments(self): 100 m = re.match('.*<!--\\s*no comments\\s*-->', self.html, re.S |re.M)109 m = re.match('.*<!--\\s*no comments\\s*-->', self.html, re.S | re.M) 101 110 self.assert_(m, 'Comments not set in') 102 111 103 112 def testTagsOrder(self): 104 113 def is_match(html, mtorder): 105 return re.search('.*'.join(['<meta.*name="%s".*/>' % t \106 for t in mtorder]), html, re.S |re.M)114 return re.search('.*'.join(['<meta.*name="%s".*/>' % t \ 115 for t in mtorder]), html, re.S | re.M) 107 116 108 metatags_order = [t for t in self.sp.getProperty('metatags_order') if t in VIEW_METATAGS] 109 self.assert_(is_match(self.html, metatags_order), "Meta tags order not supported.") 117 metatags_order = [t for t in self.sp.getProperty('metatags_order') \ 118 if t in VIEW_METATAGS] 119 self.assert_(is_match(self.html, metatags_order), 120 "Meta tags order not supported.") 110 121 111 122 metatags_order.reverse() 112 self.assertFalse(is_match(self.html, metatags_order), "Meta tags order not supported.") 123 self.assertFalse(is_match(self.html, metatags_order), 124 "Meta tags order not supported.") 113 125 114 self.sp.manage_changeProperties(metatags_order = metatags_order) 115 self.assertFalse(is_match(self.html, metatags_order), "Meta tags order not supported.") 126 self.sp.manage_changeProperties(metatags_order=metatags_order) 127 self.assertFalse(is_match(self.html, metatags_order), 128 "Meta tags order not supported.") 116 129 117 130 html = self.publish(self.abs_path, self.basic_auth).getBody() 118 self.assert_(is_match(html, metatags_order), "Meta tags order not supported.")119 131 self.assert_(is_match(html, metatags_order), 132 "Meta tags order not supported.") 120 133 121 134 def testCustomMetaTags(self): 122 135 for tag in CUSTOM_METATAGS: 123 136 m = re.match(METATAG % (tag['meta_name'], tag['meta_content']), 124 self.html, re.S |re.M)137 self.html, re.S | re.M) 125 138 if tag['meta_content']: 126 self.assert_(m, "Custom meta tag %s not applied." % tag['meta_name']) 139 self.assert_(m, "Custom meta tag %s not applied." \ 140 % tag['meta_name']) 127 141 else: 128 self.assert_(not m, "Meta tag %s has no content, but is present:" \129 "in the page." % tag['meta_name'])142 self.assert_(not m, "Meta tag %s has no content, but is " \ 143 "present: in the page." % tag['meta_name']) 130 144 131 m = re.match(METATAG % ("metatag4", "global_metatag4value"), self.html, re.S|re.M) 145 m = re.match(METATAG % ("metatag4", "global_metatag4value"), self.html, 146 re.S | re.M) 132 147 self.assert_(m, "Global custom meta tag %s not applied." % 'metatag4') 133 148 134 149 def testDeleteCustomMetaTags(self): 135 self.sp.manage_changeProperties( 136 default_custom_metatags = 'metatag1|global_metatag1value')150 self.sp.manage_changeProperties(default_custom_metatags='metatag1|' \ 151 'global_metatag1value') 137 152 form_data = {'seo_custommetatags': CUSTOM_METATAGS, 138 153 'seo_custommetatags_override:int': 0, … … 143 158 getUtility(IRAMCache).invalidateAll() 144 159 145 self.publish(path=self.abs_path +'/@@seo-context-properties',160 self.publish(path=self.abs_path + '/@@seo-context-properties', 146 161 basic=self.basic_auth, request_method='POST', 147 162 stdin=StringIO(urllib.urlencode(form_data))) 148 163 html = self.publish(self.abs_path, self.basic_auth).getBody() 149 164 150 m = re.match(METATAG % ("metatag4", "global_metatag4value"), html, re.S|re.M) 151 self.assert_(not m, "Global custom meta tag %s is prosent in the page." % 'metatag4') 165 m = re.match(METATAG % ("metatag4", "global_metatag4value"), html, 166 re.S | re.M) 167 self.assert_(not m, "Global custom meta tag %s is prosent in the " \ 168 "page." % 'metatag4') 152 169 153 m = re.match(METATAG % ("metatag1", "global_metatag1value"), html, re.S|re.M) 170 m = re.match(METATAG % ("metatag1", "global_metatag1value"), html, 171 re.S | re.M) 154 172 self.assert_(m, "Global custom meta tag %s not applied." % 'metatag1') 173 155 174 156 175 def test_suite(): -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testExposeDCMetaTags.py
r2139 r3134 3 3 from base import * 4 4 5 METATAG = '.*(<meta\s+(?:(?:name="%s"\s*)|(?:content="(?P<tagcontent>.*?)"\s*)){2}/>)' 5 METATAG = '.*(<meta\s+(?:(?:name="%s"\s*)|(?:content="(?P<tagcontent>.' \ 6 '*?)"\s*)){2}/>)' 7 6 8 7 9 class TestExposeDCMetaTags(FunctionalTestCase): … … 9 11 def afterSetUp(self): 10 12 self.sp = self.portal.portal_properties.site_properties 11 self.basic_auth = ':'.join((portal_owner, default_password))13 self.basic_auth = ':'.join((portal_owner, default_password)) 12 14 self.loginAsPortalOwner() 13 15 # Preparation for functional testing … … 16 18 17 19 def test_propertyOff(self): 18 self.sp.manage_changeProperties(exposeDCMetaTags = False) 19 self.html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth)) 20 m1 = re.match(METATAG % "DC.format", self.html, re.S|re.M) 21 m2 = re.match(METATAG % "DC.distribution", self.html, re.S|re.M) 22 self.assert_(not (m1 or m2), 'DC meta tags avaliable when exposeDCMetaTags=False') 20 self.sp.manage_changeProperties(exposeDCMetaTags=False) 21 self.html = str(self.publish(self.portal.id + '/my_doc', 22 self.basic_auth)) 23 m1 = re.match(METATAG % "DC.format", self.html, re.S | re.M) 24 m2 = re.match(METATAG % "DC.distribution", self.html, re.S | re.M) 25 self.assert_(not (m1 or m2), 'DC meta tags avaliable when ' \ 26 'exposeDCMetaTags=False') 23 27 24 28 def test_propertyOn(self): 25 self.sp.manage_changeProperties(exposeDCMetaTags = True) 26 self.html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth)) 27 m1 = re.match(METATAG % "DC.format", self.html, re.S|re.M) 28 m2 = re.match(METATAG % "DC.type", self.html, re.S|re.M) 29 self.assert_(m1 and m2, 'DC meta tags not avaliable when createManager=True') 29 self.sp.manage_changeProperties(exposeDCMetaTags=True) 30 self.html = str(self.publish(self.portal.id + '/my_doc', 31 self.basic_auth)) 32 m1 = re.match(METATAG % "DC.format", self.html, re.S | re.M) 33 m2 = re.match(METATAG % "DC.type", self.html, re.S | re.M) 34 self.assert_(m1 and m2, 'DC meta tags not avaliable when ' \ 35 'createManager=True') 30 36 31 37 def test_descriptionInPropertyOff(self): 32 self.sp.manage_changeProperties(exposeDCMetaTags =False)38 self.sp.manage_changeProperties(exposeDCMetaTags=False) 33 39 self.my_doc.setDescription("My document description") 34 self.html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth)) 35 m = re.match(METATAG % "description", self.html, re.S|re.M) 36 self.assert_(m, 'No "description" meta tag when expose DC meta tags is Off') 40 self.html = str(self.publish(self.portal.id + '/my_doc', 41 self.basic_auth)) 42 m = re.match(METATAG % "description", self.html, re.S | re.M) 43 self.assert_(m, 'No "description" meta tag when expose DC meta tags ' \ 44 'is Off') 37 45 38 46 def test_descriptionInPropertyOn(self): 39 self.sp.manage_changeProperties(exposeDCMetaTags =True)47 self.sp.manage_changeProperties(exposeDCMetaTags=True) 40 48 self.my_doc.setDescription("My document description") 41 self.html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth)) 42 m = re.match(METATAG % "description", self.html, re.S|re.M) 43 self.assert_(m, 'No "description" meta tag when expose DC meta tags is On') 49 self.html = str(self.publish(self.portal.id + '/my_doc', 50 self.basic_auth)) 51 m = re.match(METATAG % "description", self.html, re.S | re.M) 52 self.assert_(m, 'No "description" meta tag when expose DC meta tags ' \ 53 'is On') 44 54 45 55 def test_dateValidRange(self): 46 self.sp.manage_changeProperties(exposeDCMetaTags =True)47 EFFDSTR, EXPDSTR = 56 self.sp.manage_changeProperties(exposeDCMetaTags=True) 57 EFFDSTR, EXPDSTR = "2009/12/23", "2010/03/10" 48 58 self.my_doc.setExpirationDate(EXPDSTR) 49 59 self.my_doc.setEffectiveDate(EFFDSTR) 50 self.html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth)) 51 m = re.match(METATAG % "DC.date.valid_range", self.html, re.S|re.M) 60 self.html = str(self.publish(self.portal.id + '/my_doc', 61 self.basic_auth)) 62 m = re.match(METATAG % "DC.date.valid_range", self.html, re.S | re.M) 52 63 content = m and m.group("tagcontent") 53 64 fact = content and map(DateTime, content.split("-")) 54 65 expect = map(DateTime, [EFFDSTR, EXPDSTR]) 55 self.assert_( fact == expect, '"DC.date.valid_range" meta tags content="%s", ' \ 56 'but "%s" must be' % ( fact, expect )) 66 self.assert_(fact == expect, '"DC.date.valid_range" meta tags ' \ 67 'content="%s", but "%s" must be' % (fact, expect)) 68 57 69 58 70 def test_suite(): -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testInstallation.py
r2244 r3134 24 24 DEFAULT_METATAGS_ORDER = [ 25 25 'DC.contributors', 'DC.creator', 'DC.date.created', 26 'DC.date.modified', 'DC.description', 'DC.distribution',26 'DC.date.modified', 'DC.description', 'DC.distribution', 27 27 'DC.format', 'DC.language', 'DC.publisher', 'DC.rights', 28 28 'DC.subject', 'DC.type', 'description', 'distribution', … … 31 31 32 32 SEO_CONTENT = ['File', 'Document', 'News Item'] 33 CONTENTTYPES_WITH_SEOACTION = ['File', 'Document', 'News Item', 'Folder', 'Event'] 33 CONTENTTYPES_WITH_SEOACTION = ['File', 'Document', 'News Item', 'Folder', 34 'Event'] 34 35 CONTENTTYPES_WITH_SEOACTION.sort() 35 36 … … 60 61 61 62 def testAddingPropertyFields(self): 62 """ Test adding property field to portal_properties.maps_properties sheet """ 63 """ Test adding property field to portal_properties.maps_properties 64 sheet 65 """ 63 66 map_sheet = self.properties[PROPERTY_SHEET] 64 67 for key, value in PROPS.items(): 65 self.failUnless(map_sheet.hasProperty(key) and list(map_sheet.getProperty(key)) == value) 68 self.failUnless(map_sheet.hasProperty(key) and \ 69 list(map_sheet.getProperty(key)) == value) 66 70 67 71 def test_configlet_install(self): 68 72 configTool = getToolByName(self.portal, 'portal_controlpanel', None) 69 self.assert_(PROJECT_NAME in [a.getId() for a in configTool.listActions()], 'Configlet not found') 73 self.assert_(PROJECT_NAME in [a.getId() for a in \ 74 configTool.listActions()], \ 75 'Configlet not found') 70 76 71 77 def test_viewlets_install(self): … … 78 84 alsoProvides(request, IPloneSEOLayer) 79 85 view = queryMultiAdapter((self.portal, request), name="plone") 80 manager = queryMultiAdapter( 86 manager = queryMultiAdapter((self.portal['front-page'], request, view), 81 87 IViewletManager, name='plone.htmlhead') 82 88 for p in VIEWLETS: 83 self.assert_(manager.get(p) is not None, "Not registered '%s' viewlet" % p) 89 self.assert_(manager.get(p) is not None, "Not registered '%s' " \ 90 "viewlet" % p) 84 91 85 92 def test_browser_layer(self): … … 92 99 93 100 def test_action_install(self): 94 atool =getToolByName(self.portal, 'portal_actions')101 atool = getToolByName(self.portal, 'portal_actions') 95 102 action_ids = [a.id for a in atool.listActions()] 96 103 self.assert_("SEOProperties" in action_ids, 97 104 "Not added 'SEOProperties' action") 98 105 106 99 107 class TestUninstallation(TestCase): 100 108 … … 106 114 properties = getToolByName(self.portal, 'portal_properties') 107 115 self.assert_(hasattr(properties.aq_base, PROPERTY_SHEET), 108 "'%s' property sheet not uninstalled" % PROPERTY_SHEET)116 "'%s' property sheet not uninstalled" % PROPERTY_SHEET) 109 117 110 118 def test_configlet_uninstall(self): … … 113 121 114 122 configTool = getToolByName(self.portal, 'portal_controlpanel', None) 115 self.assertEqual(PROJECT_NAME in [a.getId() for a in configTool.listActions()], False, 116 'Configlet found after uninstallation') 123 self.assertEqual(PROJECT_NAME in [a.getId() for a in \ 124 configTool.listActions()], False, 125 'Configlet found after uninstallation') 117 126 118 127 def test_viewlets_uninstall(self): … … 121 130 request = self.app.REQUEST 122 131 view = queryMultiAdapter((self.portal, request), name="plone") 123 manager = queryMultiAdapter( 124 132 manager = queryMultiAdapter((self.portal['front-page'], request, view), 133 IViewletManager, name='plone.htmlhead') 125 134 for p in VIEWLETS: 126 135 self.assertEqual(manager.get(p) is None, True, … … 136 145 137 146 def test_action_uninstall(self): 138 atool =getToolByName(self.portal, 'portal_actions')147 atool = getToolByName(self.portal, 'portal_actions') 139 148 action_ids = [a.id for a in atool.listActions()] 140 149 self.assertEqual("SEOProperties" in action_ids, False, 141 "'SEOProperties' action not removed from portal_actions " \ 142 "on uninstallation") 150 "'SEOProperties' action not removed from " \ 151 "portal_actions on uninstallation") 152 143 153 144 154 class TestReinstallation(TestCase): … … 149 159 self.setup_tool = getToolByName(self.portal, 'portal_setup') 150 160 self.pprops_tool = getToolByName(self.portal, 'portal_properties') 151 self.seoprops_tool = getToolByName(self.pprops_tool, 'seo_properties', None) 152 # Set earlier version profile (2.0.0) for using upgrade steps 153 self.setup_tool.setLastVersionForProfile('%s:default' % PROJECT_NAME, '2.0.0') 161 self.seoprops_tool = getToolByName(self.pprops_tool, 'seo_properties', 162 None) 163 # Set earlier version profile (2.0.0) for using upgrade steps 164 self.setup_tool.setLastVersionForProfile('%s:default' % PROJECT_NAME, 165 '2.0.0') 154 166 155 167 def testChangeDomain(self): 156 # Test changed of content type's domain from 'quintagroup.seoptimizer' to 'plone' 168 # Test changed of content type's domain from 'quintagroup.seoptimizer' 169 # to 'plone' 157 170 for type in SEO_CONTENT: 158 self.types_tool.getTypeInfo(type).i18n_domain = 'quintagroup.seoptimizer' 171 i18n_domain = 'quintagroup.seoptimizer' 172 self.types_tool.getTypeInfo(type).i18n_domain = i18n_domain 159 173 self.qi.reinstallProducts([PROJECT_NAME]) 160 174 for type in SEO_CONTENT: 161 self.assertEqual(self.types_tool.getTypeInfo(type).i18n_domain, 'plone', 162 "Not changed of %s content type's domain to 'plone'" % type) 175 self.assertEqual(self.types_tool.getTypeInfo(type).i18n_domain, 176 'plone', "Not changed of %s content type's " \ 177 "domain to 'plone'" % type) 163 178 164 179 def testCutItemsMetatagsOrderList(self): 165 # Test changed format metatags order list from "metaname accessor" to "metaname" 166 value, expect_mto = ['name1 accessor1', 'name2 accessor2'], ['name1','name2'] 180 # Test changed format metatags order list from "metaname accessor" 181 # to "metaname" 182 value, expect_mto = ['name1 accessor1', 'name2 accessor2'], \ 183 ['name1', 'name2'] 167 184 self.seoprops_tool.manage_changeProperties(metatags_order=value) 168 185 self.qi.reinstallProducts([PROJECT_NAME]) … … 170 187 mto.sort() 171 188 self.assertEqual(mto, expect_mto, 172 "Not changed format metatags order list from \"metaname accessor\" to"\ 173 " \"metaname\". %s != %s" %(mto, expect_mto)) 189 "Not changed format metatags order list from \"" \ 190 "metaname accessor\" to \"metaname\". %s != %s" \ 191 % (mto, expect_mto)) 174 192 175 193 def testAddMetatagsOrderList(self): … … 180 198 mto.sort() 181 199 self.assertEqual(mto, DEFAULT_METATAGS_ORDER, 182 "Not added metatags order list with default values."\183 "%s != %s" %(mto, DEFAULT_METATAGS_ORDER))200 "Not added metatags order list with default values." \ 201 "%s != %s" % (mto, DEFAULT_METATAGS_ORDER)) 184 202 185 203 def testMigrationActions(self): … … 188 206 189 207 # Add seoaction to content type for testing 208 190 209 for type in CONTENTTYPES_WITH_SEOACTION: 191 self.types_tool.getTypeInfo(type).addAction(id='seo_properties', 192 name='SEO Properties', 193 action=None, 194 condition=None, 195 permission=(u'Modify portal content',), 196 category='object', 197 ) 210 self.types_tool.getTypeInfo(type).addAction( 211 id='seo_properties', 212 name='SEO Properties', 213 action=None, 214 condition=None, 215 permission=(u'Modify portal content',), 216 category='object', 217 ) 198 218 # Check presence seoaction in content type 199 seoaction = [act.id for act in self.types_tool.getTypeInfo(type).listActions() 200 if act.id == 'seo_properties'] 219 seoaction = [act.id for act in \ 220 self.types_tool.getTypeInfo(type).listActions() \ 221 if act.id == 'seo_properties'] 201 222 self.assertEqual(bool(seoaction), True, 202 "Not added seoaction to content type %s for testing" % type) 223 "Not added seoaction to content type %s for " \ 224 "testing" % type) 203 225 204 226 self.qi.reinstallProducts([PROJECT_NAME]) … … 206 228 # Check presence seoaction in content type 207 229 for type in CONTENTTYPES_WITH_SEOACTION: 208 seoaction = [act.id for act in self.types_tool.getTypeInfo(type).listActions() 209 if act.id == 'seo_properties'] 230 seoaction = [act.id for act in \ 231 self.types_tool.getTypeInfo(type).listActions() \ 232 if act.id == 'seo_properties'] 210 233 self.assertEqual(bool(seoaction), False, 211 234 "Not removed seoaction in content type %s" % type) 212 235 213 # Check added content type names in seo properties tool if content types have seoaction 236 # Check added content type names in seo properties tool 237 # if content types have seoaction 214 238 ctws = list(self.seoprops_tool.content_types_with_seoproperties) 215 239 ctws.sort() 216 240 self.assertEqual(ctws, CONTENTTYPES_WITH_SEOACTION, 217 "Not added content type names in seo properties tool if content types have seoaction."\ 218 " %s != %s" %(ctws, CONTENTTYPES_WITH_SEOACTION)) 241 "Not added content type names in seo properties " \ 242 "tool if content types have seoaction. %s != %s" \ 243 % (ctws, CONTENTTYPES_WITH_SEOACTION)) 219 244 220 245 def testRemoveSkin(self): … … 223 248 skinstool = getToolByName(self.portal, 'portal_skins') 224 249 for skin in skinstool.getSkinSelections(): 225 paths 250 paths = ','.join((skinstool.getSkinPath(skin), layer)) 226 251 skinstool.addSkinSelection(skin, paths) 227 252 self.qi.reinstallProducts([PROJECT_NAME]) … … 230 255 path = map(string.strip, string.split(path, ',')) 231 256 self.assertEqual(layer in path, False, 232 '%s layer found in %s after uninstallation' %(layer, skin)) 257 '%s layer found in %s after uninstallation' \ 258 % (layer, skin)) 233 259 234 260 def testMigrateCanonical(self): … … 239 265 doc.manage_addProperty('qSEO_canonical', 'val', 'string') 240 266 value = doc.getProperty('qSEO_canonical') 241 assert doc.getProperty('qSEO_canonical') == 'val' 267 assert doc.getProperty('qSEO_canonical') == 'val' 242 268 243 269 self.qi.reinstallProducts([PROJECT_NAME]) 244 270 value = doc.getProperty(PROPERTY_LINK) 245 271 has_prop = bool(doc.hasProperty('qSEO_canonical')) 246 self.assertEqual(has_prop, False, "Property 'qSEO_canonical' is not deleted.") 247 self.assertEqual(value == 'val', True, 248 "Property not migrated from 'qSEO_canonical' to '%s'." % PROPERTY_LINK) 272 self.assertEqual(has_prop, False, "Property 'qSEO_canonical' is " \ 273 "not deleted.") 274 self.assertEqual(value == 'val', True, "Property not migrated from " \ 275 "'qSEO_canonical' to '%s'." % PROPERTY_LINK) 276 249 277 250 278 def test_suite(): -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testMetaTagsDuplication.py
r2139 r3134 2 2 3 3 GENERATOR = re.compile('.*(<meta\s+(?:(?:name="generator"\s*)|' \ 4 '(?:content=".*?"\s*)){2}/>)', re.S |re.M)4 '(?:content=".*?"\s*)){2}/>)', re.S | re.M) 5 5 DESCRIPTION = re.compile('.*(<meta\s+(?:(?:name="description"\s*)|' \ 6 '(?:content=".*?"\s*)){2}/>)', re.S|re.M) 6 '(?:content=".*?"\s*)){2}/>)', re.S | re.M) 7 7 8 8 9 class InstallMixin: … … 28 29 def test_GeneratorMetaSEOInstalled(self): 29 30 lengen = len(GENERATOR.findall(self.html)) 30 self.assert_(lengen ==1, "There is %d generator meta tag(s) " \31 self.assert_(lengen == 1, "There is %d generator meta tag(s) " \ 31 32 "when seoptimizer installed" % lengen) 32 33 33 34 def test_DescriptionMetaSEOInstalled(self): 34 35 lendesc = len(DESCRIPTION.findall(self.html)) 35 self.assert_(lendesc ==1, "There is %d DESCRIPTION meta tag(s) " \36 self.assert_(lendesc == 1, "There is %d DESCRIPTION meta tag(s) " \ 36 37 "when seoptimizer installed" % lendesc) 37 38 … … 45 46 def test_GeneratorMetaSEOUninstalled(self): 46 47 lengen = len(GENERATOR.findall(self.html)) 47 self.assert_(lengen <=1, "There is %d generator meta tag(s) " \48 self.assert_(lengen <= 1, "There is %d generator meta tag(s) " \ 48 49 "when seoptimizer uninstalled" % lengen) 49 50 50 51 def test_DescriptionMetaSEOUninstalled(self): 51 52 lendesc = len(DESCRIPTION.findall(self.html)) 52 self.assert_(lendesc ==1, "There is %d DESCRIPTION meta tag(s) " \53 self.assert_(lendesc == 1, "There is %d DESCRIPTION meta tag(s) " \ 53 54 "when seoptimizer uninstalled" % lendesc) 54 55 -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/testUsageKeywords.py
r2928 r3134 8 8 KWSTMPL = '.*(<meta\s+(?:(?:name="keywords"\s*)|(?:content="%s"\s*)){2}/>)' 9 9 10 10 11 class TestUsageKeywords(FunctionalTestCase): 11 12 … … 13 14 self.sp = self.portal.portal_properties.seo_properties 14 15 self.pu = self.portal.plone_utils 15 self.basic_auth = ':'.join((portal_owner, default_password))16 self.basic_auth = ':'.join((portal_owner, default_password)) 16 17 self.loginAsPortalOwner() 17 18 #Preparation for functional testing … … 31 32 for seokws in [('foo',), ('foo', 'bar')]: 32 33 self.my_doc._updateProperty('qSEO_keywords', seokws) 33 html = str(self.publish(self.portal.id+'/my_doc', self.basic_auth)) 34 html = str(self.publish(self.portal.id + '/my_doc', 35 self.basic_auth)) 34 36 expect = ',\s*'.join(seokws) 35 open('/tmp/testrender_SEOKeywords', 'w').write(html)36 self.assert_(re.match(KWSTMPL % expect, html, re.S |re.M),37 open('/tmp/testrender_SEOKeywords', 'w').write(html) 38 self.assert_(re.match(KWSTMPL % expect, html, re.S | re.M), 37 39 "No '%s' keyword found" % str(seokws)) 38 40 … … 40 42 self.my_doc.setText('<p>local subject</p>') 41 43 self.my_doc.setSubject('subject') 42 html = str(self.publish(self.portal.id +'/my_doc', self.basic_auth))44 html = str(self.publish(self.portal.id + '/my_doc', self.basic_auth)) 43 45 44 46 expect = "subject" 45 self.assert_(re.match(KWSTMPL % expect, html, re.S |re.M),47 self.assert_(re.match(KWSTMPL % expect, html, re.S | re.M), 46 48 "No '%s' keyword find" % expect) 47 49 … … 51 53 self.my_doc.setSubject('subject') 52 54 self.my_doc.manage_addProperty('qSEO_keywords', SEOKWS, 'lines') 53 html = str(self.publish(self.portal.id +'/my_doc', self.basic_auth))55 html = str(self.publish(self.portal.id + '/my_doc', self.basic_auth)) 54 56 55 57 expect = ',\s*'.join(SEOKWS) 56 self.assert_(re.match(KWSTMPL % expect, html, re.S |re.M),58 self.assert_(re.match(KWSTMPL % expect, html, re.S | re.M), 57 59 "No '%s' keywords find" % SEOKWS) 58 60 59 61 def testbehave_noSEOKeywordsNoSubject(self): 60 62 """Nor seo keywords not subject added""" 61 html = str(self.publish(self.portal.id +'/my_doc', self.basic_auth))63 html = str(self.publish(self.portal.id + '/my_doc', self.basic_auth)) 62 64 self.assertFalse(re.match('.*(<meta\s[^\>]*name="keywords"[^\>]*>)', 63 html, re.S|re.M), "'keyword' meta tag found") 65 html, re.S | re.M), 66 "'keyword' meta tag found") 64 67 65 68 … … 81 84 self.chckView = queryMultiAdapter((self.my_doc, self.app.REQUEST), 82 85 name="checkSEOKeywords") 83 86 84 87 def patchURLLib(self, fnc): 85 88 self.orig_urlopen = urllib2.urlopen 86 89 self.urlfd = StringIO() 87 90 urllib2.urlopen = fnc 88 91 89 92 def unpatchURLLib(self): 90 93 urllib2.urlopen = self.orig_urlopen … … 99 102 def patch_urlopen(*args, **kwargs): 100 103 if args[0] == self.my_doc.absolute_url(): 101 self.urlfd.write(unicode(self.my_doc() + self.key).encode("utf-8")) 104 self.urlfd.write(unicode(self.my_doc() + 105 self.key).encode("utf-8")) 102 106 self.urlfd.seek(0) 103 107 return self.urlfd … … 110 114 self.assertTrue('3' in self.chckView()) 111 115 # 2. Opened urllib file descriptor must be closed 112 self.assertTrue(self.urlfd.closed, "Opened file descriptor was not closed.") 116 self.assertTrue(self.urlfd.closed, 117 "Opened file descriptor was not closed.") 113 118 self.unpatchURLLib() 114 119 115 120 def test_ExternalURLError(self): 116 121 def patch_urlopen(*args, **kwargs): … … 131 136 # 2. Opened urllib file descriptor should not be closed because 132 137 # it even not returned to the view 133 self.assertFalse(self.urlfd.closed, "Opened file descriptor was closed.") 138 self.assertFalse(self.urlfd.closed, 139 "Opened file descriptor was closed.") 134 140 self.unpatchURLLib() 135 141 136 142 def test_ExternalIOError(self): 137 143 def patch_urlopen(*args, **kwargs): 138 144 if args[0] == self.my_doc.absolute_url(): 139 self.urlfd.write(unicode(self.my_doc() + self.key).encode("utf-8")) 145 self.urlfd.write(unicode(self.my_doc() + 146 self.key).encode("utf-8")) 140 147 self.urlfd.seek(0) 141 148 return self.urlfd 142 149 else: 143 150 return self.orig_urlopen(*args, **kwargs) 151 144 152 def patch_read(*args, **kwargs): 145 153 raise Exception("General exception") 146 154 # Patch urllib2.urlopen to emulate external url retrieval 147 155 self.patchURLLib(fnc=patch_urlopen) 148 # Patch opened by urllib2 file descriptor to emulate IOError during reading 156 # Patch opened by urllib2 file descriptor to emulate 157 # IOError during reading 149 158 self.urlfd.read = patch_read 150 159 self.seo._updateProperty("external_keywords_test", True) … … 153 162 self.assertRaises(Exception, self.chckView) 154 163 # 2. Opened urllib file descriptor must be closed 155 self.assertTrue(self.urlfd.closed, "Opened file descriptor was not closed.") 164 self.assertTrue(self.urlfd.closed, 165 "Opened file descriptor was not closed.") 156 166 self.unpatchURLLib() 157 167 158 168 159 169 def test_suite(): … … 163 173 suite.addTest(makeSuite(TestCalcKeywords)) 164 174 return suite 165 -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/tests/test_doctest.py
r3011 r3134 3 3 4 4 from base import * 5 5 6 6 7 def test_suite(): -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/upgrades.py
r2238 r3134 7 7 logger = logging.getLogger('quintagroup.seoptimizer') 8 8 FIX_PTYPES_DOMAIN = ['Document', 'File', 'News Item'] 9 REMOVE_SEOPROPERTIES = ['additional_keywords', 'settings_use_keywords_sg', 10 'settings_use_keywords_lg', 'filter_keywords_by_content', 9 REMOVE_SEOPROPERTIES = ['additional_keywords', 10 'settings_use_keywords_sg', 11 'settings_use_keywords_lg', 12 'filter_keywords_by_content', 11 13 ] 14 12 15 13 16 def changeDomain(plone_tools): … … 23 26 "changed to \'plone\'." % ptype.id) 24 27 28 25 29 def changeMetatagsOrderList(plone_tools): 26 """ Change format metatags order list from "metaname accessor" to "metaname". 30 """ Change format metatags order list 31 from "metaname accessor" to "metaname". 27 32 """ 28 33 types_tool = plone_tools.types() … … 37 42 seoprops_tool.manage_changeProperties(metatags_order=mto_new) 38 43 else: 39 setup_tool.runImportStepFromProfile('profile-quintagroup.seoptimizer:default',40 44 name_profile = 'profile-quintagroup.seoptimizer:default' 45 setup_tool.runImportStepFromProfile(name_profile, 'propertiestool') 41 46 42 47 … … 47 52 types_tool = plone_tools.types() 48 53 seoprops_tool = plone_tools.properties().seo_properties 49 ctws = list(seoprops_tool.getProperty('content_types_with_seoproperties', [])) 54 property_name = 'content_types_with_seoproperties' 55 ctws = list(seoprops_tool.getProperty(property_name, [])) 50 56 flag = False 51 57 for ptype in types_tool.objectValues(): … … 60 66 "type in portal actions." % ptype.id) 61 67 if flag: 62 seoprops_tool.manage_changeProperties(content_types_with_seoproperties=ctws) 68 seo_change_properties = seoprops_tool.manage_changeProperties 69 seo_change_properties(content_types_with_seoproperties=ctws) 70 63 71 64 72 def removeNonUseSeoProperties(plone_tools): … … 68 76 remove_properties = [] 69 77 for pr in REMOVE_SEOPROPERTIES: 70 if seoprops_tool.hasProperty(pr): 71 remove_properties.append(pr) 72 logger.log(logging.INFO, "Removed %s property in seoproperties tool." % pr) 78 if seoprops_tool.hasProperty(pr): 79 remove_properties.append(pr) 80 logger.log(logging.INFO, "Removed %s property in " 81 "seoproperties tool." % pr) 73 82 if not remove_properties: 74 83 seoprops_tool.manage_delProperties(remove_properties) 84 75 85 76 86 def removeSkin(plone_tools): … … 80 90 skins_tool = plone_tools.url().getPortalObject().portal_skins 81 91 for skinName in skins_tool.getSkinSelections(): 82 skin_paths = skins_tool.getSkinPath(skinName).split(',') 83 paths = [l.strip() for l in skin_paths if not (l == layer or l.startswith(layer+'/'))] 92 skin_paths = skins_tool.getSkinPath(skinName).split(',') 93 paths = [l.strip() for l in skin_paths \ 94 if not (l == layer or l.startswith(layer + '/'))] 84 95 logger.log(logging.INFO, "Removed layers from %s skin." % skinName) 85 96 skins_tool.addSkinSelection(skinName, ','.join(paths)) 97 86 98 87 99 def migrateCanonical(plone_tools): … … 92 104 portal = plone_tools.url().getPortalObject() 93 105 allCTTypes = types.listContentTypes() 94 obj_metatypes = 95 106 obj_metatypes = [m.content_meta_type for m in types.objectValues() \ 107 if m.getId() in allCTTypes] 96 108 portal.ZopeFindAndApply( 97 109 portal, … … 99 111 apply_func=renameProperty 100 112 ) 113 101 114 102 115 def renameProperty(obj, path): … … 115 128 "property for %%(url)s object" % str(e) 116 129 117 logger.log(level, msg % {'url':obj.absolute_url(), 'name':PROPERTY_LINK} ) 130 logger.log(level, msg % {'url': obj.absolute_url(), 131 'name': PROPERTY_LINK}) 118 132 obj.manage_delProperties(['qSEO_canonical']) 133 119 134 120 135 def upgrade_2_to_3(setuptool): 121 136 """ Upgrade quintagroup.seoptimizer from version 2.x.x to 3.0.0. 122 137 """ 123 plone_tools = queryMultiAdapter((setuptool, setuptool.REQUEST), name="plone_tools") 124 setuptool.runAllImportStepsFromProfile('profile-quintagroup.seoptimizer:upgrade_2_to_3') 138 plone_tools = queryMultiAdapter((setuptool, setuptool.REQUEST), 139 name="plone_tools") 140 profile_name = 'profile-quintagroup.seoptimizer:upgrade_2_to_3' 141 setuptool.runAllImportStepsFromProfile(profile_name) 125 142 migrationActions(plone_tools) 126 143 changeDomain(plone_tools) -
quintagroup.seoptimizer/trunk/quintagroup/seoptimizer/util.py
r2139 r3134 13 13 14 14 security.declarePublic('items') 15 15 16 def items(self): 16 17 primary_metatags = self.pmt 17 lst = [(name, self[name]) for name in primary_metatags\18 if name in self.keys()] +\19 [(name, self[name]) for name in self.keys() 20 18 lst = [(name, self[name]) for name in primary_metatags \ 19 if name in self.keys()] + \ 20 [(name, self[name]) for name in self.keys() \ 21 if name not in primary_metatags] 21 22 return lst 22 23 24 security.declarePublic('__init__') 23 25 24 security.declarePublic('__init__')25 26 def __init__(self, *args, **kwargs): 26 super(SortedDict, self).__init__(*args, **kwargs)27 super(SortedDict, self).__init__(*args, **kwargs) 27 28 self.pmt = [] 29 security.declarePublic('__setitem__') 28 30 29 30 security.declarePublic('__setitem__')31 31 def __setitem__(self, i, y): 32 super(SortedDict, self).__setitem__(i, y)32 super(SortedDict, self).__setitem__(i, y) 33 33 if i not in self.pmt: 34 34 self.pmt.append(i) 35 security.declarePublic('pop') 35 36 36 security.declarePublic('pop')37 37 def pop(self, k, *args, **kwargs): 38 super(SortedDict, self).pop(k, *args, **kwargs)38 super(SortedDict, self).pop(k, *args, **kwargs) 39 39 if k in self.pmt: 40 40 self.pmt.remove(k) -
quintagroup.seoptimizer/trunk/setup.py
r3013 r3134 12 12 description="Quintagroup Search Engine Optimization Tool", 13 13 long_description=open("README.txt").read() + "\n" + 14 15 14 open(os.path.join("docs", "INSTALL.txt")).read() + "\n" + 15 open(os.path.join("docs", "HISTORY.txt")).read(), 16 16 17 # Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers 17 # Get more strings from 18 # http://www.python.org/pypi?%3Aaction=list_classifiers 18 19 classifiers=[ 19 20 "Framework :: Plone", … … 24 25 ], 25 26 keywords='', 26 author='Myroslav Opyr, Volodymyr Romaniuk, Mykola Kharechko, Vitaliy Podoba, Volodymyr Cherepanyak, Taras Melnychuk, Vitaliy Stepanov, Andriy Mylenkyy', 27 author='Myroslav Opyr, Volodymyr Romaniuk, Mykola Kharechko, ' \ 28 'Vitaliy Podoba, Volodymyr Cherepanyak, Taras Melnychuk, '\ 29 'Vitaliy Stepanov, Andriy Mylenkyy', 27 30 author_email='support@quintagroup.com', 28 url='http://quintagroup.com/services/plone-development/products/qSEOptimizer/', 31 url='http://quintagroup.com/services/'\ 32 'plone-development/products/qSEOptimizer/', 29 33 license='GPL', 30 34 packages=find_packages(exclude=['ez_setup']),
Note: See TracChangeset
for help on using the changeset viewer.