Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions geonode/metadata/handlers/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,18 @@ def _localize_subschema_labels(context, subschema: dict, lang: str, property_nam
@staticmethod
def _check_type(declared, checked):
return declared == checked or (type(declared) is list and checked in declared)

@staticmethod
def _is_nullable(subschema):
return MetadataHandler._check_type(subschema.get("type", None), "null")

@staticmethod
def _add_oneof_null_option(subschema):
# Without a null option a nullable oneOf rejects the null it gets when left empty.
# Never creates the oneOf: that would restrict a field free to take any value
oneof = subschema.get("oneOf")
if oneof is None or not MetadataHandler._is_nullable(subschema): # an empty one is to be filled in
return

if not any("const" in option and option["const"] is None for option in oneof):
oneof.insert(0, {"const": None, "title": "-"}) # not "": the client turns it into None
Comment thread
etj marked this conversation as resolved.
4 changes: 4 additions & 0 deletions geonode/metadata/handlers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,14 @@ class FrequencySubHandler(SubHandler):
@classmethod
def update_subschema(cls, subschema, lang=None):
subschema["oneOf"] = [{"const": key, "title": val} for key, val in dict(UPDATE_FREQUENCIES).items()]
MetadataHandler._add_oneof_null_option(subschema)


class LanguageSubHandler(SubHandler):
@classmethod
def update_subschema(cls, subschema, lang=None):
subschema["oneOf"] = [{"const": key, "title": val} for key, val in dict(ALL_LANGUAGES).items()]
MetadataHandler._add_oneof_null_option(subschema)


class LicenseSubHandler(SubHandler):
Expand Down Expand Up @@ -132,6 +134,7 @@ def update_subschema(cls, subschema, lang=None):
{"const": tc.identifier, "title": tc.identifier, "description": tc.description}
for tc in RestrictionCodeType.objects.order_by("identifier")
]
MetadataHandler._add_oneof_null_option(subschema)

@classmethod
def serialize(cls, db_value):
Expand All @@ -151,6 +154,7 @@ def update_subschema(cls, subschema, lang=None):
{"const": tc.identifier, "title": tc.identifier, "description": tc.description}
for tc in SpatialRepresentationType.objects.order_by("identifier")
]
MetadataHandler._add_oneof_null_option(subschema)

@classmethod
def serialize(cls, db_value):
Expand Down
22 changes: 11 additions & 11 deletions geonode/metadata/handlers/sparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,11 @@ def _recurse_thesauri_autocomplete(self, d, lang):
self._recurse_thesauri_autocomplete(item, lang)

def _add_thesaurus_options(self, d, thesaurus_id, lang):
oneof = []
for keyword in get_localized_tkeywords(lang, thesaurus_id):
oneof.append({"const": keyword["about"], "title": keyword["label"]})
d["oneOf"] = oneof
d["oneOf"] = [
{"const": keyword["about"], "title": keyword["label"] or keyword["default"]}
for keyword in get_localized_tkeywords(lang, thesaurus_id)
]
self._add_oneof_null_option(d)

def update_schema(self, jsonschema, context, lang=None):
# add all registered fields
Expand Down Expand Up @@ -139,10 +140,10 @@ def set_sparse_field(context, fieldname, value):
context[CONTEXT_ID]["fields"][fieldname] = value

def get_jsonschema_instance(self, resource, field_name, context, errors, lang=None):
field_type = context[CONTEXT_ID]["schema"]["properties"][field_name]["type"]
field_value = context[CONTEXT_ID]["fields"].get(field_name, None)

is_nullable = self._check_type(field_type, "null")
subschema = context[CONTEXT_ID]["schema"]["properties"][field_name]
is_nullable = self._is_nullable(subschema)
field_type = subschema["type"]

if field_name not in context[CONTEXT_ID]["fields"] and not is_nullable:
raise UnsetFieldException()
Expand Down Expand Up @@ -192,11 +193,10 @@ def load_deserialization_context(self, resource, jsonschema: dict, context: dict
context[CONTEXT_ID] = {"schema": jsonschema}

def update_resource(self, resource, field_name, json_instance, context, errors, **kwargs):

bare_value = json_instance.get(field_name, None)
field_type = context[CONTEXT_ID]["schema"]["properties"][field_name]["type"]

is_nullable = self._check_type(field_type, "null")
subschema = context[CONTEXT_ID]["schema"]["properties"][field_name]
field_type = subschema["type"]
is_nullable = self._is_nullable(subschema)

if self._check_type(field_type, "string"):
field_value = bare_value
Expand Down
6 changes: 6 additions & 0 deletions geonode/metadata/handlers/thesaurus.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ def update_schema(self, jsonschema, context, lang=None):
"properties": thesauri,
}

# minItems is not enough: it only constrains a thesaurus that is in the instance already.
# Same for tkeywords itself, hence the requiredness bubbling up
if mandatory_thesauri := [id for id, ct in collected_thesauri.items() if ct["card"]["minItems"] > 0]:
subschema["required"] = mandatory_thesauri # the thesauri to be found inside tkeywords
subschema["geonode:required"] = True # tkeywords itself, to be found in the resource

# We are going to hide the tkeywords property if there's no thesaurus configured
# We can't remove the property altogether, since hkeywords relies on tkeywords for positioning
if not thesauri:
Expand Down
Empty file.
Empty file.
Loading
Loading