def populate_dexterity(obj, data): request = getRequest() for schema in get_dexterity_schemas(context=obj): for name in getFieldNames(schema): field = schema[name] if name in ['expires', 'effective', 'relatedItems']: # skip some fields continue if getattr(field, 'readonly', False): continue autoform_widgets = schema.queryTaggedValue(WIDGETS_KEY, default={}) if name in autoform_widgets: try: widgetclass = utils.resolveDottedName( autoform_widgets[name]) except AttributeError: # XXX: Investigate: # AttributeError: 'ParameterizedWidget' object has no # attribute 'split' continue widget = widgetclass(field, request) else: widget = component.getMultiAdapter( (field, request), IFieldWidget) widget.context = obj widget.ignoreRequest = True widget.update() if HAS_RECURRENCE_WIDGET and IRecurrenceWidget.providedBy(widget): # We cannot yet deal with the recurrence widget continue if name == 'title': value = unicode(data['title']) else: value = widget.value if not value or value in [NOT_CHANGED, NO_VALUE] or \ not IDataConverter(widget).toFieldValue(value): value = get_dummy_dexterity_value(obj, widget, data) if value is None: continue if interfaces.ICollection.providedBy(widget.field) or \ interfaces.IChoice.providedBy(widget.field): value = [value] if value: dm = component.getMultiAdapter((obj, field), IDataManager) try: dm.set(IDataConverter(widget).toFieldValue(value)) except TypeError: dm.set(value)
def inject_default_values(self): today = date.today() title = self.widgets['title'] date_from = self.widgets['date_from'] date_to = self.widgets['date_to'] if not title.value: title.value = unicode(today.year) if not date_from.value: date_from.value = IDataConverter(date_from).toWidgetValue( date(today.year, 1, 1)) if not date_to.value: date_to.value = IDataConverter(date_to).toWidgetValue( date(today.year, 12, 31))
def _init_baseform(self): """ Initialize base form for re-use * N rows to avoid re-construction; should be called by self.update(), just once. """ row_views = { ('edit', 'Stacked'): DivRowForm, ('view', 'Stacked'): DivRowDisplayForm, ('edit', 'Columns'): RowForm, ('view', 'Columns'): RowDisplayForm, } row_view_cls = row_views[(self.VIEWNAME, self.displaymode)] self.dummy_record = self.context.create() alsoProvides(self.dummy_record, self.schema) self.baseform = row_view_cls(self.dummy_record, self.schema, self.request) self.baseform.update() # create a mapping of data converters by fieldname self.converters = {} # fieldname to converter self.defaults = {} # fieldname to default value for fieldname in self.baseform.fields: widget = self.baseform.widgets[fieldname] field = self.schema[fieldname] self.converters[fieldname] = IDataConverter(widget) self.defaults[fieldname] = field.default # lookup template once, bind -- to avoid repeated lookup widget.template = getMultiAdapter( (widget.context, self.request, self.baseform, field, widget), IPageTemplate, name=widget.mode) self.baseform.render() # force chameleon compilation here
def replace_term(self, schema, field, fkey, match): """ Replace a field term. For multi valued fields it will replace just the matching part of it. For single valued fields it replaces the whole field, where it matches. We get the widget from the actual schema field so we can use it to extract and parse the appropriate value too (!) :param schema: dotted name schema (str) :param field: field :param fkey: boolean, representing DateGridField :param match: the value being matched :return: None """ widget = self.replacement_widget replacement = widget.extract() if replacement is not NO_VALUE: try: replacement = IDataConverter(widget).toFieldValue(replacement) except WrongType: # for some reason some things that should come in as unicode are coming in as strings replacement = IDataConverter(widget).toFieldValue(IDataConverter(widget).toWidgetValue(replacement)) if not replacement or replacement is NO_VALUE: api.portal.show_message(message=_('No replacement value given'), request=self.request, type='error') return results = self.results() for brain in results: obj = brain.getObject() field_value = getattr(obj, field, None) if isinstance(field_value, str) or \ isinstance(field_value, datetime.date) or isinstance(field_value, datetime.datetime): self.set_value(obj, schema, field, replacement) elif isinstance(field_value, tuple) or isinstance(field_value, list): if fkey: for item_value in field_value: if item_value[fkey] == match: item_value[fkey] = replacement self.set_value(obj, schema, field, field_value) else: if replacement in field_value: field_value = [item_value for item_value in field_value if item_value != match] else: field_value = [item_value == match and replacement or item_value for item_value in field_value] self.set_value(obj, schema, field, field_value) api.portal.show_message(message=_('Replaced term in {} records'.format(len(results))), request=self.request, type='info')
def inject_initial_data(self): if self.request.method != 'GET': return values = self.model.get_edit_values(self.fields.keys()) for fieldname, value in values.items(): widget = self.widgets[fieldname] value = IDataConverter(widget).toWidgetValue(value) widget.value = value
def getValue(self, language): self.value = removeSecurityProxy(self.value) if not isinstance(self.value, dict) and \ not isinstance(self.value, PersistentDict): converter = IDataConverter(self) try: self.value = converter.toFieldValue(self.value) except Exception: self.value = {} if self.value is not None: return self.value.get(language)
def update(self): """Update the widget-values of the dossier add-form with the values of the selected dossiertemplate values. """ super(WrappedForm, self).update() if not getSecurityManager().getUser().getId(): # this happens during ++widget++ traversal return self.is_available() template_obj = get_saved_template_obj(self.context) if not template_obj: # This happens if the user access the step directly and # the wizard storage was expired or never existent. return self.request.RESPONSE.redirect( '{}/dossier_with_template'.format( self.context.absolute_url())) template_values = template_obj.get_schema_values() title_help = IDossierTemplateSchema(template_obj).title_help for group in self.groups: for widgetname in group.widgets: # Skip not whitelisted template fields. # We don't want to update fields which are not # whitelisted in the template. template_widget_name = self.get_template_widget_name( widgetname) if template_widget_name not in TEMPLATABLE_FIELDS: continue value = template_values.get(template_widget_name) widget = group.widgets.get(widgetname) # If the current field is the title field and the # title_help is set, we remove the input-value and # add a field description with the title_help text # instead. if widget.field == IOpenGeverBase[ 'title'] and title_help: widget.dynamic_description = title_help value = '' # Set the template value to the dossier add-form widget. widget.value = IDataConverter(widget).toWidgetValue( value) if widgetname == 'IDossier.keywords': self._modify_keyword_widget_according_to_template( widget)
def updateWidgets(self): super(ParticipationEditForm, self).updateWidgets() if self.request.method != 'GET': return widget = self.widgets['roles'] widget.value = IDataConverter(widget).toWidgetValue( [role.role for role in self.model.roles]) self.widgets.update()
def _setAsOwner(self, context, field, value): # Do some trivial transforms def transform(value, field): if isinstance(field, Set) and isinstance(value, unicode): value = set((value, )) elif isinstance(field, Set) and isinstance(value, tuple): value = set(value) elif isinstance(field, Set) and isinstance(value, list): value = set(value) elif isinstance(field, List) and isinstance(value, unicode): value = list((value, )) elif (isinstance(field, Choice) and isinstance(value, list) and len(value) == 1): value = value[0] return value # Try to set the value on created object value = transform(value, field) try: # 2) Try your luck with z3c.form adapters widget = getMultiAdapter((field, getRequest()), IFieldWidget) converter = IDataConverter(widget) dm = getMultiAdapter((context, field), IDataManager) # Convert datetimes to collective.z3cform.datetimewidget-compatible if isinstance(field, Datetime) and isinstance( widget, DatetimeWidget): # noqa value = re.compile('\d+').findall(value) # Convert dates to collective.z3cform.datetimewidget-compatible if isinstance(field, Date) and isinstance(widget, DateWidget): value = re.compile('\d+').findall(value[:10]) # YYYY-MM-DD # Convert dates to plone.app.z3cform.widgets.datewidget-compatible elif isinstance(field, Date): value = value.split()[0] dm.set(converter.toFieldValue(value)) except ConflictError: raise except Exception, e: try: # 1) Try to set it directly bound_field = field.bind(context) bound_field.validate(value) bound_field.set(context, value) except ConflictError: raise except Exception: LOG.error(e) return u'An unexpected error: {0:s} {1:s}'.format( e.__class__, e)
def inject_initial_data(self): if self.request.method != 'GET': return values = self.model.get_edit_values(self.fields.keys()) # XXX - Doing this instead of a data adapter secretary = values.get('secretary') if secretary: if isinstance(secretary, User): values['secretary'] = secretary.userid for fieldname, value in values.items(): widget = self.widgets[fieldname] value = IDataConverter(widget).toWidgetValue(value) widget.value = value
def extract(self, default=NOVALUE): # noqa action = self.request.get('{0}.action'.format(self.name), None) if self.request.get('PATH_INFO', '').endswith('kss_z3cform_inline_validation'): action = 'nochange' if action == 'remove': return None elif action == 'nochange': session = ISession(self.request)[SESSION_PKG_KEY] token = self.uploaded_token if token is None: token = self.request.get('{0}.token'.format(self.name), None) if token in session: self.uploaded_token = token return session.get(token) if self.value is not None: return self.value if self.ignoreContext: return default dm = getMultiAdapter((self.context, self.field), IDataManager) value = dm.query() if isinstance(value, Proxy): value = removeSecurityProxy(value) return value elif action == 'replace': # set the action back to 'nochange' so that the button is # preselected. Only applicable when form is reloaded with errors self.request.form['{0}.action'.format(self.name)] = 'nochange' # empty unnamed FileUploads should not count as a value value = super(NamedFileWidget, self).extract(default) if isinstance(value, FileUpload): value.seek(0, SEEK_END) empty = value.tell() == 0 value.seek(0) if empty and not value.filename: return default value.seek(0) session = ISession(self.request)[SESSION_PKG_KEY] if self.unique_token not in session: self.uploaded_token = self.unique_token value = IDataConverter(self).toFieldValue(value) session[self.unique_token] = value elif not value: return default return value
def updateWidgets(self, *args, **kwargs): super(AddWebactionForm, self).updateWidgets(*args, **kwargs) saving = 'form.buttons.save' in self.request # Prefill other widgets only upon initial rendering of the form, # not when trying to save - this is so we don't override # actual user provided inputs with missing values if saving: return # Prefill form widgets with missing values for widget in self.widgets.values(): missing_value = widget.field.missing_value if not missing_value: continue converter = IDataConverter(widget) widget.value = converter.toWidgetValue(missing_value)
def widgets(self, mode=DISPLAY_MODE): """Return the widgets for the databox # https://stackoverflow.com/questions/8476781/how-to-access-z3c-form-widget-settings-from-browser-view """ widgets = [] fields = api.get_fields(self.context) for name, field in fields.items(): widget = getMultiAdapter((field, self.request), IFieldWidget) widget.mode = mode widget.context = self.context converter = IDataConverter(widget) value = field.get(self.context) widget.value = converter.toWidgetValue(value) widget.update() widgets.append(widget) return widgets
def updateWidgets(self, *args, **kwargs): super(EditKeyForm, self).updateWidgets(*args, **kwargs) saving = 'form.buttons.save' in self.request # Prefill form widgets with persisted values from DB key = self.get_key() for widget in self.widgets.values(): # Always prefill readonly widgets. # # Prefill other widgets only upon initial rendering of the form, # not when trying to save - this is so we don't override # actual user provided inputs with persisted values from the # DB when rendering the form in the case of validation errors. if widget.field.readonly or not saving: name = widget.field.getName() value = key[name] converter = IDataConverter(widget) widget.value = converter.toWidgetValue(value)
def jsonValidate(self, id, value): """Validate the value for the witdget with the given DOM field id.""" res = u'OK' data = {} errorView = None self.context.updateWidgets() widget = util.getWidgetById(self.context, id) if widget is not None: content = self.context.widgets.content form = self.context.widgets.form try: value = IDataConverter(widget).toFieldValue(value) validator = zope.component.getMultiAdapter((content, self.request, self.context, getattr(widget, 'field', None), widget), IValidator) error = validator.validate(value) except (zope.schema.ValidationError, ValueError), error: errorView = zope.component.getMultiAdapter( (error, self.request, widget, widget.field, form, content), IErrorViewSnippet) errorView.update()
def create_content(self, *args, **kwargs): """Create content and return its UID""" disableCSRFProtection() # XXX: Because kwargs are only supported with robotframework >= 2.8.3, # we must parse them here to support robotframework < 2.8.3. for arg in [x for x in args if '=' in x]: name, value = arg.split('=', 1) kwargs[name] = value assert 'type' in kwargs, u"Keyword arguments must include 'type'." portal_type = kwargs.get('type') portal = getSite() if 'container' in kwargs: pc = getToolByName(portal, 'portal_catalog') uid_or_path = kwargs.pop('container') uid_results =\ pc.unrestrictedSearchResults(UID=uid_or_path) path_results = \ pc.unrestrictedSearchResults( path={'query': uid_or_path.rstrip('/'), 'depth': 0}) container =\ (uid_results or path_results)[0]._unrestrictedGetObject() else: container = portal # if we create 'file' and 'image' kwargs entries, they should not be # used to create the content but be set afterwards create_kwargs = {} create_kwargs.update(kwargs) if HAS_DEXTERITY: if portal_type in ('File', ) and 'file' not in kwargs: pdf_file = os.path.join(os.path.dirname(__file__), 'content', u'file.pdf') value = NamedBlobFile(data=open(pdf_file, 'r').read(), contentType='application/pdf', filename=u'file.pdf') kwargs['file'] = value if portal_type in ('Image', 'News Item') and 'image' not in kwargs: prefill_image_types(portal, kwargs) id_ = kwargs.pop('id', None) type_ = kwargs.pop('type') content = None if HAS_DEXTERITY: # The title attribute for Dexterity types needs to be unicode if 'title' in kwargs and isinstance(kwargs['title'], str): kwargs['title'] = kwargs['title'].decode('utf-8') from plone.dexterity.interfaces import IDexterityFTI from plone.dexterity.utils import createContentInContainer try: getUtility(IDexterityFTI, name=type_) content = createContentInContainer(container, type_, **create_kwargs) if id_ is not None and content.id != id_: container.manage_renameObject(content.id, id_) except ComponentLookupError: pass if HAS_DEXTERITY and content: # For dexterity-types, we need a second pass to fill all fields # using their widgets to get e.g. RichText-values created # correctly. fti = getUtility(IDexterityFTI, name=type_) schema = fti.lookupSchema() fields = {} for name in schema: fields[name] = schema[name] for schema in getAdditionalSchemata(portal_type=type_): for name in schema: fields[name] = schema[name] for name, field in fields.items(): widget = queryMultiAdapter((field, getRequest()), IFieldWidget) if widget and name in kwargs: if not IFromUnicode.providedBy(field): value = kwargs[name] elif isinstance(kwargs[name], unicode): value = kwargs[name] else: value = unicode(str(kwargs[name]), 'utf-8', errors='ignore') converter = IDataConverter(widget) dm = queryMultiAdapter((content, field), IDataManager) if dm: dm.set(converter.toFieldValue(value)) if content is None: if id_ is None: normalizer = queryUtility(IURLNormalizer) id_ = normalizer.normalize(kwargs['title']) # It must be Archetypes based content: content = container[container.invokeFactory(type_, id_, **kwargs)] content.processForm() return IUUID(content)
def dexterity_update(obj, request=None): """ Utility method to update the fields of all the schemas of the Dexterity object 'obj'. """ modified = defaultdict(list) if not request: request = obj.REQUEST # Call processInputs to decode strings to unicode, otherwise the # z3c.form dataconverters complain. processInputs(request) errors = [] for schema in get_dexterity_schemas(context=obj): for name in getFieldNames(schema): # Only update fields which are included in the form # Look specifically for the empty-marker used to mark # empty checkboxes if name not in request.form and \ '%s-empty-marker' % name not in request.form: continue field = schema[name] autoform_widgets = schema.queryTaggedValue(WIDGETS_KEY, default={}) if name in autoform_widgets: widget = autoform_widgets[name] if not isinstance(widget, ParameterizedWidget): widget = ParameterizedWidget(widget) widget = widget(field, request) else: widget = component.getMultiAdapter((field, request), IFieldWidget) widget.context = obj value = field.missing_value widget.update() try: raw = widget.extract() except MultipleErrors, e: errors.append(e) log.warn("Multiple errors while extracting field: %s" % name) continue if raw is NOT_CHANGED: continue if raw is NO_VALUE: continue if (IRichTextValue.providedBy(raw) and api.portal.get_registry_record( 'ploneintranet.workspace.sanitize_html')): sanitized = RichTextValue(raw=sanitize_html( safe_unicode(raw.raw)), mimeType=raw.mimeType, outputMimeType=raw.outputMimeType) if sanitized.raw != raw.raw: log.info( 'The HTML content of field "{}" on {} was sanitised.'. format( # noqa name, obj.absolute_url())) raw = sanitized if isinstance(field, TextLine): # textLines must not contain line breaks (field contraint) # to prevent a ConstraintNotSatisfied error in `toFieldValue` raw = u" ".join(safe_unicode(raw).splitlines()) try: value = IDataConverter(widget).toFieldValue(safe_unicode(raw)) except Exception, exc: log.warn("Error in converting value for %s: %s (%s)" % (name, raw, str(exc))) raise exc try: field.validate(value) except interfaces.RequiredMissing, e: errors.append(e) log.warn("Required field have missing value: %s" % name)
def test_widgets_render_missing_values(self): """Test that gets run for each of the portal type specific subclasses, and asserts that a rendered z3c.form widget correctly returns the missing value if that's what's currently persisted on the object. """ if self.portal_type is None: # Don't attempt to run this test for the abstract base class return self.login(self.manager) obj = self.get_obj_of_own_type() form = DefaultEditForm(obj, self.request) # Populate the form with fields according to the object's portal type with fake_interaction(): # We need a fake IInteraction context because otherwise # z3c.formwidget.query.widget fails with its checkPermission() form.update() for widget in self.iter_widgets(form): field = widget.field if field.required: # Required fields shouldn't have missing values return if field.readonly: return # Determine what this field's missing value would be missing_value = field.missing_value # Manipulate fixture obj to have missing value for this field field.set(field.interface(obj), missing_value) # Update the widget to reflect that changed value on the obj with fake_interaction(): widget.update() # Use the widget to retrieve the value - but turn it into a # field value using the field's DataConverter, in order to # compare it to missing value. dc = IDataConverter(widget) field_value_from_widget = dc.toFieldValue(widget.value) if isinstance(widget, SingleCheckBoxWidget): # Boolean fields handled by SingleCheckBoxWidgets are funny: # Their fields' missing value is None, which ends up # as a widget.value of empty list [], which # IDataConverter.toFieldValue() then turns into False. # # In other words, there isn't really a concept of missing # values for booleans - MV will always end up being # considered the same as False. if field_value_from_widget is False: field_value_from_widget = None if isinstance(field, List) and isinstance(widget, CheckBoxWidget): # zope.schema.List is weird too - it gets rendered using # a CheckBoxWidget. missing_value = [] self.assertEqual( missing_value, field_value_from_widget, 'Unexpectedly got %r instead of missing value %r ' 'from widget %r (for an %r object) ' % ( field_value_from_widget, missing_value, widget, obj.portal_type))
def updateWidgets(self): super(UpdateMetadataForm, self).updateWidgets() widget = self.widgets['issuer'] value = api.user.get_current().getId() widget.value = IDataConverter(widget).toWidgetValue(value)