From f1f01f183f08bbfa49cba765eaff25da1c71b675 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Bedna=C5=99=C3=ADk?= <jan.bednarik@gmail.com>
Date: Tue, 31 Jan 2023 20:45:57 +0100
Subject: [PATCH] Setup Wagtail Transfer

---
 .isort.cfg                                    |  2 +-
 Dockerfile                                    |  1 +
 README.md                                     |  2 ++
 ...trictarticletag_content_object_and_more.py | 33 +++++++++++++++++++
 district/models.py                            |  8 +++--
 ..._elections2021articletag_content_object.py | 24 ++++++++++++++
 elections2021/models.py                       |  4 ++-
 ...043_alter_mainarticletag_content_object.py | 24 ++++++++++++++
 main/models.py                                |  6 +++-
 majak/settings/base.py                        | 11 +++++++
 majak/settings/dev.py                         |  3 ++
 majak/settings/production.py                  |  1 +
 majak/urls.py                                 |  2 ++
 requirements/base.in                          |  1 +
 requirements/base.txt                         |  2 ++
 ...5_alter_uniwebarticletag_content_object.py | 24 ++++++++++++++
 uniweb/models.py                              |  6 +++-
 17 files changed, 148 insertions(+), 6 deletions(-)
 create mode 100644 district/migrations/0103_alter_districtarticletag_content_object_and_more.py
 create mode 100644 elections2021/migrations/0053_alter_elections2021articletag_content_object.py
 create mode 100644 main/migrations/0043_alter_mainarticletag_content_object.py
 create mode 100644 uniweb/migrations/0035_alter_uniwebarticletag_content_object.py

diff --git a/.isort.cfg b/.isort.cfg
index 2f6cd78c..e5972edc 100644
--- a/.isort.cfg
+++ b/.isort.cfg
@@ -3,4 +3,4 @@
 line_length = 88
 multi_line_output = 3
 include_trailing_comma = true
-known_third_party = PyPDF2,arrow,bleach,bs4,captcha,celery,dateutil,django,environ,faker,fastjsonschema,icalevnt,markdown,modelcluster,pirates,pytest,pytz,requests,sentry_sdk,taggit,tweepy,wagtail,wagtailmetadata,weasyprint,yaml
+known_third_party = PyPDF2,arrow,bleach,bs4,captcha,celery,dateutil,django,environ,faker,fastjsonschema,icalevnt,markdown,modelcluster,pirates,pytest,pytz,requests,sentry_sdk,taggit,tweepy,wagtail,wagtail_transfer,wagtailmetadata,weasyprint,yaml
diff --git a/Dockerfile b/Dockerfile
index 08b4f2b3..9a8045fd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -29,6 +29,7 @@ ENV DJANGO_SETTINGS_MODULE "majak.settings.production"
 # fake values for required env variables used to run collectstatic during build
 RUN DJANGO_SECRET_KEY=x DATABASE_URL=postgres://x/x DJANGO_ALLOWED_HOSTS=x \
     OIDC_RP_CLIENT_ID=x OIDC_RP_CLIENT_SECRET=x OIDC_RP_REALM_URL=x \
+    WAGTAILTRANSFER_SECRET_KEY=x \
     python manage.py collectstatic
 
 EXPOSE 8000
diff --git a/README.md b/README.md
index 0b4ba971..259a0032 100644
--- a/README.md
+++ b/README.md
@@ -148,6 +148,7 @@ V produkci musí být navíc nastaveno:
 | `DJANGO_ALLOWED_HOSTS` | | allowed hosts (více hodnot odděleno čárkami) |
 | `CELERY_BROKER_URL` | | URL pro Celery Broker |
 | `CELERY_RESULT_BACKEND` | | URL pro Celery Result Backend |
+| `WAGTAILTRANSFER_SECRET_KEY` |  | tajný klíč pro transfer stránek |
 
 Různé:
 
@@ -157,6 +158,7 @@ Různé:
 | `SENTRY_DSN` | | pokud je zadáno, pády se reportují do Sentry |
 | `SEARCH_CONFIG` | english | nastavení jazyka fulltextového vyhledávání, viz níže |
 | `DEBUG_TOOLBAR` | False | zobrazit Django Debug Toolbar (pro vývoj) |
+| `WAGTAILTRANSFER_SOURCES` | {} | `dict` s konfigurací zdrojů pro transfer stránek |
 
 Settings pro appky na weby:
 
