Include the correct protocol and port in remote IDs

This commit is contained in:
Bart Schuurmans 2024-04-07 17:32:35 +02:00
parent 609bc15406
commit 4f58b11330
21 changed files with 46 additions and 58 deletions

View file

@ -8,7 +8,7 @@ from django.contrib.postgres.indexes import GinIndex
import pgtrigger import pgtrigger
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
from bookwyrm.utils.db import format_trigger from bookwyrm.utils.db import format_trigger
from .book import BookDataModel, MergedAuthor from .book import BookDataModel, MergedAuthor
@ -70,7 +70,7 @@ class Author(BookDataModel):
def get_remote_id(self): def get_remote_id(self):
"""editions and works both use "book" instead of model_name""" """editions and works both use "book" instead of model_name"""
return f"https://{DOMAIN}/author/{self.id}" return f"{BASE_URL}/author/{self.id}"
class Meta: class Meta:
"""sets up indexes and triggers""" """sets up indexes and triggers"""

View file

@ -10,7 +10,7 @@ from django.http import Http404
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils.text import slugify from django.utils.text import slugify
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
from .fields import RemoteIdField from .fields import RemoteIdField
@ -38,7 +38,7 @@ class BookWyrmModel(models.Model):
def get_remote_id(self): def get_remote_id(self):
"""generate the url that resolves to the local object, without a slug""" """generate the url that resolves to the local object, without a slug"""
base_path = f"https://{DOMAIN}" base_path = BASE_URL
if hasattr(self, "user"): if hasattr(self, "user"):
base_path = f"{base_path}{self.user.local_path}" base_path = f"{base_path}{self.user.local_path}"
@ -53,7 +53,7 @@ class BookWyrmModel(models.Model):
@property @property
def local_path(self): def local_path(self):
"""how to link to this object in the local app, with a slug""" """how to link to this object in the local app, with a slug"""
local = self.get_remote_id().replace(f"https://{DOMAIN}", "") local = self.get_remote_id().replace(BASE_URL, "")
name = None name = None
if hasattr(self, "name_field"): if hasattr(self, "name_field"):

View file

