From 8da607b713b34b28b39f286a1132b8d760465cc8 Mon Sep 17 00:00:00 2001
From: George Katsikas <giorgakis.katsikas@gmail.com>
Date: Mon, 5 Aug 2024 17:33:10 +0200
Subject: [PATCH] add supplemental information publication resources

fixes #316
---
 scipost_django/journals/forms.py              | 16 ++++
 scipost_django/journals/managers.py           |  3 +
 .../0135_alter_publicationresource__type.py   | 25 ++++++
 scipost_django/journals/models/resource.py    |  2 +
 .../manage_publication_resources.html         |  8 +-
 .../journals/publication_detail.html          | 78 ++++++++++++-------
 scipost_django/journals/urls/general.py       |  5 ++
 scipost_django/journals/views.py              | 48 ++++++++++++
 8 files changed, 153 insertions(+), 32 deletions(-)
 create mode 100644 scipost_django/journals/migrations/0135_alter_publicationresource__type.py

diff --git a/scipost_django/journals/forms.py b/scipost_django/journals/forms.py
index 4c22f8114..c956f800e 100644
--- a/scipost_django/journals/forms.py
+++ b/scipost_django/journals/forms.py
@@ -693,6 +693,22 @@ class DraftPublicationForm(forms.ModelForm):
                 )
             self.instance.topics.add(*self.submission.topics.all())
 
+            # Create supplementary information for any provided external links
+            if self.submission.code_repository_url:
+                PublicationResource.objects.get_or_create(
+                    publication=self.instance,
+                    _type=PublicationResource.TYPE_SUP_INFO,
+                    url=self.submission.code_repository_url,
+                    comments="Code repository",
+                )
+            if self.submission.data_repository_url:
+                PublicationResource.objects.get_or_create(
+                    publication=self.instance,
+                    _type=PublicationResource.TYPE_SUP_INFO,
+                    url=self.submission.data_repository_url,
+                    comments="Data repository",
+                )
+
     def prefill_fields(self):
         if self.submission:
             self.fields["title"].initial = self.submission.title
diff --git a/scipost_django/journals/managers.py b/scipost_django/journals/managers.py
index c2bce4fdc..4d73e6848 100644
--- a/scipost_django/journals/managers.py
+++ b/scipost_django/journals/managers.py
@@ -96,3 +96,6 @@ class PublicationResourceQuerySet(models.QuerySet):
 
     def live(self):
         return self.filter(_type=self.model.TYPE_LIVE_REPO)
+    
+    def sup_info(self):
+        return self.filter(_type=self.model.TYPE_SUP_INFO)
diff --git a/scipost_django/journals/migrations/0135_alter_publicationresource__type.py b/scipost_django/journals/migrations/0135_alter_publicationresource__type.py
new file mode 100644
index 000000000..93516ca8c
--- /dev/null
+++ b/scipost_django/journals/migrations/0135_alter_publicationresource__type.py
@@ -0,0 +1,25 @@
+# Generated by Django 4.2.10 on 2024-08-05 13:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("journals", "0134_journal_alternative_journals"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="publicationresource",
+            name="_type",
+            field=models.CharField(
+                choices=[
+                    ("source_repo", "Publication source files repository"),
+                    ("release_repo", "Codebase release version (archive) repository"),
+                    ("live_repo", "Live (external) repository"),
+                    ("supplemental_info", "Supplemental information"),
+                ],
+                max_length=32,
+            ),
+        ),
+    ]
diff --git a/scipost_django/journals/models/resource.py b/scipost_django/journals/models/resource.py
index 30580074d..ecc10045e 100644
--- a/scipost_django/journals/models/resource.py
+++ b/scipost_django/journals/models/resource.py
@@ -11,10 +11,12 @@ class PublicationResource(models.Model):
     TYPE_SOURCE_REPO = "source_repo"
     TYPE_RELEASE_ARCHIVE_REPO = "release_repo"
     TYPE_LIVE_REPO = "live_repo"