diff --git a/district/migrations/0103_alter_districtarticletag_content_object_and_more.py b/district/migrations/0103_alter_districtarticletag_content_object_and_more.py
new file mode 100644
index 00000000..411bcdeb
--- /dev/null
+++ b/district/migrations/0103_alter_districtarticletag_content_object_and_more.py
@@ -0,0 +1,33 @@
+# Generated by Django 4.1.5 on 2023-01-31 19:42
+
+import django.db.models.deletion
+import modelcluster.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("district", "0102_alter_districtarticlepage_content_and_more"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="districtarticletag",
+            name="content_object",
+            field=modelcluster.fields.ParentalKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="tagged_items",
+                to="district.districtarticlepage",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="districtpersontag",
+            name="content_object",
+            field=modelcluster.fields.ParentalKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="tagged_items",
+                to="district.districtpersonpage",
+            ),
+        ),
+    ]
diff --git a/district/models.py b/district/models.py
index 608ea0e9..fbbc7e3c 100644
--- a/district/models.py
+++ b/district/models.py
@@ -339,7 +339,9 @@ class DistrictHomePage(
 
 class DistrictArticleTag(TaggedItemBase):
     content_object = ParentalKey(
-        "district.DistrictArticlePage", on_delete=models.CASCADE
+        "district.DistrictArticlePage",
+        on_delete=models.CASCADE,
+        related_name="tagged_items",
     )
 
 
@@ -577,7 +579,9 @@ class DistrictContactPage(
 
 class DistrictPersonTag(TaggedItemBase):
     content_object = ParentalKey(
-        "district.DistrictPersonPage", on_delete=models.CASCADE
+        "district.DistrictPersonPage",
+        on_delete=models.CASCADE,
+        related_name="tagged_items",
     )
 
 
diff --git a/elections2021/migrations/0053_alter_elections2021articletag_content_object.py b/elections2021/migrations/0053_alter_elections2021articletag_content_object.py
new file mode 100644
index 00000000..3850ca84
--- /dev/null
+++ b/elections2021/migrations/0053_alter_elections2021articletag_content_object.py
@@ -0,0 +1,24 @@
+# Generated by Django 4.1.5 on 2023-01-31 19:42
+
+import django.db.models.deletion
+import modelcluster.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("elections2021", "0052_alter_elections2021articlepage_content_and_more"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="elections2021articletag",
+            name="content_object",
+            field=modelcluster.fields.ParentalKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="tagged_items",
+                to="elections2021.elections2021articlepage",
+            ),
+        ),
+    ]
diff --git a/elections2021/models.py b/elections2021/models.py
index f7e2da65..436464bc 100644
--- a/elections2021/models.py
+++ b/elections2021/models.py
@@ -536,7 +536,9 @@ class Elections2021HomePage(MetadataPageMixin, RoutablePageMixin, Page):
 
 class Elections2021ArticleTag(TaggedItemBase):
     content_object = ParentalKey(
-        "elections2021.Elections2021ArticlePage", on_delete=models.CASCADE
+        "elections2021.Elections2021ArticlePage",
+        on_delete=models.CASCADE,
+        related_name="tagged_items",
     )
 
 
