[BUILD-412] Migrate existent users to the new Plan logic (#2139)

[BUILD-412] Migrate existent users to the new Plan logic (#2139)

  • BUILD-412 - create a data migration to populate the Plan’s model

  • BUILD-412 - create a script to update memberships.

  • BUILD-412 - update tier’s names and features, update script

diff --git a/ankihub/memberships/migrations/0042_populate_plan_model.py b/ankihub/memberships/migrations/0042_populate_plan_model.py
new file mode 100644
index 0000000..7ce080b
--- /dev/null
+++ b/ankihub/memberships/migrations/0042_populate_plan_model.py
@@ -0,0 +1,36 @@
+# Generated by Django 4.2.8 on 2024-06-06 12:24
+
+from django.db import migrations
+from ankihub.memberships.models import FeatureChoices
+
+
+def create_plans(apps, schema_editor):
+    Plan = apps.get_model("memberships", "Plan")
+    Plan.objects.bulk_create(
+        [
+            Plan(name="Basic", slug="basic", features=[FeatureChoices.FREE_DECKS_COLLABORATION]),
+            Plan(name="Core", slug="core",
+                 features=[FeatureChoices.FREE_DECKS_COLLABORATION, FeatureChoices.PAID_DECKS_COLLABORATION]),
+            Plan(name="AnkiHub AI", slug="ankihub_ai",
+                 features=[FeatureChoices.FREE_DECKS_COLLABORATION, FeatureChoices.PAID_DECKS_COLLABORATION,
+                           FeatureChoices.FLASHCARD_SELECTOR, FeatureChoices.REVIEWER_EXTENSION]),
+            Plan(name="Lifetime", slug="lifetime",
+                 features=[FeatureChoices.FREE_DECKS_COLLABORATION, FeatureChoices.PAID_DECKS_COLLABORATION,
+                           FeatureChoices.FLASHCARD_SELECTOR, FeatureChoices.REVIEWER_EXTENSION]),
+        ]
+    )
+
+
+def delete_plans(apps, schema_editor):
+    Plan = apps.get_model("memberships", "Plan")
+    Plan.objects.filter(name__in=["Basic", "Core", "AnkiHub AI", "Lifetime"]).delete()
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("memberships", "0041_plan_membership_plan"),
+    ]
+
+    operations = [
+        migrations.RunPython(create_plans, delete_plans),
+    ]
diff --git a/scripts/update_memberships.py b/scripts/update_memberships.py
new file mode 100644
index 0000000..90eafba
--- /dev/null
+++ b/scripts/update_memberships.py
@@ -0,0 +1,40 @@
+import logging
+
+from django.db import transaction
+
+from ankihub.memberships.models import (
+    Membership,
+    MembershipStatusChoices,
+    MembershipTypesChoices,
+    Plan,
+)
+
+
+def update_memberships(
+    plan_name, status=MembershipStatusChoices.ACTIVE, membership_type=None
+):
+    try:
+        plan = Plan.objects.get(name=plan_name)
+    except Plan.DoesNotExist:
+        logging.error(f"Plan {plan_name} does not exist")
+        return
+    memberships = Membership.objects.filter(plan__isnull=True, status=status)
+    if membership_type is not None:
+        memberships = memberships.filter(membership_type=membership_type)
+    else:
+        memberships = memberships.exclude(
+            membership_type=MembershipTypesChoices.LIFETIME
+        )
+    memberships.update(plan=plan)
+
+
+def run():
+    with transaction.atomic():
+        logging.info("Update inactive memberships to Novice-free plan")
+        update_memberships("Basic", MembershipStatusChoices.INACTIVE)
+
+        logging.info("Update active memberships to Pro plan")
+        update_memberships("Core")
+
+        logging.info("Update active / lifetime memberships to Lifetime plan")
+        update_memberships("Lifetime", membership_type=MembershipTypesChoices.LIFETIME)

GitHub
sha: 03793ac3b6cac87cb391f68474ffcfac179148ac