def __call__(self, value, *args, **kwargs): field = kwargs['field'] fieldname = field.getName() instance = kwargs['instance'] translate = getToolByName(instance, 'translation_service').translate # return directly if nothing changed if value == field.get(instance): return True # We want to use the catalog to speed things up, as using `objectValues` # is very expensive if the parent object contains many items parent_objects = [] # 1. Get the right catalog for this object catalogs = api.get_catalogs_for(instance) catalog = catalogs[0] # 2. Check if the field accessor is indexed field_index = None accessor = field.getAccessor(instance) if accessor: field_index = accessor.__name__ # 3. Check if the field index is in the indexes # Field is indexed, use the catalog instead of objectValues parent_path = api.get_parent_path(instance) portal_type = instance.portal_type catalog_query = {"portal_type": portal_type, "path": {"query": parent_path, "depth": 1}} if field_index and field_index in catalog.indexes(): # We use the field index to reduce the results list catalog_query[field_index] = value parent_objects = map(api.get_object, catalog(catalog_query)) elif fieldname in catalog.indexes(): # We use the fieldname as index to reduce the results list catalog_query[fieldname] = value parent_objects = map(api.get_object, catalog(catalog_query)) else: # fall back to the objectValues :( parent_object = api.get_parent(instance) parent_objects = parent_object.objectValues() for item in parent_objects: if hasattr(item, 'UID') and item.UID() != instance.UID() and \ fieldname in item.Schema() and \ str(item.Schema()[fieldname].get(item)) == str(value): # We have to compare them as strings because # even if a number (as an id) is saved inside # a string widget and string field, it will be # returned as an int. I don't know if it is # caused because is called with # <item.Schema()[fieldname].get(item)>, # but it happens... msg = _("Validation failed: '${value}' is not unique", mapping={'value': safe_unicode(value)}) return to_utf8(translate(msg)) return True
def folderitem(self, obj, item, index): """Service triggered each time an item is iterated in folderitems. The use of this service prevents the extra-loops in child objects. :obj: the instance of the class to be foldered :item: dict containing the properties of the object to be used by the template :index: current index of the item """ item["replace"]["Title"] = get_link_for(obj) item["Description"] = obj.Description() retention_period = obj.getRetentionPeriod() if retention_period: hours = retention_period.get("hours", "0") minutes = retention_period.get("minutes", "0") days = retention_period.get("days", "0") item["RetentionPeriod"] = _( "hours: {} minutes: {} days: {}".format(hours, minutes, days)) sample_matrix = obj.getSampleMatrix() item["replace"]["SampleMatrix"] = get_link_for(sample_matrix) container_type = obj.getContainerType() item["replace"]["ContainerType"] = get_link_for(container_type) # Hide sample points assigned to this sample type that do not belong # to the same container (Client or Setup) sample_points = obj.getSamplePoints() path = api.get_path(self.context) setup = api.get_setup() if api.get_parent(self.context) == setup: path = api.get_path(setup.bika_samplepoints) sample_points = filter(lambda sp: api.get_parent_path(sp) == path, sample_points) # Display the links to the sample points links = map(get_link_for, sample_points) item["replace"]["SamplePoints"] = ", ".join(links) return item
def make_catalog_query(self, context, field, value): """Create a catalog query for the field """ # get the catalogs for the context catalogs = api.get_catalogs_for(context) # context not in any catalog? if not catalogs: logger.warn("UniqueFieldValidator: Context '{}' is not assigned" "to any catalog!".format(repr(context))) return None # take the first catalog catalog = catalogs[0] # Check if the field accessor is indexed field_index = field.getName() accessor = field.getAccessor(context) if accessor: field_index = accessor.__name__ # return if the field is not indexed if field_index not in catalog.indexes(): return None # build a catalog query query = { "portal_type": api.get_portal_type(context), "path": { "query": api.get_parent_path(context), "depth": 1, } } query[field_index] = value logger.info("UniqueFieldValidator:Query={}".format(query)) return query
def __call__(self, value, *args, **kwargs): field = kwargs['field'] fieldname = field.getName() instance = kwargs['instance'] translate = getToolByName(instance, 'translation_service').translate # return directly if nothing changed if value == field.get(instance): return True # We want to use the catalog to speed things up, as using `objectValues` # is very expensive if the parent object contains many items parent_objects = [] # 1. Get the right catalog for this object catalogs = api.get_catalogs_for(instance) catalog = catalogs[0] # 2. Check if the field accessor is indexed field_index = None accessor = field.getAccessor(instance) if accessor: field_index = accessor.__name__ # 3. Check if the field index is in the indexes # Field is indexed, use the catalog instead of objectValues parent_path = api.get_parent_path(instance) portal_type = instance.portal_type catalog_query = { "portal_type": portal_type, "path": { "query": parent_path, "depth": 1 } } if field_index and field_index in catalog.indexes(): # We use the field index to reduce the results list catalog_query[field_index] = value parent_objects = map(api.get_object, catalog(catalog_query)) elif fieldname in catalog.indexes(): # We use the fieldname as index to reduce the results list catalog_query[fieldname] = value parent_objects = map(api.get_object, catalog(catalog_query)) else: # fall back to the objectValues :( parent_object = api.get_parent(instance) parent_objects = parent_object.objectValues() for item in parent_objects: if hasattr(item, 'UID') and item.UID() != instance.UID() and \ fieldname in item.Schema() and \ str(item.Schema()[fieldname].get(item)) == str(value): # We have to compare them as strings because # even if a number (as an id) is saved inside # a string widget and string field, it will be # returned as an int. I don't know if it is # caused because is called with # <item.Schema()[fieldname].get(item)>, # but it happens... msg = _("Validation failed: '${value}' is not unique", mapping={'value': safe_unicode(value)}) return to_utf8(translate(msg)) return True
def get_parent_path(brain_or_object): """Proxy to bika.lims.api.get_parent_path """ return api.get_parent_path(brain_or_object)
def get_parent_path(brain_or_object): """Proxy to senaite.api.get_parent_path """ return api.get_parent_path(brain_or_object)