Skip to content

GNIP 97: New metadata editor #11511

@etj

Description

@etj

GNIP 97 - New metadata editor

Overview

The metadata editor still relies on a legacy template engine which is quite hard to customize.
Also it uses unmaintained vulnerable js libraries that should be removed.

Proposed By

  • @etj Emanuele Tajariol

Assigned to Release

This proposal is for GeoNode 5

State

  • Under Discussion
  • In Progress
  • Completed
  • Rejected
  • Deferred

Motivation

  • Allow easier customization
  • Allow different editing frontends
  • Make a clear distincton between descriptive metadata and operational metadata (owner, group)
  • Remove old unmaintained vulnerable js libraries

Proposal

The idea is to switch to standard procedures to document the metadata schema and to return the metadata info.

The metadata schema is presented using the JSON schema conventions.

The GeoNode API has been extended to provide

  • /api/v2/metadata/schema metadata schema
  • /api/v2/metadata/instance/<PK> resource metadata instances handling (GET/PUT)
  • /api/v2/metadata/xxx other utility calls for the metadata handling (autocomplete endpoints referred into the schema, etc)

One of the basic driving features has been the customization of the schema. The implementation relies on a set of metadata handlers that can be easily extended. We embedded into GeoNode the optional inspire module, mostly a (working) showcase that documents how the GeoNode base model can be customized.

Implementation

Intro

The package geonode.metadata contains all the metadata code.

The manager module contains the base engine that calls methods on the registered field handlers.
Handlers are the objects that manage the field definition (the json schema), and that take care of converting database objects into json schema instances and viceversa.
A single handler may handle one or more fields.

MetadataManager

The geonode.metadata.manager.MetadataManager class provides these main methods:

  def get_schema(self, lang=None)`

Builds and returns the metadata json schema.
The schema is created by looping on the sorted set of metadata handlers, asking them to update the schema incrementally via def update_schema(self, jsonschema: dict, context, lang=None).
Handlers may add their own field, remove fields added by previously called
The schema localization is only related to the title and description annotations

This method is used by the /api/v2/metadata/schema endpoint.
The default language used is the one set in the cookies, or it can be overriden by adding the query param lang.

   def build_schema_instance(self, resource: ResourceBase, lang=None)

Builds and returns the json schema instance related to the resource.

The instance is created by examining the json schema and looping on each field.
Then, the related handler is called to fill in the serialized value for such field.

Called handler methods:

  • def load_serialization_context(resource: ResourceBase, jsonschema: dict, context: dict)
    Allow handlers to pre-load some common info for all the handled fields
  • def get_jsonschema_instance(resource: ResourceBase, field_name, context, errors, lang=None)
    Returns the instance of the sub-schema associated with the field field_name.
   def update_schema_instance(self, resource, json_instance)

Parses the incoming json schema instance and stores the value into the DB.

Persistence is done by examining the json schema and looping on each field.
Then, the related handler is called to parse and store the deserialized value(s) for such field.
If the field is a complex object, it's up to the handler parse and handle it.

Called handler methods:

  • def load_deserialization_context(self, resource: ResourceBase, jsonschema: dict, context: dict)
    Allow handlers to pre-load some common info for all the handled fields
  • def update_resource(resource: ResourceBase, field_name: str, json_instance: dict, context: dict, errors: dict, **kwargs)
    Logic to parse and persist the field

Handlers

The list of handlers is declared in geonode.metadata.settings.METADATA_HANDLERS.
Order is important since later declared handlers may want to customize previously defined fields.
Within each field subschema there are some geonode-specific annotations (custom annotation are allowed by the json schema standard), some are needed for backend logic (for instance geonode:handler'), other for the client UI (e.g. ui:options`)

BaseHandler

BaseHandler handles most of the fields declared inside the ResourceBase class.
The BaseHandler will read the main schema from a file (metadata/schemas/base.json ) , augmenting its info programmatically (such as autocomplete URLs).

SparseHandler

This handler is not actively used by the default GeoNode schema, since it's more aimed at customizations.
You may see an example of its use in the inspire package.

The idea for the SparseField (the single model change in metadata) is to have a "vertical" table with free form fields:
image

In the default case, its use is as simple as declaring the field:

  "instrumentations": {
    "type": "array",
    "title": "instrumentations",
    "description": "Provides information about any instruments used in the data collection. The description should include vendor, model number, optional equipment, etc.",
    "items": {
      "type": "string",
      "minLength": 1,
      "default": ""
    },
    "minItems": 1,
    "geonode:handler": "sparse"
  }

Some custom annotation

  • geonode:handler: key to the handlers defined in METADATA_HANDLERS; tells which is the handler to be called to handle the field's content. Pls note that this annotation may be replaced by subsequent handler if they want to handle the field differently.
  • geonode:required: the jsonschema specs wants the required array outside the subschema definition. By defining this annotation as true, the metadata manager will add the current field in the required list.

Localization

So far the static labels for metadata editor have been localized using gettext() and i18n .po files.

Since the jsonschema is much more dynamic in its behaviour, allowing very custom schema, we need other ways for localizing the schema fields labels.

The proposed/implemented idea is to use a thesaurus with a well known identifier labels_i18n where

  • Thesaurus:
    • identifier = "labels_i18n"
  • ThesaurusKeyword:
    • about = field name
    • alt_label= field name
  • ThesaurusKeywordLabel:
    • localized stuff

In order to avoid clashes, the schema fields titles should be prefixed with the metadata handler id ("inspire", "cnr", ...)

The implementation will look for translations in the thesaurus, and then will the gettext as fallback.

Some improvements to the thesauri manament commands will be done in order to better manage updates.
For instance, we may want to

  • merge a thesaurus file into an existing thesaurus
  • import from a thesaurus file only a subset of the keywords
  • ...

Backwards Compatibility

TODO

Future evolution

This refactoring allows for other major improvemetns in GeoNode.
Since this is quite a big improvement in GeoNode that introduces breaking changes, the plans before releasing a stable 5.0 include some other improvements/refactoring, that will be discussed each in its own issue:

  • contact roles refactoring
    • improve the model allowing non-system users to be contact points
    • easier customization
  • codelists into thesauri
    • remove many custom codelist tables
    • improve localization
  • move owner and group outside the metadata editor, since they are not informative metadata, but operative info, and should be handler in a differet localtion and with different privileges. At the moment we don't want the metadata schema to chhange according to user privileges.

Most of the pure metadata fields in ResourceBase can be moved as SparseFields, improving the overall performance of the ORM procedures.

Feedback

TODO

Voting

Project Steering Committee:

  • Alessio Fabiani:
  • Francesco Bartoli:
  • Giovanni Allegri:
  • Simone Dalmasso:
  • Toni Schoenbuchner:
  • Florian Hoedt:

Links

Remove unused links below.

Metadata

Metadata

Labels

gnipA GeoNodeImprovementProcess Issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions