Repository: LibraryOfCongress/concordia

Issue:
Move admin functions to Django admin
**Is your feature request related to a problem? Please describe.**
The site can't be cached because of the presence of admin buttons in the end-user view. 

**Describe the solution you'd like**
The following admin functions need to be implemented in the Django admin:
Move admin functions from campaigns public UI page to Django admin
- [x] export CSV
- [x] export BagIt
- [x] publish
- [x] unpublish
- [x] delete
- [x] Report

Project admin functions move to django admin
- [x] publish
- [x] unpublish 
- [x] delete

Assets admin function: 

- [x] hiding individual assets



Discussion:

Resolving patch:
diff --git a/concordia/admin.py b/concordia/admin.py
--- a/concordia/admin.py
+++ b/concordia/admin.py
@@ -12,6 +12,7 @@
 from django.utils.html import format_html
 from django.views.decorators.cache import never_cache
 
+from exporter import views as exporter_views
 from importer.tasks import import_items_into_project_from_url
 from importer.utils.excel import slurp_excel
 
@@ -26,6 +27,7 @@
     Transcription,
     UserAssetTagCollection,
 )
+from .views import ReportCampaignView
 
 
 def publish_action(modeladmin, request, queryset):
@@ -201,6 +203,32 @@ class CampaignAdmin(admin.ModelAdmin, CustomListDisplayFieldsMixin):
 
     actions = (publish_action, unpublish_action)
 
+    def get_urls(self):
+        urls = super().get_urls()
+
+        app_label = self.model._meta.app_label
+        model_name = self.model._meta.model_name
+
+        custom_urls = [
+            path(
+                "exportCSV/<path:campaign_slug>",
+                exporter_views.ExportCampaignToCSV.as_view(),
+                name=f"{app_label}_{model_name}_export-csv",
+            ),
+            path(
+                "exportBagIt/<path:campaign_slug>",
+                exporter_views.ExportCampaignToBagit.as_view(),
+                name=f"{app_label}_{model_name}_export-bagit",
+            ),
+            path(
+                "report/<path:campaign_slug>",
+                ReportCampaignView.as_view(),
+                name=f"{app_label}_{model_name}_report",
+            ),
+        ]
+
+        return custom_urls + urls
+
 
 @admin.register(Resource)
 class ResourceAdmin(admin.ModelAdmin, CustomListDisplayFieldsMixin):
diff --git a/concordia/urls.py b/concordia/urls.py
--- a/concordia/urls.py
+++ b/concordia/urls.py
@@ -26,13 +26,13 @@
             views.ConcordiaAlternateAssetView.as_view(),
             name="alternate-asset",
         ),
-        re_path(
-            r"exportCSV/([^/]+)/$",
+        path(
+            "exportCSV/<slug:campaign_slug>/",
             exporter_views.ExportCampaignToCSV.as_view(),
             name="export-csv",
         ),
-        re_path(
-            r"exportBagIt/([^/]+)/$",
+        path(
+            "exportBagIt/<slug:campaign_slug>/",
             exporter_views.ExportCampaignToBagit.as_view(),
             name="export-bagit",
         ),
diff --git a/exporter/views.py b/exporter/views.py
--- a/exporter/views.py
+++ b/exporter/views.py
@@ -4,10 +4,11 @@
 
 import bagit
 from django.conf import settings
-from django.http import HttpResponse
-from django.views.generic import TemplateView
 from django.contrib.auth.decorators import login_required
+from django.http import HttpResponse
 from django.utils.decorators import method_decorator
+from django.views.generic import TemplateView
+
 from concordia.models import Asset, Campaign, Transcription, UserAssetTagCollection
 from concordia.storage import ASSET_STORAGE
 
@@ -22,7 +23,7 @@ class ExportCampaignToCSV(TemplateView):
 
     @method_decorator(login_required)
     def get(self, request, *args, **kwargs):
-        campaign = Campaign.objects.get(slug=self.args[0])
+        campaign = Campaign.objects.get(slug=self.kwargs["campaign_slug"])
         asset_list = Asset.objects.filter(item__project__campaign=campaign).order_by(
             "title", "sequence"
         )
@@ -75,7 +76,7 @@ class ExportCampaignToBagit(TemplateView):
 
     @method_decorator(login_required)
     def get(self, request, *args, **kwargs):
-        campaign = Campaign.objects.get(slug=self.args[0])
+        campaign = Campaign.objects.get(slug=self.kwargs["campaign_slug"])
         asset_list = Asset.objects.filter(item__project__campaign=campaign).order_by(
             "title", "sequence"
         )


Test patch:
diff --git a/concordia/tests/utils.py b/concordia/tests/utils.py
--- a/concordia/tests/utils.py
+++ b/concordia/tests/utils.py
@@ -85,12 +85,18 @@ def create_asset(
     slug="test-asset",
     media_type=MediaType.IMAGE,
     media_url="1.jpg",
+    published=True,
     **kwargs,
 ):
     if item is None:
         item = create_item()
     asset = item.asset_set.create(
-        title=title, slug=slug, media_type=media_type, media_url=media_url, **kwargs
+        title=title,
+        slug=slug,
+        media_type=media_type,
+        published=published,
+        media_url=media_url,
+        **kwargs,
     )
     asset.full_clean()
     asset.save()