+    TYPE_SUP_INFO = "supplemental_info"
     TYPE_CHOICES = (
         (TYPE_SOURCE_REPO, "Publication source files repository"),
         (TYPE_RELEASE_ARCHIVE_REPO, "Codebase release version (archive) repository"),
         (TYPE_LIVE_REPO, "Live (external) repository"),
+        (TYPE_SUP_INFO, "Supplemental information"),
     )
     _type = models.CharField(max_length=32, choices=TYPE_CHOICES)
     publication = models.ForeignKey(
diff --git a/scipost_django/journals/templates/journals/manage_publication_resources.html b/scipost_django/journals/templates/journals/manage_publication_resources.html
index 5a400bcda..e3045e99e 100644
--- a/scipost_django/journals/templates/journals/manage_publication_resources.html
+++ b/scipost_django/journals/templates/journals/manage_publication_resources.html
@@ -26,6 +26,10 @@
   <div hx-get="{% url "journals:_hx_publication_resource_list" doi_label=publication.doi_label %}"
        hx-trigger="load once"></div>
 
-  <a class="btn btn-sm btn-primary"
-     href="{{ publication.get_absolute_url }}">Back to Publication</a>
+  <div class="d-flex flex-row">
+    <a class="btn btn-sm btn-secondary"
+       href="{{ publication.get_absolute_url }}">Back to Publication</a>
+    <a class="btn btn-sm btn-primary ms-auto"
+       href="{% url "journals:fetch_publication_resources" publication.doi_label %}">Fetch from preprint server</a>
+  </div>
 {% endblock content %}
diff --git a/scipost_django/journals/templates/journals/publication_detail.html b/scipost_django/journals/templates/journals/publication_detail.html
index bcd95c126..9c8e1c6fd 100644
--- a/scipost_django/journals/templates/journals/publication_detail.html
+++ b/scipost_django/journals/templates/journals/publication_detail.html
@@ -85,38 +85,56 @@
   {% endif %}
   <hr class="mt-5 mb-4"/>
 
-  {% if publication.topics.all or perms.scipost.can_manage_ontology %}
-    <h3 class="mt-2">Ontology / Topics</h3>
-    See full <a href="{% url 'ontology:ontology' %}">Ontology</a> or <a href="{% url 'ontology:topics' %}">Topics</a> database.
-    <br>
-    <br>
-
-    <div>
-      {% for topic in publication.topics.all %}
-        <span class="label label-secondary"><a href="{% url 'ontology:topic_details' slug=topic.slug %}">{{ topic }}</a>{% if perms.scipost.can_manage_ontology %} <a href="{% url 'journals:publication_remove_topic' doi_label=publication.doi_label slug=topic.slug %}"><span class="text-danger">{% include 'bi/x-circle-fill.html' %}</span></a>{% endif %}</span>
-      {% empty %}
-        <div>No Topic has yet been associated to this Publication</div>
-      {% endfor %}
-    </div>
+  <div class="row">
+    <div class="col">
+      {% if publication.topics.all or perms.scipost.can_manage_ontology %}
+        <h3 class="mt-2">Ontology / Topics</h3>
+        See full <a href="{% url 'ontology:ontology' %}">Ontology</a> or <a href="{% url 'ontology:topics' %}">Topics</a> database.
+        <br>
+        <br>
 
-    {% if perms.scipost.can_manage_ontology %}
-
-      <br>
-      <ul class="list-inline">
-        <li class="list-inline-item">
-          <form class="form-inline" action="{% url 'journals:publication_add_topic' doi_label=publication.doi_label %}" method="post">
-            <ul class="list-inline">
-              <li class="list-inline-item">Add an existing Topic:</li>
-              <li class="list-inline-item">{% csrf_token %}{{ select_topic_form }}</li>
-              <li class="list-inline-item"><input class="btn btn-outline-secondary" type="submit" value="Link"></li>
-            </ul>
-          </form>
-        </li>
-        <li class="list-inline-item p-2">Can't find the Topic you need? <a href="{% url 'ontology:topic_create' %}" target="_blank">Create it</a> (opens in new window)</li>
-      </ul>
-    {% endif %}
+        <div>
+          {% for topic in publication.topics.all %}
+            <span class="label label-secondary"><a href="{% url 'ontology:topic_details' slug=topic.slug %}">{{ topic }}</a>{% if perms.scipost.can_manage_ontology %} <a href="{% url 'journals:publication_remove_topic' doi_label=publication.doi_label slug=topic.slug %}"><span class="text-danger">{% include 'bi/x-circle-fill.html' %}</span></a>{% endif %}</span>
+          {% empty %}
+            <div>No Topic has yet been associated to this Publication</div>
+          {% endfor %}
+        </div>
 
-  {% endif %}
+        {% if perms.scipost.can_manage_ontology %}
+
+          <br>
+          <ul class="list-inline">
+            <li class="list-inline-item">
+              <form class="form-inline" action="{% url 'journals:publication_add_topic' doi_label=publication.doi_label %}" method="post">
+                <ul class="list-inline">
+                  <li class="list-inline-item">Add an existing Topic:</li>
+                  <li class="list-inline-item">{% csrf_token %}{{ select_topic_form }}</li>
+                  <li class="list-inline-item"><input class="btn btn-outline-secondary" type="submit" value="Link"></li>
+                </ul>
+              </form>
+            </li>
+            <li class="list-inline-item p-2">Can't find the Topic you need? <a href="{% url 'ontology:topic_create' %}" target="_blank">Create it</a> (opens in new window)</li>
+          </ul>
+        {% endif %}
+
+      {% endif %}
+    </div>
+    {% if publication.resources.sup_info %}
+      <div class="col-12 col-md col-xl-4">
+        <details {% if publication.resources.sup_info|length < 4 %}open{% endif %}
+          class="hcard hcard-secondary bg-opacity-25">
+          <summary class="list-triangle"><h3>Supplemental Information</h3></summary>
+          <p class="text-muted">External links to supplemental resources; opens in a new tab.</p>
+          <ul class="list-unstyled">
+            {% for sup_info in publication.resources.sup_info.all %}
+            <li><a class="fs-6" href="{{ sup_info.url }}" target="_blank">{{ sup_info.comments }}</a></li>
+            {% endfor %}
+          </ul>
+        </details>
+      </div>
+    {% endif %}
+  </div>
 
   <h3 class="mt-4">
     Author{{ publication.authors.all|length|pluralize }} / Affiliation{{ affiliations_list|length|pluralize }}: mappings to Contributors and Organizations
diff --git a/scipost_django/journals/urls/general.py b/scipost_django/journals/urls/general.py
index d258dd286..93f940bec 100644
--- a/scipost_django/journals/urls/general.py
+++ b/scipost_django/journals/urls/general.py
@@ -218,6 +218,11 @@ urlpatterns = [
         journals_views.HTMXInlinePublicationResourceListView.as_view(),
         name="_hx_publication_resource_list",
     ),
+    path(
+        "admin/<publication_doi_label:doi_label>/fetch_publication_resources",
+        journals_views.fetch_publication_resources,
+        name="fetch_publication_resources",
+    ),
     # Admin: Volumes and Issues
     path(
         "admin/volumes/",
diff --git a/scipost_django/journals/views.py b/scipost_django/journals/views.py
index d6f18a81d..36ddd23f6 100644
--- a/scipost_django/journals/views.py
+++ b/scipost_django/journals/views.py
@@ -735,14 +735,62 @@ def draft_accompanying_publication(request, doi_label):
 @permission_required("scipost.can_draft_publication", raise_exception=True)
 def manage_publication_resources(request, doi_label):
     publication = get_object_or_404(Publication, doi_label=doi_label)
+
+    # Determine whether to display button with automatic creation of resource
+    # Currently, only possible for ChemaRxiv submissions
+    can_fetch_resources = (
+        "chemrxiv"
+        in publication.accepted_submission.preprint.identifier_w_vn_nr.lower()
+    )
+
     context = {
         "publication": publication,
+        "can_fetch_resources": can_fetch_resources,
     }
     return TemplateResponse(
         request, "journals/manage_publication_resources.html", context
     )
 
 
+def fetch_publication_resources(request, doi_label):
+    publication = get_object_or_404(Publication, doi_label=doi_label)
+    if (
+        "chemrxiv"
+        not in publication.accepted_submission.preprint.identifier_w_vn_nr.lower()
+    ):
+        messages.error(
+            request, "Resource fetching is only available for ChemRxiv submissions"
+        )
+        return redirect(
+            reverse("journals:manage_publication_resources", args=(doi_label,))
+        )
+
+    # Fetch resources from ChemRxiv
+    response = requests.get(
+        f"https://chemrxiv.org/engage/chemrxiv/public-api/v1/items/doi/"
+        + publication.accepted_submission.preprint.identifier_w_vn_nr
+    )
+
+    if response.status_code != 200:
+        messages.error(request, "Resource fetching failed.")
+        return redirect(
+            reverse("journals:manage_publication_resources", args=(doi_label,))
+        )
+
+    if resources := response.json().get("suppItems", []):
+        resources = sorted(resources, key=lambda x: x.get("id"))
+
+    for resource in resources:
+        PublicationResource.objects.get_or_create(
+            publication=publication,
+            comments=resource.get("title"),
+            url=resource.get("asset", {}).get("original", {}).get("url", ""),
+            _type=PublicationResource.TYPE_SUP_INFO,
+        )
+
+    return redirect(reverse("journals:manage_publication_resources", args=(doi_label,)))
+
+
 @method_decorator(login_required, name="dispatch")
 @method_decorator(
     permission_required("scipost.can_draft_publication", raise_exception=True),
-- 
GitLab