@ -21,7 +21,7 @@ from bookwyrm import activitypub
from bookwyrm.isbn.isbn import hyphenator_singleton as hyphenator from bookwyrm.isbn.isbn import hyphenator_singleton as hyphenator
from bookwyrm.preview_images import generate_edition_preview_image_task from bookwyrm.preview_images import generate_edition_preview_image_task
from bookwyrm.settings import ( from bookwyrm.settings import (
DOMAIN, BASE_URL,
DEFAULT_LANGUAGE, DEFAULT_LANGUAGE,
LANGUAGE_ARTICLES, LANGUAGE_ARTICLES,
ENABLE_PREVIEW_IMAGES, ENABLE_PREVIEW_IMAGES,
@ -327,7 +327,7 @@ class Book(BookDataModel):
def get_remote_id(self): def get_remote_id(self):
"""editions and works both use "book" instead of model_name""" """editions and works both use "book" instead of model_name"""
return f"https://{DOMAIN}/book/{self.id}" return f"{BASE_URL}/book/{self.id}"
def guess_sort_title(self): def guess_sort_title(self):
"""Get a best-guess sort title for the current book""" """Get a best-guess sort title for the current book"""

View file

@ -1,7 +1,7 @@
""" do book related things with other users """ """ do book related things with other users """
from django.db import models, IntegrityError, transaction from django.db import models, IntegrityError, transaction
from django.db.models import Q from django.db.models import Q
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
from . import fields from . import fields
from .relationship import UserBlocks from .relationship import UserBlocks
@ -17,7 +17,7 @@ class Group(BookWyrmModel):
def get_remote_id(self): def get_remote_id(self):
"""don't want the user to be in there in this case""" """don't want the user to be in there in this case"""
return f"https://{DOMAIN}/group/{self.id}" return f"{BASE_URL}/group/{self.id}"
@classmethod @classmethod
def followers_filter(cls, queryset, viewer): def followers_filter(cls, queryset, viewer):

View file

@ -7,7 +7,7 @@ from django.db.models import Q
from django.utils import timezone from django.utils import timezone
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
@ -50,7 +50,7 @@ class List(OrderedCollectionMixin, BookWyrmModel):
def get_remote_id(self): def get_remote_id(self):
"""don't want the user to be in there in this case""" """don't want the user to be in there in this case"""
return f"https://{DOMAIN}/list/{self.id}" return f"{BASE_URL}/list/{self.id}"
@property @property
def collection_queryset(self): def collection_queryset(self):

View file

@ -3,7 +3,7 @@ from django.core.exceptions import PermissionDenied
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
@ -46,7 +46,7 @@ class Report(BookWyrmModel):
raise PermissionDenied() raise PermissionDenied()
def get_remote_id(self): def get_remote_id(self):
return f"https://{DOMAIN}/settings/reports/{self.id}" return f"{BASE_URL}/settings/reports/{self.id}"
def comment(self, user, note): def comment(self, user, note):
"""comment on a report""" """comment on a report"""

View file

@ -6,7 +6,7 @@ from django.db import models
from django.utils import timezone from django.utils import timezone
from bookwyrm import activitypub from bookwyrm import activitypub
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
from bookwyrm.tasks import BROADCAST from bookwyrm.tasks import BROADCAST
from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
@ -71,7 +71,7 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel):
@property @property
def local_path(self): def local_path(self):
"""No slugs""" """No slugs"""
return self.get_remote_id().replace(f"https://{DOMAIN}", "") return self.get_remote_id().replace(BASE_URL, "")
def raise_not_deletable(self, viewer): def raise_not_deletable(self, viewer):
"""don't let anyone delete a default shelf""" """don't let anyone delete a default shelf"""

View file

@ -19,7 +19,7 @@ from bookwyrm.connectors import get_data, ConnectorException
from bookwyrm.models.shelf import Shelf from bookwyrm.models.shelf import Shelf
from bookwyrm.models.status import Status from bookwyrm.models.status import Status
from bookwyrm.preview_images import generate_user_preview_image_task from bookwyrm.preview_images import generate_user_preview_image_task
from bookwyrm.settings import BASE_URL, DOMAIN, ENABLE_PREVIEW_IMAGES, USE_HTTPS, LANGUAGES from bookwyrm.settings import BASE_URL, ENABLE_PREVIEW_IMAGES, LANGUAGES
from bookwyrm.signatures import create_key_pair from bookwyrm.signatures import create_key_pair
from bookwyrm.tasks import app, MISC from bookwyrm.tasks import app, MISC
from bookwyrm.utils import regex from bookwyrm.utils import regex
@ -42,12 +42,6 @@ def get_feed_filter_choices():
return [f[0] for f in FeedFilterChoices] return [f[0] for f in FeedFilterChoices]
def site_link():
"""helper for generating links to the site"""
protocol = "https" if USE_HTTPS else "http"
return f"{protocol}://{DOMAIN}"
# pylint: disable=too-many-public-methods # pylint: disable=too-many-public-methods
class User(OrderedCollectionPageMixin, AbstractUser): class User(OrderedCollectionPageMixin, AbstractUser):
"""a user who wants to read books""" """a user who wants to read books"""
@ -368,11 +362,10 @@ class User(OrderedCollectionPageMixin, AbstractUser):
with transaction.atomic(): with transaction.atomic():
# populate fields for local users # populate fields for local users
link = site_link() self.remote_id = f"{BASE_URL}/user/{self.localname}"
self.remote_id = f"{link}/user/{self.localname}"
self.followers_url = f"{self.remote_id}/followers" self.followers_url = f"{self.remote_id}/followers"
self.inbox = f"{self.remote_id}/inbox" self.inbox = f"{self.remote_id}/inbox"
self.shared_inbox = f"{link}/inbox" self.shared_inbox = f"{BASE_URL}/inbox"
self.outbox = f"{self.remote_id}/outbox" self.outbox = f"{self.remote_id}/outbox"
# an id needs to be set before we can proceed with related models # an id needs to be set before we can proceed with related models

View file

@ -6,7 +6,7 @@ import responses
from bookwyrm import models from bookwyrm import models
from bookwyrm.connectors import abstract_connector, ConnectorException from bookwyrm.connectors import abstract_connector, ConnectorException
from bookwyrm.connectors.abstract_connector import Mapping, get_data from bookwyrm.connectors.abstract_connector import Mapping, get_data
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
class AbstractConnector(TestCase): class AbstractConnector(TestCase):
@ -86,7 +86,7 @@ class AbstractConnector(TestCase):
def test_get_or_create_book_existing(self): def test_get_or_create_book_existing(self):
"""find an existing book by remote/origin id""" """find an existing book by remote/origin id"""
self.assertEqual(models.Book.objects.count(), 1) self.assertEqual(models.Book.objects.count(), 1)
self.assertEqual(self.book.remote_id, f"https://{DOMAIN}/book/{self.book.id}") self.assertEqual(self.book.remote_id, f"{BASE_URL}/book/{self.book.id}")
self.assertEqual(self.book.origin_id, "https://example.com/book/1234") self.assertEqual(self.book.origin_id, "https://example.com/book/1234")
# dedupe by origin id # dedupe by origin id
@ -95,9 +95,7 @@ class AbstractConnector(TestCase):
self.assertEqual(result, self.book) self.assertEqual(result, self.book)
# dedupe by remote id # dedupe by remote id
result = self.connector.get_or_create_book( result = self.connector.get_or_create_book(f"{BASE_URL}/book/{self.book.id}")
f"https://{DOMAIN}/book/{self.book.id}"
)
self.assertEqual(models.Book.objects.count(), 1) self.assertEqual(models.Book.objects.count(), 1)
self.assertEqual(result, self.book) self.assertEqual(result, self.book)

View file

@ -29,7 +29,9 @@
"bookwyrmUser": true, "bookwyrmUser": true,
"manuallyApprovesFollowers": false, "manuallyApprovesFollowers": false,
"discoverable": false, "discoverable": false,
"alsoKnownAs": ["https://your.domain.here/user/rat"], "alsoKnownAs": [
"https://your.domain.here:4242/user/rat"
],
"devices": "https://friend.camp/users/tripofmice/collections/devices", "devices": "https://friend.camp/users/tripofmice/collections/devices",
"tag": [], "tag": [],
"icon": { "icon": {
@ -37,4 +39,4 @@
"mediaType": "image/png", "mediaType": "image/png",
"url": "https://example.com/images/avatars/AL-2-crop-50.png" "url": "https://example.com/images/avatars/AL-2-crop-50.png"
} }
} }

