From 6d74bccb7d38beddd06abe76ff6dfe542ca87a1d Mon Sep 17 00:00:00 2001
From: George Katsikas <giorgakis.katsikas@gmail.com>
Date: Thu, 21 Sep 2023 17:41:24 +0200
Subject: [PATCH] refactor templates to return all projects used

update git repo creation to handle collection papers
---
 scipost_django/production/admin.py            |  5 +-
 .../management/commands/advance_git_repos.py  | 62 +++++++++++++------
 scipost_django/production/models.py           | 50 ++++++++++++---
 .../production/tests/test_models.py           |  8 +--
 4 files changed, 91 insertions(+), 34 deletions(-)

diff --git a/scipost_django/production/admin.py b/scipost_django/production/admin.py
index 191991474..0df3196c3 100644
--- a/scipost_django/production/admin.py
+++ b/scipost_django/production/admin.py
@@ -109,12 +109,15 @@ class ProofsRepositoryAdmin(GuardedModelAdmin):
 
     list_filter = ["status"]
     list_display = ["name", "status", "gitlab_link"]
-    readonly_fields = ["stream", "template_path", "gitlab_link"]
+    readonly_fields = ["stream", "template_paths", "gitlab_link"]
 
     def gitlab_link(self, obj):
         return format_html(
             '<a href="{1}" target="_blank">{0}</a>', obj.git_path, obj.git_url
         )
 
+    def template_paths(self, obj):
+        return format_html("<br>".join(obj.template_paths))
+
 
 admin.site.register(ProofsRepository, ProofsRepositoryAdmin)
diff --git a/scipost_django/production/management/commands/advance_git_repos.py b/scipost_django/production/management/commands/advance_git_repos.py
index ae1ec0bae..42da5e382 100644
--- a/scipost_django/production/management/commands/advance_git_repos.py
+++ b/scipost_django/production/management/commands/advance_git_repos.py
@@ -161,9 +161,17 @@ class Command(BaseCommand):
         """
         Return a list of gitlab actions required to fully clone a project.
         """
-        filenames = list(
-            map(lambda x: x["path"], project.repository_tree(get_all=True))
-        )
+        try:
+            filenames = list(
+                map(lambda x: x["path"], project.repository_tree(get_all=True))
+            )
+        except:
+            self.stdout.write(
+                self.style.WARNING(
+                    f"Could not get the files of {project.path_with_namespace}, it may be empty"
+                )
+            )
+            return []
 
         actions = []
         for filename in filenames:
@@ -192,24 +200,23 @@ class Command(BaseCommand):
         """
         project = self.GL.projects.get(repo.git_path)
 
-        journal_template_project = self.GL.projects.get(repo.template_path)
-        base_template_project = self.GL.projects.get(
-            "{ROOT}/Templates/Base".format(ROOT=settings.GITLAB_ROOT)
-        )
+        # Get the cloning actions for each template project
+        actions = [
+            self._get_project_cloning_actions(self.GL.projects.get(template_path))
+            for template_path in repo.template_paths
+        ]
+        actions = list(chain(*actions))  # Flatten the list of lists
 
-        all_actions = []
-        # Add "Base" and Journal specific templates to the repo
-        all_actions.append(self._get_project_cloning_actions(base_template_project))
-        all_actions.append(self._get_project_cloning_actions(journal_template_project))
+        # Keep the last action if there are multiple actions for the same file
+        # (i.e. the same file_path key in the dictionary)
+        non_duplicate_actions = []
+        file_paths_to_clone = []
 
-        # Add the "Selected" template if the submission has been accepted in Selections
-        if "Selections" in repo.stream.submission.editorial_decision.for_journal.name:
-            selected_template_project = self.GL.projects.get(
-                "{ROOT}/Templates/Selected".format(ROOT=settings.GITLAB_ROOT)
-            )
-            all_actions.append(
-                self._get_project_cloning_actions(selected_template_project)
-            )
+        for action in reversed(actions):
+            file_path = action.get("file_path", None)
+            if (file_path is not None) and (file_path not in file_paths_to_clone):
+                file_paths_to_clone.append(file_path)
+                non_duplicate_actions.append(action)
 
         # Add some delays to avoid:
         # - Commiting the files before the branch has finished being created
@@ -220,7 +227,7 @@ class Command(BaseCommand):
             {
                 "branch": "main",
                 "commit_message": "copy pure templates",
-                "actions": list(chain(*all_actions)),
+                "actions": non_duplicate_actions,
             }
         )
         sleep(3)
@@ -396,6 +403,21 @@ class Command(BaseCommand):
             selections_logo_img = r"[width=34.55mm]{logo_select.pdf}"
             replacements_dict[default_logo_img] = (lambda _: selections_logo_img, None)
 
+        # Add collection specific information if the submission is part of a collection
+        if repo.stream.submission.collections.exists():
+            collection = repo.stream.submission.collections.first()
+            series = collection.series
+
+            collection_replacements_dict = {
+                "<|COLLECTION_NAME|>": (lambda _: collection.name, None),
+                "<|COLLECTION_URL|>": (lambda _: collection.get_absolute_url(), None),
+                "<|EVENT_DETAILS|>": (lambda _: collection.event_details, None),
+                "<|SERIES_NAME|>": (lambda _: series.name, None),
+                "<|SERIES_URL|>": (lambda _: series.get_absolute_url(), None),
+            }
+
+            replacements_dict.update(collection_replacements_dict)
+
         # Define a helper function to try to format and replace a placeholder
         # which catches any errors and prints them to the console non-intrusively
         def try_format_replace(
diff --git a/scipost_django/production/models.py b/scipost_django/production/models.py
index 2b6fbd925..44fe27351 100644
--- a/scipost_django/production/models.py
+++ b/scipost_django/production/models.py
@@ -2,6 +2,7 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
+from typing import List
 from django.db import models
 from django.contrib.contenttypes.fields import GenericRelation
 from django.urls import reverse
@@ -410,22 +411,53 @@ class ProofsRepository(models.Model):
             git_path=self.git_path,
         )
 
-    @property
-    def template_path(self) -> str:
+    @cached_property
+    def template_paths(self) -> List[str]:
         """
