Beispiel #1
0
    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
Beispiel #2
0
 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
Beispiel #4
0
    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
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
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
Beispiel #8
0
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)
Beispiel #9
0
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)
Beispiel #10
0
    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
Beispiel #13
0
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
Beispiel #15
0
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
Beispiel #18
0
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
        )
Beispiel #19
0
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 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
Beispiel #21
0
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"
Beispiel #23
0
 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
Beispiel #25
0
    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
Beispiel #26
0
 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
Beispiel #27
0
 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
Beispiel #28
0
 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
Beispiel #29
0
 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
Beispiel #30
0
 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
Beispiel #31
0
 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
Beispiel #32
0
    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
Beispiel #33
0
    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
Beispiel #34
0
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
Beispiel #35
0
 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
Beispiel #36
0
    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
Beispiel #37
0
    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
Beispiel #38
0
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
Beispiel #39
0
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
Beispiel #41
0
    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)
Beispiel #42
0
    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
Beispiel #43
0
    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)
Beispiel #44
0
    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)
Beispiel #45
0
    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
Beispiel #46
0
    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)
Beispiel #47
0
    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
Beispiel #48
0
    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
Beispiel #50
0
 def get_list_type_id(self):
     return extract_entity_id(
         self.recordlist.get(ANNAL.CURIE.default_type, None) or "Default_type"
         )
Beispiel #51
0
 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
Beispiel #52
0
    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
Beispiel #53
0
 def get_list_type_id(self):
     return extract_entity_id(
         self.recordlist.get(ANNAL.CURIE.default_type, None)
         or "Default_type")
Beispiel #54
0
    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