def __call__(self): """ Perform the update seo properties and redirect if necessary, or render the page Call method. """ context = aq_inner(self.context) request = self.request form = self.request.form submitted = form.get('form.submitted', False) if submitted: msgtype = "info" save = form.get('form.button.Save', False) if save: msg = self.manageSEOProps(**form) if not msg: msg = _('seoproperties_saved', default=u'Content SEO properties have been saved.') kwargs = {'modification_date': DateTime()} context.plone_utils.contentEdit(context, **kwargs) else: msgtype = "error" else: # Cancel msg = _('seoproperties_canceled', default=u'No content SEO ' 'properties have been changed.') context.plone_utils.addPortalMessage(msg, msgtype) if msgtype == "info": return request.response.redirect(self.context.absolute_url()) return self.template()
class ISEOConfigletAdvancedSchema(Interface): custom_script = SourceText( title=_("label_custom_script", default=u'Header JavaScript'), description=_("help_custom_script", default=u"This JavaScript code will be included in " "the rendered HTML as entered in the page header."), default=u'', required=False) fields = List( title=_("label_fields", default='Fields for keywords statistic ' 'calculation.'), description=_("help_fields", default='Fill in filds (one per line)' 'which statistics of keywords usage should ' 'be calculated for.'), required=False) stop_words = List( title=_("label_stop_words", default='Stop words.'), description=_("help_stop_words", default='Fill in stop words ' '(one per line) which will be excluded from kewords ' 'statistics calculation.'), required=False) external_keywords_test = Bool( title=_("label_external_keywords_test", default='External keywords check'), description=_("description_external_keywords_test", default='Make keywords test by opening context url as ' 'external resource with urllib2.openurl(). This is ' 'useful when xdv/Deliverance transformation is used ' 'on the site.'), default=False, required=False)
def validateKeywords(self): """ see interface """ text = self.request.get('text') ts = getToolByName(self.context, 'translation_service') transforms = getUtility(IPortalTransformsTool) portal = getToolByName(self.context, 'portal_url').getPortalObject() isExternal = queryAdapter(portal, ISEOConfigletSchema).external_keywords_test # extract keywords from text enc = getSiteEncoding(self.context) if text.lower().strip(): keywords = filter(None, map(lambda x: safe_unicode(x.strip(), enc), text.lower().strip().split('\n'))) else: return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'Keywords list is empty!'), context=self.context) # Get html page internally or with external request error_url = "" if isExternal: # Not pass timeout option because: # 1. its value get from the global default timeout settings. # 2. timeout option added in python 2.6 (so acceptable only in plone4+) try: resp = urllib2.urlopen(self.context.absolute_url()) try: html = resp.read() finally: resp.close() except (urllib2.URLError, urllib2.HTTPError), e: # In case of exceed timeout period or other URL connection errors. # Get nearest to context error_log object (stolen from Zope2/App/startup.py) html = None info = sys.exc_info() elog = getToolByName(self.context, "error_log") error_url = elog.raising(info)
class SEOConfiglet(ControlPanelForm): form_fields = FormFieldsets(baseset, advancedset) type_seo_enabled = MultiCheckBoxThreeColumnWidget form_fields['default_custom_metatags'].custom_widget = Text2ListWidget form_fields['metatags_order'].custom_widget = Text2ListWidget form_fields['types_seo_enabled'].custom_widget = type_seo_enabled form_fields['types_seo_enabled'].custom_widget.cssClass = 'label' form_fields['fields'].custom_widget = Text2ListWidget form_fields['stop_words'].custom_widget = Text2ListWidget label = _("Search Engine Optimizer configuration") description = _("seo_configlet_description", default="You can select what " "content types are qSEOptimizer-enabled, and control if " "Dublin Core metatags are exposed in the header of content" " pages.") form_name = _("")
def validateKeywords(self, text): """ see interface """ ts = getToolByName(self.context, 'translation_service') # extract keywords from text if text.lower().strip(): keywords = map(lambda x: x.strip(), text.lower().strip().split('\n')) else: return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'Keywords list is empty!'), context=self.context) # request html page of context object url = '%s?without_metatag_keywords=1' % self.context.absolute_url() # extract words from url page using lynx browser (test page by 'url' randered without metatag keywords) page_text = commands.getoutput('lynx --dump --nolist %s' % url).lower() if page_text and page_text != 'sh: lynx: command not found': page_text = page_text.decode('utf8') else: return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'Could not find lynx browser!'), context=self.context) # check every keyword on appearing in body of html page missing = [] finding = [] added = {} finded = {} for keyword in keywords: keyword = keyword.decode('utf8') if keyword: keyword_on_page = len(re.findall(u'\\b%s\\b' % keyword, page_text, re.I|re.U)) if keyword not in added.keys() and not keyword_on_page: missing.append(keyword+u' - 0') added[keyword] = 1 if keyword not in finded.keys() and keyword_on_page: finding.append(keyword+u' - '+repr(keyword_on_page)) finded[keyword] = 1 # return list of missing and fount keywords if missing or finding: msg = ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'number_keywords'), default=u'Number of keywords at page:\n${found}\n${missing}', mapping={'missing':'\n'.join(missing), 'found': '\n'.join(finding)}, context=self.context) else: msg = '' return msg
def validateSEOProperty(self, property, value): """ Validate a seo property. """ purl = getToolByName(self.context, 'portal_url')() state = '' if property == PROP_PREFIX+'canonical': # validate seo canonical url property pdomain = self.getMainDomain(purl) if not pdomain == self.getMainDomain(value): state = _('canonical_msg', default=u'Canonical URL mast be in ${pdomain} domain.', mapping={'pdomain': pdomain}) return state
def validateKeywords(self): """ see interface """ text = self.request.get('text') ts = getToolByName(self.context, 'translation_service') # extract keywords from text enc = getSiteEncoding(self.context) if text.lower().strip(): keywords = filter(None, map(lambda x: safe_unicode(x.strip(), enc), text.lower().strip().split('\n'))) else: return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'Keywords list is empty!'), context=self.context) # request html page of context object url = '%s?without_metatag_keywords=1' % self.context.absolute_url() # extract words from url page using lynx browser (test page by 'url' # randered without metatag keywords) page_text = commands.getoutput('lynx --dump --nolist %s' % url).lower() if page_text and page_text != 'sh: lynx: command not found': page_text = safe_unicode(page_text, 'utf-8') else: return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'Could not find lynx browser!'), context=self.context) # check every keyword on appearing in body of html page result = [] for keyword in keywords: keyword_on_page = unicode(len(re.findall(u'\\b%s\\b' % keyword, page_text, re.I|re.U))) result.append(' - '.join((keyword, keyword_on_page))) return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'number_keywords', default=u'Number of keywords at page:\n${result}', mapping={'result':'\n'.join(result)}), context=self.context)
def __call__( self ): """ Perform the update seo properties and redirect if necessary, or render the page Call method. """ context = aq_inner(self.context) request = self.request form = self.request.form submitted = form.get('form.submitted', False) if submitted: state = self.manageSEOProps(**form) if not state: state = _('seoproperties_saved', default=u'Content SEO properties have been saved.') context.plone_utils.addPortalMessage(state) kwargs = {'modification_date' : DateTime()} context.plone_utils.contentEdit(context, **kwargs) return request.response.redirect(self.context.absolute_url()) context.plone_utils.addPortalMessage(state, 'error') return self.template()
class ISEOConfigletBaseSchema(Interface): exposeDCMetaTags = Bool( title=_("label_exposeDCMetaTags", default='Expose <abbr title="Dublin Core">DC</abbr> ' 'meta tags'), description=_("description_seo_dc_metatags", default='Controls if <abbr title="Dublin Core">DC</abbr>' ' metatags are exposed to page header. They include ' 'DC.description, DC.type, DC.format, DC.creator and ' 'others.'), default=True, required=False) metatags_order = List( title=_("label_metatags_order", default='Meta tags order in the page.'), description=_("help_metatags_order", default='Fill in meta tags (one per line) in the order ' 'in which they will appear on site source pages. ' 'Example: "metaname accessor".'), required=False) types_seo_enabled = Tuple( title=_("label_content_type_title", default='Content Types'), description=_("description_seo_content_types", default='Select content types that will have SEO ' 'properties enabled.'), required=False, missing_value=tuple(), value_type=Choice( vocabulary="plone.app.vocabularies.ReallyUserFriendlyTypes")) default_custom_metatags = List( title=_("label_default_custom_metatags", default='Default custom metatags.'), description=_("help_default_custom_metatags", default='Fill in custom metatag names (one per line) ' 'which will appear on qseo_properties edit tab. ' 'Example: "metaname|metacontent" or "metaname".'), required=False)
return self.context._type() else: return self.context._type(filter(None, self.splitter.split(input))) def _toFormValue(self, value): if value == self.context.missing_value or \ value == self.context._type(): return self._missing else: return u'\r\n'.join(list(value)) # Fieldset configurations baseset = FormFieldsets(ISEOConfigletBaseSchema) baseset.id = 'seobase' baseset.label = _(u'label_seobase', default=u'Base') advancedset = FormFieldsets(ISEOConfigletAdvancedSchema) advancedset.id = 'seoadvanced' advancedset.label = _(u'label_seoadvanced', default=u'Advanced') class SEOConfiglet(ControlPanelForm): form_fields = FormFieldsets(baseset, advancedset) type_seo_enabled = MultiCheckBoxThreeColumnWidget form_fields['default_custom_metatags'].custom_widget = Text2ListWidget form_fields['metatags_order'].custom_widget = Text2ListWidget form_fields['types_seo_enabled'].custom_widget = type_seo_enabled form_fields['types_seo_enabled'].custom_widget.cssClass = 'label'
if input == self._missing: return self.context._type() else: return self.context._type(filter(None, self.splitter.split(input))) def _toFormValue(self, value): if value == self.context.missing_value or value == self.context._type(): return self._missing else: return u'\r\n'.join(list(value)) # Fieldset configurations baseset = FormFieldsets(ISEOConfigletBaseSchema) baseset.id = 'seobase' baseset.label = _(u'label_seobase', default=u'Base') advancedset = FormFieldsets(ISEOConfigletAdvancedSchema) advancedset.id = 'seoadvanced' advancedset.label = _(u'label_seoadvanced', default=u'Advanced') class SEOConfiglet(ControlPanelForm): form_fields = FormFieldsets(baseset, advancedset) form_fields['default_custom_metatags'].custom_widget = Text2ListWidget form_fields['metatags_order'].custom_widget = Text2ListWidget form_fields['types_seo_enabled'].custom_widget = MultiCheckBoxThreeColumnWidget form_fields['types_seo_enabled'].custom_widget.cssClass='label' form_fields['fields'].custom_widget = Text2ListWidget form_fields['stop_words'].custom_widget = Text2ListWidget
finally: resp.close() except (urllib2.URLError, urllib2.HTTPError), e: # In case of exceed timeout period or other URL connection errors. # Get nearest to context error_log object (stolen from Zope2/App/startup.py) html = None info = sys.exc_info() elog = getToolByName(self.context, "error_log") error_url = elog.raising(info) else: html = unicode(self.context()).encode(enc) # If no html - information about problem with page retrieval should be returned result = [] if html is None: result.append("Problem with page retrieval.") if error_url: result.append("Details at %s." % error_url) else: page_text = transforms.convert("html_to_text", html).getData() # check every keyword on appearing in body of html page for keyword in keywords: keyword_on_page = unicode(len(re.findall(u'\\b%s\\b' % keyword, page_text, re.I|re.U))) result.append(' - '.join((keyword, keyword_on_page))) return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'number_keywords', default=u'Number of keywords at page:\n${result}', mapping={'result':'\n'.join(result)}), context=self.context)
if input == self._missing: return self.context._type() else: return self.context._type(filter(None, self.splitter.split(input))) def _toFormValue(self, value): if value == self.context.missing_value or value == self.context._type(): return self._missing else: return u"\r\n".join(list(value)) # Fieldset configurations baseset = FormFieldsets(ISEOConfigletBaseSchema) baseset.id = "seobase" baseset.label = _(u"label_seobase", default=u"Base") advancedset = FormFieldsets(ISEOConfigletAdvancedSchema) advancedset.id = "seoadvanced" advancedset.label = _(u"label_seoadvanced", default=u"Advanced") class SEOConfiglet(ControlPanelForm): form_fields = FormFieldsets(baseset, advancedset) type_seo_enabled = MultiCheckBoxThreeColumnWidget form_fields["default_custom_metatags"].custom_widget = Text2ListWidget form_fields["metatags_order"].custom_widget = Text2ListWidget form_fields["types_seo_enabled"].custom_widget = type_seo_enabled form_fields["types_seo_enabled"].custom_widget.cssClass = "label"
def validateKeywords(self): """ see interface """ text = self.request.get('text') ts = getToolByName(self.context, 'translation_service') transforms = getUtility(IPortalTransformsTool) portal = getToolByName(self.context, 'portal_url').getPortalObject() query_adapter = queryAdapter(portal, ISEOConfigletSchema) isExternal = query_adapter.external_keywords_test # extract keywords from text enc = getSiteEncoding(self.context) if text.lower().strip(): keywords = filter(None, map(lambda x: safe_unicode(x.strip(), enc), text.lower().strip().split('\n'))) else: return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'Keywords list is empty!'), context=self.context) # Get html page internally or with external request error_url = "" if isExternal: # Not pass timeout option because: # 1. its value get from the global default timeout settings. # 2. timeout option added in python 2.6 # (so acceptable only in plone4+) try: resp = urllib2.urlopen(self.context.absolute_url()) try: html = resp.read() finally: resp.close() except (urllib2.URLError, urllib2.HTTPError): # In case of exceed timeout period or # other URL connection errors. # Get nearest to context error_log object # (stolen from Zope2/App/startup.py) html = None info = sys.exc_info() elog = getToolByName(self.context, "error_log") error_url = elog.raising(info) else: html = unicode(self.context()).encode(enc) # If no html - information about problem with page retrieval # should be returned result = [] if html is None: result.append("Problem with page retrieval.") if error_url: result.append("Details at %s." % error_url) else: page_text = transforms.convert("html_to_text", html).getData() # check every keyword on appearing in body of html page for keyword in keywords: keyword_on_page = unicode(len(re.findall(u'\\b%s\\b' % keyword, page_text, re.I | re.U))) result.append(' - '.join((keyword, keyword_on_page))) return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'number_keywords', default=u'Number of keywords at page:\n' '${result}', mapping={'result': '\n'.join(result)}), context=self.context)
def validateKeywords(self): """ see interface """ text = self.request.get('text') ts = getToolByName(self.context, 'translation_service') transforms = getUtility(IPortalTransformsTool) portal = getToolByName(self.context, 'portal_url').getPortalObject() query_adapter = queryAdapter(portal, ISEOConfigletSchema) isExternal = query_adapter.external_keywords_test # extract keywords from text enc = getSiteEncoding(self.context) if text.lower().strip(): keywords = filter( None, map(lambda x: safe_unicode(x.strip(), enc), text.lower().strip().split('\n'))) else: return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'Keywords list is empty!'), context=self.context) # Get html page internally or with external request error_url = "" if isExternal: # Not pass timeout option because: # 1. its value get from the global default timeout settings. # 2. timeout option added in python 2.6 # (so acceptable only in plone4+) try: resp = urllib2.urlopen(self.context.absolute_url()) try: html = resp.read() finally: resp.close() except (urllib2.URLError, urllib2.HTTPError): # In case of exceed timeout period or # other URL connection errors. # Get nearest to context error_log object # (stolen from Zope2/App/startup.py) html = None info = sys.exc_info() elog = getToolByName(self.context, "error_log") error_url = elog.raising(info) else: html = unicode(self.context()).encode(enc) # If no html - information about problem with page retrieval # should be returned result = [] if html is None: result.append("Problem with page retrieval.") if error_url: result.append("Details at %s." % error_url) else: page_text = transforms.convert("html_to_text", html).getData() # check every keyword on appearing in body of html page for keyword in keywords: keyword_on_page = unicode( len( re.findall(u'\\b%s\\b' % keyword, page_text, re.I | re.U))) result.append(' - '.join((keyword, keyword_on_page))) return ts.utranslate(domain='quintagroup.seoptimizer', msgid=_(u'number_keywords', default=u'Number of keywords at page:\n' '${result}', mapping={'result': '\n'.join(result)}), context=self.context)