-        Return the path to the template repository.
+        Return the list of paths to the various templates used for the proofs.
         """
+        paths = ["{ROOT}/Templates/Base".format(ROOT=settings.GITLAB_ROOT)]
+
+        # Determine whether to add the proceedings template or of some other journal
         if self.stream.submission.proceedings is not None:
-            return "{ROOT}/Templates/{journal_subdivision}".format(
-                ROOT=settings.GITLAB_ROOT,
-                journal_subdivision=self.journal_subdivision,
+            paths.append(
+                "{ROOT}/Templates/{journal_subdivision}".format(
+                    ROOT=settings.GITLAB_ROOT,
+                    journal_subdivision=self.journal_subdivision,
+                )
             )
+        # Add extra paths for any collections associated with the submission
+        # First add the base template for the series and then the collection
+        elif collections := self.stream.submission.collections.all():
+            for collection in collections:
+                paths.append(
+                    "{ROOT}/Templates/Series/{series}/Base".format(
+                        ROOT=settings.GITLAB_ROOT,
+                        series=collection.series.slug,
+                        collection=collection.slug,
+                    )
+                )
+                paths.append(
+                    "{ROOT}/Templates/Series/{series}/{collection}".format(
+                        ROOT=settings.GITLAB_ROOT,
+                        series=collection.series.slug,
+                        collection=collection.slug,
+                    )
+                )
         else:
-            return "{ROOT}/Templates/{journal}".format(
-                ROOT=settings.GITLAB_ROOT,
-                journal=self.journal_abbrev,
+            paths.append(
+                "{ROOT}/Templates/{journal}".format(
+                    ROOT=settings.GITLAB_ROOT,
+                    journal=self.journal_abbrev,
+                )
             )
 
+        # Add the selected template if the submission is a Selections paper
+        if "Selections" in self.stream.submission.editorial_decision.for_journal.name:
+            paths.append("{ROOT}/Templates/Selected".format(ROOT=settings.GITLAB_ROOT))
+
+        return paths
+
     def __str__(self) -> str:
         return f"Proofs repo for {self.stream}"
 
diff --git a/scipost_django/production/tests/test_models.py b/scipost_django/production/tests/test_models.py
index e82a62c0c..dcaee0bdb 100644
--- a/scipost_django/production/tests/test_models.py
+++ b/scipost_django/production/tests/test_models.py
@@ -207,8 +207,8 @@ class TestProofRepository(TestCase):
             "ProjectRoot/Proofs/SciPostPhys/2021/01/scipost_202101_00001v1_User",
         )
 
-        self.assertEqual(
-            proofs_repo.template_path,
+        self.assertIn(
+            proofs_repo.template_paths,
             "ProjectRoot/Templates/SciPostPhys",
         )
 
@@ -254,7 +254,7 @@ class TestProofRepository(TestCase):
             "ProjectRoot/Proofs/SciPostPhysProc/2021/ProcName21/scipost_202101_00001v1_User",
         )
 
-        self.assertEqual(
-            proofs_repo.template_path,
+        self.assertIn(
+            proofs_repo.template_paths,
             "ProjectRoot/Templates/SciPostPhysProc/2021/ProcName21",
         )
-- 
GitLab