diff --git a/src/apps/dashboard/migrations/0002_applet_userapplet.py b/src/apps/dashboard/migrations/0002_applet_userapplet.py new file mode 100644 index 0000000..0e92bff --- /dev/null +++ b/src/apps/dashboard/migrations/0002_applet_userapplet.py @@ -0,0 +1,37 @@ +# Generated by Django 6.0 on 2026-03-04 20:34 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dashboard', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Applet', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('slug', models.SlugField(unique=True)), + ('name', models.CharField(max_length=100)), + ('default_visible', models.BooleanField(default=True)), + ], + ), + migrations.CreateModel( + name='UserApplet', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('visible', models.BooleanField(default=True)), + ('applet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='dashboard.applet')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_applets', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('user', 'applet')}, + }, + ), + ] diff --git a/src/apps/dashboard/migrations/0003_seed_applets.py b/src/apps/dashboard/migrations/0003_seed_applets.py new file mode 100644 index 0000000..78c4666 --- /dev/null +++ b/src/apps/dashboard/migrations/0003_seed_applets.py @@ -0,0 +1,17 @@ +from django.db import migrations + + +def seed_applets(apps, schema_editor): + Applet = apps.get_model("dashboard", "Applet") + Applet.objects.get_or_create(slug="username", defaults={"name": "Username"}) + Applet.objects.get_or_create(slug="theme-switcher", defaults={"name": "Theme Switcher"}) + + +class Migration(migrations.Migration): + dependencies = [ + ("dashboard", "0002_applet_userapplet"), + ] + + operations = [ + migrations.RunPython(seed_applets, migrations.RunPython.noop), + ] diff --git a/src/apps/dashboard/models.py b/src/apps/dashboard/models.py index bb1b7f0..e6e9784 100644 --- a/src/apps/dashboard/models.py +++ b/src/apps/dashboard/models.py @@ -38,3 +38,26 @@ class Item(models.Model): def __str__(self): return self.text +class Applet(models.Model): + slug = models.SlugField(unique=True) + name = models.CharField(max_length=100) + default_visible = models.BooleanField(default=True) + + def __str__(self): + return self.name + +class UserApplet(models.Model): + user = models.ForeignKey( + "lyric.User", + related_name="user_applets", + on_delete=models.CASCADE, + ) + applet = models.ForeignKey( + Applet, + on_delete=models.CASCADE, + ) + visible = models.BooleanField(default=True) + + class Meta: + unique_together = ("user", "applet") + diff --git a/src/apps/dashboard/tests/integrated/test_models.py b/src/apps/dashboard/tests/integrated/test_models.py index 4564c88..72355b3 100644 --- a/src/apps/dashboard/tests/integrated/test_models.py +++ b/src/apps/dashboard/tests/integrated/test_models.py @@ -2,7 +2,7 @@ from django.core.exceptions import ValidationError from django.db.utils import IntegrityError from django.test import TestCase -from apps.dashboard.models import Item, List +from apps.dashboard.models import Applet, Item, List, UserApplet from apps.lyric.models import User @@ -68,3 +68,27 @@ class ListModelTest(TestCase): Item.objects.create(list=list_, text="first item") Item.objects.create(list=list_, text="second item") self.assertEqual(list_.name, "first item") + +class AppletModelTest(TestCase): + def test_applet_can_be_created(self): + applet = Applet.objects.create(slug="my-applet", name="My Applet", default_visible=True) + self.assertEqual(Applet.objects.get(slug="my-applet"), applet) + + def test_applet_slug_is_unique(self): + Applet.objects.create(slug="my-applet", name="First") + with self.assertRaises(IntegrityError): + Applet.objects.create(slug="my-applet", name="Second") + +class UserAppletModelTest(TestCase): + def setUp(self): + self.user = User.objects.create(email="a@b.cde") + self.applet = Applet.objects.create(slug="username", name="Username") + + def test_user_applet_links_user_to_applet(self): + ua = UserApplet.objects.create(user=self.user, applet=self.applet, visible=True) + self.assertIn(ua, self.user.user_applets.all()) + + def test_user_applet_unique_per_user_and_applet(self): + UserApplet.objects.create(user=self.user, applet=self.applet, visible=True) + with self.assertRaises(IntegrityError): + UserApplet.objects.create(user=self.user, applet=self.applet, visible=False) diff --git a/src/templates/apps/dashboard/home.html b/src/templates/apps/dashboard/home.html index 1852bd4..e55146b 100644 --- a/src/templates/apps/dashboard/home.html +++ b/src/templates/apps/dashboard/home.html @@ -15,7 +15,7 @@ {% block content %} {% if user.is_authenticated %} -
+
{% for theme in themes %}