diff --git a/geonode/base/forms.py b/geonode/base/forms.py index 62bc078506a..f9292102122 100644 --- a/geonode/base/forms.py +++ b/geonode/base/forms.py @@ -740,6 +740,7 @@ class Meta: "was_approved", "was_published", "funders", + "related_identifier", ) diff --git a/geonode/base/models.py b/geonode/base/models.py index 858e25bbf29..a377b951d57 100644 --- a/geonode/base/models.py +++ b/geonode/base/models.py @@ -671,9 +671,8 @@ def __str__(self): class RelatedIdentifier(models.Model): - related_identifier = models.CharField( - max_length=255, help_text=_("Identifiers of related resources. These must be globally unique identifiers.") - ) + related_identifer_help_text = _("Identifiers of related resources. These must be globally unique identifiers.") + related_identifier = models.CharField(max_length=255, help_text=related_identifer_help_text) related_identifier_type = models.ForeignKey(RelatedIdentifierType, on_delete=models.CASCADE) relation_type = models.ForeignKey(RelationType, on_delete=models.CASCADE) @@ -685,32 +684,45 @@ class FundingReference(models.Model): """Funding Reference Identifiers""" funder_name = models.CharField( - max_length=255, help_text=_("Name of the funding provider. (e.g. European Commission)") + blank=True, null=True, max_length=255, help_text=_("Name of the funding provider. (e.g. European Commission)") ) funder_identifier = models.CharField( + blank=True, + null=True, max_length=255, help_text=_( "Uniquely identifies a funding entity, according to various types. (e.g. http://doi.org/10.13039/501100000780)" ), ) - funder_identifier_type = models.CharField(max_length=255, help_text=_("The type of the Identifier. (e.g. BMBF)")) + funder_identifier_type = models.CharField( + blank=True, null=True, max_length=255, help_text=_("The type of the Identifier. (e.g. BMBF)") + ) def __str__(self): return f"{self.funder_name}" class Funder(models.Model): - funding_reference = models.ForeignKey(FundingReference, null=False, blank=False, on_delete=models.CASCADE) + funders_help_text = _("List of funders, funded dataset creators") + + funding_reference = models.ForeignKey(FundingReference, null=True, blank=True, on_delete=models.CASCADE) award_number = models.CharField( - max_length=255, help_text=_("The code assigned by the funder to a sponsored award (grant). (e.g. 282625)") + blank=True, + null=True, + max_length=255, + help_text=funders_help_text, ) award_uri = models.CharField( + blank=True, + null=True, max_length=255, help_text=_( "The URI leading to a page provided by the funder for more information about the award (grant). (e.g. http://cordis.europa.eu/project/rcn/100180_en.html)" ), ) award_title = models.CharField( + blank=True, + null=True, max_length=255, help_text=_( "The human readable title of the award (grant). (e.g. MOTivational strength of ecosystem services)" @@ -1137,7 +1149,7 @@ class ResourceBase(PolymorphicModel, PermissionLevelMixin, ItemBase): Funder, verbose_name=_("Funder names"), null=True, blank=True, help_text=funders_help_text ) related_projects = models.ManyToManyField( - RelatedProject, verbose_name=_("related project"), null=True, blank=True, help_text=related_projects_help_text + RelatedProject, verbose_name=_("Related project"), null=True, blank=True, help_text=related_projects_help_text ) use_contraints = models.TextField( diff --git a/geonode/layers/templates/datasets/dataset_metadata_advanced.html b/geonode/layers/templates/datasets/dataset_metadata_advanced.html index d1c4b202bce..be512acfea4 100644 --- a/geonode/layers/templates/datasets/dataset_metadata_advanced.html +++ b/geonode/layers/templates/datasets/dataset_metadata_advanced.html @@ -129,11 +129,9 @@

{% trans "Edit Metadata" %}

{% block funder_form %} +
{{funder_form.management_form }}
- - -
@@ -144,25 +142,25 @@

{% trans "Edit Metadata" %}

{% else %}
  • {{ forloop.counter }} -
  • {% endif %} {%endfor%} @@ -234,9 +232,119 @@

    {% trans "Edit Metadata" %}

    - + + {% endblock funder_form %} + {% block related_identifier_form %} + + + + {% endblock related_identifier_form %} @@ -377,8 +485,9 @@ }); + {% comment %} {% endcomment %} {% endblock %} \ No newline at end of file diff --git a/geonode/layers/views.py b/geonode/layers/views.py index b5ed1a52584..0a8f5c36c4e 100644 --- a/geonode/layers/views.py +++ b/geonode/layers/views.py @@ -53,7 +53,7 @@ from geonode.base.auth import get_or_create_token from geonode.base.forms import CategoryForm, TKeywordForm, ThesaurusAvailableForm from geonode.base.views import batch_modify -from geonode.base.models import Thesaurus, TopicCategory, Funder +from geonode.base.models import Thesaurus, TopicCategory, Funder, RelatedIdentifier from geonode.base.enumerations import CHARSETS from geonode.decorators import check_keyword_write_perms from geonode.layers.forms import DatasetForm, DatasetTimeSerieForm, LayerAttributeForm, NewLayerUploadForm @@ -363,6 +363,14 @@ def dataset_metadata( extra=0, min_num=1, ) + + RelatedIdentifierFormset = modelformset_factory( + RelatedIdentifier, + fields=["related_identifier", "related_identifier_type", "relation_type"], + can_delete=True, + extra=0, + min_num=1, + ) current_keywords = [keyword.name for keyword in layer.keywords.all()] topic_category = layer.category @@ -419,10 +427,15 @@ def dataset_metadata( "errors": [re.sub(re.compile("<.*?>"), "", str(err)) for err in attribute_form.errors], } return HttpResponse(json.dumps(out), content_type="application/json", status=400) - funders_intial_values = Funder.objects.all().filter(resourcebase=layer) + funder_form = FunderFormset( request.POST, - prefix="funder_form", + prefix="form_funder", + ) + + related_identifier_form = RelatedIdentifierFormset( + request.POST, + prefix="form_related_identifier", ) category_form = CategoryForm( request.POST, @@ -483,7 +496,13 @@ def dataset_metadata( ) funders_intial_values = Funder.objects.all().filter(resourcebase=layer) - funder_form = FunderFormset(prefix="funder_form", queryset=funders_intial_values) + funder_form = FunderFormset(prefix="form_funder", queryset=funders_intial_values) + + related_identifier_intial_values = RelatedIdentifier.objects.all().filter(resourcebase=layer) + related_identifier_form = RelatedIdentifierFormset( + prefix="form_related_identifier", queryset=related_identifier_intial_values + ) + category_form = CategoryForm( prefix="category_choice_field", initial=topic_category.id if topic_category else None ) @@ -555,6 +574,7 @@ def dataset_metadata( and dataset_form.is_valid() and attribute_form.is_valid() and funder_form.is_valid() + and related_identifier_form.is_valid() and category_form.is_valid() and tkeywords_form.is_valid() and timeseries_form.is_valid() @@ -580,7 +600,13 @@ def dataset_metadata( layer.set_contact_roles_from_metadata_edit(dataset_form) funder_form.save() instance = funder_form.save(commit=False) + layer.funders.add(*instance) + + related_identifier_form.save() + instance = related_identifier_form.save(commit=False) + layer.related_identifier.add(*instance) + layer.save() new_keywords = current_keywords if request.keyword_readonly else dataset_form.cleaned_data["keywords"] @@ -694,6 +720,7 @@ def dataset_metadata( "attribute_form": attribute_form, "timeseries_form": timeseries_form, "funder_form": funder_form, + "related_identifier_form": related_identifier_form, "category_form": category_form, "tkeywords_form": tkeywords_form, "preview": getattr(settings, "GEONODE_CLIENT_LAYER_PREVIEW_LIBRARY", "mapstore"), diff --git a/geonode/static/geonode/js/utils/formsetsInTabs.js b/geonode/static/geonode/js/utils/formsetsInTabs.js index 5b78f4ac0be..8be8629a2c1 100644 --- a/geonode/static/geonode/js/utils/formsetsInTabs.js +++ b/geonode/static/geonode/js/utils/formsetsInTabs.js @@ -1,38 +1,66 @@ +for (let name of formsetsInTabs) { -let totalForms = $('#id_' + prefix + '-TOTAL_FORMS').val(); -let initialForms = $('#id_' + prefix + '-INITIAL_FORMS').val(); -let maxForms = $('#id_' + prefix + '-MAX_NUM_FORMS').val(); -let minForms = $('#id_' + prefix + '-MIN_NUM_FORMS').val(); -let deleteInput = $("#id_FORM-xx-DELETE") -let hiddenInput = $("#id_FORM-xx-id") + form = $('#' + name) + reOrder(form) + hideDeleteCheckbox(form) +} + + +function dataForm(form) { + instance = form.attr('id') + totalForms = $('#id_' + instance + '-TOTAL_FORMS').val(); + initialForms = $('#id_' + instance + '-INITIAL_FORMS').val(); + maxForms = $('#id_' + instance + '-MAX_NUM_FORMS').val(); + minForms = $('#id_' + instance + '-MIN_NUM_FORMS').val(); + + allDelete = form.find('#DELETE') -let allDelete = $('#DELETE') + actualForms = totalForms -let actualForms = totalForms + templateTab = form.find('.templateTab') + templateContent = form.find('.templateContent') + allTabs = form.find('.allTabs') + allForms = form.find('.allContent') + + + + return { + totalForms, + initialForms, + maxForms, + minForms, + allDelete, + actualForms, + templateTab, + templateContent, + allTabs, + allForms, + } +} -let templateTab = $('.templateTab') -let templateContent = $('.templateContent') -let allTabs = $('.allTabs') -let allforms = $('.allContent') -reOrder() -hideDeleteCheckbox() -$("#nav-add").on("click", function () { +function addNewTab(element) { + button = $("#" + element.id) + form = $(element).closest("div[id^='form']") + infosForm = dataForm(form) + prefix = form.attr("id") + actualForms = infosForm.actualForms label = Number(actualForms) + 1 - removeActive() - newTab = templateTab.clone(true).removeClass('hidden') + removeActive(form) + newTab = infosForm.templateTab.clone(true).removeClass('hidden') newTab.removeClass('templateTab').removeClass('nav-empty') newTab.attr('id', '') newTab.find('a').attr('href', '#' + prefix + '-' + actualForms) newTab.attr('aria-controls', prefix + '-' + actualForms) newTab.find('.newTabTex').text(label) newTab.find('.newTabTex').addClass('tabTex').removeClass('newTabTex') - newTab.insertBefore($('.li-add')) - newTab.addClass('active') + newTab.insertBefore(form.find('.li-add')) + newTab.addClass('active') + templateContent = infosForm.templateContent newContent = templateContent.clone(true).removeClass('hidden') newContent.removeClass('templateContent').removeClass('nav-empty') newContent.attr('id', prefix + '-' + actualForms) @@ -42,38 +70,50 @@ $("#nav-add").on("click", function () { $(this).attr('name', $(this).attr('name').replace("__prefix__", actualForms)) $(this).attr('id', $(this).attr('id').replace("__prefix__", actualForms)) }) - newContent.insertBefore($('.templateContent')) + newContent.insertBefore(form.find('.templateContent')) actualForms++ $('#id_' + prefix + '-TOTAL_FORMS').attr("value", actualForms) -}); +}; -$(".nav-remove").on("click", function () { - removeActive() - number = $(this).parent('a').attr('href').split('-')[1] - tabToRemove = $(this).parent('a').parent('li') +function removeTab(element) { + removeActive(form) + element = $(element) + form = element.closest("div[id^=form]") + infosForm = dataForm(form) + prefix = form.attr("id") + actualForms = infosForm.actualForms + + number = element.parent('a').attr('href').split('-')[1] + tabToRemove = element.parent('a').parent('li') tabToRemove.remove() - contentToRemove = $('#' + prefix + '-' + number) - contentToRemove.find('#DELETE input').prop("checked", true) + contentToRemove = form.find('#' + prefix + '-' + number) + contentToRemove.find('#DELETE input') contentToRemove.removeAttr('role') toDjango = contentToRemove.children('div') - toDjango.hide().insertAfter(templateContent) + template = form.find('.templateContent') + toDjango.hide().insertAfter(template).find('#DELETE input').prop("checked", true) contentToRemove.remove() - $('.allContent').find('.tab-pane').first().addClass('active') - $('.allTabs').find('li:first').addClass('active').find('a').attr('aria-expanded', true) - reOrder() + + form.find('.allContent').find('.tab-pane').first().addClass('active') + form.find('.allTabs').find('li:first').addClass('active').find('a').attr('aria-expanded', true) + reOrder(form) actualForms-- + return -}); -function reOrder() { + +}; + +function reOrder(form) { + prefix = form.attr("id") counter = 0 - $('.allTabs').find('li:first').addClass('active').find('a').attr('aria-expanded', true) - $('.allTabs').find('li a').each( + + form.find('.allTabs').find('li a').each( function () { $(this).attr('href', '#' + prefix + '-' + counter) $(this).attr('aria-controls', prefix + '-' + counter) @@ -84,7 +124,7 @@ function reOrder() { ) counterCont = 0 - $('.allContent').find('.tab-pane').each( + form.find('.allContent').find('.tab-pane').each( function () { if ($(this).attr('id') != 'templateContent') { $(this).attr('id', prefix + '-' + counterCont) @@ -99,14 +139,18 @@ function reOrder() { ) } +form.find('.allTabs').find('li:first').addClass('active').find('a').attr('aria-expanded', true) + +form.find('tab-content').find('.tab-pane').removeClass('active') +form.find('tab-content').find('.tab-pane:first').addClass('active') -function removeActive() { - $('.allTabs').find('li').each( +function removeActive(form) { + form.find('.allTabs').find('li').each( function () { $(this).removeClass('active') $(this).find('a').attr('aria-expanded', false) }) - $('.allContent').find('.tab-pane').each( + form.find('.allContent').find('.tab-pane').each( function () { $(this).removeClass('active') @@ -114,7 +158,7 @@ function removeActive() { } -function hideDeleteCheckbox() { - allforms.find('#DELETE').hide() - allforms.find('#DELETE').prev().hide() +function hideDeleteCheckbox(form) { + form.find('.allContent').find('#DELETE').hide() + form.find('.allContent').find('#DELETE').prev().hide() }