def _save(self): form = self.request.form context = self.context label = form.get('label') _ = getToolByName(context, 'translation_service').utranslate if form.get('row-index') is not None and form.get('addLabel'): # adding new but not in the last line index = form.get('row-index') self.storage.add({'__label__': label, '__uuid__': str(uuid.uuid4())}, index) self._addNewVersion(_(msgid="Label added", domain="collective.tablepage", context=context)) elif form.get('row-index') is not None: # updating label index = form.get('row-index') self.storage.update(index, {'__label__': label}) self._addNewVersion(_(msgid="Label changed", domain="collective.tablepage", context=context)) else: self.storage.add({'__label__': label, '__uuid__': str(uuid.uuid4())}) self._addNewVersion(_(msgid="Label added", domain="collective.tablepage", context=context))
def __call__(self, *args, **kwargs): request = self.request form = request.form context = self.context putils = getToolByName(context, 'plone_utils') b_start = form.get('b_start', None) if not self.check_labeling_permission(): raise Unauthorized("You can't modify the label") if form.get('cancel'): return request.response.redirect( "%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) if form.get('form.submitted'): if not form.get('label'): putils.addPortalMessage(_('Label is required'), type="error") return request.response.redirect( "%s/edit-label%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) # saving self._save() putils.addPortalMessage(_('Label has been saved')) return request.response.redirect( "%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) elif form.get('row-index') is not None and not form.get('addLabel'): # load an existing row self.data = self.storage[form.get('row-index')].get( '__label__', '') return self.index()
def __call__(self, context): terms = [SimpleTerm(value='SearchableText', token='SearchableText', title=_(u'Use in full text search')), SimpleTerm(value='single_value', token='single_value', title=_(u'Single value search')), ] return SimpleVocabulary(terms)
def __call__(self): form = self.request.form context = self.context index = form.get('row-index') direction = form.get('direction') b_start = form.get('b_start', None) if index is not None and direction in ('up', 'down'): tp_catalog = getToolByName(context, config.CATALOG_ID) direction = direction=='up' and -1 or 1 storage = self.storage row = storage[index] del storage[index] storage.add(row, index+direction) tp_catalog.reindex_rows(context, [row['__uuid__'], storage[index]['__uuid__']]) putils = getToolByName(context, 'plone_utils') _ = getToolByName(context, 'translation_service').utranslate putils.addPortalMessage(_(msgid='Row has been moved', domain="collective.tablepage", context=context)) # if the table is changed, the content is changed self._addNewVersion(_(msgid="Row moved", domain="collective.tablepage", context=context)) self.request.response.redirect("%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or ''))
def validate_pageColumns(self, value): """Need to check some table format""" ids = [] for record in value: # do not validate the hidden empty row if record.get("orderindex_").isdigit(): id = record.get("id", "") try: ids.index(id) return _( "pagecolumn_validation_error_duplicated_id", default=u'Id "${col_name}" is duplicated', mapping={"col_name": id}, ) except ValueError: ids.append(id) if not re.match(r"^[a-zA-Z][a-zA-Z0-9.\-_]*$", id): return _( "pagecolumn_validation_error_id_format", default=u'Invalid value: "${col_name}". "Column Id" must not contains special characters', mapping={"col_name": id}, ) if id in config.RESERVED_IDS: return _( "pagecolumn_validation_error_id_invalid", default=u'A reserved value has been used for "id"' )
def render_view(self, data, index=None, storage=None): """When in view, render data in the proper monetary (and localized) format""" self.data = data or '' if self.data: try: float(self.data) except ValueError: # Do not continue return self.data parts = self.data.split('.') try: i_data = int(parts[0]) except ValueError: return self.view_template(data='') i_data = self.intWithCommas(i_data) if len(parts) > 1: dec_data = parts[1] else: dec_data = '00' if len(dec_data) < 2: dec_data = dec_data + "0" dec_data = dec_data[0:2] decimal_separator = translate(_('decimal_separator', default="."), context=self.request) monetary_sign = translate(_('monetary_sign', default="$"), context=self.request) self.data = "%s %s%s%s" % (monetary_sign, i_data, decimal_separator, dec_data) return self.view_template(data=self.data) return ''
def _save(self): form = self.request.form context = self.context label = form.get('label') _ = getToolByName(context, 'translation_service').utranslate if form.get('row-index') is not None and form.get('addLabel'): # adding new but not in the last line index = form.get('row-index') self.storage.add( { '__label__': label, '__uuid__': str(uuid.uuid4()) }, index) self._addNewVersion( _(msgid="Label added", domain="collective.tablepage", context=context)) elif form.get('row-index') is not None: # updating label index = form.get('row-index') self.storage.update(index, {'__label__': label}) self._addNewVersion( _(msgid="Label changed", domain="collective.tablepage", context=context)) else: self.storage.add({ '__label__': label, '__uuid__': str(uuid.uuid4()) }) self._addNewVersion( _(msgid="Label added", domain="collective.tablepage", context=context))
def __call__(self, *args, **kwargs): request = self.request form = request.form context = self.context putils = getToolByName(context, 'plone_utils') b_start = form.get('b_start', None) if not self.check_labeling_permission(): raise Unauthorized("You can't modify the label") if form.get('cancel'): return request.response.redirect("%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) if form.get('form.submitted'): if not form.get('label'): putils.addPortalMessage(_('Label is required'), type="error") return request.response.redirect("%s/edit-label%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) # saving self._save() putils.addPortalMessage(_('Label has been saved')) return request.response.redirect("%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) elif form.get('row-index') is not None and not form.get('addLabel'): # load an existing row self.data = self.storage[form.get('row-index')].get('__label__', '') return self.index()
def __call__(self): form = self.request.form context = self.context index = form.get('row-index') direction = form.get('direction') b_start = form.get('b_start', None) if index is not None and direction in ('up', 'down'): tp_catalog = getToolByName(context, config.CATALOG_ID) direction = direction == 'up' and -1 or 1 storage = self.storage row = storage[index] del storage[index] storage.add(row, index + direction) tp_catalog.reindex_rows( context, [row['__uuid__'], storage[index]['__uuid__']]) putils = getToolByName(context, 'plone_utils') _ = getToolByName(context, 'translation_service').utranslate putils.addPortalMessage( _(msgid='Row has been moved', domain="collective.tablepage", context=context)) # if the table is changed, the content is changed self._addNewVersion( _(msgid="Row moved", domain="collective.tablepage", context=context)) self.request.response.redirect( "%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or ''))
def showHeadersVocabulary(self): return atapi.DisplayList( ( ("view_only", _("... only on page view")), ("edit_only", _("... only when editing table")), ("always", _("... always display")), ) )
def __call__(self, context): request = context.REQUEST adapters = getAdapters((context, context.REQUEST), IColumnField) elements = [a[0] for a in adapters] elements.sort(cmp=lambda x, y: cmp(translate(_(x), context=request), translate(_(y), context=request))) terms = [SimpleTerm(value=e, token=e, title=_(e)) for e in elements] return SimpleVocabulary(terms)
def __call__(self, context): request = context.REQUEST adapters = getAdapters((context, context.REQUEST), IColumnField) elements = [a[0] for a in adapters] elements.sort(cmp=lambda x,y: cmp(translate(_(x), context=request), translate(_(y), context=request))) terms = [SimpleTerm(value=e, token=e, title=_(e)) for e in elements] return SimpleVocabulary(terms)
def __call__(self, context): terms = [ SimpleTerm(value='required', token='required', title=_('row_options_required', default=u'Required')), SimpleTerm(value='unique', token='unique', title=_('row_options_unique', default=u'Unique')), # SimpleTerm(value='enforceVocabulary', token='enforceVocabulary', title=_('row_options_enforceVocabulary', # default=u'Fulfil vocabulary')), ] return SimpleVocabulary(terms)
def __call__(self, context): terms = [ SimpleTerm(value='SearchableText', token='SearchableText', title=_(u'Use in full text search')), SimpleTerm(value='single_value', token='single_value', title=_(u'Single value search')), ] return SimpleVocabulary(terms)
def __call__(self): context = self.context request = self.request indexes = self.request.form.get('row-index') b_start = request.form.get('b_start', None) tp_catalog = getToolByName(context, config.CATALOG_ID) if indexes is not None: member = getMultiAdapter((context, request), name=u'plone_portal_state').member() putils = getToolByName(context, 'plone_utils') _ = getToolByName(context, 'translation_service').utranslate sm = getSecurityManager() # check permissions: must be the owner user or have the "Manage table" permission storage = self.storage if isinstance(indexes, int): # we get an int when clicking on single row delete command indexes = [ indexes, ] for c, index in enumerate(indexes): if not sm.checkPermission(config.MANAGE_TABLE, context) \ and member.getId()!=storage[index-c].get('__creator__'): raise Unauthorized("You can't delete that record") tp_catalog.uncatalog_row(context, storage[index - c].get('__uuid__')) del storage[index - c] # Now we need to reindex all rows that follow, to fill the hole min_index = min(indexes) self._reindex_following(min_index - c) if len(indexes) == 1: msg = _(msgid="Row deleted", domain="collective.tablepage", context=context) else: msg = _(msgid='${count} rows deleted', domain="collective.tablepage", mapping={'count': len(indexes)}, context=context) putils.addPortalMessage(msg) # if the table is changed, the content is changed self._addNewVersion(msg) request.response.redirect( "%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or ''))
def __call__(self, *args, **kwargs): context = self.context request = self.request form = request.form self.row_index = form.get('row-index', None) b_start = form.get('b_start', None) if form.get('cancel'): request.response.redirect( "%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) return if form.get('form.submitted'): # saving putils = getToolByName(context, 'plone_utils') self._save() if self.errors: del form['form.submitted'] self.data.update(**form) return self.index() putils.addPortalMessage(_('Row has been saved')) request.response.redirect( "%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) return elif self.row_index is not None and not form.get('addRow'): # load an existing row if not self.check_manager_or_mine_record(self.row_index): raise Unauthorized("You can't modify that record") else: self.data = self.storage[self.row_index] return self.index()
def __call__(self, *args, **kwargs): context = self.context request = self.request catalog = getToolByName(context, config.CATALOG_ID) storage = IDataStorage(context) # now we load the tabel view and rebuild all rows by using the ignore_cache parameter table_view = getMultiAdapter((context, request), name=u'view-table') table_view.rows(ignore_cache=True) for index, row in enumerate(storage): uuid = row.get('__uuid__') if not uuid: # this should not happen logger.warning( "Row without an uuid! index %d, document at %s" % (index, context.absolute_url_path())) continue catalog.reindex_rows(context, uuid, storage) if index and index % 100 == 0: logger.info("Refreshing catalog (%d)" % index) transaction.savepoint() logger.info("Refreshing catalog and caches: done") getToolByName(context, 'plone_utils').addPortalMessage( _('reindex_performed_message', u'$count rows has been updated', mapping={'count': index + 1})) request.response.redirect('%s/edit-table' % context.absolute_url())
def __call__(self, *args, **kwargs): context = self.context request = self.request form = request.form self.row_index = form.get('row-index', None) b_start = form.get('b_start', None) if form.get('cancel'): request.response.redirect("%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) return if form.get('form.submitted'): # saving putils = getToolByName(context, 'plone_utils') self._save() if self.errors: del form['form.submitted'] self.data.update(**form) return self.index() putils.addPortalMessage(_('Row has been saved')) request.response.redirect("%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or '')) return elif self.row_index is not None and not form.get('addRow'): # load an existing row if not self.check_manager_or_mine_record(self.row_index): raise Unauthorized("You can't modify that record") else: self.data = self.storage[self.row_index] return self.index()
def validate(self, configuration, data=None): data = data or self.field.request.form.get(configuration['id'], '') if data: ptool = getToolByName(self.field.context, 'plone_utils') if ptool.validateEmailAddresses(data): return return _('error_field_not_email', default='The field "$name" is not a valid e-mail address', mapping={'name': configuration.get('label', configuration['id']).decode('utf-8')})
def validate(self, configuration, data=None): if 'required' not in configuration.get('options', []): return None form = self.field.request.form field_id = configuration['id'] if not form.get("%s_0" % field_id) and not form.get('existing_%s' % field_id) and not data: return _('error_field_required', default='The field "$name" is required', mapping={'name': configuration.get('label', configuration['id']).decode('utf-8')})
def __call__(self, context): configuration = context.getPageColumns() adaptables = [x[0] for x in getUtilitiesFor(ISearchableColumn)] terms = [SimpleTerm(value='SearchableText', token='SearchableText', title=_(u'Search in text'))] for conf in configuration: if conf['type'] in adaptables: terms.append(SimpleTerm(value=conf['id'], token=conf['id'], title=conf['label'])) return SimpleVocabulary(terms)
def get_from_request(self, name, request): if request.get(name) and request.get(name).filename: folder = self.context.getAttachmentStorage() or aq_parent(aq_inner(self.context)) title = request.get('title_%s' % name) description = request.get('description_%s' % name) file = request.get(name) newId = folder.generateUniqueId(self.portal_type) plone_utils = getToolByName(self.context, 'plone_utils') if not title and file.filename in folder.objectIds(): # WARNING: we don't get the file title, to obtain the id plone_utils.addPortalMessage(_('duplicate_file_error_with_link', default=u'There is already an item named ${name} in this folder.\n' u'Loading of the new attachment has been aborted ' u'and a reference to that existing file has been created.', mapping={'name': file.filename}), type='warning') return {name: folder[file.filename].UID()} folder.invokeFactory(id=newId, type_name=self.portal_type, title=title, description=description) new_doc = folder[newId] if HAS_DEXTERITY and IDexterityContent.providedBy(new_doc): setattr(new_doc, self.field_name, self.field_value_class(file, filename=unicode(file.filename))) modified(new_doc) if not folder.has_key(file.filename): folder.manage_renameObject(new_doc.getId(), file.filename) else: # force rename (processForm will not work with files) new_doc._renameAfterCreation() # this will trigger proper lifecycle events new_doc.processForm() try: new_doc.edit(**{self.field_name: file}) except BadRequest: # Still don't get how, but sometimes this happen (at least on Plone 3) plone_utils.addPortalMessage(_('duplicate_file_critical_error', default=u'There is already an item named ${name} in this folder.\n' u'Loading of the attachment has been aborted.', mapping={'name': file.filename}), type='error') return None return {name: new_doc.UID()} elif request.get("existing_%s" % name): return {name: request.get("existing_%s" % name)} return {name: ''}
def validate(self, configuration, data=None): data = data or self.field.request.form.get(configuration['id'], '') if data: try: float(data) return except ValueError: return _('error_field_not_number', default='The value "$value" is not numeric', mapping={'value': data.decode('utf-8')})
def validate(self, configuration, data=None): col_id = configuration['id'] self.field.configuration = configuration vocabulary = self.field.vocabulary() data = data or self.field.request.form.get(col_id) if data and data not in vocabulary: return _('error_enforce_vocabulary', default='The field "$name" does not fit any of the vocabulary values', mapping={'name': configuration.get('label', col_id).decode('utf-8')})
def __call__(self): context = self.context request = self.request indexes = self.request.form.get('row-index') b_start = request.form.get('b_start', None) tp_catalog = getToolByName(context, config.CATALOG_ID) if indexes is not None: member = getMultiAdapter((context, request), name=u'plone_portal_state').member() putils = getToolByName(context, 'plone_utils') _ = getToolByName(context, 'translation_service').utranslate sm = getSecurityManager() # check permissions: must be the owner user or have the "Manage table" permission storage = self.storage if isinstance(indexes, int): # we get an int when clicking on single row delete command indexes = [indexes,] for c, index in enumerate(indexes): if not sm.checkPermission(config.MANAGE_TABLE, context) \ and member.getId()!=storage[index-c].get('__creator__'): raise Unauthorized("You can't delete that record") tp_catalog.uncatalog_row(context, storage[index-c].get('__uuid__')) del storage[index-c] # Now we need to reindex all rows that follow, to fill the hole min_index = min(indexes) self._reindex_following(min_index-c) if len(indexes)==1: msg = _(msgid="Row deleted", domain="collective.tablepage", context=context) else: msg = _(msgid='${count} rows deleted', domain="collective.tablepage", mapping={'count': len(indexes)}, context=context) putils.addPortalMessage(msg) # if the table is changed, the content is changed self._addNewVersion(msg) request.response.redirect("%s/edit-table%s" % (context.absolute_url(), b_start and '?b_start:int=%d' % b_start or ''))
def intWithCommas(self, x): if x < 0: return '-' + self.intWithCommas(-x) result = '' while x >= 1000: x, r = divmod(x, 1000) thousand_separator = translate(_('thousand_separator', default=","), context=self.request) result = "%s%03d%s" % (thousand_separator, r, result) return "%d%s" % (x, result)
def validate(self, configuration, data=None): if 'required' not in configuration.get('options', []): return None if not data and not self.field.request.form.get(configuration['id']): return _('error_field_required', default='The field "$name" is required', mapping={ 'name': configuration.get('label', configuration['id']).decode('utf-8') })
def validate_pageColumns(self, value): """Need to check some table format""" ids = [] for record in value: # do not validate the hidden empty row if record.get('orderindex_').isdigit(): id = record.get('id', '') try: ids.index(id) return _('pagecolumn_validation_error_duplicated_id', default=u'Id "${col_name}" is duplicated', mapping={'col_name': id}) except ValueError: ids.append(id) if not re.match(r"^[a-zA-Z][a-zA-Z0-9.\-_]*$", id): return _('pagecolumn_validation_error_id_format', default=u'Invalid value: "${col_name}". "Column Id" must not contains special characters', mapping={'col_name': id}) if id in config.RESERVED_IDS: return _('pagecolumn_validation_error_id_invalid', default=u'A reserved value has been used for "id"')
def validate(self, configuration, data=None): col_id = configuration['id'] self.field.configuration = configuration vocabulary = self.field.vocabulary() data = data or self.field.request.form.get(col_id) if data and data.decode("utf-8") not in vocabulary: return _( 'error_enforce_vocabulary', default= 'The field "$name" does not fit any of the vocabulary values', mapping={ 'name': configuration.get('label', col_id).decode('utf-8') })
def validate(self, configuration, data=None): if 'unique' not in configuration.get('options', []): return None col_id = configuration['id'] data = data or self.field.request.form.get(col_id) if data: context = self.field.context storage = IDataStorage(context) for i, row in enumerate(storage): if i!=self.field.request.form.get('row-index') and row.get(col_id)==data: return _('error_field_unique', default='The value "$value" is already present in the column \"$name\"', mapping={'name': configuration.get('label', col_id).decode('utf-8'), 'value': data.decode('utf-8')})
def __init__(self, context, request): BaseField.__init__(self, context, request) self.rows = 5 self.widget = RichWidget(description='', label=_('Html'), filter_buttons=( 'tablecontrols', 'code', 'fullscreen', 'attribs', ), rows=25, allow_file_upload=False)
def validate(self, configuration, data=None): data = data or self.field.request.form.get(configuration['id'], '') if data: ptool = getToolByName(self.field.context, 'plone_utils') if ptool.validateEmailAddresses(data): return return _('error_field_not_email', default='The field "$name" is not a valid e-mail address', mapping={ 'name': configuration.get('label', configuration['id']).decode('utf-8') })
def get_from_request(self, name, request): if request.get(name) and request.get(name).filename: folder = self.context.getAttachmentStorage() or aq_parent(aq_inner(self.context)) title = request.get('title_%s' % name) description = request.get('description_%s' % name) file = request.get(name) newId = folder.generateUniqueId(TYPE_TO_CREATE) if not title and file.filename in folder.objectIds(): # WARNING: we don't get the file title, to obtain the id plone_utils = getToolByName(self.context, 'plone_utils') plone_utils.addPortalMessage(_('duplicate_file_error_with_link', default=u'There is already an item named ${name} in this folder.\n' u'Loading of the new attachment has been aborted ' u'and a reference to that existing file has been created.', mapping={'name': file.filename}), type='warning') return {name: folder[file.filename].UID()} folder.invokeFactory(id=newId, type_name=TYPE_TO_CREATE, title=title, description=description) new_doc = folder[newId] # force rename (processForm will not work with files) new_doc._renameAfterCreation() # this will trigger proper lifecycle events new_doc.processForm() try: new_doc.edit(file=file) except BadRequest: # Still don't get how, but sometimes this happen (at least on Plone 3) plone_utils.addPortalMessage(_('duplicate_file_critical_error', default=u'There is already an item named ${name} in this folder.\n' u'Loading of the attachment has been aborted.', mapping={'name': file.filename}), type='error') return None return {name: new_doc.UID()} elif request.get("existing_%s" % name): return {name: request.get("existing_%s" % name)} return {name: ''}
def validate_searchConfig(self, value): """Need to check table page ids""" ids = [] for record in value: # do not validate the hidden empty row if record.get('orderindex_').isdigit(): id = record.get('id', '') try: ids.index(id) return _('searchconfig_validation_error_duplicated_id', default=u'The column "${col_name}" has already been used', mapping={'col_name': id}) except ValueError: ids.append(id)
def validate(self, configuration, data=None): if 'required' not in configuration.get('options', []): return None form = self.field.request.form field_id = configuration['id'] if not form.get("external_%s" % field_id) and not form.get( 'internal_%s' % field_id) and not data: return _('error_field_required', default='The field "$name" is required', mapping={ 'name': configuration.get('label', configuration['id']).decode('utf-8') })
def __call__(self, context): configuration = context.getPageColumns() adaptables = [x[0] for x in getUtilitiesFor(ISearchableColumn)] terms = [ SimpleTerm(value='SearchableText', token='SearchableText', title=_(u'Search in text')) ] for conf in configuration: if conf['type'] in adaptables: terms.append( SimpleTerm(value=conf['id'], token=conf['id'], title=conf['label'])) return SimpleVocabulary(terms)
def render_view(self, data, index=None, storage=None): """When in view, render data in the proper monetary (and localized) format""" self.data = data or '' if self.data: try: float(self.data) except ValueError: # Do not continue return self.data parts = self.data.split('.') try: i_data = int(parts[0]) except ValueError: return self.view_template(data='') i_data = self.intWithCommas(i_data) if len(parts)>1: dec_data = parts[1] else: dec_data = '00' if len(dec_data)<2: dec_data = dec_data + "0" dec_data = dec_data[0:2] decimal_separator = translate(_('decimal_separator', default="."), context=self.request) monetary_sign = translate(_('monetary_sign', default="$"), context=self.request) self.data = "%s %s%s%s" % (monetary_sign, i_data, decimal_separator, dec_data) return self.view_template(data=self.data) return ''
def checkSearchConfig(context, event): """Warn user if tablepage_catalog configuration is not proper""" sm = getSecurityManager() if not sm.checkPermission(MANAGE_SEARCH_PERMISSION, context): return tp_catalog = getToolByName(context, 'tablepage_catalog') indexes = tp_catalog.indexes() warn_fields = [] for conf in context.getSearchConfig(): if conf['id'] not in indexes: warn_fields.append(conf['id']) if warn_fields: putils = getToolByName(context, 'plone_utils') putils.addPortalMessage(_('bad_configured_search_cols', default=u"There are columns ($cols) defined as searchable but no indexes " u"with same has been found in the tablepage_catalog tool.\n" u"Search form will use them.", mapping={'cols': ', '.join(warn_fields)}), type="warning")
def get_from_request(self, name, request): results = [] context = self.context folder = context.getAttachmentStorage() or aq_parent(aq_inner(context)) plone_utils = getToolByName(context, 'plone_utils') # first of all we need also to check for existings selected files for existing_selection in request.get("existing_%s" % name, []): results.append(existing_selection) cnt = 0 while True: if request.get("%s_%s" % (name, cnt)) and request.get("%s_%s" % (name, cnt)).filename: title = request.get('title_%s_%s' % (name, cnt)) description = request.get('description_%s_%s' % (name, cnt)) file = request.get("%s_%s" % (name, cnt)) cnt += 1 newId = folder.generateUniqueId(self.portal_type) if not title and file.filename in folder.objectIds(): # WARNING: we don't get the file title, to obtain the id plone_utils.addPortalMessage(_('duplicate_file_error', default=u'There is already an item named ${name} in this folder.\n' u'Loading of the attachment has been aborted.', mapping={'name': file.filename}), type='warning') results.append(folder[file.filename].UID()) continue folder.invokeFactory(id=newId, type_name=self.portal_type, title=title, description=description) new_doc = folder[newId] if HAS_DEXTERITY and IDexterityContent.providedBy(new_doc): setattr(new_doc, self.field_name, self.field_value_class(file, filename=unicode(file.filename))) modified(new_doc) if not folder.has_key(file.filename): folder.manage_renameObject(new_doc.getId(), file.filename) else: # force rename (processForm will not work with files) new_doc._renameAfterCreation() # this will trigger proper lifecycle events new_doc.processForm() new_doc.edit(**{self.field_name: file}) results.append(new_doc.UID()) else: break return {name: '\n'.join(results)}
def validate(self, configuration, data=None): if 'unique' not in configuration.get('options', []): return None col_id = configuration['id'] data = data or self.field.request.form.get(col_id) if data: context = self.field.context storage = IDataStorage(context) for i, row in enumerate(storage): if i != self.field.request.form.get('row-index') and row.get( col_id) == data: return _( 'error_field_unique', default= 'The value "$value" is already present in the column \"$name\"', mapping={ 'name': configuration.get('label', col_id).decode('utf-8'), 'value': data.decode('utf-8') })
def __call__(self, *args, **kwargs): context = self.context request = self.request catalog = getToolByName(context, config.CATALOG_ID) storage = IDataStorage(context) # now we load the tabel view and rebuild all rows by using the ignore_cache parameter table_view = getMultiAdapter((context, request), name=u'view-table') table_view.rows(ignore_cache=True) for index, row in enumerate(storage): uuid = row.get('__uuid__') if not uuid: # this should not happen logger.warning("Row without an uuid! index %d, document at %s" % (index, context.absolute_url_path())) continue catalog.reindex_rows(context, uuid, storage) if index and index % 100 == 0: logger.info("Refreshing catalog (%d)" % index) transaction.savepoint() logger.info("Refreshing catalog and caches: done") getToolByName(context, 'plone_utils').addPortalMessage(_('reindex_performed_message', u'$count rows has been updated', mapping={'count': index+1})) request.response.redirect('%s/edit-table' % context.absolute_url())
def get_from_request(self, name, request): results = [] context = self.context folder = context.getAttachmentStorage() or aq_parent(aq_inner(context)) plone_utils = getToolByName(context, 'plone_utils') # first of all we need also to check for existings selected files for existing_selection in request.get("existing_%s" % name, []): results.append(existing_selection) cnt = 0 while True: if request.get("%s_%s" % (name, cnt)) and request.get("%s_%s" % (name, cnt)).filename: title = request.get('title_%s_%s' % (name, cnt)) description = request.get('description_%s_%s' % (name, cnt)) file = request.get("%s_%s" % (name, cnt)) cnt += 1 newId = folder.generateUniqueId(TYPE_TO_CREATE) if not title and file.filename in folder.objectIds(): # WARNING: we don't get the file title, to obtain the id plone_utils.addPortalMessage(_('duplicate_file_error', default=u'There is already an item named ${name} in this folder.\n' u'Loading of the attachment has been aborted.', mapping={'name': file.filename}), type='warning') results.append(folder[file.filename].UID()) continue folder.invokeFactory(id=newId, type_name=TYPE_TO_CREATE, title=title, description=description) new_doc = folder[newId] # force rename (processForm will not work with files) new_doc._renameAfterCreation() # this will trigger proper lifecycle events new_doc.processForm() new_doc.edit(file=file) results.append(new_doc.UID()) else: break return {name: '\n'.join(results)}
def search_fields(self): """Return a set of search field to be rendered""" context = self.context utilities = {} tableConf = {} # All registered search fields for name, ut in getUtilitiesFor(ISearchableColumn): utilities[name] = ut # table configuration for conf in context.getPageColumns(): tableConf[conf['id']] = conf catalog_keys = self.get_valid_catalog_indexes() fields = [] for conf in context.getSearchConfig(): if not conf: continue field_id = conf['id'] if field_id=='SearchableText': field_type = 'Text' else: field_type = tableConf[field_id]['type'] if field_type not in utilities.keys() or field_id not in catalog_keys.keys(): continue field = utilities[field_type] field.id = field_id field.configuration = tableConf.get(field_id) or {} field.search_configuration = conf field.context = context field.request = self.request field.label = conf.get('label') or field.configuration.get('label') or _(u'Search in text') field.description = conf.get('description') or field.configuration.get('description') or '' fields.append(field.render(meta_type=catalog_keys[field_id].meta_type)) return fields
def sortOrderVocabulary(self): return atapi.DisplayList(( ('asc', _("Ascending")), ('desc', _("Descending")), ))
def __call__(self): # PLEASE refactorgin this mess request = self.request context = self.context file = request.form.get('csv') check_duplicate = request.form.get('look_for_duplicate') tp_catalog = getToolByName(context, config.CATALOG_ID) if file and file.filename: try: dialect = csv.Sniffer().sniff(file.read(1024), delimiters=";,") if not dialect.delimiter: # some stupid Python 2.4 CSV bug may happens raise csv.Error except csv.Error: dialect = 'excel' file.seek(0) counter = 0 storage = IDataStorage(context) member = getMultiAdapter((context, request), name=u'plone_portal_state').member() reader = csv.reader(file, dialect) configuration = self.context.getPageColumns() valid_headers = [c['id'] for c in configuration] valid_retrievers = [self._getRetrieverAdapter(c['type']) for c in configuration] validators = [self._getRetrieveValidators(c['type']) for c in configuration] headers = [] first = True putils = getToolByName(context, 'plone_utils') for line, row in enumerate(reader): logger.info("Importing line %04d" % line) if first: headers = [h.strip() for h in row if h.strip()] if configuration: # CSV row is accessed by index headers = [(h, headers.index(h)) for h in headers if h in valid_headers] else: # No configuration. Let's guess a configuration using CSV headers self.context.setPageColumns([{'id' : h, 'label' : h, 'description' : '', 'type' : 'String', 'vocabulary' : '', 'options' : [], } for h in headers]) headers = [(h, headers.index(h)) for h in headers] configuration = self.context.getPageColumns() valid_retrievers = [self._getRetrieverAdapter(c['type']) for c in configuration] validators = [self._getRetrieveValidators(c['type']) for c in configuration] first = False continue tobe_saved = {} skip_row = False if len(row)<len(headers): putils.addPortalMessage(_('error_row_count_dont_match', default=u"Skipping line $line. Found $lrow columns instead of $lheaders", mapping={'line': line+1, 'lrow': len(row), 'lheaders': len(headers)}), type="error") continue for header, hindex in headers: skip_cell = False if request.form.get('validate'): required_field_validation_failed = False for vname, v in validators[hindex]: msg = v.validate(configuration[hindex], data=row[hindex]) if msg: if vname==u'required': putils.addPortalMessage(_('warn_invalid_row', default=u"Line $line can't be imported due to missing " u"required data", mapping={'line': line+1}), type="warning") required_field_validation_failed = True break putils.addPortalMessage(_('warn_invalid_cell', default=u"Line $line, cell $cell: can't import data " u"due to failed validator check", mapping={'line': line+1, 'cell': hindex}), type="warning") skip_cell = True break if required_field_validation_failed: skip_row = True break # do not spend time to save data if this will be discarded if not skip_row and not skip_cell: try: tobe_saved[header] = valid_retrievers[hindex].data_to_storage(row[hindex]) except NotImplementedError: # column is not implementing CSV data load continue if not skip_row and tobe_saved: if check_duplicate and self._checkDuplicateRow(tobe_saved, storage): putils.addPortalMessage(_('warn_duplicate', default=u"Line ${line_number} not added because duplicated " u"data has been found", mapping={'line_number': line+1}), type="warning") continue tobe_saved['__creator__'] = member.getId() tobe_saved['__uuid__'] = str(uuid.uuid4()) counter += 1 storage.add(tobe_saved) tp_catalog.catalog_row(context, tobe_saved) msg = _('count_rows_added', default=u'${count} rows added', mapping={'count': counter}) putils.addPortalMessage(msg) self._addNewVersion(msg) #return request.response.redirect('%s/edit-table' % context.absolute_url()) return self.index()
def insertTypeVocabulary(self): return atapi.DisplayList( (('append', _("At the end")), ('prepend', _("At the beginning"))), )
def showHeadersVocabulary(self): return atapi.DisplayList( (('view_only', _("... only on page view")), ('edit_only', _("... only when editing table")), ('always', _("... always display"))), )
from archetypes.referencebrowserwidget import ReferenceBrowserWidget except ImportError: from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget TablePageSchema = ATDocumentSchema.copy() + atapi.Schema( ( atapi.TextField( "textBefore", required=False, searchable=True, storage=atapi.AnnotationStorage(migrate=True), validators=("isTidyHtmlWithCleanup",), default_output_type="text/x-html-safe", widget=atapi.RichWidget( label=_(u"label_text_before", default=u"Text before the table"), visible={"view": "invisible", "edit": "visible"}, rows=25, allow_file_upload=zconf.ATDocument.allow_document_upload, ), ), DataGridField( "pageColumns", required=True, storage=atapi.AnnotationStorage(), columns=("id", "label", "description", "type", "vocabulary", "options"), widget=DataGridWidget( label=_(u"Columns"), description=_("help_pageColumns", default=u"Definition of rows inside the table"), visible={"view": "invisible", "edit": "visible"}, helper_js=("datagridwidget.js", "datagridwidget_patches.js", "datagridmultiselect.js"),
def _save(self): """Save a new row or update one""" form = self.request.form context = self.context storage = self.storage configuration = self.configuration row_index = form.get('row-index', -1) tp_catalog = getToolByName(context, config.CATALOG_ID) if context.getInsertType()=='prepend': # this is the first row in the section, so you want to add something above it row_index = self._first_index_in_section(row_index) else: # this is the last row in the section, so you want to add something below it (default) row_index = self._last_index_in_section(row_index) # Run validations for conf in configuration: id = conf['id'] col_type = conf['type'] field = getMultiAdapter((context, self.request), IColumnField, name=col_type) validators = getAdapters((field, ), IFieldValidator) for name, validator in validators: msg = validator.validate(conf) if msg: self.errors[id] = msg break to_be_saved = {} if not self.errors: # As some IColumnDataRetriever adapter do some stuff, we read data only if no error has been get for conf in configuration: id = conf['id'] col_type = conf['type'] try: retriever = getAdapter(context, IColumnDataRetriever, name=col_type) except ComponentLookupError: retriever = IColumnDataRetriever(context) try: data = retriever.get_from_request(id, form) except NotImplementedError: data = None if data: to_be_saved.update(**data) else: putils = getToolByName(context, 'plone_utils') putils.addPortalMessage(pmf(u'Please correct the indicated errors.'), type="error") return if to_be_saved: member = getMultiAdapter((context, self.request), name=u'plone_portal_state').member() _ = getToolByName(context, 'translation_service').utranslate if form.get('row-index') is not None and not form.get('addRow'): # Edit row row_index = form.get('row-index') if not self.check_manager_or_mine_record(row_index): raise Unauthorized("You can't modify that record") to_be_saved['__uuid__'] = storage[row_index]['__uuid__'] storage.update(row_index, to_be_saved) self._addNewVersion(_(msgid="Row changed", domain="collective.tablepage", context=context)) else: # Add row to_be_saved['__creator__'] = member.getId() to_be_saved['__uuid__'] = str(uuid.uuid4()) storage.add(to_be_saved, row_index) self._addNewVersion(_(msgid="Row added", domain="collective.tablepage", context=context)) self._populateCache(storage, row_index) tp_catalog.catalog_row(context, storage[row_index])
try: from archetypes.referencebrowserwidget import ReferenceBrowserWidget except ImportError: from Products.ATReferenceBrowserWidget.ATReferenceBrowserWidget import ReferenceBrowserWidget TablePageSchema = ATDocumentSchema.copy() + atapi.Schema(( atapi.TextField('textBefore', required=False, searchable=True, storage=atapi.AnnotationStorage(migrate=True), validators=('isTidyHtmlWithCleanup',), default_output_type='text/x-html-safe', widget=atapi.RichWidget( label=_(u'label_text_before', default=u'Text before the table'), visible={'view': 'invisible', 'edit': 'visible'}, rows=25, allow_file_upload=zconf.ATDocument.allow_document_upload), ), DataGridField('pageColumns', required=True, storage=atapi.AnnotationStorage(), columns=("id", "label", "description", "type", "vocabulary", "options"), widget=DataGridWidget( label=_(u"Columns"), description=_('help_pageColumns', default=u"Definition of rows inside the table"), visible={'view': 'invisible', 'edit': 'visible'}, helper_js=('datagridwidget.js', 'datagridwidget_patches.js', 'datagridmultiselect.js'),
def insertTypeVocabulary(self): return atapi.DisplayList((("append", _("At the end")), ("prepend", _("At the beginning"))))
def _save(self): """Save a new row or update one""" form = self.request.form context = self.context storage = self.storage configuration = self.configuration row_index = form.get('row-index', -1) tp_catalog = getToolByName(context, config.CATALOG_ID) if context.getInsertType() == 'prepend': # this is the first row in the section, so you want to add something above it row_index = self._first_index_in_section(row_index) else: # this is the last row in the section, so you want to add something below it (default) row_index = self._last_index_in_section(row_index) # Run validations for conf in configuration: id = conf['id'] col_type = conf['type'] field = getMultiAdapter((context, self.request), IColumnField, name=col_type) validators = getAdapters((field, ), IFieldValidator) for name, validator in validators: msg = validator.validate(conf) if msg: self.errors[id] = msg break to_be_saved = {} if not self.errors: # As some IColumnDataRetriever adapter do some stuff, we read data only if no error has been get for conf in configuration: id = conf['id'] col_type = conf['type'] try: retriever = getAdapter(context, IColumnDataRetriever, name=col_type) except ComponentLookupError: retriever = IColumnDataRetriever(context) try: data = retriever.get_from_request(id, form) except NotImplementedError: data = None if data: to_be_saved.update(**data) else: putils = getToolByName(context, 'plone_utils') putils.addPortalMessage( pmf(u'Please correct the indicated errors.'), type="error") return if to_be_saved: member = getMultiAdapter((context, self.request), name=u'plone_portal_state').member() _ = getToolByName(context, 'translation_service').utranslate to_be_saved['__tablerowstyle__'] = form.get('__tablerowstyle__') if form.get('row-index') is not None and not form.get('addRow'): # Edit row row_index = form.get('row-index') if not self.check_manager_or_mine_record(row_index): raise Unauthorized("You can't modify that record") to_be_saved['__uuid__'] = storage[row_index]['__uuid__'] storage.update(row_index, to_be_saved) self._addNewVersion( _(msgid="Row changed", domain="collective.tablepage", context=context)) else: # Add row to_be_saved['__creator__'] = member.getId() to_be_saved['__uuid__'] = str(uuid.uuid4()) storage.add(to_be_saved, row_index) self._addNewVersion( _(msgid="Row added", domain="collective.tablepage", context=context)) self._populateCache(storage, row_index) tp_catalog.catalog_row(context, storage[row_index])