From 63075a6fe92269c979f2e60fd1c5a03e24286405 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sun, 9 Jan 2022 14:21:13 -0800 Subject: [PATCH] Updates models --- bookwyrm/forms.py | 2 +- .../0126_filelink_link_linkdomain.py | 93 ++++++++++--------- bookwyrm/models/__init__.py | 2 +- bookwyrm/models/link.py | 17 +++- bookwyrm/tests/models/test_link.py | 41 ++++++++ 5 files changed, 110 insertions(+), 45 deletions(-) create mode 100644 bookwyrm/tests/models/test_link.py diff --git a/bookwyrm/forms.py b/bookwyrm/forms.py index 8c3785f8..f73da648 100644 --- a/bookwyrm/forms.py +++ b/bookwyrm/forms.py @@ -219,7 +219,7 @@ class CoverForm(CustomForm): class FileLinkForm(CustomForm): class Meta: model = models.FileLink - exclude = ["remote_id"] + fields = ["url", "filetype", "book"] class EditionForm(CustomForm): diff --git a/bookwyrm/migrations/0126_filelink_link_linkdomain.py b/bookwyrm/migrations/0126_filelink_link_linkdomain.py index 1235e81d..52be86c5 100644 --- a/bookwyrm/migrations/0126_filelink_link_linkdomain.py +++ b/bookwyrm/migrations/0126_filelink_link_linkdomain.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.10 on 2022-01-09 21:16 +# Generated by Django 3.2.10 on 2022-01-09 22:10 import bookwyrm.models.activitypub_mixin import bookwyrm.models.fields @@ -13,6 +13,47 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name="LinkDomain", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_date", models.DateTimeField(auto_now_add=True)), + ("updated_date", models.DateTimeField(auto_now=True)), + ( + "remote_id", + bookwyrm.models.fields.RemoteIdField( + max_length=255, + null=True, + validators=[bookwyrm.models.fields.validate_remote_id], + ), + ), + ("domain", models.CharField(max_length=255, unique=True)), + ( + "status", + models.CharField( + choices=[ + ("approved", "Approved"), + ("blocked", "Blocked"), + ("pending", "Pending"), + ], + default="pending", + max_length=50, + ), + ), + ("name", models.CharField(max_length=100)), + ], + options={ + "abstract": False, + }, + ), migrations.CreateModel( name="Link", fields=[ @@ -36,53 +77,21 @@ class Migration(migrations.Migration): ), ), ("url", bookwyrm.models.fields.URLField(max_length=255)), + ( + "domain", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="bookwyrm.linkdomain", + ), + ), ], options={ "abstract": False, }, bases=(bookwyrm.models.activitypub_mixin.ActivitypubMixin, models.Model), ), - migrations.CreateModel( - name="LinkDomain", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("created_date", models.DateTimeField(auto_now_add=True)), - ("updated_date", models.DateTimeField(auto_now=True)), - ( - "remote_id", - bookwyrm.models.fields.RemoteIdField( - max_length=255, - null=True, - validators=[bookwyrm.models.fields.validate_remote_id], - ), - ), - ("domain", models.CharField(max_length=255)), - ( - "status", - models.CharField( - choices=[ - ("approved", "Approved"), - ("blocked", "Blocked"), - ("pending", "Pending"), - ], - default="pending", - max_length=50, - ), - ), - ("name", models.CharField(max_length=100)), - ], - options={ - "abstract": False, - }, - ), migrations.CreateModel( name="FileLink", fields=[ diff --git a/bookwyrm/models/__init__.py b/bookwyrm/models/__init__.py index 8063d5aa..4c6305f9 100644 --- a/bookwyrm/models/__init__.py +++ b/bookwyrm/models/__init__.py @@ -4,7 +4,7 @@ import sys from .book import Book, Work, Edition, BookDataModel from .author import Author -from .link import Link, FileLink +from .link import Link, FileLink, LinkDomain from .connector import Connector from .shelf import Shelf, ShelfBook diff --git a/bookwyrm/models/link.py b/bookwyrm/models/link.py index 12a5fae1..e3c72b3f 100644 --- a/bookwyrm/models/link.py +++ b/bookwyrm/models/link.py @@ -1,4 +1,6 @@ """ outlink data """ +from urllib.parse import urlparse + from django.db import models from django.utils.translation import gettext_lazy as _ @@ -12,12 +14,25 @@ class Link(ActivitypubMixin, BookWyrmModel): """a link to a website""" url = fields.URLField(max_length=255, activitypub_field="href") + domain = models.ForeignKey( + "LinkDomain", on_delete=models.PROTECT, null=True, blank=True + ) activity_serializer = activitypub.Link reverse_unfurl = True + @property + def name(self): + """link name via the assocaited domain""" + return self.domain.name + def save(self, *args, **kwargs): """create a link""" + # get or create the associated domain + if not self.domain: + domain = urlparse(self.url).netloc + self.domain, _ = LinkDomain.objects.get_or_create(domain=domain) + # this is never broadcast, the owning model broadcasts an update if "broadcast" in kwargs: del kwargs["broadcast"] @@ -43,7 +58,7 @@ StatusChoices = [ class LinkDomain(BookWyrmModel): """List of domains used in links""" - domain = models.CharField(max_length=255) + domain = models.CharField(max_length=255, unique=True) status = models.CharField(max_length=50, choices=StatusChoices, default="pending") name = models.CharField(max_length=100) diff --git a/bookwyrm/tests/models/test_link.py b/bookwyrm/tests/models/test_link.py new file mode 100644 index 00000000..8afecd6c --- /dev/null +++ b/bookwyrm/tests/models/test_link.py @@ -0,0 +1,41 @@ +""" testing models """ +from unittest.mock import patch +from django.test import TestCase + +from bookwyrm import models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +class Link(TestCase): + """some activitypub oddness ahead""" + + def setUp(self): + """look, a list""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" + ) + work = models.Work.objects.create(title="hello") + self.book = models.Edition.objects.create(title="hi", parent_work=work) + + def test_create_domain(self, _): + """generated default name""" + domain = models.LinkDomain.objects.create(domain="beep.com") + self.assertEqual(domain.name, "beep.com") + self.assertEqual(domain.status, "pending") + + def test_create_link_new_domain(self, _): + """generates link and sets domain""" + link = models.Link.objects.create(url="https://www.hello.com/hi-there") + self.assertEqual(link.domain.domain, "www.hello.com") + self.assertEqual(link.name, "www.hello.com") + + def test_create_link_existing_domain(self, _): + """generate link with a known domain""" + domain = models.LinkDomain.objects.create(domain="www.hello.com", name="Hi") + + link = models.Link.objects.create(url="https://www.hello.com/hi-there") + self.assertEqual(link.domain, domain) + self.assertEqual(link.name, "Hi")