View file

@ -214,7 +214,7 @@
"attributedTo": "https://www.example.com//user/rat", "attributedTo": "https://www.example.com//user/rat",
"content": "<p>I like it</p>", "content": "<p>I like it</p>",
"to": [ "to": [
"https://your.domain.here/user/rat/followers" "https://your.domain.here:4242/user/rat/followers"
], ],
"cc": [], "cc": [],
"replies": { "replies": {
@ -395,7 +395,7 @@
"https://local.lists/9999" "https://local.lists/9999"
], ],
"follows": [ "follows": [
"https://your.domain.here/user/rat" "https://your.domain.here:4242/user/rat"
], ],
"blocks": ["https://your.domain.here/user/badger"] "blocks": ["https://your.domain.here:4242/user/badger"]
} }

View file

@ -5,7 +5,7 @@ from django.test import TestCase
from bookwyrm import models from bookwyrm import models
from bookwyrm.models import base_model from bookwyrm.models import base_model
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
# pylint: disable=attribute-defined-outside-init # pylint: disable=attribute-defined-outside-init
@ -44,14 +44,14 @@ class BaseModel(TestCase):
"""these should be generated""" """these should be generated"""
self.test_model.id = 1 # pylint: disable=invalid-name self.test_model.id = 1 # pylint: disable=invalid-name
expected = self.test_model.get_remote_id() expected = self.test_model.get_remote_id()
self.assertEqual(expected, f"https://{DOMAIN}/bookwyrmtestmodel/1") self.assertEqual(expected, f"{BASE_URL}/bookwyrmtestmodel/1")
def test_remote_id_with_user(self): def test_remote_id_with_user(self):
"""format of remote id when there's a user object""" """format of remote id when there's a user object"""
self.test_model.user = self.local_user self.test_model.user = self.local_user
self.test_model.id = 1 self.test_model.id = 1
expected = self.test_model.get_remote_id() expected = self.test_model.get_remote_id()
self.assertEqual(expected, f"https://{DOMAIN}/user/mouse/bookwyrmtestmodel/1") self.assertEqual(expected, f"{BASE_URL}/user/mouse/bookwyrmtestmodel/1")
def test_set_remote_id(self): def test_set_remote_id(self):
"""this function sets remote ids after creation""" """this function sets remote ids after creation"""
@ -60,7 +60,7 @@ class BaseModel(TestCase):
instance = models.Work.objects.create(title="work title") instance = models.Work.objects.create(title="work title")
instance.remote_id = None instance.remote_id = None
base_model.set_remote_id(None, instance, True) base_model.set_remote_id(None, instance, True)
self.assertEqual(instance.remote_id, f"https://{DOMAIN}/book/{instance.id}") self.assertEqual(instance.remote_id, f"{BASE_URL}/book/{instance.id}")
# shouldn't set remote_id if it's not created # shouldn't set remote_id if it's not created
instance.remote_id = None instance.remote_id = None

