Updating string format synatx part 2
This commit is contained in:
parent
be86fbcf4d
commit
acfb1bb376
|
@ -24,5 +24,5 @@ jobs:
|
||||||
pip install pylint
|
pip install pylint
|
||||||
- name: Analysing the code with pylint
|
- name: Analysing the code with pylint
|
||||||
run: |
|
run: |
|
||||||
pylint bookwyrm/ --ignore=migrations,tests --disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801,C0209
|
pylint bookwyrm/ --ignore=migrations,tests --disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ class AbstractMinimalConnector(ABC):
|
||||||
params["min_confidence"] = min_confidence
|
params["min_confidence"] = min_confidence
|
||||||
|
|
||||||
data = self.get_search_data(
|
data = self.get_search_data(
|
||||||
"%s%s" % (self.search_url, query),
|
f"{self.search_url}{query}",
|
||||||
params=params,
|
params=params,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
)
|
)
|
||||||
|
@ -57,7 +57,7 @@ class AbstractMinimalConnector(ABC):
|
||||||
"""isbn search"""
|
"""isbn search"""
|
||||||
params = {}
|
params = {}
|
||||||
data = self.get_search_data(
|
data = self.get_search_data(
|
||||||
"%s%s" % (self.isbn_search_url, query),
|
f"{self.isbn_search_url}{query}",
|
||||||
params=params,
|
params=params,
|
||||||
)
|
)
|
||||||
results = []
|
results = []
|
||||||
|
@ -131,7 +131,7 @@ class AbstractConnector(AbstractMinimalConnector):
|
||||||
work_data = data
|
work_data = data
|
||||||
|
|
||||||
if not work_data or not edition_data:
|
if not work_data or not edition_data:
|
||||||
raise ConnectorException("Unable to load book data: %s" % remote_id)
|
raise ConnectorException(f"Unable to load book data: {remote_id}")
|
||||||
|
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
# create activitypub object
|
# create activitypub object
|
||||||
|
@ -223,7 +223,7 @@ def get_data(url, params=None, timeout=10):
|
||||||
# check if the url is blocked
|
# check if the url is blocked
|
||||||
if models.FederatedServer.is_blocked(url):
|
if models.FederatedServer.is_blocked(url):
|
||||||
raise ConnectorException(
|
raise ConnectorException(
|
||||||
"Attempting to load data from blocked url: {:s}".format(url)
|
f"Attempting to load data from blocked url: {url}"
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -283,6 +283,7 @@ class SearchResult:
|
||||||
confidence: int = 1
|
confidence: int = 1
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
# pylint: disable=consider-using-f-string
|
||||||
return "<SearchResult key={!r} title={!r} author={!r}>".format(
|
return "<SearchResult key={!r} title={!r} author={!r}>".format(
|
||||||
self.key, self.title, self.author
|
self.key, self.title, self.author
|
||||||
)
|
)
|
||||||
|
|
|
@ -109,10 +109,10 @@ def get_or_create_connector(remote_id):
|
||||||
connector_info = models.Connector.objects.create(
|
connector_info = models.Connector.objects.create(
|
||||||
identifier=identifier,
|
identifier=identifier,
|
||||||
connector_file="bookwyrm_connector",
|
connector_file="bookwyrm_connector",
|
||||||
base_url="https://%s" % identifier,
|
base_url=f"https://{identifier}",
|
||||||
books_url="https://%s/book" % identifier,
|
books_url=f"https://{identifier}/book",
|
||||||
covers_url="https://%s/images/covers" % identifier,
|
covers_url=f"https://{identifier}/images/covers",
|
||||||
search_url="https://%s/search?q=" % identifier,
|
search_url=f"https://{identifier}/search?q=",
|
||||||
priority=2,
|
priority=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ def load_more_data(connector_id, book_id):
|
||||||
def load_connector(connector_info):
|
def load_connector(connector_info):
|
||||||
"""instantiate the connector class"""
|
"""instantiate the connector class"""
|
||||||
connector = importlib.import_module(
|
connector = importlib.import_module(
|
||||||
"bookwyrm.connectors.%s" % connector_info.connector_file
|
f"bookwyrm.connectors.{connector_info.connector_file}"
|
||||||
)
|
)
|
||||||
return connector.Connector(connector_info.identifier)
|
return connector.Connector(connector_info.identifier)
|
||||||
|
|
||||||
|
@ -141,4 +141,4 @@ def load_connector(connector_info):
|
||||||
def create_connector(sender, instance, created, *args, **kwargs):
|
def create_connector(sender, instance, created, *args, **kwargs):
|
||||||
"""create a connector to an external bookwyrm server"""
|
"""create a connector to an external bookwyrm server"""
|
||||||
if instance.application_type == "bookwyrm":
|
if instance.application_type == "bookwyrm":
|
||||||
get_or_create_connector("https://{:s}".format(instance.server_name))
|
get_or_create_connector(f"https://{instance.server_name}")
|
||||||
|
|
|
@ -59,7 +59,7 @@ class Connector(AbstractConnector):
|
||||||
|
|
||||||
def get_remote_id(self, value):
|
def get_remote_id(self, value):
|
||||||
"""convert an id/uri into a url"""
|
"""convert an id/uri into a url"""
|
||||||
return "{:s}?action=by-uris&uris={:s}".format(self.books_url, value)
|
return f"{self.books_url}?action=by-uris&uris={value}"
|
||||||
|
|
||||||
def get_book_data(self, remote_id):
|
def get_book_data(self, remote_id):
|
||||||
data = get_data(remote_id)
|
data = get_data(remote_id)
|
||||||
|
@ -88,7 +88,7 @@ class Connector(AbstractConnector):
|
||||||
def format_search_result(self, search_result):
|
def format_search_result(self, search_result):
|
||||||
images = search_result.get("image")
|
images = search_result.get("image")
|
||||||
cover = (
|
cover = (
|
||||||
"{:s}/img/entities/{:s}".format(self.covers_url, images[0])
|
f"{self.covers_url}/img/entities/{images[0]}"
|
||||||
if images
|
if images
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
@ -99,9 +99,7 @@ class Connector(AbstractConnector):
|
||||||
title=search_result.get("label"),
|
title=search_result.get("label"),
|
||||||
key=self.get_remote_id(search_result.get("uri")),
|
key=self.get_remote_id(search_result.get("uri")),
|
||||||
author=search_result.get("description"),
|
author=search_result.get("description"),
|
||||||
view_link="{:s}/entity/{:s}".format(
|
view_link=f"{self.base_url}/entity/{search_result.get('uri')}",
|
||||||
self.base_url, search_result.get("uri")
|
|
||||||
),
|
|
||||||
cover=cover,
|
cover=cover,
|
||||||
confidence=confidence,
|
confidence=confidence,
|
||||||
connector=self,
|
connector=self,
|
||||||
|
@ -123,9 +121,7 @@ class Connector(AbstractConnector):
|
||||||
title=title[0],
|
title=title[0],
|
||||||
key=self.get_remote_id(search_result.get("uri")),
|
key=self.get_remote_id(search_result.get("uri")),
|
||||||
author=search_result.get("description"),
|
author=search_result.get("description"),
|
||||||
view_link="{:s}/entity/{:s}".format(
|
view_link=f"{self.base_url}/entity/{search_result.get('uri')}",
|
||||||
self.base_url, search_result.get("uri")
|
|
||||||
),
|
|
||||||
cover=self.get_cover_url(search_result.get("image")),
|
cover=self.get_cover_url(search_result.get("image")),
|
||||||
connector=self,
|
connector=self,
|
||||||
)
|
)
|
||||||
|
@ -136,9 +132,7 @@ class Connector(AbstractConnector):
|
||||||
def load_edition_data(self, work_uri):
|
def load_edition_data(self, work_uri):
|
||||||
"""get a list of editions for a work"""
|
"""get a list of editions for a work"""
|
||||||
url = (
|
url = (
|
||||||
"{:s}?action=reverse-claims&property=wdt:P629&value={:s}&sort=true".format(
|
f"{self.books_url}?action=reverse-claims&property=wdt:P629&value={work_uri}&sort=true"
|
||||||
self.books_url, work_uri
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return get_data(url)
|
return get_data(url)
|
||||||
|
|
||||||
|
@ -195,7 +189,7 @@ class Connector(AbstractConnector):
|
||||||
# cover may or may not be an absolute url already
|
# cover may or may not be an absolute url already
|
||||||
if re.match(r"^http", cover_id):
|
if re.match(r"^http", cover_id):
|
||||||
return cover_id
|
return cover_id
|
||||||
return "%s%s" % (self.covers_url, cover_id)
|
return f"{self.covers_url}{cover_id}"
|
||||||
|
|
||||||
def resolve_keys(self, keys):
|
def resolve_keys(self, keys):
|
||||||
"""cool, it's "wd:Q3156592" now what the heck does that mean"""
|
"""cool, it's "wd:Q3156592" now what the heck does that mean"""
|
||||||
|
@ -213,9 +207,7 @@ class Connector(AbstractConnector):
|
||||||
link = links.get("enwiki")
|
link = links.get("enwiki")
|
||||||
if not link:
|
if not link:
|
||||||
return ""
|
return ""
|
||||||
url = "{:s}/api/data?action=wp-extract&lang=en&title={:s}".format(
|
url = f"{self.base_url}/api/data?action=wp-extract&lang=en&title={link}"
|
||||||
self.base_url, link
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
data = get_data(url)
|
data = get_data(url)
|
||||||
except ConnectorException:
|
except ConnectorException:
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Connector(AbstractConnector):
|
||||||
key = data["key"]
|
key = data["key"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ConnectorException("Invalid book data")
|
raise ConnectorException("Invalid book data")
|
||||||
return "%s%s" % (self.books_url, key)
|
return f"{self.books_url}{key}"
|
||||||
|
|
||||||
def is_work_data(self, data):
|
def is_work_data(self, data):
|
||||||
return bool(re.match(r"^[\/\w]+OL\d+W$", data["key"]))
|
return bool(re.match(r"^[\/\w]+OL\d+W$", data["key"]))
|
||||||
|
@ -81,7 +81,7 @@ class Connector(AbstractConnector):
|
||||||
key = data["key"]
|
key = data["key"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ConnectorException("Invalid book data")
|
raise ConnectorException("Invalid book data")
|
||||||
url = "%s%s/editions" % (self.books_url, key)
|
url = f"{self.books_url}{key}/editions"
|
||||||
data = self.get_book_data(url)
|
data = self.get_book_data(url)
|
||||||
edition = pick_default_edition(data["entries"])
|
edition = pick_default_edition(data["entries"])
|
||||||
if not edition:
|
if not edition:
|
||||||
|
@ -93,7 +93,7 @@ class Connector(AbstractConnector):
|
||||||
key = data["works"][0]["key"]
|
key = data["works"][0]["key"]
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
raise ConnectorException("No work found for edition")
|
raise ConnectorException("No work found for edition")
|
||||||
url = "%s%s" % (self.books_url, key)
|
url = f"{self.books_url}{key}"
|
||||||
return self.get_book_data(url)
|
return self.get_book_data(url)
|
||||||
|
|
||||||
def get_authors_from_data(self, data):
|
def get_authors_from_data(self, data):
|
||||||
|
@ -102,7 +102,7 @@ class Connector(AbstractConnector):
|
||||||
author_blob = author_blob.get("author", author_blob)
|
author_blob = author_blob.get("author", author_blob)
|
||||||
# this id is "/authors/OL1234567A"
|
# this id is "/authors/OL1234567A"
|
||||||
author_id = author_blob["key"]
|
author_id = author_blob["key"]
|
||||||
url = "%s%s" % (self.base_url, author_id)
|
url = f"{self.base_url}{author_id}"
|
||||||
author = self.get_or_create_author(url)
|
author = self.get_or_create_author(url)
|
||||||
if not author:
|
if not author:
|
||||||
continue
|
continue
|
||||||
|
@ -113,8 +113,8 @@ class Connector(AbstractConnector):
|
||||||
if not cover_blob:
|
if not cover_blob:
|
||||||
return None
|
return None
|
||||||
cover_id = cover_blob[0]
|
cover_id = cover_blob[0]
|
||||||
image_name = "%s-%s.jpg" % (cover_id, size)
|
image_name = f"{cover_id}-{size}.jpg"
|
||||||
return "%s/b/id/%s" % (self.covers_url, image_name)
|
return f"{self.covers_url}/b/id/{image_name}"
|
||||||
|
|
||||||
def parse_search_data(self, data):
|
def parse_search_data(self, data):
|
||||||
return data.get("docs")
|
return data.get("docs")
|
||||||
|
@ -152,7 +152,7 @@ class Connector(AbstractConnector):
|
||||||
|
|
||||||
def load_edition_data(self, olkey):
|
def load_edition_data(self, olkey):
|
||||||
"""query openlibrary for editions of a work"""
|
"""query openlibrary for editions of a work"""
|
||||||
url = "%s/works/%s/editions" % (self.books_url, olkey)
|
url = f"{self.books_url}/works/{olkey}/editions"
|
||||||
return self.get_book_data(url)
|
return self.get_book_data(url)
|
||||||
|
|
||||||
def expand_book_data(self, book):
|
def expand_book_data(self, book):
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Connector(AbstractConnector):
|
||||||
def format_search_result(self, search_result):
|
def format_search_result(self, search_result):
|
||||||
cover = None
|
cover = None
|
||||||
if search_result.cover:
|
if search_result.cover:
|
||||||
cover = "%s%s" % (self.covers_url, search_result.cover)
|
cover = f"{self.covers_url}{search_result.cover}"
|
||||||
|
|
||||||
return SearchResult(
|
return SearchResult(
|
||||||
title=search_result.title,
|
title=search_result.title,
|
||||||
|
|
|
@ -127,6 +127,7 @@ def handle_imported_book(source, user, item, include_reviews, privacy):
|
||||||
# but "now" is a bad guess
|
# but "now" is a bad guess
|
||||||
published_date_guess = item.date_read or item.date_added
|
published_date_guess = item.date_read or item.date_added
|
||||||
if item.review:
|
if item.review:
|
||||||
|
# pylint: disable=consider-using-f-string
|
||||||
review_title = (
|
review_title = (
|
||||||
"Review of {!r} on {!r}".format(
|
"Review of {!r} on {!r}".format(
|
||||||
item.book.title,
|
item.book.title,
|
||||||
|
|
|
@ -266,7 +266,7 @@ class ObjectMixin(ActivitypubMixin):
|
||||||
signed_message = signer.sign(SHA256.new(content.encode("utf8")))
|
signed_message = signer.sign(SHA256.new(content.encode("utf8")))
|
||||||
|
|
||||||
signature = activitypub.Signature(
|
signature = activitypub.Signature(
|
||||||
creator="%s#main-key" % user.remote_id,
|
creator=f"{user.remote_id}#main-key",
|
||||||
created=activity_object.published,
|
created=activity_object.published,
|
||||||
signatureValue=b64encode(signed_message).decode("utf8"),
|
signatureValue=b64encode(signed_message).decode("utf8"),
|
||||||
)
|
)
|
||||||
|
@ -285,16 +285,16 @@ class ObjectMixin(ActivitypubMixin):
|
||||||
return activitypub.Delete(
|
return activitypub.Delete(
|
||||||
id=self.remote_id + "/activity",
|
id=self.remote_id + "/activity",
|
||||||
actor=user.remote_id,
|
actor=user.remote_id,
|
||||||
to=["%s/followers" % user.remote_id],
|
to=[f"{user.remote_id}/followers"],
|
||||||
cc=["https://www.w3.org/ns/activitystreams#Public"],
|
cc=["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
object=self,
|
object=self,
|
||||||
).serialize()
|
).serialize()
|
||||||
|
|
||||||
def to_update_activity(self, user):
|
def to_update_activity(self, user):
|
||||||
"""wrapper for Updates to an activity"""
|
"""wrapper for Updates to an activity"""
|
||||||
activity_id = "%s#update/%s" % (self.remote_id, uuid4())
|
uuid = uuid4()
|
||||||
return activitypub.Update(
|
return activitypub.Update(
|
||||||
id=activity_id,
|
id=f"{self.remote_id}#update/{uuid}",
|
||||||
actor=user.remote_id,
|
actor=user.remote_id,
|
||||||
to=["https://www.w3.org/ns/activitystreams#Public"],
|
to=["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
object=self,
|
object=self,
|
||||||
|
@ -337,8 +337,8 @@ class OrderedCollectionPageMixin(ObjectMixin):
|
||||||
paginated = Paginator(queryset, PAGE_LENGTH)
|
paginated = Paginator(queryset, PAGE_LENGTH)
|
||||||
# add computed fields specific to orderd collections
|
# add computed fields specific to orderd collections
|
||||||
activity["totalItems"] = paginated.count
|
activity["totalItems"] = paginated.count
|
||||||
activity["first"] = "%s?page=1" % remote_id
|
activity["first"] = f"{remote_id}?page=1"
|
||||||
activity["last"] = "%s?page=%d" % (remote_id, paginated.num_pages)
|
activity["last"] = f"{remote_id}?page={paginated.num_pages}"
|
||||||
|
|
||||||
return serializer(**activity)
|
return serializer(**activity)
|
||||||
|
|
||||||
|
@ -420,7 +420,7 @@ class CollectionItemMixin(ActivitypubMixin):
|
||||||
"""AP for shelving a book"""
|
"""AP for shelving a book"""
|
||||||
collection_field = getattr(self, self.collection_field)
|
collection_field = getattr(self, self.collection_field)
|
||||||
return activitypub.Add(
|
return activitypub.Add(
|
||||||
id="{:s}#add".format(collection_field.remote_id),
|
id=f"{collection_field.remote_id}#add",
|
||||||
actor=user.remote_id,
|
actor=user.remote_id,
|
||||||
object=self.to_activity_dataclass(),
|
object=self.to_activity_dataclass(),
|
||||||
target=collection_field.remote_id,
|
target=collection_field.remote_id,
|
||||||
|
@ -430,7 +430,7 @@ class CollectionItemMixin(ActivitypubMixin):
|
||||||
"""AP for un-shelving a book"""
|
"""AP for un-shelving a book"""
|
||||||
collection_field = getattr(self, self.collection_field)
|
collection_field = getattr(self, self.collection_field)
|
||||||
return activitypub.Remove(
|
return activitypub.Remove(
|
||||||
id="{:s}#remove".format(collection_field.remote_id),
|
id=f"{collection_field.remote_id}#remove",
|
||||||
actor=user.remote_id,
|
actor=user.remote_id,
|
||||||
object=self.to_activity_dataclass(),
|
object=self.to_activity_dataclass(),
|
||||||
target=collection_field.remote_id,
|
target=collection_field.remote_id,
|
||||||
|
@ -458,7 +458,7 @@ class ActivityMixin(ActivitypubMixin):
|
||||||
"""undo an action"""
|
"""undo an action"""
|
||||||
user = self.user if hasattr(self, "user") else self.user_subject
|
user = self.user if hasattr(self, "user") else self.user_subject
|
||||||
return activitypub.Undo(
|
return activitypub.Undo(
|
||||||
id="%s#undo" % self.remote_id,
|
id=f"{self.remote_id}#undo",
|
||||||
actor=user.remote_id,
|
actor=user.remote_id,
|
||||||
object=self,
|
object=self,
|
||||||
).serialize()
|
).serialize()
|
||||||
|
@ -555,11 +555,11 @@ def to_ordered_collection_page(
|
||||||
|
|
||||||
prev_page = next_page = None
|
prev_page = next_page = None
|
||||||
if activity_page.has_next():
|
if activity_page.has_next():
|
||||||
next_page = "%s?page=%d" % (remote_id, activity_page.next_page_number())
|
next_page = f"{remote_id}?page={activity_page.next_page_number()}"
|
||||||
if activity_page.has_previous():
|
if activity_page.has_previous():
|
||||||
prev_page = "%s?page=%d" % (remote_id, activity_page.previous_page_number())
|
prev_page = f"{remote_id}?page=%d{activity_page.previous_page_number()}"
|
||||||
return activitypub.OrderedCollectionPage(
|
return activitypub.OrderedCollectionPage(
|
||||||
id="%s?page=%s" % (remote_id, page),
|
id=f"{remote_id}?page={page}",
|
||||||
partOf=remote_id,
|
partOf=remote_id,
|
||||||
orderedItems=items,
|
orderedItems=items,
|
||||||
next=next_page,
|
next=next_page,
|
||||||
|
|
|
@ -35,7 +35,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 "https://%s/author/%s" % (DOMAIN, self.id)
|
return f"https://{DOMAIN}/author/{self.id}"
|
||||||
|
|
||||||
activity_serializer = activitypub.Author
|
activity_serializer = activitypub.Author
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,11 @@ class BookWyrmModel(models.Model):
|
||||||
|
|
||||||
def get_remote_id(self):
|
def get_remote_id(self):
|
||||||
"""generate a url that resolves to the local object"""
|
"""generate a url that resolves to the local object"""
|
||||||
base_path = "https://%s" % DOMAIN
|
base_path = f"https://{DOMAIN}"
|
||||||
if hasattr(self, "user"):
|
if hasattr(self, "user"):
|
||||||
base_path = "%s%s" % (base_path, self.user.local_path)
|
base_path = f"{base_path}{self.user.local_path}"
|
||||||
model_name = type(self).__name__.lower()
|
model_name = type(self).__name__.lower()
|
||||||
return "%s/%s/%d" % (base_path, model_name, self.id)
|
return f"{base_path}/{model_name}/{self.id}"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""this is just here to provide default fields for other models"""
|
"""this is just here to provide default fields for other models"""
|
||||||
|
@ -46,7 +46,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"""
|
"""how to link to this object in the local app"""
|
||||||
return self.get_remote_id().replace("https://%s" % DOMAIN, "")
|
return self.get_remote_id().replace(f"https://{DOMAIN}", "")
|
||||||
|
|
||||||
def visible_to_user(self, viewer):
|
def visible_to_user(self, viewer):
|
||||||
"""is a user authorized to view an object?"""
|
"""is a user authorized to view an object?"""
|
||||||
|
|
|
@ -164,9 +164,9 @@ class Book(BookDataModel):
|
||||||
@property
|
@property
|
||||||
def alt_text(self):
|
def alt_text(self):
|
||||||
"""image alt test"""
|
"""image alt test"""
|
||||||
text = "%s" % self.title
|
text = self.title
|
||||||
if self.edition_info:
|
if self.edition_info:
|
||||||
text += " (%s)" % self.edition_info
|
text += f" ({self.edition_info})"
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
|
@ -177,9 +177,10 @@ 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 "https://%s/book/%d" % (DOMAIN, self.id)
|
return f"https://{DOMAIN}/book/{self.id}"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
# pylint: disable=consider-using-f-string
|
||||||
return "<{} key={!r} title={!r}>".format(
|
return "<{} key={!r} title={!r}>".format(
|
||||||
self.__class__,
|
self.__class__,
|
||||||
self.openlibrary_key,
|
self.openlibrary_key,
|
||||||
|
@ -216,7 +217,7 @@ class Work(OrderedCollectionPageMixin, Book):
|
||||||
"""an ordered collection of editions"""
|
"""an ordered collection of editions"""
|
||||||
return self.to_ordered_collection(
|
return self.to_ordered_collection(
|
||||||
self.editions.order_by("-edition_rank").all(),
|
self.editions.order_by("-edition_rank").all(),
|
||||||
remote_id="%s/editions" % self.remote_id,
|
remote_id=f"{self.remote_id}/editions",
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,4 @@ class Connector(BookWyrmModel):
|
||||||
isbn_search_url = models.CharField(max_length=255, null=True, blank=True)
|
isbn_search_url = models.CharField(max_length=255, null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{} ({})".format(
|
return f"{self.identifier} ({self.id})"
|
||||||
self.identifier,
|
|
||||||
self.id,
|
|
||||||
)
|
|
||||||
|
|
|
@ -308,7 +308,7 @@ class ManyToManyField(ActivitypubFieldMixin, models.ManyToManyField):
|
||||||
|
|
||||||
def field_to_activity(self, value):
|
def field_to_activity(self, value):
|
||||||
if self.link_only:
|
if self.link_only:
|
||||||
return "%s/%s" % (value.instance.remote_id, self.name)
|
return f"{value.instance.remote_id}/{self.name}"
|
||||||
return [i.remote_id for i in value.all()]
|
return [i.remote_id for i in value.all()]
|
||||||
|
|
||||||
def field_from_activity(self, value):
|
def field_from_activity(self, value):
|
||||||
|
@ -388,7 +388,7 @@ def image_serializer(value, alt):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
if not url[:4] == "http":
|
if not url[:4] == "http":
|
||||||
url = "https://{:s}{:s}".format(DOMAIN, url)
|
url = f"https://{DOMAIN}{url}"
|
||||||
return activitypub.Document(url=url, name=alt)
|
return activitypub.Document(url=url, name=alt)
|
||||||
|
|
||||||
|
|
||||||
|
@ -448,7 +448,7 @@ class ImageField(ActivitypubFieldMixin, models.ImageField):
|
||||||
|
|
||||||
image_content = ContentFile(response.content)
|
image_content = ContentFile(response.content)
|
||||||
extension = imghdr.what(None, image_content.read()) or ""
|
extension = imghdr.what(None, image_content.read()) or ""
|
||||||
image_name = "{:s}.{:s}".format(str(uuid4()), extension)
|
image_name = f"{uuid4()}.{extension}"
|
||||||
return [image_name, image_content]
|
return [image_name, image_content]
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
|
|
|
@ -198,7 +198,9 @@ class ImportItem(models.Model):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
# pylint: disable=consider-using-f-string
|
||||||
return "<{!r}Item {!r}>".format(self.data["import_source"], self.data["Title"])
|
return "<{!r}Item {!r}>".format(self.data["import_source"], self.data["Title"])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
# pylint: disable=consider-using-f-string
|
||||||
return "{} by {}".format(self.data["Title"], self.data["Author"])
|
return "{} by {}".format(self.data["Title"], self.data["Author"])
|
||||||
|
|
|
@ -42,7 +42,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 "https://%s/list/%d" % (DOMAIN, self.id)
|
return f"https://{DOMAIN}/list/{self.id}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def collection_queryset(self):
|
def collection_queryset(self):
|
||||||
|
|
|
@ -53,7 +53,7 @@ class UserRelationship(BookWyrmModel):
|
||||||
def get_remote_id(self):
|
def get_remote_id(self):
|
||||||
"""use shelf identifier in remote_id"""
|
"""use shelf identifier in remote_id"""
|
||||||
base_path = self.user_subject.remote_id
|
base_path = self.user_subject.remote_id
|
||||||
return "%s#follows/%d" % (base_path, self.id)
|
return f"{base_path}#follows/{self.id}"
|
||||||
|
|
||||||
|
|
||||||
class UserFollows(ActivityMixin, UserRelationship):
|
class UserFollows(ActivityMixin, UserRelationship):
|
||||||
|
@ -144,7 +144,8 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
|
||||||
"""get id for sending an accept or reject of a local user"""
|
"""get id for sending an accept or reject of a local user"""
|
||||||
|
|
||||||
base_path = self.user_object.remote_id
|
base_path = self.user_object.remote_id
|
||||||
return "%s#%s/%d" % (base_path, status, self.id or 0)
|
status_id = self.id or 0
|
||||||
|
return f"{base_path}#{status}/{status_id}"
|
||||||
|
|
||||||
def accept(self, broadcast_only=False):
|
def accept(self, broadcast_only=False):
|
||||||
"""turn this request into the real deal"""
|
"""turn this request into the real deal"""
|
||||||
|
|
|
@ -44,7 +44,7 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel):
|
||||||
def get_identifier(self):
|
def get_identifier(self):
|
||||||
"""custom-shelf-123 for the url"""
|
"""custom-shelf-123 for the url"""
|
||||||
slug = re.sub(r"[^\w]", "", self.name).lower()
|
slug = re.sub(r"[^\w]", "", self.name).lower()
|
||||||
return "{:s}-{:d}".format(slug, self.id)
|
return f"{slug}-{self.id}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def collection_queryset(self):
|
def collection_queryset(self):
|
||||||
|
@ -55,7 +55,7 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel):
|
||||||
"""shelf identifier instead of id"""
|
"""shelf identifier instead of id"""
|
||||||
base_path = self.user.remote_id
|
base_path = self.user.remote_id
|
||||||
identifier = self.identifier or self.get_identifier()
|
identifier = self.identifier or self.get_identifier()
|
||||||
return "%s/books/%s" % (base_path, identifier)
|
return f"{base_path}/books/{identifier}"
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""user/shelf unqiueness"""
|
"""user/shelf unqiueness"""
|
||||||
|
|
|
@ -81,7 +81,7 @@ class SiteInvite(models.Model):
|
||||||
@property
|
@property
|
||||||
def link(self):
|
def link(self):
|
||||||
"""formats the invite link"""
|
"""formats the invite link"""
|
||||||
return "https://{}/invite/{}".format(DOMAIN, self.code)
|
return f"https://{DOMAIN}/invite/{self.code}"
|
||||||
|
|
||||||
|
|
||||||
class InviteRequest(BookWyrmModel):
|
class InviteRequest(BookWyrmModel):
|
||||||
|
@ -121,7 +121,7 @@ class PasswordReset(models.Model):
|
||||||
@property
|
@property
|
||||||
def link(self):
|
def link(self):
|
||||||
"""formats the invite link"""
|
"""formats the invite link"""
|
||||||
return "https://{}/password-reset/{}".format(DOMAIN, self.code)
|
return "https://{DOMAIN}/password-reset/{self.code}"
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
|
|
|
@ -179,7 +179,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||||
"""helper function for loading AP serialized replies to a status"""
|
"""helper function for loading AP serialized replies to a status"""
|
||||||
return self.to_ordered_collection(
|
return self.to_ordered_collection(
|
||||||
self.replies(self),
|
self.replies(self),
|
||||||
remote_id="%s/replies" % self.remote_id,
|
remote_id=f"{self.remote_id}/replies",
|
||||||
collection_only=True,
|
collection_only=True,
|
||||||
**kwargs
|
**kwargs
|
||||||
).serialize()
|
).serialize()
|
||||||
|
@ -226,10 +226,10 @@ class GeneratedNote(Status):
|
||||||
"""indicate the book in question for mastodon (or w/e) users"""
|
"""indicate the book in question for mastodon (or w/e) users"""
|
||||||
message = self.content
|
message = self.content
|
||||||
books = ", ".join(
|
books = ", ".join(
|
||||||
'<a href="%s">"%s"</a>' % (book.remote_id, book.title)
|
f'<a href="{book.remote_id}">"{book.title}"</a>'
|
||||||
for book in self.mention_books.all()
|
for book in self.mention_books.all()
|
||||||
)
|
)
|
||||||
return "%s %s %s" % (self.user.display_name, message, books)
|
return f"{self.user.display_name} {message} {books}"
|
||||||
|
|
||||||
activity_serializer = activitypub.GeneratedNote
|
activity_serializer = activitypub.GeneratedNote
|
||||||
pure_type = "Note"
|
pure_type = "Note"
|
||||||
|
@ -277,11 +277,7 @@ class Comment(BookStatus):
|
||||||
@property
|
@property
|
||||||
def pure_content(self):
|
def pure_content(self):
|
||||||
"""indicate the book in question for mastodon (or w/e) users"""
|
"""indicate the book in question for mastodon (or w/e) users"""
|
||||||
return '%s<p>(comment on <a href="%s">"%s"</a>)</p>' % (
|
return f'{self.content}<p>(comment on <a href="{self.book.remote_id}">"{self.book.title}"</a>)</p>'
|
||||||
self.content,
|
|
||||||
self.book.remote_id,
|
|
||||||
self.book.title,
|
|
||||||
)
|
|
||||||
|
|
||||||
activity_serializer = activitypub.Comment
|
activity_serializer = activitypub.Comment
|
||||||
|
|
||||||
|
@ -306,12 +302,7 @@ class Quotation(BookStatus):
|
||||||
"""indicate the book in question for mastodon (or w/e) users"""
|
"""indicate the book in question for mastodon (or w/e) users"""
|
||||||
quote = re.sub(r"^<p>", '<p>"', self.quote)
|
quote = re.sub(r"^<p>", '<p>"', self.quote)
|
||||||
quote = re.sub(r"</p>$", '"</p>', quote)
|
quote = re.sub(r"</p>$", '"</p>', quote)
|
||||||
return '%s <p>-- <a href="%s">"%s"</a></p>%s' % (
|
return f'{quote} <p>-- <a href="{self.book.remote_id}">"{self.book.title}"</a></p>{self.content}'
|
||||||
quote,
|
|
||||||
self.book.remote_id,
|
|
||||||
self.book.title,
|
|
||||||
self.content,
|
|
||||||
)
|
|
||||||
|
|
||||||
activity_serializer = activitypub.Quotation
|
activity_serializer = activitypub.Quotation
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ register = template.Library()
|
||||||
@register.filter(name="uuid")
|
@register.filter(name="uuid")
|
||||||
def get_uuid(identifier):
|
def get_uuid(identifier):
|
||||||
"""for avoiding clashing ids when there are many forms"""
|
"""for avoiding clashing ids when there are many forms"""
|
||||||
return "%s%s" % (identifier, uuid4())
|
return f"{identifier}{uuid4()}"
|
||||||
|
|
||||||
|
|
||||||
@register.filter(name="username")
|
@register.filter(name="username")
|
||||||
|
@ -50,7 +50,7 @@ def truncatepath(value, arg):
|
||||||
length = int(arg)
|
length = int(arg)
|
||||||
except ValueError: # invalid literal for int()
|
except ValueError: # invalid literal for int()
|
||||||
return path_list[-1] # Fail silently.
|
return path_list[-1] # Fail silently.
|
||||||
return "%s/…%s" % (path_list[0], path_list[-1][-length:])
|
return f"{path_list[0]}/…{path_list[-1][-length:]}"
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag(takes_context=False)
|
@register.simple_tag(takes_context=False)
|
||||||
|
@ -60,7 +60,7 @@ def get_book_cover_thumbnail(book, size="medium", ext="jpg"):
|
||||||
if size == "":
|
if size == "":
|
||||||
size = "medium"
|
size = "medium"
|
||||||
try:
|
try:
|
||||||
cover_thumbnail = getattr(book, "cover_bw_book_%s_%s" % (size, ext))
|
cover_thumbnail = getattr(book, f"cover_bw_book_{size}_{ext}")
|
||||||
return cover_thumbnail.url
|
return cover_thumbnail.url
|
||||||
except OSError:
|
except OSError:
|
||||||
return static("images/no_cover.jpg")
|
return static("images/no_cover.jpg")
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
DOMAIN = r"[\w_\-\.]+\.[a-z]{2,}"
|
DOMAIN = r"[\w_\-\.]+\.[a-z]{2,}"
|
||||||
LOCALNAME = r"@?[a-zA-Z_\-\.0-9]+"
|
LOCALNAME = r"@?[a-zA-Z_\-\.0-9]+"
|
||||||
STRICT_LOCALNAME = r"@[a-zA-Z_\-\.0-9]+"
|
STRICT_LOCALNAME = r"@[a-zA-Z_\-\.0-9]+"
|
||||||
USERNAME = r"%s(@%s)?" % (LOCALNAME, DOMAIN)
|
USERNAME = rf"{LOCALNAME}(@{DOMAIN})?"
|
||||||
STRICT_USERNAME = r"\B%s(@%s)?\b" % (STRICT_LOCALNAME, DOMAIN)
|
STRICT_USERNAME = rf"\B{STRICT_LOCALNAME}(@{DOMAIN})?\b"
|
||||||
FULL_USERNAME = r"%s@%s\b" % (LOCALNAME, DOMAIN)
|
FULL_USERNAME = rf"{LOCALNAME}@{DOMAIN}\b"
|
||||||
# should match (BookWyrm/1.0.0; or (BookWyrm/99.1.2;
|
# should match (BookWyrm/1.0.0; or (BookWyrm/99.1.2;
|
||||||
BOOKWYRM_USER_AGENT = r"\(BookWyrm/[0-9]+\.[0-9]+\.[0-9]+;"
|
BOOKWYRM_USER_AGENT = r"\(BookWyrm/[0-9]+\.[0-9]+\.[0-9]+;"
|
||||||
|
|
|
@ -55,4 +55,4 @@ class EditAuthor(View):
|
||||||
return TemplateResponse(request, "author/edit_author.html", data)
|
return TemplateResponse(request, "author/edit_author.html", data)
|
||||||
author = form.save()
|
author = form.save()
|
||||||
|
|
||||||
return redirect("/author/%s" % author.id)
|
return redirect(f"/author/{author.id}")
|
||||||
|
|
|
@ -79,7 +79,7 @@ def save_user_form(form):
|
||||||
|
|
||||||
# set the name to a hash
|
# set the name to a hash
|
||||||
extension = form.files["avatar"].name.split(".")[-1]
|
extension = form.files["avatar"].name.split(".")[-1]
|
||||||
filename = "%s.%s" % (uuid4(), extension)
|
filename = f"{uuid4()}.{extension}"
|
||||||
user.avatar.save(filename, image, save=False)
|
user.avatar.save(filename, image, save=False)
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
|
@ -96,4 +96,4 @@ def switch_edition(request):
|
||||||
readthrough.book = new_edition
|
readthrough.book = new_edition
|
||||||
readthrough.save()
|
readthrough.save()
|
||||||
|
|
||||||
return redirect("/book/%d" % new_edition.id)
|
return redirect(f"/book/{new_edition.id}")
|
||||||
|
|
|
@ -42,7 +42,7 @@ class Feed(View):
|
||||||
"tab": tab,
|
"tab": tab,
|
||||||
"streams": STREAMS,
|
"streams": STREAMS,
|
||||||
"goal_form": forms.GoalForm(),
|
"goal_form": forms.GoalForm(),
|
||||||
"path": "/%s" % tab["key"],
|
"path": f"/{tab['key']}",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return TemplateResponse(request, "feed/feed.html", data)
|
return TemplateResponse(request, "feed/feed.html", data)
|
||||||
|
|
|
@ -86,4 +86,4 @@ def delete_follow_request(request):
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
follow_request.delete()
|
follow_request.delete()
|
||||||
return redirect("/user/%s" % request.user.localname)
|
return redirect(f"/user/{request.user.localname}")
|
||||||
|
|
|
@ -113,7 +113,7 @@ def handle_remote_webfinger(query):
|
||||||
try:
|
try:
|
||||||
user = models.User.objects.get(username__iexact=query)
|
user = models.User.objects.get(username__iexact=query)
|
||||||
except models.User.DoesNotExist:
|
except models.User.DoesNotExist:
|
||||||
url = "https://%s/.well-known/webfinger?resource=acct:%s" % (domain, query)
|
url = f"https://{domain}/.well-known/webfinger?resource=acct:{query}"
|
||||||
try:
|
try:
|
||||||
data = get_data(url)
|
data = get_data(url)
|
||||||
except (ConnectorException, HTTPError):
|
except (ConnectorException, HTTPError):
|
||||||
|
|
|
@ -68,7 +68,7 @@ class Import(View):
|
||||||
|
|
||||||
importer.start_import(job)
|
importer.start_import(job)
|
||||||
|
|
||||||
return redirect("/import/%d" % job.id)
|
return redirect(f"/import/{job.id}")
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
|
||||||
|
@ -112,4 +112,4 @@ class ImportStatus(View):
|
||||||
items,
|
items,
|
||||||
)
|
)
|
||||||
importer.start_import(job)
|
importer.start_import(job)
|
||||||
return redirect("/import/%d" % job.id)
|
return redirect(f"/import/{job.id}")
|
||||||
|
|
|
@ -71,7 +71,7 @@ def is_blocked_user_agent(request):
|
||||||
user_agent = request.headers.get("User-Agent")
|
user_agent = request.headers.get("User-Agent")
|
||||||
if not user_agent:
|
if not user_agent:
|
||||||
return False
|
return False
|
||||||
url = re.search(r"https?://{:s}/?".format(regex.DOMAIN), user_agent)
|
url = re.search(rf"https?://{regex.DOMAIN}/?", user_agent)
|
||||||
if not url:
|
if not url:
|
||||||
return False
|
return False
|
||||||
url = url.group()
|
url = url.group()
|
||||||
|
|
|
@ -322,7 +322,7 @@ def add_book(request):
|
||||||
path = reverse("list", args=[book_list.id])
|
path = reverse("list", args=[book_list.id])
|
||||||
params = request.GET.copy()
|
params = request.GET.copy()
|
||||||
params["updated"] = True
|
params["updated"] = True
|
||||||
return redirect("{:s}?{:s}".format(path, urlencode(params)))
|
return redirect(f"{path}?{urlencode(params)}")
|
||||||
|
|
||||||
|
|
||||||
@require_POST
|
@require_POST
|
||||||
|
@ -396,7 +396,7 @@ def set_book_position(request, list_item_id):
|
||||||
def increment_order_in_reverse(
|
def increment_order_in_reverse(
|
||||||
book_list_id: int, start: int, end: Optional[int] = None
|
book_list_id: int, start: int, end: Optional[int] = None
|
||||||
):
|
):
|
||||||
"""increase the order nu,ber for every item in a list"""
|
"""increase the order number for every item in a list"""
|
||||||
try:
|
try:
|
||||||
book_list = models.List.objects.get(id=book_list_id)
|
book_list = models.List.objects.get(id=book_list_id)
|
||||||
except models.List.DoesNotExist:
|
except models.List.DoesNotExist:
|
||||||
|
|
|
@ -46,7 +46,7 @@ class Login(View):
|
||||||
except models.User.DoesNotExist: # maybe it's a full username?
|
except models.User.DoesNotExist: # maybe it's a full username?
|
||||||
username = localname
|
username = localname
|
||||||
else:
|
else:
|
||||||
username = "%s@%s" % (localname, DOMAIN)
|
username = f"{localname}@{DOMAIN}"
|
||||||
password = login_form.data["password"]
|
password = login_form.data["password"]
|
||||||
|
|
||||||
# perform authentication
|
# perform authentication
|
||||||
|
|
|
@ -38,7 +38,7 @@ class PasswordResetRequest(View):
|
||||||
# create a new reset code
|
# create a new reset code
|
||||||
code = models.PasswordReset.objects.create(user=user)
|
code = models.PasswordReset.objects.create(user=user)
|
||||||
password_reset_email(code)
|
password_reset_email(code)
|
||||||
data = {"message": _("A password reset link sent to %s" % email)}
|
data = {"message": _(f"A password reset link sent to {email}")}
|
||||||
return TemplateResponse(request, "password_reset_request.html", data)
|
return TemplateResponse(request, "password_reset_request.html", data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Register(View):
|
||||||
return TemplateResponse(request, "invite.html", data)
|
return TemplateResponse(request, "invite.html", data)
|
||||||
return TemplateResponse(request, "login.html", data)
|
return TemplateResponse(request, "login.html", data)
|
||||||
|
|
||||||
username = "%s@%s" % (localname, DOMAIN)
|
username = f"{localname}@{DOMAIN}"
|
||||||
user = models.User.objects.create_user(
|
user = models.User.objects.create_user(
|
||||||
username,
|
username,
|
||||||
email,
|
email,
|
||||||
|
|
|
@ -63,7 +63,7 @@ class Search(View):
|
||||||
data["results"] = paginated
|
data["results"] = paginated
|
||||||
data["remote"] = search_remote
|
data["remote"] = search_remote
|
||||||
|
|
||||||
return TemplateResponse(request, "search/{:s}.html".format(search_type), data)
|
return TemplateResponse(request, f"search/{search_type}.html", data)
|
||||||
|
|
||||||
|
|
||||||
def book_search(query, _, min_confidence, search_remote=False):
|
def book_search(query, _, min_confidence, search_remote=False):
|
||||||
|
|
|
@ -36,7 +36,7 @@ class CreateStatus(View):
|
||||||
status_type = status_type[0].upper() + status_type[1:]
|
status_type = status_type[0].upper() + status_type[1:]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
form = getattr(forms, "%sForm" % status_type)(request.POST)
|
form = getattr(forms, f"{status_type}Form")(request.POST)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
|
@ -58,8 +58,8 @@ class CreateStatus(View):
|
||||||
|
|
||||||
# turn the mention into a link
|
# turn the mention into a link
|
||||||
content = re.sub(
|
content = re.sub(
|
||||||
r"%s([^@]|$)" % mention_text,
|
rf"{mention_text}([^@]|$)",
|
||||||
r'<a href="%s">%s</a>\g<1>' % (mention_user.remote_id, mention_text),
|
rf'<a href="{mention_user.remote_id}">{mention_text}</a>\g<1>',
|
||||||
content,
|
content,
|
||||||
)
|
)
|
||||||
# add reply parent to mentions
|
# add reply parent to mentions
|
||||||
|
@ -182,7 +182,7 @@ def format_links(content):
|
||||||
if url.fragment != "":
|
if url.fragment != "":
|
||||||
link += "#" + url.fragment
|
link += "#" + url.fragment
|
||||||
|
|
||||||
formatted_content += '<a href="%s">%s</a>' % (potential_link, link)
|
formatted_content += f'<a href="{potential_link}">{link}</a>'
|
||||||
except (ValidationError, UnicodeError):
|
except (ValidationError, UnicodeError):
|
||||||
formatted_content += potential_link
|
formatted_content += potential_link
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ def webfinger(request):
|
||||||
|
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
"subject": "acct:%s" % (user.username),
|
"subject": f"acct:{user.username}",
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"rel": "self",
|
"rel": "self",
|
||||||
|
@ -46,7 +46,7 @@ def nodeinfo_pointer(_):
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.0",
|
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.0",
|
||||||
"href": "https://%s/nodeinfo/2.0" % DOMAIN,
|
"href": f"https://{DOMAIN}/nodeinfo/2.0",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue