class IRule(form.Schema): source_path = TextLine( title=_(u'label_source_path', default=u'Source Path')) destination = TextLine( title=_(u'label_destination', default=u'Destination'))
def validate_source_path(self, rownum, value): if not value: raise Invalid( _(u'source_path_required', default=u'Row ${rownum}: source path required.', mapping={'rownum': rownum})) if value == '/': raise Invalid( _(u'source_path_invalid_root', default=u'Row ${rownum}: invalid source path: cannot' u' redirect from root.', mapping={'rownum': rownum})) if value.startswith('/'): return raise Invalid( _(u'source_path_must_start_with_slash', default=u'Row ${rownum}: the source path "${value}"' u' must start with a slash.', mapping={ 'rownum': rownum, 'value': value }))
def create_rules_excel(): portal = api.portal.get() request = portal.REQUEST rules = IRedirectConfig(portal).rules if not rules: rules = [] book = Workbook() sheet = book.active title = translate(_(u'Redirect Configuration'), context=request) source_title = translate(_(u'label_source_path', default=u'Source Path'), context=request) destination_title = translate(_(u'label_destination', default=u'Destination'), context=request) # HEADER sheet.title = title bold = Font(bold=True) cell = sheet.cell(column=1, row=1) cell.font = bold cell.value = source_title cell = sheet.cell(column=2, row=1) cell.font = bold cell.value = destination_title # DATA for rule_nr, rule in enumerate(rules): cell = sheet.cell(column=1, row=RULES_START_ROW + rule_nr) cell.value = rule['source_path'] cell = sheet.cell(column=2, row=RULES_START_ROW + rule_nr) cell.value = rule['destination'] # match the width to the longest entry for column in sheet.columns: maxwidth = 0 for cell in column: if not cell.value: continue cwidth = len(cell.value) maxwidth = cwidth if cwidth > maxwidth else maxwidth # a bit more space for readability sheet.column_dimensions[cell.column].width = maxwidth + 5 return save_virtual_workbook(book)
def create_rules_excel(): portal = api.portal.get() request = portal.REQUEST rules = IRedirectConfig(portal).rules if not rules: rules = [] book = Workbook() sheet = book.active title = translate(_(u'Redirect Configuration'), context=request) source_title = translate(_(u'label_source_path', default=u'Source Path'), context=request) destination_title = translate(_(u'label_destination', default=u'Destination'), context=request) # HEADER sheet.title = title bold = Font(bold=True) cell = sheet.cell(column=1, row=1) cell.font = bold cell.value = source_title cell = sheet.cell(column=2, row=1) cell.font = bold cell.value = destination_title # DATA for rule_nr, rule in enumerate(rules): cell = sheet.cell(column=1, row=RULES_START_ROW+rule_nr) cell.value = rule['source_path'] cell = sheet.cell(column=2, row=RULES_START_ROW+rule_nr) cell.value = rule['destination'] # match the width to the longest entry for column in sheet.columns: maxwidth = 0 for cell in column: if not cell.value: continue cwidth = len(cell.value) maxwidth = cwidth if cwidth > maxwidth else maxwidth # a bit more space for readability sheet.column_dimensions[cell.column].width = maxwidth + 5 return save_virtual_workbook(book)
class ImportRedirectConfigView(form.SchemaForm): schema = IRulesUploadSchema ignoreContext = True label = _(u"Upload redirect config") def updateWidgets(self): # use the basic widget to disable "keep existing file" self.fields['rules_file'].widgetFactory = ForceFileUploadFieldWidget super(ImportRedirectConfigView, self).updateWidgets() @button.buttonAndHandler(u'Upload') def handleApply(self, action): data, errors = self.extractData() if errors: # since we have only one field we can copy the error message # to make it more visible self.status = errors[0].message return excel_file = StringIO(data['rules_file'].data) rules = load_rules_from_excel(excel_file) rconfig = IRedirectConfig(self.context) rconfig.rules = rules messages = IStatusMessage(self.request) messages.add(_("The redirect config has been replaced."), type=u'info') self.request.RESPONSE.redirect(self.context.absolute_url())
def validate(self, value): if not value: raise Invalid(_(u'missing_input_data', default=u'Please upload a rules excel file.')) excel_file = StringIO(value.data) rules = load_rules_from_excel(excel_file) map(self.validate_row, enumerate(rules, RULES_START_ROW))
def validate_destination(self, rownum, value): if not value: raise Invalid( _(u'destination_required', default=u'Row ${rownum}: destination required.', mapping={'rownum': rownum})) if value.startswith('/'): return if re.match(r'^https?://', value): return raise Invalid( _(u'destination_must_be_path_or_url', default=u'Row ${rownum}: the destination "${value}"' u' must be a path (start with slash)' u' or a full qualified URL.', mapping={'rownum': rownum, 'value': value}))
def validate_destination(self, rownum, value): if not value: raise Invalid( _(u'destination_required', default=u'Row ${rownum}: destination required.', mapping={'rownum': rownum})) if value.startswith('/'): return if re.match(r'^https?://', value): return raise Invalid( _(u'destination_must_be_path_or_url', default=u'Row ${rownum}: the destination "${value}"' u' must be a path (start with slash)' u' or a full qualified URL.', mapping={ 'rownum': rownum, 'value': value }))
def validate_source_path(self, rownum, value): if not value: raise Invalid( _(u'source_path_required', default=u'Row ${rownum}: source path required.', mapping={'rownum': rownum})) if value == '/': raise Invalid( _(u'source_path_invalid_root', default=u'Row ${rownum}: invalid source path: cannot' u' redirect from root.', mapping={'rownum': rownum})) if value.startswith('/'): return raise Invalid( _(u'source_path_must_start_with_slash', default=u'Row ${rownum}: the source path "${value}"' u' must start with a slash.', mapping={'rownum': rownum, 'value': value}))
def handleApply(self, action): data, errors = self.extractData() if errors: # since we have only one field we can copy the error message # to make it more visible self.status = errors[0].message return excel_file = StringIO(data['rules_file'].data) rules = load_rules_from_excel(excel_file) rconfig = IRedirectConfig(self.context) rconfig.rules = rules messages = IStatusMessage(self.request) messages.add(_("The redirect config has been replaced."), type=u'info') self.request.RESPONSE.redirect(self.context.absolute_url())
class IRulesUploadSchema(form.Schema): form.primary('rules_file') rules_file = NamedBlobFile( title=_(u'redirect_config_file', default=u'Excel redirect config'), required=True)
class IRedirectConfigSchema(form.Schema): form.widget('rules', DataGridFieldFactory, allow_reorder=True) rules = List(title=_(u'label_redirect_rules', default=u'Redirect rules'), value_type=DictRow(schema=IRule), description=RULES_DESCRIPTION)
def Title(self): return _(u'Redirect Configuration')
from z3c.form.validator import SimpleFieldValidator from z3c.form.validator import WidgetValidatorDiscriminators from zope.component import adapter from zope.i18nmessageid import Message from zope.interface import alsoProvides from zope.interface import implementer from zope.interface import implements from zope.interface import Invalid from zope.schema import List from zope.schema import TextLine import re REDIRECT_CONFIG_ID = 'redirect-config' RULES = dict((u'm{}'.format(idx), msg) for (idx, msg) in enumerate(( _(u'Redirects are only applied if no content is found (404).'), _(u'Redirect rules are applied top-down: top roles have higher' u' priority. The first matching rule is applied, later rules are' u' not considered.'), _(u'Redirects match when the request path starts with the' u' source path.'), _(u'Each rule requires a source path and a destination.'), _(u'The source path must start with a slash and should not' u' be the site root.'), _(u'The destination may be a path (starting with a slash)' u' or an URL to an external site.'), ))) RULES_DESCRIPTION = Message( u'<ul>' + ''.join('<li>${%s}</li>' % key for key in sorted(RULES.keys())) + u'</ul>',
from zope.interface import implementer from zope.interface import implements from zope.interface import Invalid from zope.schema import List from zope.schema import TextLine import re REDIRECT_CONFIG_ID = 'redirect-config' RULES = dict( (u'm{}'.format(idx), msg) for (idx, msg) in enumerate(( _(u'Redirects are only applied if no content is found (404).'), _(u'Redirect rules are applied top-down: top roles have higher' u' priority. The first matching rule is applied, later rules are' u' not considered.'), _(u'Redirects match when the request path starts with the' u' source path.'), _(u'Each rule requires a source path and a destination.'), _(u'The source path must start with a slash and should not' u' be the site root.'), _(u'The destination may be a path (starting with a slash)' u' or an URL to an external site.'), ))) RULES_DESCRIPTION = Message( u'<ul>' +