diff --git a/main/migrations/0043_alter_mainarticletag_content_object.py b/main/migrations/0043_alter_mainarticletag_content_object.py
new file mode 100644
index 00000000..97772e76
--- /dev/null
+++ b/main/migrations/0043_alter_mainarticletag_content_object.py
@@ -0,0 +1,24 @@
+# Generated by Django 4.1.5 on 2023-01-31 19:42
+
+import django.db.models.deletion
+import modelcluster.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("main", "0042_alter_mainarticlepage_content_and_more"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="mainarticletag",
+            name="content_object",
+            field=modelcluster.fields.ParentalKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="tagged_items",
+                to="main.mainarticlepage",
+            ),
+        ),
+    ]
diff --git a/main/models.py b/main/models.py
index 6c6803a7..642daf43 100644
--- a/main/models.py
+++ b/main/models.py
@@ -495,7 +495,11 @@ class MainArticlesPage(
 
 
 class MainArticleTag(TaggedItemBase):
-    content_object = ParentalKey("main.MainArticlePage", on_delete=models.CASCADE)
+    content_object = ParentalKey(
+        "main.MainArticlePage",
+        on_delete=models.CASCADE,
+        related_name="tagged_items",
+    )
 
 
 class MainArticlePage(
diff --git a/majak/settings/base.py b/majak/settings/base.py
index 7672ef0c..bad6d65a 100644
--- a/majak/settings/base.py
+++ b/majak/settings/base.py
@@ -72,6 +72,7 @@ INSTALLED_APPS = [
     "wagtail.core",
     "wagtailmetadata",
     "wagtail_trash",
+    "wagtail_transfer",
     "modelcluster",
     "taggit",
     "django_extensions",
@@ -259,6 +260,16 @@ WAGTAILEMBEDS_RESPONSIVE_HTML = True
 BASE_URL = env.str("BASE_URL", default="https://majak.pirati.cz")
 WAGTAILADMIN_BASE_URL = BASE_URL
 
+# WAGTAIL TRANSFER SETTINGS
+# ------------------------------------------------------------------------------
+
+WAGTAILTRANSFER_SOURCES = env.json("WAGTAILTRANSFER_SOURCES", default={})
+WAGTAILTRANSFER_UPDATE_RELATED_MODELS = ["wagtailimages.Image", "wagtaildocs.Document"]
+WAGTAILTRANSFER_LOOKUP_FIELDS = {
+    "users.User": ["sso_id"],
+    "taggit.tag": ["slug"],
+}
+
 # CUSTOM SETTINGS
 # ------------------------------------------------------------------------------
 MAJAK_ENV = env.str("MAJAK_ENV", default="prod")
diff --git a/majak/settings/dev.py b/majak/settings/dev.py
index a58152a4..84a953fb 100644
--- a/majak/settings/dev.py
+++ b/majak/settings/dev.py
@@ -8,6 +8,9 @@ SECRET_KEY = env("DJANGO_SECRET_KEY", default="58asda4d6nasd*jkj!dbska83asd54")
 ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["*"])
 INSTALLED_APPS += ["wagtail.contrib.styleguide"]
 MAJAK_ENV = env.str("MAJAK_ENV", default="dev")
+WAGTAILTRANSFER_SECRET_KEY = env.str(
+    "WAGTAILTRANSFER_SECRET_KEY", default="sfdjhfssah856asjhd"
+)
 
 # django-debug-toolbar
 # ------------------------------------------------------------------------------
diff --git a/majak/settings/production.py b/majak/settings/production.py
index 33c990f1..36645db3 100644
--- a/majak/settings/production.py
+++ b/majak/settings/production.py
@@ -18,6 +18,7 @@ SECURE_HSTS_SECONDS = 518400
 SECURE_HSTS_INCLUDE_SUBDOMAINS = True
 SECURE_HSTS_PRELOAD = True
 SECURE_CONTENT_TYPE_NOSNIFF = True
+WAGTAILTRANSFER_SECRET_KEY = env.str("WAGTAILTRANSFER_SECRET_KEY")
 
 # TEMPLATES
 # ------------------------------------------------------------------------------
diff --git a/majak/urls.py b/majak/urls.py
index 7967cf7c..478994bb 100644
--- a/majak/urls.py
+++ b/majak/urls.py
@@ -7,6 +7,7 @@ from wagtail.admin import urls as wagtailadmin_urls
 from wagtail.contrib.sitemaps.views import sitemap
 from wagtail.core import urls as wagtail_urls
 from wagtail.documents import urls as wagtaildocs_urls
+from wagtail_transfer import urls as wagtailtransfer_urls
 
 from elections2021 import views as elections2021_views
 from maps_utils import urls as maps_utils_urls
@@ -27,6 +28,7 @@ urlpatterns = [
     path("captcha/", include(captcha.urls)),
     path("seznam-webu/", SitesListView.as_view()),
     path("sitemap.xml", sitemap),
+    path("wagtail-transfer/", include(wagtailtransfer_urls)),
 ] + pirates_urlpatterns
 
 
diff --git a/requirements/base.in b/requirements/base.in
index 0cd088a7..a5ce82ca 100644
--- a/requirements/base.in
+++ b/requirements/base.in
@@ -1,6 +1,7 @@
 wagtail
 wagtail-metadata
 wagtail-trash
+wagtail-transfer
 django-environ
 django-extensions
 django-redis
diff --git a/requirements/base.txt b/requirements/base.txt
index e07195ba..211b0de4 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -272,6 +272,8 @@ wagtail==4.1.1
     #   wagtail-trash
 wagtail-metadata==4.0.2
     # via -r base.in
+wagtail-transfer==0.8.5
+    # via -r base.in
 wagtail-trash==0.3.0
     # via -r base.in
 wcwidth==0.2.6
diff --git a/uniweb/migrations/0035_alter_uniwebarticletag_content_object.py b/uniweb/migrations/0035_alter_uniwebarticletag_content_object.py
new file mode 100644
index 00000000..8e63a019
--- /dev/null
+++ b/uniweb/migrations/0035_alter_uniwebarticletag_content_object.py
@@ -0,0 +1,24 @@
+# Generated by Django 4.1.5 on 2023-01-31 19:42
+
+import django.db.models.deletion
+import modelcluster.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("uniweb", "0034_alter_uniwebarticlepage_content_and_more"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="uniwebarticletag",
+            name="content_object",
+            field=modelcluster.fields.ParentalKey(
+                on_delete=django.db.models.deletion.CASCADE,
+                related_name="tagged_items",
+                to="uniweb.uniwebarticlepage",
+            ),
+        ),
+    ]
diff --git a/uniweb/models.py b/uniweb/models.py
index 4b0533fa..bc703145 100644
--- a/uniweb/models.py
+++ b/uniweb/models.py
@@ -284,7 +284,11 @@ CONTENT_STREAM_BLOCKS = [
 
 
 class UniwebArticleTag(TaggedItemBase):
-    content_object = ParentalKey("uniweb.UniwebArticlePage", on_delete=models.CASCADE)
+    content_object = ParentalKey(
+        "uniweb.UniwebArticlePage",
+        on_delete=models.CASCADE,
+        related_name="tagged_items",
+    )
 
 
 class UniwebHomePage(
-- 
GitLab