View file

@ -31,7 +31,7 @@ class Book(TestCase):
def test_remote_id(self): def test_remote_id(self):
"""fanciness with remote/origin ids""" """fanciness with remote/origin ids"""
remote_id = f"https://{settings.DOMAIN}/book/{self.work.id}" remote_id = f"{settings.BASE_URL}/book/{self.work.id}"
self.assertEqual(self.work.get_remote_id(), remote_id) self.assertEqual(self.work.get_remote_id(), remote_id)
self.assertEqual(self.work.remote_id, remote_id) self.assertEqual(self.work.remote_id, remote_id)

View file

@ -28,7 +28,7 @@ class List(TestCase):
def test_remote_id(self, *_): def test_remote_id(self, *_):
"""shelves use custom remote ids""" """shelves use custom remote ids"""
book_list = models.List.objects.create(name="Test List", user=self.local_user) book_list = models.List.objects.create(name="Test List", user=self.local_user)
expected_id = f"https://{settings.DOMAIN}/list/{book_list.id}" expected_id = f"{settings.BASE_URL}/list/{book_list.id}"
self.assertEqual(book_list.get_remote_id(), expected_id) self.assertEqual(book_list.get_remote_id(), expected_id)
def test_to_activity(self, *_): def test_to_activity(self, *_):

View file

@ -35,7 +35,7 @@ class Shelf(TestCase):
shelf = models.Shelf.objects.create( shelf = models.Shelf.objects.create(
name="Test Shelf", identifier="test-shelf", user=self.local_user name="Test Shelf", identifier="test-shelf", user=self.local_user
) )
expected_id = f"https://{settings.DOMAIN}/user/mouse/books/test-shelf" expected_id = f"{settings.BASE_URL}/user/mouse/books/test-shelf"
self.assertEqual(shelf.get_remote_id(), expected_id) self.assertEqual(shelf.get_remote_id(), expected_id)
def test_to_activity(self, *_): def test_to_activity(self, *_):

View file

@ -60,7 +60,7 @@ class Status(TestCase):
def test_status_generated_fields(self, *_): def test_status_generated_fields(self, *_):
"""setting remote id""" """setting remote id"""
status = models.Status.objects.create(content="bleh", user=self.local_user) status = models.Status.objects.create(content="bleh", user=self.local_user)
expected_id = f"https://{settings.DOMAIN}/user/mouse/status/{status.id}" expected_id = f"{settings.BASE_URL}/user/mouse/status/{status.id}"
self.assertEqual(status.remote_id, expected_id) self.assertEqual(status.remote_id, expected_id)
self.assertEqual(status.privacy, "public") self.assertEqual(status.privacy, "public")
@ -151,7 +151,7 @@ class Status(TestCase):
self.assertEqual(activity["tag"][0]["type"], "Hashtag") self.assertEqual(activity["tag"][0]["type"], "Hashtag")
self.assertEqual(activity["tag"][0]["name"], "#content") self.assertEqual(activity["tag"][0]["name"], "#content")
self.assertEqual( self.assertEqual(
activity["tag"][0]["href"], f"https://{settings.DOMAIN}/hashtag/{tag.id}" activity["tag"][0]["href"], f"{settings.BASE_URL}/hashtag/{tag.id}"
) )
def test_status_with_mention_to_activity(self, *_): def test_status_with_mention_to_activity(self, *_):

View file

