def _migrate_values(self, entitydata): """ List description entity format migration method. The specification for this method is that it returns an entitydata value which is a copy of the supplied entitydata with format migrations applied. NOTE: implementations are free to apply migrations in-place. The resulting entitydata should be exactly as the supplied data *should* appear in storage to conform to the current format of the data. The migration function should be idempotent; i.e. x._migrate_values(x._migrate_values(e)) == x._migrate_values(e) """ for fkey, ftype in [(ANNAL.CURIE.display_type, "_enum_list_type")]: entitydata[fkey] = make_type_entity_id( ftype, extract_entity_id(entitydata[fkey]) ) migration_map = ( [ (ANNAL.CURIE.record_type, ANNAL.CURIE.list_entity_type) ]) entitydata = self._migrate_values_map_field_names(migration_map, entitydata) if ANNAL.CURIE.list_fields in entitydata: for f in entitydata[ANNAL.CURIE.list_fields]: field_id = extract_entity_id(f[ANNAL.CURIE.field_id]) if field_id == "Field_render": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/Field_render_type" if field_id == "Field_type": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/Field_value_type" if field_id == "View_target_type": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/View_entity_type" if field_id == "List_target_type": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/List_entity_type" # Return result return entitydata
def get_coll_jsonld_context(self): """ Return dictionary containing context structure for collection. """ # Use OrderedDict to allow some control over ordering of context file contents: # this is for humane purposes only, and is not technically important. context = OrderedDict( { "@base": self.get_url() + layout.META_COLL_BASE_REF , ANNAL.CURIE.type: { "@type": "@id" } , ANNAL.CURIE.entity_list: { "@container": "@list" } }) # Collection-local URI prefix context.update( { 'coll': self._entityviewurl }) # Common import/upload fields context.update( { 'resource_name': "annal:resource_name" , 'resource_type': "annal:resource_type" }) # upload-file fields context.update( { 'upload_name': "annal:upload_name" , 'uploaded_file': "annal:uploaded_file" , 'uploaded_size': "annal:uploaded_size" }) # import-resource fields context.update( { 'import_name': "annal:import_name" , 'import_url': { "@id": "annal:import_url" , "@type": "@id" } }) # Scan vocabs, generate prefix data for v in self.child_entities(RecordVocab, altscope="all"): vid = v.get_id() if vid != "_initial_values": context[v.get_id()] = v[ANNAL.CURIE.uri] # Scan view fields and generate context data for property URIs used for v in self.child_entities(RecordView, altscope="all"): for fref in v[ANNAL.CURIE.view_fields]: fid = extract_entity_id(fref[ANNAL.CURIE.field_id]) vuri = fref.get(ANNAL.CURIE.property_uri, None) furi, fcontext = self.get_field_uri_jsonld_context(fid, self.get_field_jsonld_context) if fcontext is not None: fcontext['vid'] = v.get_id() fcontext['fid'] = fid self.set_field_uri_jsonld_context(vuri or furi, fid, fcontext, context) # Scan group fields and generate context data for property URIs used for g in self.child_entities(RecordGroup, altscope="all"): for gref in g[ANNAL.CURIE.group_fields]: fid = extract_entity_id(gref[ANNAL.CURIE.field_id]) guri = gref.get(ANNAL.CURIE.property_uri, None) furi, fcontext = self.get_field_uri_jsonld_context(fid, self.get_field_jsonld_context) if fcontext is not None: fcontext['gid'] = g.get_id() fcontext['fid'] = fid self.set_field_uri_jsonld_context(guri or furi, fid, fcontext, context) return context
def types_using_field(coll, field_id, property_uri): """ Returns a list of type ids that may use a specified field or property URI """ type_ids = set() type_uris = set() group_ids = set() # Look at field definition f = coll_field(coll, field_id) add_to_set(f.get(ANNAL.CURIE.field_entity_type, ""), type_uris) # Look at groups that reference field for g in coll_groups(coll): if field_in_field_list(g[ANNAL.CURIE.group_fields], field_id, property_uri): add_to_set(g.get_id(), group_ids) add_to_set(extract_entity_id(g.get(ANNAL.CURIE.record_type, "")), type_uris) # Look at views that reference field or groups for v in coll_views(coll): if ( field_in_field_list(v[ANNAL.CURIE.view_fields], field_id, property_uri) or group_in_field_list(v[ANNAL.CURIE.view_fields], coll, group_ids) ): add_to_set(extract_entity_id(v.get(ANNAL.CURIE.record_type, "")), type_uris) # Look at lists that reference field or groups for l in coll_lists(coll): if ( field_in_field_list(l[ANNAL.CURIE.list_fields], field_id, property_uri) or group_in_field_list(l[ANNAL.CURIE.list_fields], coll, group_ids) ): add_to_set(extract_entity_id(l.get(ANNAL.CURIE.record_type, "")), type_uris) add_to_set(extract_entity_id(l.get(ANNAL.CURIE.default_type, "")), type_uris) # Collect type ids for t in coll_types(coll): type_uri = t.get(ANNAL.CURIE.uri, "") supertype_uris = set( s[ANNAL.CURIE.supertype_uri] for s in t.get(ANNAL.CURIE.supertype_uris,[]) ) if (type_uri in type_uris) or (supertype_uris & type_uris): add_to_set(t.get_id(), type_ids) return type_ids
def get_field_jsonld_context(fdesc): """ Returns a context description for the supplied field description. Returns None if no property context information is needed for the supplied field. """ rtype = extract_entity_id(fdesc[ANNAL.CURIE.field_render_type]) vmode = extract_entity_id(fdesc[ANNAL.CURIE.field_value_mode]) if vmode in ["Value_entity", "Value_field"]: rtype = "Enum" elif vmode == "Value_import": rtype = "URIImport" elif vmode == "Value_upload": rtype = "FileUpload" if is_render_type_literal(rtype): fcontext = {} # { "@type": "xsd:string" } elif is_render_type_id(rtype): fcontext = {"@type": "@id"} # Add type from field descr? elif is_render_type_object(rtype): fcontext = {} else: raise ValueError("Unexpected value mode or render type (%s, %s)" % (vmode, rtype)) if is_render_type_set(rtype): fcontext["@container"] = "@set" elif is_render_type_list(rtype): fcontext["@container"] = "@list" return fcontext
def get_field_jsonld_context(fdesc): """ Returns a context description for the supplied field description. Returns None if no property context information is needed for the supplied field. """ rtype = extract_entity_id(fdesc[ANNAL.CURIE.field_render_type]) vmode = extract_entity_id(fdesc[ANNAL.CURIE.field_value_mode]) if vmode in ["Value_entity", "Value_field"]: rtype = "Enum" elif vmode == "Value_import": rtype = "URIImport" elif vmode == "Value_upload": rtype = "FileUpload" if is_render_type_literal(rtype): fcontext = {} # { "@type": "xsd:string" } elif is_render_type_id(rtype): fcontext = { "@type": "@id" } # Add type from field descr? elif is_render_type_object(rtype): fcontext = {} else: msg = "Unexpected value mode or render type (%s, %s)"%(vmode, rtype) log.error(msg) raise ValueError(msg) if is_render_type_set(rtype): fcontext["@container"] = "@set" elif is_render_type_list(rtype): fcontext["@container"] = "@list" return fcontext
def check_context_field( test, context_field, field_id=None, field_name=None, field_label=None, field_placeholder=None, field_property_uri=None, field_render_type=None, field_value_mode=None, field_value_type=None, field_placement=None, field_value=None, options=None, ): """ Check values in context field against supplied parameters. This function allows certain variations for robustness of tests. """ test.assertEqual(context_field.field_id, field_id) test.assertEqual(context_field.field_name, field_name) if field_label: test.assertEqual(context_field.field_label, field_label) if field_placeholder: test.assertEqual(context_field.description['field_placeholder'], field_placeholder) if field_property_uri: test.assertEqual(context_field.description['field_property_uri'], field_property_uri) test.assertEqual( extract_entity_id(context_field.description['field_render_type']), field_render_type) test.assertEqual( extract_entity_id(context_field.description['field_value_mode']), field_value_mode) test.assertEqual(context_field.description['field_value_type'], field_value_type) if options: if set(context_field['options']) != set(options): log.info("@@ Options expected: %r" % (context_field['options'], )) log.info("@@ Options seen: %r" % (options, )) log.info("@@ context_field: %r" % (context_field, )) test.assertEqual(set(context_field['options']), set(options)) if field_placement: test.assertEqual(context_field.description['field_placement'].field, field_placement) check_context_field_value(test, context_field, field_value_type=field_value_type, field_value=field_value) return
def field_description_from_view_field(collection, field, view_context=None, group_ids_seen=[]): """ Returns a field description value created using information from a field reference in a view description record (i.e. a dictionary containing a field id value and optional field property URI and placement values. (The optional values, if not provided, are obtained from the referenced field description) collection is a collection from which data is being rendered. field is a dictionary with the field description from a view or list description, containing a field id and placement values. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. group_ids_seen group ids expanded so far, to check for recursive reference. """ #@@TODO: for resilience, revert this when all tests pass? # field_id = field.get(ANNAL.CURIE.field_id, "Field_id_missing") # Field ID slug in URI #@@ field_id = extract_entity_id(field[ANNAL.CURIE.field_id]) recordfield = RecordField.load(collection, field_id, altscope="all") if recordfield is None: log.warning("Can't retrieve definition for field %s" % (field_id)) recordfield = RecordField.load(collection, "Field_missing", altscope="all") # If field references group, pull in group details group_ref = extract_entity_id(recordfield.get(ANNAL.CURIE.group_ref, None)) if group_ref: group_view = RecordGroup.load(collection, group_ref, altscope="all") if not group_view: log.error("Group %s used in field %s" % (group_ref, field_id)) # log.error("".join(traceback.format_stack())) # ex_type, ex, tb = sys.exc_info() # traceback.print_tb(tb) # raise EntityNotFound_Error("Group %s used in field %s"%(group_ref, field_id)) else: group_view = None # If present, `field_property` and `field_placement` override values in the field dexcription return FieldDescription(collection, recordfield, view_context=view_context, field_property=field.get(ANNAL.CURIE.property_uri, None), field_placement=field.get( ANNAL.CURIE.field_placement, None), group_view=group_view, group_ids_seen=group_ids_seen)
def field_description_from_view_field(collection, field, view_context=None, field_ids_seen=[]): """ Returns a field description value created using information from a field reference in a view description record (i.e. a dictionary containing a field id value and optional field property URI and placement values. (The optional values, if not provided, are obtained from the referenced field description) collection is a collection from which data is being rendered. field is a dictionary with the field description from a view or list description, containing a field id and placement values. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. field_ids_seen field ids expanded so far, to check for recursive reference. """ field_id = extract_entity_id(field[ANNAL.CURIE.field_id]) # recordfield = RecordField.load(collection, field_id, altscope="all") recordfield = collection.get_field(field_id) if recordfield is None: log.warning("Can't retrieve definition for field %s" % (field_id)) # recordfield = RecordField.load(collection, "Field_missing", altscope="all") recordfield = collection.get_field("Field_missing") recordfield[RDFS.CURIE.label] = message.MISSING_FIELD_LABEL % { 'id': field_id } # If field references group, pull in group details field_list = recordfield.get(ANNAL.CURIE.field_fields, None) if not field_list: group_ref = extract_entity_id( recordfield.get(ANNAL.CURIE.group_ref, None)) if group_ref: raise UnexpectedValue_Error("Group %s used in field %s" % (group_ref, field_id)) # If present, `field_property` and `field_placement` override values in the field dexcription return FieldDescription(collection, recordfield, view_context=view_context, field_property=field.get(ANNAL.CURIE.property_uri, None), field_placement=field.get( ANNAL.CURIE.field_placement, None), field_list=field_list, field_ids_seen=field_ids_seen)
def add_task_button_context(self, task_buttons_name, task_buttons, context): """ Adds context values to a supplied context dictionary corresponding to the supplied task_buttons value(s) from a view description. @NOTE: subsequent versions of this function may extract values from an identified task description record. """ if isinstance(task_buttons, list): context.update({ task_buttons_name: [{ 'button_id': b[ANNAL.CURIE.button_id], 'button_name': extract_entity_id(b[ANNAL.CURIE.button_id]), 'button_label': b.get(ANNAL.CURIE.button_label, "@@annal:button_label@@"), 'button_help': b.get(ANNAL.CURIE.button_help, "@@annal:button_help@@") } for b in task_buttons] }) elif task_buttons is not None: log.error( "DisplayInfo.context_data: Unexpected value for task_buttons: %r" % (task_buttons)) return
def get_entity(self, entity_id, action="view"): """ Loads and returns an entity for the current type, or returns None if the entity does not exist. If `action` is "new" then a new entity is initialized (but not saved). """ # log.debug( # "EntityTypeInfo.get_entity id %s, parent %s, altparent %s, action %s"% # (entity_id, self.entityparent, self.entityaltparent, action) # ) entity = None entity_id = extract_entity_id(entity_id) if valid_id(entity_id): if action == "new": entity = self._new_entity(entity_id) entity_initial_values = self.get_initial_entity_values( entity_id) entity.set_values(entity_initial_values) elif self.entityclass.exists(self.entityparent, entity_id, altscope="all"): entity = self.entityclass.load(self.entityparent, entity_id, altscope="all") else: log.debug( "EntityTypeInfo.get_entity %s/%s at %s not found" % (self.type_id, entity_id, self.entityparent._entitydir)) return entity
def check_context_field_value(test, context_field, field_value_type=None, field_value=None): """ Check field value in context field against supplied parameters. This function allows certain variations for robustness of tests. """ context_field_value = context_field['field_value'] if field_value is None: context_field_value = None elif field_value_type in [ "annal:Slug", "annal:Type", "annal:View", "annal:List" ]: context_field_value = extract_entity_id(context_field_value) if isinstance(field_value, (list, tuple)): for i in range(len(field_value)): log.debug("check_context_field_value (list): [%d] %r" % (i, field_value[i])) test.assertDictionaryMatch(context_field_value[i], field_value[i], prefix="[%d]" % i) elif isinstance(field_value, dict): test.assertDictionaryMatch(context_field_value, field_value[i], prefix="") else: test.assertEqual(context_field_value, field_value) return
def field_description_from_view_field(collection, field, view_context=None, group_ids_seen=[]): """ Returns a field description value created using information from a field reference in a view description record (i.e. a dictionary containing a field id value and optional field property URI and placement values. (The optional values, if not provided, are obtained from the referenced field description) collection is a collection from which data is being rendered. field is a dictionary with the field description from a view or list description, containing a field id and placement values. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. group_ids_seen group ids expanded so far, to check for recursive reference. """ #@@TODO: for resilience, revert this when all tests pass? # field_id = field.get(ANNAL.CURIE.field_id, "Field_id_missing") # Field ID slug in URI #@@ field_id = extract_entity_id(field[ANNAL.CURIE.field_id]) recordfield = RecordField.load(collection, field_id, altscope="all") if recordfield is None: log.warning("Can't retrieve definition for field %s"%(field_id)) recordfield = RecordField.load(collection, "Field_missing", altscope="all") # If field references group, pull in group details group_ref = extract_entity_id(recordfield.get(ANNAL.CURIE.group_ref, None)) if group_ref: group_view = RecordGroup.load(collection, group_ref, altscope="all") if not group_view: log.error("Group %s used in field %s"%(group_ref, field_id)) # log.error("".join(traceback.format_stack())) # ex_type, ex, tb = sys.exc_info() # traceback.print_tb(tb) # raise EntityNotFound_Error("Group %s used in field %s"%(group_ref, field_id)) else: group_view = None # If present, `field_property` and `field_placement` override values in the field dexcription return FieldDescription( collection, recordfield, view_context=view_context, field_property=field.get(ANNAL.CURIE.property_uri, None), field_placement=field.get(ANNAL.CURIE.field_placement, None), group_view=group_view, group_ids_seen=group_ids_seen )
def field_in_field_list(field_list, field_id, property_uri): """ Tests to see if field is referenced in field list """ for fref in field_list: if ((extract_entity_id(fref.get(ANNAL.CURIE.field_id, "")) == field_id) or (fref.get(ANNAL.CURIE.property_uri, "") == property_uri)): return True return False
def field_in_field_list(field_list, field_id, property_uri): """ Tests to see if field is referenced in field list """ for fref in field_list: if ( (extract_entity_id(fref.get(ANNAL.CURIE.field_id, "")) == field_id) or (fref.get(ANNAL.CURIE.property_uri, "") == property_uri) ): return True return False
def group_in_field_list(field_list, coll, group_ids): """ Tests to see if any of group ids are referenced in field list """ for fref in field_list: fid = extract_entity_id(fref.get(ANNAL.CURIE.field_id, "")) fdef = coll_field(coll, fid) if fdef.get(ANNAL.CURIE.group_ref, "") in group_ids: return True return False
def types_using_field(coll, field_id, property_uri): """ Returns a list of type ids that may use a specified field or property URI """ type_ids = set() type_uris = set() group_ids = set() # Look at field definition f = coll_field(coll, field_id) add_to_set(f.get(ANNAL.CURIE.field_entity_type, ""), type_uris) # Look at groups that reference field for g in coll_groups(coll): if field_in_field_list(g[ANNAL.CURIE.group_fields], field_id, property_uri): add_to_set(g.get_id(), group_ids) add_to_set(extract_entity_id(g.get(ANNAL.CURIE.record_type, "")), type_uris) # Look at views that reference field or groups for v in coll_views(coll): if (field_in_field_list(v[ANNAL.CURIE.view_fields], field_id, property_uri) or group_in_field_list(v[ANNAL.CURIE.view_fields], coll, group_ids)): add_to_set(extract_entity_id(v.get(ANNAL.CURIE.record_type, "")), type_uris) # Look at lists that reference field or groups for l in coll_lists(coll): if (field_in_field_list(l[ANNAL.CURIE.list_fields], field_id, property_uri) or group_in_field_list(l[ANNAL.CURIE.list_fields], coll, group_ids)): add_to_set(extract_entity_id(l.get(ANNAL.CURIE.record_type, "")), type_uris) add_to_set(extract_entity_id(l.get(ANNAL.CURIE.default_type, "")), type_uris) # Collect type ids for t in coll_types(coll): type_uri = t.get(ANNAL.CURIE.uri, "") supertype_uris = set(s[ANNAL.CURIE.supertype_uri] for s in t.get(ANNAL.CURIE.supertype_uris, [])) if (type_uri in type_uris) or (supertype_uris & type_uris): add_to_set(t.get_id(), type_ids) return type_ids
def field_description_from_view_field( collection, field, view_context=None, field_ids_seen=[] ): """ Returns a field description value created using information from a field reference in a view description record (i.e. a dictionary containing a field id value and optional field property URI and placement values. (The optional values, if not provided, are obtained from the referenced field description) collection is a collection from which data is being rendered. field is a dictionary with the field description from a view or list description, containing a field id and placement values. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. field_ids_seen field ids expanded so far, to check for recursive reference. """ field_id = extract_entity_id(field[ANNAL.CURIE.field_id]) # recordfield = RecordField.load(collection, field_id, altscope="all") recordfield = collection.get_field(field_id) if recordfield is None: log.warning("Can't retrieve definition for field %s"%(field_id)) # recordfield = RecordField.load(collection, "Field_missing", altscope="all") recordfield = collection.get_field("Field_missing") recordfield[RDFS.CURIE.label] = message.MISSING_FIELD_LABEL%{ 'id': field_id } # If field references group, pull in group details field_list = recordfield.get(ANNAL.CURIE.field_fields, None) if not field_list: group_ref = extract_entity_id(recordfield.get(ANNAL.CURIE.group_ref, None)) if group_ref: raise UnexpectedValue_Error("Group %s used in field %s"%(group_ref, field_id)) # If present, `field_property` and `field_placement` override values in the field dexcription return FieldDescription( collection, recordfield, view_context=view_context, field_property=field.get(ANNAL.CURIE.property_uri, None), field_placement=field.get(ANNAL.CURIE.field_placement, None), field_list=field_list, field_ids_seen=field_ids_seen )
def compare_field_list(old_coll, new_coll, old_field_list, new_field_list, reporting_prefix): """ Report URI changes between fields lists as seen in group, view and list definitions """ old_len = len(old_field_list) new_len = len(new_field_list) if new_len != old_len: print("* %s, field count changed from %d to %d" % (reporting_prefix, old_len, new_len)) for i in range(new_len): for j in range(old_len): # Look for field in old group. # If not found, ignore it - we're looking for URI changes # @@TODO: ... or are we? new_f = new_field_list[i] old_f = old_field_list[j] field_id = extract_entity_id(new_f[ANNAL.CURIE.field_id]) if field_id == extract_entity_id(old_f[ANNAL.CURIE.field_id]): # Field found - check for incompatible URI override # Note that field definitions are already checked old_uri = old_f.get(ANNAL.CURIE.property_uri, "") new_uri = new_f.get(ANNAL.CURIE.property_uri, "") if (not old_uri) and new_uri: old_field = coll_field(old_coll, field_id) old_uri = old_field[ANNAL.CURIE.property_uri] if old_uri and (not new_uri): new_field = coll_field(new_coll, field_id) new_uri = new_field[ANNAL.CURIE.property_uri] if old_uri != new_uri: print( "* %s, field %s, property URI changed from '%s' to '%s'" % (reporting_prefix, field_id, old_uri, new_uri)) print( " Consider adding supertype '%s' to type '%s' in collection '%s'" % (old_uri, type_id, new_coll_id)) report_property_references(new_coll, old_uri, "URI '%s'" % (old_uri)) break return
def compare_field_list(old_coll, new_coll, old_field_list, new_field_list, reporting_prefix): """ Report URI changes between fields lists as seen in group, view and list definitions """ old_len = len(old_field_list) new_len = len(new_field_list) if new_len != old_len: print("* %s, field count changed from %d to %d"%(reporting_prefix, old_len, new_len)) for i in range(new_len): for j in range(old_len): # Look for field in old group. # If not found, ignore it - we're looking for URI changes # @@TODO: ... or are we? new_f = new_field_list[i] old_f = old_field_list[j] field_id = extract_entity_id(new_f[ANNAL.CURIE.field_id]) if field_id == extract_entity_id(old_f[ANNAL.CURIE.field_id]): # Field found - check for incompatible URI override # Note that field definitions are already checked old_uri = old_f.get(ANNAL.CURIE.property_uri, "") new_uri = new_f.get(ANNAL.CURIE.property_uri, "") if (not old_uri) and new_uri: old_field = coll_field(old_coll, field_id) old_uri = old_field[ANNAL.CURIE.property_uri] if old_uri and (not new_uri): new_field = coll_field(new_coll, field_id) new_uri = new_field[ANNAL.CURIE.property_uri] if old_uri != new_uri: print( "* %s, field %s, property URI changed from '%s' to '%s'"% (reporting_prefix, field_id, old_uri, new_uri) ) print( " Consider adding supertype '%s' to type '%s' in collection '%s'"% (old_uri, type_id, new_coll_id) ) report_property_references(new_coll, old_uri, "URI '%s'"%(old_uri)) break return
def get_default_view_id(self): """ Returns the default view id for the current record type """ view_id = None if self.recordtype: view_id = extract_entity_id( self.recordtype.get(ANNAL.CURIE.type_view, None)) else: log.warning( "EntityTypeInfo.get_default_view_id: no type data for %s" % (self.type_id)) return view_id or "Default_view"
def get_type_list_id(self, type_id): """ Return default list_id for listing defined type, or None """ list_id = None # print "@@ get_type_list_id type_id %s, list_id %s"%(type_id, list_id) if type_id: if self.entitytypeinfo.recordtype: list_id = extract_entity_id( self.entitytypeinfo.recordtype.get(ANNAL.CURIE.type_list, None) ) else: log.warning("DisplayInfo.get_type_list_id no type data for %s"%(type_id)) # print "@@ get_type_list_id %s"%list_id return list_id
def entitydata_recordtype_view_form_data( coll_id="testcoll", type_id="testtype", orig_type=None, type_uri=None, entity_id="", orig_id=None, action=None, cancel=None, update="Entity", add_view_field=None, open_view=None, customize=None): # log.info("entitydata_recordtype_view_form_data: entity_id %s"%(entity_id)) form_data_dict = ( { 'Type_label': '%s data ... (%s/%s)'%(update, coll_id, type_id) , 'Type_comment': '%s description ... (%s/%s)'%(update, coll_id, type_id) , 'orig_id': 'orig_entity_id' , 'continuation_url': entitydata_list_type_url(coll_id, orig_type or type_id) }) if entity_id is not None: form_data_dict['entity_id'] = entity_id if entity_id and type_id: type_url = entity_url(coll_id=coll_id, type_id=type_id, entity_id=entity_id) type_url = type_url.replace("___", entity_id) # Preserve bad type in form data form_data_dict['entity_id'] = entity_id form_data_dict['Type_uri'] = "" # type_url form_data_dict['orig_id'] = entity_id if orig_id: form_data_dict['orig_id'] = orig_id label_id = entity_id or orig_id if label_id and type_id: form_data_dict['Type_label'] = '%s %s/%s/%s'%(update, coll_id, type_id, label_id) form_data_dict['Type_comment'] = '%s coll %s, type %s, entity %s'%(update, coll_id, type_id, label_id) if type_id: form_data_dict['entity_type'] = "_type/"+type_id form_data_dict['orig_type'] = extract_entity_id(type_id) if type_uri: form_data_dict['Type_uri'] = type_uri if orig_type: form_data_dict['orig_type'] = orig_type if action: form_data_dict['action'] = action if cancel: form_data_dict['cancel'] = "Cancel" elif add_view_field: form_data_dict['add_view_field'] = add_view_field elif open_view: form_data_dict['open_view'] = open_view elif customize: form_data_dict['customize'] = customize else: form_data_dict['save'] = 'Save' return form_data_dict
def get_copy_entity(self, entity_id, copy_entity_id): """ Read or create an entity with the indicated entity_id. If the identified entity does not already exist, a new entity is created but not (yet) saved. The newly created entity is a copy of 'copy_entity_id'. """ entity_id = extract_entity_id(entity_id) entity = self.get_entity(entity_id) if entity is None: entity = self._new_entity(entity_id) entity.set_values( self.get_initial_entity_values(entity_id, copy_entity_id=copy_entity_id)) return entity
def get_type_list_id(self, type_id): """ Return default list_id for listing defined type, or None """ list_id = None # print "@@ get_type_list_id type_id %s, list_id %s"%(type_id, list_id) if type_id: if self.entitytypeinfo.recordtype: list_id = extract_entity_id( self.entitytypeinfo.recordtype.get(ANNAL.CURIE.type_list, None)) else: log.warning( "DisplayInfo.get_type_list_id no type data for %s" % (type_id)) # print "@@ get_type_list_id %s"%list_id return list_id
def _set_alt_parent_coll(cls, parent, coll): """ Set alternative parent collection - sets up search path for subsequent references. """ coll_id = coll.get_id() parent_coll_id = extract_entity_id( coll.get(ANNAL.CURIE.inherit_from, None)) if parent_coll_id and parent_coll_id != layout.SITEDATA_ID: parent_coll = Collection.load(parent, parent_coll_id) if parent_coll is None: log.warning( "Collection._set_alt_parent_coll: coll %s references non-existent parent %s" % (coll_id, parent_coll_id)) else: log.debug( "Collection._set_alt_parent_coll: coll %s references parent %s" % (coll_id, parent_coll_id)) coll.set_alt_entities(parent_coll) return coll
def _set_alt_parent_coll(cls, parent, coll): """ Set alternative parent collection - sets up search path for subsequent references. """ coll_id = coll.get_id() parent_coll_id = extract_entity_id(coll.get(ANNAL.CURIE.inherit_from, None)) if parent_coll_id and parent_coll_id != layout.SITEDATA_ID: parent_coll = Collection.load(parent, parent_coll_id) if parent_coll is None: err_msg = message.COLL_PARENT_NOT_EXIST%{"id": coll_id, "parent_id": parent_coll_id} coll.set_error(err_msg) log.warning("Collection._set_alt_parent_coll: "+err_msg) else: log.debug( "Collection._set_alt_parent_coll: coll %s references parent %s"% (coll_id, parent_coll_id) ) coll.set_alt_entities(parent_coll) return coll
def get_list_info(self, list_id): """ Retrieve list definition to use for display """ if not self.http_response: assert ((self.site and self.collection) is not None) assert list_id # log.debug( # "DisplayInfo.get_list_info: collection.get_alt_entities %r"% # [ c.get_id() for c in self.collection.get_alt_entities(altscope="all") ] # ) if not RecordList.exists(self.collection, list_id, altscope="all"): log.warning( "DisplayInfo.get_list_info: RecordList %s not found" % list_id) self.http_response = self.view.error( dict(self.view.error404values(), message=message.RECORD_LIST_NOT_EXISTS % ({ 'id': list_id, 'coll_id': self.coll_id }))) else: self.list_id = list_id self.recordlist = RecordList.load(self.collection, list_id, altscope="all") if "@error" in self.recordlist: self.http_response = self.view.error( dict(self.view.error500values(), message=message.RECORD_LIST_LOAD_ERROR % ({ 'id': list_id, 'file': self.recordlist["@error"], 'message': self.recordlist["@message"] }))) elif self.type_id is None and self.entitytypeinfo is None: self.get_type_info( extract_entity_id( self.recordlist[ANNAL.CURIE.default_type])) # log.debug("DisplayInfo.get_list_info: %r"%(self.recordlist.get_values())) return self.http_response
def _set_alt_parent_coll(cls, parent, coll): """ Set alternative parent collection - sets up search path for subsequent references. """ coll_id = coll.get_id() parent_coll_id = extract_entity_id(coll.get(ANNAL.CURIE.inherit_from, None)) if parent_coll_id and parent_coll_id != layout.SITEDATA_ID: parent_coll = Collection.load(parent, parent_coll_id) if parent_coll is None: log.warning( "Collection._set_alt_parent_coll: coll %s references non-existent parent %s"% (coll_id, parent_coll_id) ) else: log.debug( "Collection._set_alt_parent_coll: coll %s references parent %s"% (coll_id, parent_coll_id) ) coll.set_alt_entities(parent_coll) return coll
def _migrate_values(self, entitydata): """ Group description entity format migration method. The specification for this method is that it returns an entitydata value which is a copy of the supplied entitydata with format migrations applied. NOTE: implementations are free to apply migrations in-place. The resulting entitydata should be exactly as the supplied data *should* appear in storage to conform to the current format of the data. The migration function should be idempotent; i.e. x._migrate_values(x._migrate_values(e)) == x._migrate_values(e) """ for f in entitydata[ANNAL.CURIE.group_fields]: field_id = extract_entity_id(f[ANNAL.CURIE.field_id]) if field_id == "Field_render": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/Field_render_type" if field_id == "Field_type": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/Field_value_type" # Return result return entitydata
def _migrate_values(self, entitydata): """ List description entity format migration method. The specification for this method is that it returns an entitydata value which is a copy of the supplied entitydata with format migrations applied. NOTE: implementations are free to apply migrations in-place. The resulting entitydata should be exactly as the supplied data *should* appear in storage to conform to the current format of the data. The migration function should be idempotent; i.e. x._migrate_values(x._migrate_values(e)) == x._migrate_values(e) """ for f in entitydata[ANNAL.CURIE.list_fields]: field_id = extract_entity_id(f[ANNAL.CURIE.field_id]) if field_id == "Field_render": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/Field_render_type" if field_id == "Field_type": f[ANNAL.CURIE.field_id] = layout.FIELD_TYPEID+"/Field_value_type" # Return result return entitydata
def check_context_field_value(test, context_field, field_value_type=None, field_value=None): """ Check field value in context field against supplied parameters. This function allows certain variations for robustness of tests. """ context_field_value = context_field['field_value'] if field_value is None: context_field_value = None elif field_value_type in [ "annal:EntityRef", "annal:Type", "annal:View", "annal:List" ]: context_field_value = extract_entity_id(context_field_value) if isinstance(field_value, (list, tuple)): if len(field_value) != len(context_field_value): #@@ Diagnostic: log.warning("@@ field_value: %r" % (field_value, )) log.warning("@@ context_field_value: %r" % (context_field_value, )) #@@ test.assertEqual(len(field_value), len(context_field_value)) for i in range(len(field_value)): # print "@@ check_context_field_value (list): [%d] %r"%(i, field_value[i]) # print "@@ check_context_field_value (list): [%d] %r (context)"%(i, context_field_value[i]) log.debug("check_context_field_value (list): [%d] %r" % (i, field_value[i])) test.assertDictionaryMatch(context_field_value[i], field_value[i], prefix="[%d]" % i) elif isinstance(field_value, dict): test.assertDictionaryMatch(context_field_value, field_value[i], prefix="") else: test.assertEqual(context_field_value, field_value) return
def get_list_info(self, list_id): """ Retrieve list definition to use for display """ if not self.http_response: assert ((self.site and self.collection) is not None) assert list_id # log.debug( # "DisplayInfo.get_list_info: collection.get_alt_entities %r"% # [ c.get_id() for c in self.collection.get_alt_entities(altscope="all") ] # ) if not RecordList.exists(self.collection, list_id, altscope="all"): log.warning("DisplayInfo.get_list_info: RecordList %s not found"%list_id) self.http_response = self.view.error( dict(self.view.error404values(), message=message.RECORD_LIST_NOT_EXISTS%( {'id': list_id, 'coll_id': self.coll_id}) ) ) else: self.list_id = list_id self.recordlist = RecordList.load(self.collection, list_id, altscope="all") if "@error" in self.recordlist: self.http_response = self.view.error( dict(self.view.error500values(), message=message.RECORD_LIST_LOAD_ERROR%( { 'id': list_id , 'file': self.recordlist["@error"] , 'message': self.recordlist["@message"] }) ) ) elif self.type_id is None and self.entitytypeinfo is None: self.get_type_info( extract_entity_id(self.recordlist[ANNAL.CURIE.default_type]) ) # log.debug("DisplayInfo.get_list_info: %r"%(self.recordlist.get_values())) return self.http_response
def add_task_button_context(self, task_buttons_name, task_buttons, context): """ Adds context values to a supplied context dictionary corresponding to the supplied task_buttons value(s) from a view description. @NOTE: subsequent versions of this function may extract values from an identified task description record. """ if isinstance(task_buttons, list): context.update( { task_buttons_name: [ { 'button_id': b[ANNAL.CURIE.button_id] , 'button_name': extract_entity_id(b[ANNAL.CURIE.button_id]) , 'button_label': b.get(ANNAL.CURIE.button_label, "@@annal:button_label@@") , 'button_help': b.get(ANNAL.CURIE.button_help, "@@annal:button_help@@") } for b in task_buttons ] }) elif task_buttons is not None: log.error( "DisplayInfo.context_data: Unexpected value for task_buttons: %r"% (task_buttons) ) return
def __init__(self, collection, recordfield, view_context=None, field_property=None, field_placement=None, field_list=None, field_ids_seen=[], field_placement_classes=None): """ Creates a field description value to use in a context value when rendering a form. Values defined here are mentioned in field rendering templates. The FieldDescription object behaves as a dictionary containing the various field attributes. collection is a collection from which data is being rendered. recordfield is a RecordField value or dictionary containing details of the field for which a descriptor is constructed. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. field_property if supplied, overrides the field property URI from `recordfield` field_placement if supplied, overrides field placement from `recordfield` field_list if the field itself contains or references a list of fields, this is that list of fields. field_ids_seen field ids expanded so far, to check for recursive reference. field_placement_classes if supplied, overrides field placement classes derived from value for `field_placement` string. """ self._collection = collection # log.debug("FieldDescription recordfield: %r"%(recordfield,)) field_id = recordfield.get(ANNAL.CURIE.id, "_missing_id_") field_name = recordfield.get(ANNAL.CURIE.field_name, field_id) # Field name in form field_label = recordfield.get(RDFS.CURIE.label, "") field_help = recordfield.get(RDFS.CURIE.comment, "") field_property = field_property or recordfield.get( ANNAL.CURIE.property_uri, "") field_placement = field_placement or recordfield.get( ANNAL.CURIE.field_placement, "") field_placement_c = field_placement_classes or get_placement_classes( field_placement) field_placeholder = recordfield.get(ANNAL.CURIE.placeholder, "") field_tooltip = recordfield.get(ANNAL.CURIE.tooltip, "") field_render_type = extract_entity_id( recordfield.get(ANNAL.CURIE.field_render_type, "")) field_value_mode = extract_entity_id( recordfield.get(ANNAL.CURIE.field_value_mode, "@@FieldDescription:value_mode@@")) field_ref_type = extract_entity_id( recordfield.get(ANNAL.CURIE.field_ref_type, None)) field_entity_type = recordfield.get(ANNAL.CURIE.field_entity_type, None) field_group_ref = extract_entity_id( recordfield.get(ANNAL.CURIE.group_ref, None)) self._field_desc = ({ 'field_id': field_id, 'field_name': field_name, 'field_instance_name': field_name, 'field_render_type': field_render_type, 'field_value_mode': field_value_mode, 'field_value_type': recordfield.get(ANNAL.CURIE.field_value_type, ""), 'field_label': field_label, 'field_help': field_help, 'field_property_uri': field_property, 'field_placement': field_placement_c, 'field_placeholder': field_placeholder, 'field_tooltip': field_tooltip, 'field_tooltip_test': field_tooltip or (field_help) or "", 'field_default_value': recordfield.get(ANNAL.CURIE.default_value, None), 'field_ref_type': field_ref_type, 'field_ref_field': recordfield.get(ANNAL.CURIE.field_ref_field, None), 'field_ref_restriction': recordfield.get(ANNAL.CURIE.field_ref_restriction, "ALL"), 'field_entity_type': field_entity_type, 'field_choices': None, 'field_group_ref': field_group_ref, 'group_label': None, 'group_add_label': None, 'group_delete_label': None, 'group_field_list': None, 'group_field_descs': None, 'field_renderer': FieldRenderer(field_render_type, field_value_mode), 'field_value_mapper': get_value_mapper(field_render_type) # Used by fieldvaluemap.py }) self._field_suffix_index = 0 # No dup self._field_suffix = "" # If field references type, pull in copy of type id and link values type_ref = self._field_desc['field_ref_type'] if type_ref: restrict_values = self._field_desc['field_ref_restriction'] entity_finder = EntityFinder(collection, selector=restrict_values) entities = entity_finder.get_entities_sorted(type_id=type_ref, context=view_context, altscope="select") # Note: the options list may be used more than once, so the id generator # returned must be materialized as a list # Uses collections.OrderedfDict to preserve entity ordering self._field_desc['field_choices'] = collections.OrderedDict() if field_render_type in ["Enum_optional", "Enum_choice_opt"]: # Add blank choice for optional selections self._field_desc['field_choices'][''] = FieldChoice( '', label=field_placeholder) for e in entities: eid = e.get_id() val = e.get_type_entity_id() if eid != layout.INITIAL_VALUES_ID: self._field_desc['field_choices'][val] = FieldChoice( val, label=e.get_label(), link=e.get_view_url_path()) # If field references or contains field list, pull in field details if field_list: if field_id in field_ids_seen: raise Annalist_Error( field_id, "Recursive field reference in field group") field_ids_seen = field_ids_seen + [field_id] group_label = field_label add_label = recordfield.get(ANNAL.CURIE.repeat_label_add, None) or "Add " + field_id remove_label = recordfield.get(ANNAL.CURIE.repeat_label_delete, None) or "Remove " + field_id group_field_descs = [] for subfield in field_list: f = field_description_from_view_field(collection, subfield, view_context, field_ids_seen) group_field_descs.append(f) self._field_desc.update({ 'group_id': field_id, 'group_label': group_label, 'group_add_label': add_label, 'group_delete_label': remove_label, 'group_field_list': field_list # Description from field/group , 'group_field_descs': group_field_descs # Resulting field description list }) # log.debug("FieldDescription: %s"%field_id) # log.info("FieldDescription._field_desc %r"%(self._field_desc,)) # log.info("FieldDescription.field_placement %r"%(self._field_desc['field_placement'],)) return
def type_view_form_data(action=None, coll_id="testcoll", orig_coll=None, type_type_id="_type", orig_type=None, type_entity_id="", orig_id=None, type_entity_uri=None, cancel=None, close=None, edit=None, copy=None, task=None, add_view_field=None, open_view=None, customize=None, update="RecordType", ): """ Returns a request dictionary that can be used with the Django test client. Per Django documentation, multiple values for a key are provided as a list. See: https://docs.djangoproject.com/en/1.8/topics/testing/tools/#making-requests Note: historically, some tests use Type_view to display non-type data, hence explicit type_type_id and type_entity_id parameters. """ form_data_dict = ( { 'Type_label': '%s data ... (%s/%s)'%(update, coll_id, type_entity_id) , 'Type_comment': '%s description ... (%s/%s)'%(update, coll_id, type_entity_id) , 'continuation_url': entitydata_list_type_url(coll_id, type_type_id) }) if action: form_data_dict['action'] = action if type_type_id: form_data_dict['entity_type'] = "_type/"+type_type_id form_data_dict['orig_type'] = extract_entity_id(type_type_id) if type_entity_id is not None: form_data_dict['entity_id'] = type_entity_id form_data_dict['orig_id'] = type_entity_id if type_entity_id and type_type_id: entity_url = recordtype_url(coll_id=coll_id, type_id=type_entity_id) form_data_dict['entity_id'] = type_entity_id form_data_dict['Type_uri'] = entity_url or "" form_data_dict['Type_view'] = "_view/Default_view" form_data_dict['Type_list'] = "_list/Default_list" form_data_dict['orig_coll'] = coll_id if orig_coll: form_data_dict['orig_coll'] = orig_coll if orig_type: form_data_dict['orig_type'] = orig_type if orig_id: form_data_dict['orig_id'] = orig_id label_id = type_entity_id or orig_id if label_id and type_type_id: form_data_dict['Type_label'] = ( '%s %s/%s/%s'%(update, coll_id, type_type_id, label_id) ) form_data_dict['Type_comment'] = ( '%s coll %s, type %s, entity %s'%(update, coll_id, type_type_id, label_id) ) if type_entity_uri: form_data_dict['Type_uri'] = type_entity_uri type_uri_rstrip = type_entity_uri.rstrip() form_data_dict['Type_supertype_uris__0__Type_supertype_uri'] = type_uri_rstrip+"/super1" form_data_dict['Type_supertype_uris__1__Type_supertype_uri'] = type_uri_rstrip+"/super2" if cancel: form_data_dict['cancel'] = "Cancel" elif close: form_data_dict['close'] = "Close" elif edit: form_data_dict['edit'] = "Edit" elif copy: form_data_dict['copy'] = "Copy" elif add_view_field: form_data_dict['add_view_field'] = add_view_field elif open_view: form_data_dict['open_view'] = open_view elif customize: form_data_dict['customize'] = customize elif task: form_data_dict[task] = task else: form_data_dict['save'] = "Save" return form_data_dict
def type_view_form_data( action=None, coll_id="testcoll", orig_coll=None, type_type_id="_type", orig_type=None, type_entity_id="", orig_id=None, type_entity_uri=None, cancel=None, close=None, edit=None, copy=None, task=None, add_view_field=None, open_view=None, customize=None, update="RecordType", ): """ Returns a request dictionary that can be used with the Django test client. Per Django documentation, multiple values for a key are provided as a list. See: https://docs.djangoproject.com/en/1.8/topics/testing/tools/#making-requests Note: historically, some tests use Type_view to display non-type data, hence explicit type_type_id and type_entity_id parameters. """ form_data_dict = ({ 'Type_label': '%s data ... (%s/%s)' % (update, coll_id, type_entity_id), 'Type_comment': '%s description ... (%s/%s)' % (update, coll_id, type_entity_id), 'continuation_url': entitydata_list_type_url(coll_id, type_type_id) }) if action: form_data_dict['action'] = action if type_type_id: form_data_dict['entity_type'] = "_type/" + type_type_id form_data_dict['orig_type'] = extract_entity_id(type_type_id) if type_entity_id is not None: form_data_dict['entity_id'] = type_entity_id form_data_dict['orig_id'] = type_entity_id if type_entity_id and type_type_id: entity_url = recordtype_url(coll_id=coll_id, type_id=type_entity_id) form_data_dict['entity_id'] = type_entity_id form_data_dict['Type_uri'] = entity_url or "" form_data_dict['Type_view'] = "_view/Default_view" form_data_dict['Type_list'] = "_list/Default_list" form_data_dict['orig_coll'] = coll_id if orig_coll: form_data_dict['orig_coll'] = orig_coll if orig_type: form_data_dict['orig_type'] = orig_type if orig_id: form_data_dict['orig_id'] = orig_id label_id = type_entity_id or orig_id if label_id and type_type_id: form_data_dict['Type_label'] = ( '%s %s/%s/%s' % (update, coll_id, type_type_id, label_id)) form_data_dict['Type_comment'] = ( '%s coll %s, type %s, entity %s' % (update, coll_id, type_type_id, label_id)) if type_entity_uri: form_data_dict['Type_uri'] = type_entity_uri type_uri_rstrip = type_entity_uri.rstrip() form_data_dict[ 'Type_supertype_uris__0__Type_supertype_uri'] = type_uri_rstrip + "/super1" form_data_dict[ 'Type_supertype_uris__1__Type_supertype_uri'] = type_uri_rstrip + "/super2" if cancel: form_data_dict['cancel'] = "Cancel" elif close: form_data_dict['close'] = "Close" elif edit: form_data_dict['edit'] = "Edit" elif copy: form_data_dict['copy'] = "Copy" elif add_view_field: form_data_dict['add_view_field'] = add_view_field elif open_view: form_data_dict['open_view'] = open_view elif customize: form_data_dict['customize'] = customize elif task: form_data_dict[task] = task else: form_data_dict['save'] = "Save" return form_data_dict
def entitydata_recordtype_view_form_data(coll_id="testcoll", type_id="testtype", orig_type=None, type_uri=None, entity_id="", orig_id=None, action=None, cancel=None, update="Entity", add_view_field=None, open_view=None, customize=None): # log.info("entitydata_recordtype_view_form_data: entity_id %s"%(entity_id)) form_data_dict = ({ 'Type_label': '%s data ... (%s/%s)' % (update, coll_id, type_id), 'Type_comment': '%s description ... (%s/%s)' % (update, coll_id, type_id), 'orig_id': 'orig_entity_id', 'continuation_url': entitydata_list_type_url(coll_id, orig_type or type_id) }) if entity_id is not None: form_data_dict['entity_id'] = entity_id if entity_id and type_id: type_url = entity_url(coll_id=coll_id, type_id=type_id, entity_id=entity_id) type_url = type_url.replace( "___", entity_id) # Preserve bad type in form data form_data_dict['entity_id'] = entity_id form_data_dict['Type_uri'] = "" # type_url form_data_dict['orig_id'] = entity_id if orig_id: form_data_dict['orig_id'] = orig_id label_id = entity_id or orig_id if label_id and type_id: form_data_dict['Type_label'] = '%s %s/%s/%s' % (update, coll_id, type_id, label_id) form_data_dict['Type_comment'] = '%s coll %s, type %s, entity %s' % ( update, coll_id, type_id, label_id) if type_id: form_data_dict['entity_type'] = "_type/" + type_id form_data_dict['orig_type'] = extract_entity_id(type_id) if type_uri: form_data_dict['Type_uri'] = type_uri if orig_type: form_data_dict['orig_type'] = orig_type if action: form_data_dict['action'] = action if cancel: form_data_dict['cancel'] = "Cancel" elif add_view_field: form_data_dict['add_view_field'] = add_view_field elif open_view: form_data_dict['open_view'] = open_view elif customize: form_data_dict['customize'] = customize else: form_data_dict['save'] = 'Save' return form_data_dict
def post(self, request, coll_id=None, type_id=None, list_id=None): """ Handle response from dynamically generated list display form. """ log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s"%(coll_id, type_id, list_id)) log.log(settings.TRACE_FIELD_VALUE, " %s"%(self.get_request_path())) log.log(settings.TRACE_FIELD_VALUE, " form data %r"%(request.POST)) listinfo = self.list_setup(coll_id, type_id, list_id, request.POST.dict()) if listinfo.http_response: return listinfo.http_response if 'close' in request.POST: return HttpResponseRedirect(listinfo.get_continuation_url() or self.collection_view_url) # Process requested action redirect_uri = None entity_ids = request.POST.getlist('entity_select') log.debug("entity_ids %r"%(entity_ids)) if len(entity_ids) > 1: action = "" redirect_uri = self.check_value_supplied( None, message.TOO_MANY_ENTITIES_SEL, continuation_url=listinfo.get_continuation_url() ) else: entity_type = type_id or listinfo.get_list_type_id() entity_id = None if len(entity_ids) == 1: (entity_type, entity_id) = split_type_entity_id(entity_ids[0], entity_type) if "new" in request.POST: action = "new" redirect_uri = uri_with_params( listinfo.get_new_view_uri(coll_id, entity_type), {'continuation_url': listinfo.get_continuation_here()} ) if "copy" in request.POST: action = "copy" redirect_uri = ( self.check_value_supplied(entity_id, message.NO_ENTITY_FOR_COPY, continuation_url=listinfo.get_continuation_url() ) or uri_with_params( listinfo.get_edit_view_uri( coll_id, entity_type, entity_id, action ), {'continuation_url': listinfo.get_continuation_here()} ) ) if "edit" in request.POST: action = "edit" redirect_uri = ( self.check_value_supplied(entity_id, message.NO_ENTITY_FOR_EDIT, continuation_url=listinfo.get_continuation_url() ) or uri_with_params( listinfo.get_edit_view_uri( coll_id, entity_type, entity_id, action ), {'continuation_url': listinfo.get_continuation_here()} ) ) if "delete" in request.POST: action = "delete" redirect_uri = ( self.check_value_supplied(entity_id, message.NO_ENTITY_FOR_DELETE, continuation_url=listinfo.get_continuation_url() ) or listinfo.check_collection_entity(entity_id, entity_type, message.SITE_ENTITY_FOR_DELETE%{'id': entity_id} ) or self.check_delete_type_values(listinfo, entity_id, entity_type, message.TYPE_VALUES_FOR_DELETE%{'type_id': entity_id} ) ) if not redirect_uri: # Get user to confirm action before actually doing it confirmed_action_uri = self.view_uri( "AnnalistEntityDataDeleteView", coll_id=coll_id, type_id=entity_type ) # log.info("coll_id %s, type_id %s, confirmed_action_uri %s"%(coll_id, entity_type, confirmed_action_uri)) delete_params = dict_querydict( { "entity_delete": ["Delete"] , "entity_id": [entity_id] , "completion_url": [listinfo.get_continuation_here()] , "search_for": [request.POST['search_for']] }) curi = listinfo.get_continuation_url() if curi: dict_querydict["continuation_url"] = [curi] message_vals = {'id': entity_id, 'type_id': entity_type, 'coll_id': coll_id} typeinfo = listinfo.entitytypeinfo if typeinfo is None: typeinfo = EntityTypeInfo(listinfo.collection, entity_type) return ( self.form_action_auth( "delete", listinfo.collection, typeinfo.permissions_map ) or ConfirmView.render_form(request, action_description= message.REMOVE_ENTITY_DATA%message_vals, confirmed_action_uri= confirmed_action_uri, action_params= delete_params, cancel_action_uri= listinfo.get_continuation_here(), title= self.site_data()["title"] ) ) if "default_view" in request.POST: if listinfo.entitytypeinfo: permissions_map = listinfo.entitytypeinfo.permissions_map else: permissions_map = CONFIG_PERMISSIONS auth_check = self.form_action_auth("config", listinfo.collection, permissions_map) if auth_check: return auth_check listinfo.collection.set_default_list(list_id) action = "list" msg = message.DEFAULT_LIST_UPDATED%{'coll_id': coll_id, 'list_id': list_id} redirect_uri = ( uri_with_params( self.get_request_path(), self.info_params(msg), listinfo.get_continuation_url_dict() ) ) if ( ("list_type" in request.POST) or ("list_all" in request.POST) ): action = "list" redirect_uri = self.get_list_url( coll_id, extract_entity_id(request.POST['list_choice']), type_id=None if "list_all" in request.POST else type_id, scope="all" if "list_scope_all" in request.POST else None, search=request.POST['search_for'], query_params=listinfo.get_continuation_url_dict() ) if "customize" in request.POST: action = "config" redirect_uri = ( uri_with_params( self.view_uri( "AnnalistCollectionEditView", coll_id=coll_id ), {'continuation_url': listinfo.get_continuation_here()} ) ) if redirect_uri: return ( listinfo.check_authorization(action) or HttpResponseRedirect(redirect_uri) ) # Report unexpected form data # This shouldn't happen, but just in case... # Redirect to continuation with error log.error("Unexpected form data posted to %s: %r"%(request.get_full_path(), request.POST)) err_values = self.error_params( message.UNEXPECTED_FORM_DATA%(request.POST), message.SYSTEM_ERROR ) redirect_uri = uri_with_params(listinfo.get_continuation_next(), err_values) return HttpResponseRedirect(redirect_uri)
def __init__(self, collection, recordfield, view_context=None, field_property=None, field_placement=None, group_view=None, group_ids_seen=[], field_placement_classes=None ): """ Creates a field description value to use in a context value when rendering a form. Values defined here are mentioned in field rendering templates. The FieldDescription object behaves as a dictionary containing the various field attributes. collection is a collection from which data is being rendered. Used when generating enumerated values. recordfield is a RecordField value or dictionary containing details of the field for which a descriptor is constructed. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. field_property if supplied, overrides the field property URI from `recordfield` field_placement if supplied, overrides field placement from `recordfield` group_view if the field itself references a list of fields, this is a RecordGroup value or dictionary containing the referenced list of fields. group_ids_seen group ids expanded so far, to check for recursive reference. field_classes if supplied, overrides field placement classes derived from value for `field_placement` string. """ self._collection = collection # log.debug("FieldDescription recordfield: %r"%(recordfield,)) field_id = recordfield.get(ANNAL.CURIE.id, "_missing_id_") field_name = recordfield.get(ANNAL.CURIE.field_name, field_id) # Field name in form field_label = recordfield.get(RDFS.CURIE.label, "") field_property = field_property or recordfield.get(ANNAL.CURIE.property_uri, "") field_placement = field_placement or recordfield.get(ANNAL.CURIE.field_placement, "") field_placement_c = field_placement_classes or get_placement_classes(field_placement) field_placeholder = recordfield.get(ANNAL.CURIE.placeholder, "") field_render_type = extract_entity_id(recordfield.get(ANNAL.CURIE.field_render_type, "")) field_value_mode = extract_entity_id(recordfield.get(ANNAL.CURIE.field_value_mode, "@@FieldDescription:value_mode@@")) field_ref_type = extract_entity_id(recordfield.get(ANNAL.CURIE.field_ref_type, None)) field_entity_type = recordfield.get(ANNAL.CURIE.field_entity_type, None) field_group_ref = extract_entity_id(recordfield.get(ANNAL.CURIE.group_ref, None)) self._field_desc = ( { 'field_id': field_id , 'field_name': field_name , 'field_instance_name': field_name , 'field_render_type': field_render_type , 'field_value_mode': field_value_mode , 'field_value_type': recordfield.get(ANNAL.CURIE.field_value_type, "") , 'field_label': field_label , 'field_help': recordfield.get(RDFS.CURIE.comment, "") , 'field_property_uri': field_property , 'field_placement': field_placement_c , 'field_placeholder': field_placeholder , 'field_default_value': recordfield.get(ANNAL.CURIE.default_value, None) , 'field_ref_type': field_ref_type , 'field_ref_field': recordfield.get(ANNAL.CURIE.field_ref_field, None) , 'field_ref_restriction': recordfield.get(ANNAL.CURIE.field_ref_restriction, "ALL") , 'field_entity_type': field_entity_type , 'field_choices': None # , 'field_choice_labels': None # , 'field_choice_links': None , 'field_group_ref': field_group_ref , 'group_label': None , 'group_add_label': None , 'group_delete_label': None , 'group_view': None , 'group_field_descs': None , 'field_render_label': get_label_renderer( field_render_type, field_value_mode) , 'field_render_view': get_view_renderer( field_render_type, field_value_mode) , 'field_render_edit': get_edit_renderer( field_render_type, field_value_mode) , 'field_render_label_view': get_label_view_renderer( field_render_type, field_value_mode) , 'field_render_label_edit': get_label_edit_renderer( field_render_type, field_value_mode) , 'field_render_colhead': get_col_head_renderer( field_render_type, field_value_mode) , 'field_render_colhead_view': get_col_head_view_renderer(field_render_type, field_value_mode) , 'field_render_colhead_edit': get_col_head_edit_renderer(field_render_type, field_value_mode) , 'field_render_colview': get_col_view_renderer( field_render_type, field_value_mode) , 'field_render_coledit': get_col_edit_renderer( field_render_type, field_value_mode) , 'field_render_mode': get_mode_renderer( field_render_type, field_value_mode) , 'field_value_mapper': get_value_mapper(field_render_type) }) self._field_suffix_index = 0 # No dup self._field_suffix = "" # If field references type, pull in copy of type id and link values type_ref = self._field_desc['field_ref_type'] if type_ref: restrict_values = self._field_desc['field_ref_restriction'] entity_finder = EntityFinder(collection, selector=restrict_values) # Determine subtypes of field entity type, if specified # @@TODO: subtype logic here is just pig ugly... # need context to provide info that can be used to calculate supertypes # on-the-fly as needed by the field restriction expression. E.g. include # collection object in context. if field_entity_type and restrict_values: field_entity_subtypes = ( [ t.get_type_uri() for t in entity_finder.get_collection_uri_subtypes(field_entity_type, altscope="all") ]) self._field_desc['field_entity_subtypes'] = field_entity_subtypes field_view_context = dict(view_context or {}, field={'subtypes': field_entity_subtypes}) else: field_view_context = view_context entities = entity_finder.get_entities_sorted( type_id=type_ref, context=field_view_context, altscope="select" ) # Note: the options list may be used more than once, so the id generator # returned must be materialized as a list # Uses collections.OrderedfDict to preserve entity ordering self._field_desc['field_choices'] = collections.OrderedDict() if field_render_type in ["Enum_optional", "Enum_choice_opt"]: # Add blank choice for optional selections self._field_desc['field_choices'][''] = FieldChoice('', label=field_placeholder) for e in entities: eid = e.get_id() val = e.get_type_entity_id() if eid != "_initial_values": self._field_desc['field_choices'][val] = FieldChoice( val, label=e.get_label(), link=e.get_view_url_path() ) # log.debug("FieldDescription: typeref %s: %r"% # (self._field_desc['field_ref_type'], list(self._field_desc['field_choices'].items())) # ) # If field references group, pull in field details if group_view: if field_id in group_ids_seen: raise Annalist_Error(field_id, "Recursive field reference in field group") group_ids_seen = group_ids_seen + [field_id] group_label = (field_label or group_view.get(RDFS.CURIE.label, self._field_desc['field_group_ref']) ) add_label = recordfield.get(ANNAL.CURIE.repeat_label_add, None) or "Add "+field_id remove_label = recordfield.get(ANNAL.CURIE.repeat_label_delete, None) or "Remove "+field_id group_field_descs = [] for subfield in group_view[ANNAL.CURIE.group_fields]: f = field_description_from_view_field(collection, subfield, view_context, group_ids_seen) group_field_descs.append(f) self._field_desc.update( { 'group_id': field_id , 'group_label': group_label , 'group_add_label': add_label , 'group_delete_label': remove_label , 'group_view': group_view , 'group_field_descs': group_field_descs }) # log.debug("FieldDescription: %s"%field_id) # log.info("FieldDescription._field_desc %r"%(self._field_desc,)) # log.info("FieldDescription.field_placement %r"%(self._field_desc['field_placement'],)) return
def post(self, request, coll_id=None, type_id=None, list_id=None): """ Handle response from dynamically generated list display form. """ log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s" % (coll_id, type_id, list_id)) log.log(settings.TRACE_FIELD_VALUE, " %s" % (self.get_request_path())) # log.log(settings.TRACE_FIELD_VALUE, " form data %r"%(request.POST)) listinfo = self.list_setup(coll_id, type_id, list_id, request.POST.dict()) if listinfo.http_response: return listinfo.http_response if 'close' in request.POST: return HttpResponseRedirect(listinfo.get_continuation_url() or self.collection_view_url) # Process requested action action = None redirect_path = None redirect_cont = listinfo.get_continuation_here() redirect_params = {} entity_ids = request.POST.getlist('entity_select') log.debug("entity_ids %r" % (entity_ids)) if len(entity_ids) > 1: listinfo.display_error_response(message.TOO_MANY_ENTITIES_SEL) else: entity_type = type_id or listinfo.get_list_type_id() entity_id = None if len(entity_ids) == 1: (entity_type, entity_id) = split_type_entity_id(entity_ids[0], entity_type) if "new" in request.POST: action = "new" redirect_path = listinfo.get_new_view_uri(coll_id, entity_type) if "copy" in request.POST: action = "copy" if not entity_id: listinfo.display_error_response(message.NO_ENTITY_FOR_COPY) else: redirect_path = listinfo.get_edit_view_uri( coll_id, entity_type, entity_id, action) if "edit" in request.POST: action = "edit" if not entity_id: listinfo.display_error_response(message.NO_ENTITY_FOR_EDIT) else: redirect_path = listinfo.get_edit_view_uri( coll_id, entity_type, entity_id, action) if "delete" in request.POST: action = "delete" confirmed_deletion_uri = self.view_uri( "AnnalistEntityDataDeleteView", coll_id=coll_id, type_id=entity_type) return listinfo.confirm_delete_entity_response( entity_type, entity_id, confirmed_deletion_uri) if "default_view" in request.POST: #@@ # auth_check = self.form_action_auth("config", listinfo.collection, CONFIG_PERMISSIONS) #@@ auth_check = listinfo.check_authorization("config") if auth_check: return auth_check listinfo.collection.set_default_list(list_id) listinfo.add_info_message(message.DEFAULT_LIST_UPDATED % { 'coll_id': coll_id, 'list_id': list_id }) redirect_path, redirect_params = listinfo.redisplay_path_params( ) redirect_cont = listinfo.get_continuation_next() if (("list_type" in request.POST) or ("list_all" in request.POST)): action = "list" redirect_path = self.get_list_url( coll_id, extract_entity_id(request.POST['list_choice']), type_id=None if "list_all" in request.POST else type_id) redirect_params = dict( scope="all" if "list_scope_all" in request.POST else None, search=request.POST['search_for']) redirect_cont = listinfo.get_continuation_next() # redirect_cont = None if "customize" in request.POST: action = "config" redirect_path = self.view_uri("AnnalistCollectionEditView", coll_id=coll_id) if redirect_path: if redirect_cont: redirect_params.update({"continuation_url": redirect_cont}) listinfo.redirect_response(redirect_path, redirect_params=redirect_params, action=action) # return ( # listinfo.check_authorization(action) or # HttpResponseRedirect(redirect_uri) # ) if listinfo.http_response: return listinfo.http_response # Report unexpected form data # This shouldn't happen, but just in case... # Redirect to continuation with error log.error("Unexpected form data posted to %s: %r" % (request.get_full_path(), request.POST)) err_values = self.error_params( message.UNEXPECTED_FORM_DATA % (request.POST), message.SYSTEM_ERROR) redirect_uri = uri_with_params(listinfo.get_continuation_next(), err_values) return HttpResponseRedirect(redirect_uri)
def post(self, request, coll_id=None, type_id=None, list_id=None): """ Handle response from dynamically generated list display form. """ log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s" % (coll_id, type_id, list_id)) log.log(settings.TRACE_FIELD_VALUE, " %s" % (self.get_request_path())) log.log(settings.TRACE_FIELD_VALUE, " form data %r" % (request.POST)) listinfo = self.list_setup(coll_id, type_id, list_id, request.POST.dict()) if listinfo.http_response: return listinfo.http_response if 'close' in request.POST: return HttpResponseRedirect(listinfo.get_continuation_url() or self.collection_view_url) # Process requested action redirect_uri = None entity_ids = request.POST.getlist('entity_select') log.debug("entity_ids %r" % (entity_ids)) if len(entity_ids) > 1: action = "" redirect_uri = self.check_value_supplied( None, message.TOO_MANY_ENTITIES_SEL, continuation_url=listinfo.get_continuation_url()) else: entity_type = type_id or listinfo.get_list_type_id() entity_id = None if len(entity_ids) == 1: (entity_type, entity_id) = split_type_entity_id(entity_ids[0], entity_type) if "new" in request.POST: action = "new" redirect_uri = uri_with_params( listinfo.get_new_view_uri(coll_id, entity_type), {'continuation_url': listinfo.get_continuation_here()}) if "copy" in request.POST: action = "copy" redirect_uri = ( self.check_value_supplied( entity_id, message.NO_ENTITY_FOR_COPY, continuation_url=listinfo.get_continuation_url()) or uri_with_params( listinfo.get_edit_view_uri(coll_id, entity_type, entity_id, action), {'continuation_url': listinfo.get_continuation_here() })) if "edit" in request.POST: action = "edit" redirect_uri = ( self.check_value_supplied( entity_id, message.NO_ENTITY_FOR_EDIT, continuation_url=listinfo.get_continuation_url()) or uri_with_params( listinfo.get_edit_view_uri(coll_id, entity_type, entity_id, action), {'continuation_url': listinfo.get_continuation_here() })) if "delete" in request.POST: action = "delete" redirect_uri = (self.check_value_supplied( entity_id, message.NO_ENTITY_FOR_DELETE, continuation_url=listinfo.get_continuation_url()) or listinfo.check_collection_entity( entity_id, entity_type, message.SITE_ENTITY_FOR_DELETE % {'id': entity_id}) or self.check_delete_type_values( listinfo, entity_id, entity_type, message.TYPE_VALUES_FOR_DELETE % {'type_id': entity_id})) if not redirect_uri: # Get user to confirm action before actually doing it confirmed_action_uri = self.view_uri( "AnnalistEntityDataDeleteView", coll_id=coll_id, type_id=entity_type) # log.info("coll_id %s, type_id %s, confirmed_action_uri %s"%(coll_id, entity_type, confirmed_action_uri)) delete_params = dict_querydict({ "entity_delete": ["Delete"], "entity_id": [entity_id], "completion_url": [listinfo.get_continuation_here()], "search_for": [request.POST['search_for']] }) curi = listinfo.get_continuation_url() if curi: dict_querydict["continuation_url"] = [curi] message_vals = { 'id': entity_id, 'type_id': entity_type, 'coll_id': coll_id } typeinfo = listinfo.entitytypeinfo if typeinfo is None: typeinfo = EntityTypeInfo(listinfo.collection, entity_type) return (self.form_action_auth( "delete", listinfo.collection, typeinfo.permissions_map) or ConfirmView.render_form( request, action_description=message.REMOVE_ENTITY_DATA % message_vals, confirmed_action_uri=confirmed_action_uri, action_params=delete_params, cancel_action_uri=listinfo.get_continuation_here(), title=self.site_data()["title"])) if "default_view" in request.POST: if listinfo.entitytypeinfo: permissions_map = listinfo.entitytypeinfo.permissions_map else: permissions_map = CONFIG_PERMISSIONS auth_check = self.form_action_auth("config", listinfo.collection, permissions_map) if auth_check: return auth_check listinfo.collection.set_default_list(list_id) action = "list" msg = message.DEFAULT_LIST_UPDATED % { 'coll_id': coll_id, 'list_id': list_id } redirect_uri = (uri_with_params( self.get_request_path(), self.info_params(msg), listinfo.get_continuation_url_dict())) if (("list_type" in request.POST) or ("list_all" in request.POST)): action = "list" redirect_uri = self.get_list_url( coll_id, extract_entity_id(request.POST['list_choice']), type_id=None if "list_all" in request.POST else type_id, scope="all" if "list_scope_all" in request.POST else None, search=request.POST['search_for'], query_params=listinfo.get_continuation_url_dict()) if "customize" in request.POST: action = "config" redirect_uri = (uri_with_params( self.view_uri("AnnalistCollectionEditView", coll_id=coll_id), {'continuation_url': listinfo.get_continuation_here()})) if redirect_uri: return (listinfo.check_authorization(action) or HttpResponseRedirect(redirect_uri)) # Report unexpected form data # This shouldn't happen, but just in case... # Redirect to continuation with error log.error("Unexpected form data posted to %s: %r" % (request.get_full_path(), request.POST)) err_values = self.error_params( message.UNEXPECTED_FORM_DATA % (request.POST), message.SYSTEM_ERROR) redirect_uri = uri_with_params(listinfo.get_continuation_next(), err_values) return HttpResponseRedirect(redirect_uri)
def get_coll_jsonld_context(self): """ Return dictionary containing context structure for collection. Entry '@errs' is set to a list of errors encountered, or an empty list. """ # Use OrderedDict to allow some control over ordering of context file contents: # this is for humane purposes only, and is not technically critical. errs = [] context = OrderedDict( # { "@base": self.get_url() + layout.META_COLL_BASE_REF { ANNAL.CURIE.type: { "@type": "@id" } , ANNAL.CURIE.entity_list: { "@container": "@list" } }) # Collection-local URI prefix context.update( { '_site_': self.get_site().get_url() , '_coll_': self.get_url() , '_base_': self.get_url() + layout.COLL_BASE_REF }) # Common import/upload fields context.update( { 'resource_name': "annal:resource_name" , 'resource_type': "annal:resource_type" }) # upload-file fields context.update( { 'upload_name': "annal:upload_name" , 'uploaded_file': "annal:uploaded_file" , 'uploaded_size': "annal:uploaded_size" }) # import-resource fields context.update( { 'import_name': "annal:import_name" , 'import_url': { "@id": "annal:import_url" , "@type": "@id" } }) # Scan types, generate prefix data for t in self.child_entities(RecordType, altscope="all"): tid = t.get_id() if tid != layout.INITIAL_VALUES_ID: tns = t.get(ANNAL.CURIE.ns_prefix, "") if tns != "": context[tns] = self.get_url() + layout.COLL_TYPEDATA_VIEW%({"id": tid}) # Scan vocabs, generate prefix data (possibly overriding type-derived data) for v in self.child_entities(RecordVocab, altscope="all"): vid = v.get_id() if vid != layout.INITIAL_VALUES_ID: if ANNAL.CURIE.uri in v: vuri = v[ANNAL.CURIE.uri] if vuri[-1] not in {":", "/", "?", "#"}: msg = ( "Vocabulary %s namespace URI %s does not end with an expected delimiter"% (vid, vuri) ) log.warning(msg) errs.append(msg) context[vid] = v[ANNAL.CURIE.uri] # Scan view fields and generate context data for property URIs used for v in self.child_entities(RecordView, altscope="all"): view_fields = v.get(ANNAL.CURIE.view_fields, []) for fref in view_fields: fid = extract_entity_id(fref[ANNAL.CURIE.field_id]) vuri = fref.get(ANNAL.CURIE.property_uri, None) furi, fcontext, field_list = self.get_field_uri_jsonld_context( fid, self.get_field_jsonld_context ) if fcontext is not None: fcontext['vid'] = v.get_id() fcontext['fid'] = fid e = self.set_field_uri_jsonld_context(vuri or furi, fid, fcontext, context) errs.extend(e) # If this field contains a list of subfields, scan those # NOTE: current implementation handles only a single level of field nesting if field_list: for subfref in field_list: subfid = extract_entity_id(subfref[ANNAL.CURIE.field_id]) subfuri = subfref.get(ANNAL.CURIE.property_uri, None) furi, fcontext, field_list = self.get_field_uri_jsonld_context( subfid, self.get_field_jsonld_context ) if fcontext is not None: fcontext['fid'] = fid fcontext['subfid'] = subfid e = self.set_field_uri_jsonld_context(subfuri or furi, subfid, fcontext, context) errs.extend(e) # Scan group fields and generate context data for property URIs used #@@TODO - to be deprecated # In due course, field groups will replaced by inline field lists. # This code does not process field lists for fields referenced by a group. #@@ for g in self.child_entities(RecordGroup_migration, altscope="all"): for gref in g[ANNAL.CURIE.group_fields]: fid = extract_entity_id(gref[ANNAL.CURIE.field_id]) guri = gref.get(ANNAL.CURIE.property_uri, None) furi, fcontext, field_list = self.get_field_uri_jsonld_context( fid, self.get_field_jsonld_context ) if fcontext is not None: fcontext['gid'] = g.get_id() fcontext['fid'] = fid e = self.set_field_uri_jsonld_context(guri or furi, fid, fcontext, context) errs.extend(e) if errs: context['@errs'] = errs return context
def post(self, request, coll_id=None, type_id=None, list_id=None): """ Handle response from dynamically generated list display form. """ log.info("views.entitylist.post: coll_id %s, type_id %s, list_id %s"%(coll_id, type_id, list_id)) log.log(settings.TRACE_FIELD_VALUE, " %s"%(self.get_request_path())) # log.log(settings.TRACE_FIELD_VALUE, " form data %r"%(request.POST)) listinfo = self.list_setup(coll_id, type_id, list_id, request.POST.dict()) if listinfo.http_response: return listinfo.http_response if 'close' in request.POST: return HttpResponseRedirect(listinfo.get_continuation_url() or self.collection_view_url) # Process requested action action = None redirect_path = None redirect_cont = listinfo.get_continuation_here() redirect_params = {} entity_ids = request.POST.getlist('entity_select') log.debug("entity_ids %r"%(entity_ids)) if len(entity_ids) > 1: listinfo.display_error_response(message.TOO_MANY_ENTITIES_SEL) else: entity_type = type_id or listinfo.get_list_type_id() entity_id = None if len(entity_ids) == 1: (entity_type, entity_id) = split_type_entity_id(entity_ids[0], entity_type) log.info("EntityList.post entity_ids: entity_type %s, entity_id %s"%(entity_type, entity_id)) if "new" in request.POST: action = "new" redirect_path = listinfo.get_new_view_uri(coll_id, entity_type) if "copy" in request.POST: action = "copy" if not entity_id: listinfo.display_error_response(message.NO_ENTITY_FOR_COPY) else: redirect_path = listinfo.get_edit_view_uri( coll_id, entity_type, entity_id, action ) if "edit" in request.POST: action = "edit" if not entity_id: listinfo.display_error_response(message.NO_ENTITY_FOR_EDIT) else: redirect_path = listinfo.get_edit_view_uri( coll_id, entity_type, entity_id, action ) if "delete" in request.POST: action = "delete" confirmed_deletion_uri = self.view_uri( "AnnalistEntityDataDeleteView", coll_id=coll_id, type_id=entity_type ) return listinfo.confirm_delete_entity_response( entity_type, entity_id, confirmed_deletion_uri ) if "default_view" in request.POST: #@@ # auth_check = self.form_action_auth("config", listinfo.collection, CONFIG_PERMISSIONS) #@@ auth_check = listinfo.check_authorization("config") if auth_check: return auth_check listinfo.collection.set_default_list(list_id) listinfo.add_info_message( message.DEFAULT_LIST_UPDATED%{'coll_id': coll_id, 'list_id': list_id} ) redirect_path, redirect_params = listinfo.redisplay_path_params() redirect_cont = listinfo.get_continuation_next() if ( ("list_type" in request.POST) or ("list_all" in request.POST) ): action = "list" redirect_path = self.get_list_url( coll_id, extract_entity_id(request.POST['list_choice']), type_id=None if "list_all" in request.POST else type_id ) redirect_params = dict( scope="all" if "list_scope_all" in request.POST else None, search=request.POST['search_for'] ) redirect_cont = listinfo.get_continuation_next() # redirect_cont = None if "customize" in request.POST: action = "config" redirect_path = self.view_uri( "AnnalistCollectionEditView", coll_id=coll_id ) if redirect_path: if redirect_cont: redirect_params.update( { "continuation_url": redirect_cont } ) listinfo.redirect_response( redirect_path, redirect_params=redirect_params, action=action ) # return ( # listinfo.check_authorization(action) or # HttpResponseRedirect(redirect_uri) # ) if listinfo.http_response: return listinfo.http_response # Report unexpected form data # This shouldn't happen, but just in case... # Redirect to continuation with error log.error("Unexpected form data posted to %s: %r"%(request.get_full_path(), request.POST)) err_values = self.error_params( message.UNEXPECTED_FORM_DATA%(request.POST), message.SYSTEM_ERROR ) redirect_uri = uri_with_params(listinfo.get_continuation_next(), err_values) return HttpResponseRedirect(redirect_uri)
def _migrate_values(self, entitydata): """ Field description entity format migration method. The specification for this method is that it returns an entitydata value which is a copy of the supplied entitydata with format migrations applied. NOTE: implementations are free to apply migrations in-place. The resulting entitydata should be exactly as the supplied data *should* appear in storage to conform to the current format of the data. The migration function should be idempotent; i.e. x._migrate_values(x._migrate_values(e)) == x._migrate_values(e) """ field_id = entitydata[ANNAL.CURIE.id] migration_map = ( [ (ANNAL.CURIE.options_typeref, ANNAL.CURIE.field_ref_type ) , (ANNAL.CURIE.restrict_values, ANNAL.CURIE.field_ref_restriction) , (ANNAL.CURIE.target_field, ANNAL.CURIE.field_ref_field ) , (ANNAL.CURIE.field_target_type, ANNAL.CURIE.field_value_type ) ]) entitydata = self._migrate_values_map_field_names(migration_map, entitydata) # Fix up enumerated values to use new enumeration type names field_enum_types = ( [ (ANNAL.CURIE.field_render_type, "_enum_render_type") , (ANNAL.CURIE.field_value_mode, "_enum_value_mode") ]) for fkey, ftype in field_enum_types: if fkey in entitydata and entitydata[fkey]: entitydata[fkey] = make_type_entity_id( ftype, extract_entity_id(entitydata[fkey]) ) # If comment and no tooltip, create tooltip and update comment if (RDFS.CURIE.comment in entitydata) and (ANNAL.CURIE.tooltip not in entitydata): label = entitydata.get(RDFS.CURIE.label, "Field '%s'"%field_id) comment = entitydata[RDFS.CURIE.comment] entitydata[ANNAL.CURIE.tooltip] = comment entitydata[RDFS.CURIE.comment] = "# %s\r\n\r\n%s"%(label, comment) # If reference to field group, copy group field list inline if ANNAL.CURIE.group_ref in entitydata: group_type_id, group_id = split_type_entity_id( entitydata[ANNAL.CURIE.group_ref], default_type_id=layout.GROUP_TYPEID ) if group_id != "": log.info("Migrating group reference %s in field %s"%(group_id, field_id)) group_obj = RecordGroup_migration.load(self._parent, group_id) if not group_obj: msg = ( "Failed to load group '%s' for field '%s' in collection '%s'"% (group_id, field_id, self._parent.get_id()) ) log.warning(msg) self.set_error(msg) # raise Annalist_Error(msg) else: field_value_type = entitydata[ANNAL.CURIE.field_value_type] group_entity_type = group_obj[ANNAL.CURIE.group_entity_type] if field_value_type and group_entity_type and field_value_type != group_entity_type: log.warning( "Group %s entity type %s differs from field %s value type %s"% (group_id, group_entity_type, field_id, field_value_type) ) entitydata[ANNAL.CURIE.field_fields] = group_obj[ANNAL.CURIE.group_fields] del entitydata[ANNAL.CURIE.group_ref] # Default render type to "Text" if ANNAL.CURIE.field_render_type not in entitydata: entitydata[ANNAL.CURIE.field_render_type] = "_enum_render_type/Text" # Migrate changed render type names entitydata = self._map_entity_field_enum_val( entitydata, ANNAL.CURIE.field_render_type, "_enum_render_type", "RepeatGroup", "Group_Seq" ) entitydata = self._map_entity_field_enum_val( entitydata, ANNAL.CURIE.field_render_type, "_enum_render_type", "RepeatGroupRow", "Group_Seq_Row" ) entitydata = self._map_entity_field_enum_val( entitydata, ANNAL.CURIE.field_render_type, "_enum_render_type", "Slug", "EntityRef" ) # Calculate mode from other fields if not defined val_render = entitydata[ANNAL.CURIE.field_render_type] ref_type = entitydata.get(ANNAL.CURIE.field_ref_type, None) ref_field = entitydata.get(ANNAL.CURIE.field_ref_field, None) if ANNAL.CURIE.field_value_mode in entitydata: val_mode = entitydata[ANNAL.CURIE.field_value_mode] else: val_mode = "Value_direct" if ref_type and ref_field: val_mode = "Value_field" elif val_render == "RefMultifield": val_mode = "Value_entity" elif val_render == "URIImport": val_mode = "Value_import" elif val_render == "FileUpload": val_mode = "Value_upload" entitydata[ANNAL.CURIE.field_value_mode] = val_mode # Consistency checks if val_mode == "Value_field": if ( not (ref_type and ref_field) ): log.warning( "RecordField %s: val_mode 'Value_field' requires values for %s and %s"% (field_id, ANNAL.CURIE.field_ref_type, ANNAL.CURIE.field_ref_field) ) elif val_mode == "Value_entity": if not ref_type: log.warning( "RecordField %s: val_mode 'Value_entity' requires value for %s"% (field_id, ANNAL.CURIE.field_ref_type) ) if ref_field: log.warning( "RecordField %s: val_mode 'Value_entity' should not define value for %s"% (field_id, ANNAL.CURIE.field_ref_field) ) # Return result return entitydata
def __init__(self, collection, recordfield, view_context=None, field_property=None, field_placement=None, field_list=None, field_ids_seen=[], field_placement_classes=None ): """ Creates a field description value to use in a context value when rendering a form. Values defined here are mentioned in field rendering templates. The FieldDescription object behaves as a dictionary containing the various field attributes. collection is a collection from which data is being rendered. recordfield is a RecordField value or dictionary containing details of the field for which a descriptor is constructed. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. field_property if supplied, overrides the field property URI from `recordfield` field_placement if supplied, overrides field placement from `recordfield` field_list if the field itself contains or references a list of fields, this is that list of fields. field_ids_seen field ids expanded so far, to check for recursive reference. field_placement_classes if supplied, overrides field placement classes derived from value for `field_placement` string. """ self._collection = collection # log.debug("FieldDescription recordfield: %r"%(recordfield,)) field_id = recordfield.get(ANNAL.CURIE.id, "_missing_id_") field_name = recordfield.get(ANNAL.CURIE.field_name, field_id) # Field name in form field_label = recordfield.get(RDFS.CURIE.label, "") field_help = recordfield.get(RDFS.CURIE.comment, "") field_property = field_property or recordfield.get(ANNAL.CURIE.property_uri, "") field_placement = field_placement or recordfield.get(ANNAL.CURIE.field_placement, "") field_placement_c = field_placement_classes or get_placement_classes(field_placement) field_placeholder = recordfield.get(ANNAL.CURIE.placeholder, "") field_tooltip = recordfield.get(ANNAL.CURIE.tooltip, "") field_render_type = extract_entity_id(recordfield.get(ANNAL.CURIE.field_render_type, "")) field_value_mode = extract_entity_id(recordfield.get(ANNAL.CURIE.field_value_mode, "@@FieldDescription:value_mode@@")) field_ref_type = extract_entity_id(recordfield.get(ANNAL.CURIE.field_ref_type, None)) field_entity_type = recordfield.get(ANNAL.CURIE.field_entity_type, None) field_group_ref = extract_entity_id(recordfield.get(ANNAL.CURIE.group_ref, None)) self._field_desc = ( { 'field_id': field_id , 'field_name': field_name , 'field_instance_name': field_name , 'field_render_type': field_render_type , 'field_value_mode': field_value_mode , 'field_value_type': recordfield.get(ANNAL.CURIE.field_value_type, "") , 'field_label': field_label , 'field_help': field_help , 'field_property_uri': field_property , 'field_placement': field_placement_c , 'field_placeholder': field_placeholder , 'field_tooltip': field_tooltip , 'field_tooltip_test': field_tooltip or (field_help) or "" , 'field_default_value': recordfield.get(ANNAL.CURIE.default_value, None) , 'field_ref_type': field_ref_type , 'field_ref_field': recordfield.get(ANNAL.CURIE.field_ref_field, None) , 'field_ref_restriction': recordfield.get(ANNAL.CURIE.field_ref_restriction, "ALL") , 'field_entity_type': field_entity_type , 'field_choices': None , 'field_group_ref': field_group_ref , 'group_label': None , 'group_add_label': None , 'group_delete_label': None , 'group_field_list': None , 'group_field_descs': None , 'field_renderer': FieldRenderer(field_render_type, field_value_mode) , 'field_value_mapper': get_value_mapper(field_render_type) # Used by fieldvaluemap.py }) self._field_suffix_index = 0 # No dup self._field_suffix = "" # If field references type, pull in copy of type id and link values type_ref = self._field_desc['field_ref_type'] if type_ref: restrict_values = self._field_desc['field_ref_restriction'] entity_finder = EntityFinder(collection, selector=restrict_values) entities = entity_finder.get_entities_sorted( type_id=type_ref, context=view_context, altscope="select" ) # Note: the options list may be used more than once, so the id generator # returned must be materialized as a list # Uses collections.OrderedfDict to preserve entity ordering self._field_desc['field_choices'] = OrderedDict() if field_render_type in ["Enum_optional", "Enum_choice_opt"]: # Add blank choice for optional selections self._field_desc['field_choices'][''] = FieldChoice('', label=field_placeholder) for e in entities: eid = e.get_id() val = e.get_type_entity_id() if eid != layout.INITIAL_VALUES_ID: self._field_desc['field_choices'][val] = FieldChoice( val, label=e.get_label(), link=e.get_view_url_path() ) # If field references or contains field list, pull in field details if field_list: if field_id in field_ids_seen: raise Annalist_Error(field_id, "Recursive field reference in field group") field_ids_seen = field_ids_seen + [field_id] group_label = field_label add_label = recordfield.get(ANNAL.CURIE.repeat_label_add, None) or "Add "+field_id remove_label = recordfield.get(ANNAL.CURIE.repeat_label_delete, None) or "Remove "+field_id group_field_descs = [] for subfield in field_list: f = field_description_from_view_field(collection, subfield, view_context, field_ids_seen) group_field_descs.append(f) self._field_desc.update( { 'group_id': field_id , 'group_label': group_label , 'group_add_label': add_label , 'group_delete_label': remove_label , 'group_field_list': field_list # Description from field/group , 'group_field_descs': group_field_descs # Resulting field description list }) # log.debug("FieldDescription: %s"%field_id) # log.info("FieldDescription._field_desc %r"%(self._field_desc,)) # log.info("FieldDescription.field_placement %r"%(self._field_desc['field_placement'],)) return
def check_field_record( test, field_record, field_id=None, field_ref=None, field_types=None, field_name=None, field_type_id=None, field_type=None, field_uri=None, field_url=None, field_label=None, field_comment=None, field_render_type=None, field_value_mode=None, field_property_uri=None, field_placement=None, field_entity_type=None, field_value_type=None, field_placeholder=None, field_default=None, ): if field_id: test.assertEqual(field_id, field_record['annal:id']) if field_ref: test.assertEqual(field_ref, field_record['@id']) if field_types: test.assertEqual(field_types, field_record['@type']) if field_type_id: test.assertEqual(field_type_id, field_record['annal:type_id']) if field_type: test.assertEqual(field_type, field_record['annal:type']) if field_uri: test.assertEqual(field_uri, field_record['annal:uri']) if field_url: test.assertEqual(field_url, field_record['annal:url']) if field_label: test.assertEqual(field_label, field_record['rdfs:label']) if field_comment: test.assertEqual(field_comment, field_record['rdfs:comment']) if field_name: test.assertEqual(field_name, field_record['annal:field_name']) if field_render_type: test.assertEqual( field_render_type, extract_entity_id(field_record['annal:field_render_type'])) if field_value_mode: test.assertEqual( field_value_mode, extract_entity_id(field_record['annal:field_value_mode'])) if field_property_uri: test.assertEqual(field_property_uri, field_record['annal:property_uri']) if field_placement: test.assertEqual(field_placement, field_record['annal:field_placement']) if field_entity_type: test.assertEqual(field_entity_type, field_record['annal:field_entity_type']) if field_value_type: test.assertEqual(field_value_type, field_record['annal:field_value_type']) if field_placeholder: test.assertEqual(field_placeholder, field_record['annal:placeholder']) if field_default: test.assertEqual(field_default, field_record['annal:default_value']) return
def get_list_type_id(self): return extract_entity_id( self.recordlist.get(ANNAL.CURIE.default_type, None) or "Default_type" )
def get_coll_jsonld_context(self): """ Return dictionary containing context structure for collection. """ # Use OrderedDict to allow some control over ordering of context file contents: # this is for humane purposes only, and is not technically important. context = OrderedDict({ "@base": self.get_url() + layout.META_COLL_BASE_REF, ANNAL.CURIE.type: { "@type": "@id" }, ANNAL.CURIE.entity_list: { "@container": "@list" } }) # Collection-local URI prefix context.update({'coll': self._entityviewurl}) # Common import/upload fields context.update({ 'resource_name': "annal:resource_name", 'resource_type': "annal:resource_type" }) # upload-file fields context.update({ 'upload_name': "annal:upload_name", 'uploaded_file': "annal:uploaded_file", 'uploaded_size': "annal:uploaded_size" }) # import-resource fields context.update({ 'import_name': "annal:import_name", 'import_url': { "@id": "annal:import_url", "@type": "@id" } }) # Scan vocabs, generate prefix data for v in self.child_entities(RecordVocab, altscope="all"): vid = v.get_id() if vid != "_initial_values": context[v.get_id()] = v[ANNAL.CURIE.uri] # Scan view fields and generate context data for property URIs used for v in self.child_entities(RecordView, altscope="all"): for fref in v[ANNAL.CURIE.view_fields]: fid = extract_entity_id(fref[ANNAL.CURIE.field_id]) vuri = fref.get(ANNAL.CURIE.property_uri, None) furi, fcontext = self.get_field_uri_jsonld_context( fid, self.get_field_jsonld_context) if fcontext is not None: fcontext['vid'] = v.get_id() fcontext['fid'] = fid self.set_field_uri_jsonld_context(vuri or furi, fid, fcontext, context) # Scan group fields and generate context data for property URIs used for g in self.child_entities(RecordGroup, altscope="all"): for gref in g[ANNAL.CURIE.group_fields]: fid = extract_entity_id(gref[ANNAL.CURIE.field_id]) guri = gref.get(ANNAL.CURIE.property_uri, None) furi, fcontext = self.get_field_uri_jsonld_context( fid, self.get_field_jsonld_context) if fcontext is not None: fcontext['gid'] = g.get_id() fcontext['fid'] = fid self.set_field_uri_jsonld_context(guri or furi, fid, fcontext, context) return context
def __init__(self, collection, recordfield, view_context=None, field_property=None, field_placement=None, group_view=None, group_ids_seen=[], field_placement_classes=None): """ Creates a field description value to use in a context value when rendering a form. Values defined here are mentioned in field rendering templates. The FieldDescription object behaves as a dictionary containing the various field attributes. collection is a collection from which data is being rendered. Used when generating enumerated values. recordfield is a RecordField value or dictionary containing details of the field for which a descriptor is constructed. view_context is a dictionary of additional values that may be used in assembling values to be used when rendering the field. In particular, a copy of the view description record provides context for some enumeration type selections. field_property if supplied, overrides the field property URI from `recordfield` field_placement if supplied, overrides field placement from `recordfield` group_view if the field itself references a list of fields, this is a RecordGroup value or dictionary containing the referenced list of fields. group_ids_seen group ids expanded so far, to check for recursive reference. field_classes if supplied, overrides field placement classes derived from value for `field_placement` string. """ self._collection = collection # log.debug("FieldDescription recordfield: %r"%(recordfield,)) field_id = recordfield.get(ANNAL.CURIE.id, "_missing_id_") field_name = recordfield.get(ANNAL.CURIE.field_name, field_id) # Field name in form field_label = recordfield.get(RDFS.CURIE.label, "") field_property = field_property or recordfield.get( ANNAL.CURIE.property_uri, "") field_placement = field_placement or recordfield.get( ANNAL.CURIE.field_placement, "") field_placement_c = field_placement_classes or get_placement_classes( field_placement) field_placeholder = recordfield.get(ANNAL.CURIE.placeholder, "") field_render_type = extract_entity_id( recordfield.get(ANNAL.CURIE.field_render_type, "")) field_value_mode = extract_entity_id( recordfield.get(ANNAL.CURIE.field_value_mode, "@@FieldDescription:value_mode@@")) field_ref_type = extract_entity_id( recordfield.get(ANNAL.CURIE.field_ref_type, None)) field_entity_type = recordfield.get(ANNAL.CURIE.field_entity_type, None) field_group_ref = extract_entity_id( recordfield.get(ANNAL.CURIE.group_ref, None)) self._field_desc = ({ 'field_id': field_id, 'field_name': field_name, 'field_instance_name': field_name, 'field_render_type': field_render_type, 'field_value_mode': field_value_mode, 'field_value_type': recordfield.get(ANNAL.CURIE.field_value_type, ""), 'field_label': field_label, 'field_help': recordfield.get(RDFS.CURIE.comment, ""), 'field_property_uri': field_property, 'field_placement': field_placement_c, 'field_placeholder': field_placeholder, 'field_default_value': recordfield.get(ANNAL.CURIE.default_value, None), 'field_ref_type': field_ref_type, 'field_ref_field': recordfield.get(ANNAL.CURIE.field_ref_field, None), 'field_ref_restriction': recordfield.get(ANNAL.CURIE.field_ref_restriction, "ALL"), 'field_entity_type': field_entity_type, 'field_choices': None # , 'field_choice_labels': None # , 'field_choice_links': None , 'field_group_ref': field_group_ref, 'group_label': None, 'group_add_label': None, 'group_delete_label': None, 'group_view': None, 'group_field_descs': None, 'field_render_label': get_label_renderer(field_render_type, field_value_mode), 'field_render_view': get_view_renderer(field_render_type, field_value_mode), 'field_render_edit': get_edit_renderer(field_render_type, field_value_mode), 'field_render_label_view': get_label_view_renderer(field_render_type, field_value_mode), 'field_render_label_edit': get_label_edit_renderer(field_render_type, field_value_mode), 'field_render_colhead': get_col_head_renderer(field_render_type, field_value_mode), 'field_render_colhead_view': get_col_head_view_renderer(field_render_type, field_value_mode), 'field_render_colhead_edit': get_col_head_edit_renderer(field_render_type, field_value_mode), 'field_render_colview': get_col_view_renderer(field_render_type, field_value_mode), 'field_render_coledit': get_col_edit_renderer(field_render_type, field_value_mode), 'field_render_mode': get_mode_renderer(field_render_type, field_value_mode), 'field_value_mapper': get_value_mapper(field_render_type) }) self._field_suffix_index = 0 # No dup self._field_suffix = "" # If field references type, pull in copy of type id and link values type_ref = self._field_desc['field_ref_type'] if type_ref: restrict_values = self._field_desc['field_ref_restriction'] entity_finder = EntityFinder(collection, selector=restrict_values) # Determine subtypes of field entity type, if specified # @@TODO: subtype logic here is just pig ugly... # need context to provide info that can be used to calculate supertypes # on-the-fly as needed by the field restriction expression. E.g. include # collection object in context. if field_entity_type and restrict_values: field_entity_subtypes = ([ t.get_type_uri() for t in entity_finder.get_collection_uri_subtypes( field_entity_type, altscope="all") ]) self._field_desc[ 'field_entity_subtypes'] = field_entity_subtypes field_view_context = dict( view_context or {}, field={'subtypes': field_entity_subtypes}) else: field_view_context = view_context entities = entity_finder.get_entities_sorted( type_id=type_ref, context=field_view_context, altscope="select") # Note: the options list may be used more than once, so the id generator # returned must be materialized as a list # Uses collections.OrderedfDict to preserve entity ordering self._field_desc['field_choices'] = collections.OrderedDict() if field_render_type in ["Enum_optional", "Enum_choice_opt"]: # Add blank choice for optional selections self._field_desc['field_choices'][''] = FieldChoice( '', label=field_placeholder) for e in entities: eid = e.get_id() val = e.get_type_entity_id() if eid != "_initial_values": self._field_desc['field_choices'][val] = FieldChoice( val, label=e.get_label(), link=e.get_view_url_path()) # log.debug("FieldDescription: typeref %s: %r"% # (self._field_desc['field_ref_type'], list(self._field_desc['field_choices'].items())) # ) # If field references group, pull in field details if group_view: if field_id in group_ids_seen: raise Annalist_Error( field_id, "Recursive field reference in field group") group_ids_seen = group_ids_seen + [field_id] group_label = (field_label or group_view.get( RDFS.CURIE.label, self._field_desc['field_group_ref'])) add_label = recordfield.get(ANNAL.CURIE.repeat_label_add, None) or "Add " + field_id remove_label = recordfield.get(ANNAL.CURIE.repeat_label_delete, None) or "Remove " + field_id group_field_descs = [] for subfield in group_view[ANNAL.CURIE.group_fields]: f = field_description_from_view_field(collection, subfield, view_context, group_ids_seen) group_field_descs.append(f) self._field_desc.update({ 'group_id': field_id, 'group_label': group_label, 'group_add_label': add_label, 'group_delete_label': remove_label, 'group_view': group_view, 'group_field_descs': group_field_descs }) # log.debug("FieldDescription: %s"%field_id) # log.info("FieldDescription._field_desc %r"%(self._field_desc,)) # log.info("FieldDescription.field_placement %r"%(self._field_desc['field_placement'],)) return
def get_list_type_id(self): return extract_entity_id( self.recordlist.get(ANNAL.CURIE.default_type, None) or "Default_type")