-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
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 fieldsdef get_jsonschema_instance(resource: ResourceBase, field_name, context, errors, lang=None)
Returns the instance of the sub-schema associated with the fieldfield_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 fieldsdef 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:
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 inMETADATA_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 therequired
array outside the subschema definition. By defining this annotation astrue
, the metadata manager will add the current field in therequired
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 namealt_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.
- Pull Request: GNIP 97: New metadata editor #12794
- Linked Issue