@ -9,15 +9,12 @@ import responses
from bookwyrm import models from bookwyrm import models
from bookwyrm.management.commands import initdb from bookwyrm.management.commands import initdb
from bookwyrm.settings import USE_HTTPS, DOMAIN from bookwyrm.settings import DOMAIN, BASE_URL
# pylint: disable=missing-class-docstring # pylint: disable=missing-class-docstring
# pylint: disable=missing-function-docstring # pylint: disable=missing-function-docstring
class User(TestCase): class User(TestCase):
protocol = "https://" if USE_HTTPS else "http://"
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
with ( with (
@ -49,11 +46,11 @@ class User(TestCase):
def test_computed_fields(self): def test_computed_fields(self):
"""username instead of id here""" """username instead of id here"""
expected_id = f"{self.protocol}{DOMAIN}/user/mouse" expected_id = f"{BASE_URL}/user/mouse"
self.assertEqual(self.user.remote_id, expected_id) self.assertEqual(self.user.remote_id, expected_id)
self.assertEqual(self.user.username, f"mouse@{DOMAIN}") self.assertEqual(self.user.username, f"mouse@{DOMAIN}")
self.assertEqual(self.user.localname, "mouse") self.assertEqual(self.user.localname, "mouse")
self.assertEqual(self.user.shared_inbox, f"{self.protocol}{DOMAIN}/inbox") self.assertEqual(self.user.shared_inbox, f"{BASE_URL}/inbox")
self.assertEqual(self.user.inbox, f"{expected_id}/inbox") self.assertEqual(self.user.inbox, f"{expected_id}/inbox")
self.assertEqual(self.user.outbox, f"{expected_id}/outbox") self.assertEqual(self.user.outbox, f"{expected_id}/outbox")
self.assertEqual(self.user.followers_url, f"{expected_id}/followers") self.assertEqual(self.user.followers_url, f"{expected_id}/followers")
@ -130,7 +127,7 @@ class User(TestCase):
patch("bookwyrm.lists_stream.populate_lists_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"),
): ):
user = models.User.objects.create_user( user = models.User.objects.create_user(
f"test2{DOMAIN}", "test2",
"test2@bookwyrm.test", "test2@bookwyrm.test",
localname="test2", localname="test2",
**user_attrs, **user_attrs,
@ -145,7 +142,7 @@ class User(TestCase):
patch("bookwyrm.lists_stream.populate_lists_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"),
): ):
user = models.User.objects.create_user( user = models.User.objects.create_user(
f"test1{DOMAIN}", "test1",
"test1@bookwyrm.test", "test1@bookwyrm.test",
localname="test1", localname="test1",
**user_attrs, **user_attrs,

View file

@ -27,7 +27,6 @@ class ViewsHelpers(TestCase):
patch("bookwyrm.lists_stream.populate_lists_task.delay"), patch("bookwyrm.lists_stream.populate_lists_task.delay"),
patch("bookwyrm.suggested_users.rerank_user_task.delay"), patch("bookwyrm.suggested_users.rerank_user_task.delay"),
): ):
cls.local_user = models.User.objects.create_user( cls.local_user = models.User.objects.create_user(
"rat", "rat",
"rat@rat.com", "rat@rat.com",
@ -35,7 +34,6 @@ class ViewsHelpers(TestCase):
local=True, local=True,
discoverable=True, discoverable=True,
localname="rat", localname="rat",
remote_id="https://your.domain.here/user/rat",
) )
with ( with (

View file

@ -8,7 +8,7 @@ from django.test.client import RequestFactory
from bookwyrm import models, views from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html from bookwyrm.tests.validate_html import validate_html
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
class IsbnViews(TestCase): class IsbnViews(TestCase):
@ -55,7 +55,7 @@ class IsbnViews(TestCase):
data = json.loads(response.content) data = json.loads(response.content)
self.assertEqual(len(data), 1) self.assertEqual(len(data), 1)
self.assertEqual(data[0]["title"], "Test Book") self.assertEqual(data[0]["title"], "Test Book")
self.assertEqual(data[0]["key"], f"https://{DOMAIN}/book/{self.book.id}") self.assertEqual(data[0]["key"], f"{BASE_URL}/book/{self.book.id}")
def test_isbn_html_response(self): def test_isbn_html_response(self):
"""searches local data only and returns book data in json format""" """searches local data only and returns book data in json format"""

View file

@ -10,7 +10,7 @@ from django.test.client import RequestFactory
from bookwyrm import models, views from bookwyrm import models, views
from bookwyrm.book_search import SearchResult from bookwyrm.book_search import SearchResult
from bookwyrm.settings import DOMAIN from bookwyrm.settings import BASE_URL
from bookwyrm.tests.validate_html import validate_html from bookwyrm.tests.validate_html import validate_html
@ -57,7 +57,7 @@ class Views(TestCase):
data = json.loads(response.content) data = json.loads(response.content)
self.assertEqual(len(data), 1) self.assertEqual(len(data), 1)
self.assertEqual(data[0]["title"], "Test Book") self.assertEqual(data[0]["title"], "Test Book")
self.assertEqual(data[0]["key"], f"https://{DOMAIN}/book/{self.book.id}") self.assertEqual(data[0]["key"], f"{BASE_URL}/book/{self.book.id}")
def test_search_no_query(self): def test_search_no_query(self):
"""just the search page""" """just the search page"""