From b9bee24047f21f9b86a76682ab43d047e3f76f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Sun, 9 Mar 2025 23:11:48 +0100 Subject: [PATCH] Move more logic into bookmark form --- bookmarks/forms.py | 94 +++++++++++++++++++++ bookmarks/models.py | 50 ----------- bookmarks/templates/bookmarks/edit.html | 3 +- bookmarks/templates/bookmarks/form.html | 6 +- bookmarks/templates/bookmarks/new.html | 3 +- bookmarks/templatetags/bookmarks.py | 18 ---- bookmarks/tests/test_bookmark_new_view.py | 4 +- bookmarks/tests/test_bookmark_validation.py | 15 +++- bookmarks/views/bookmarks.py | 42 ++------- 9 files changed, 119 insertions(+), 116 deletions(-) create mode 100644 bookmarks/forms.py diff --git a/bookmarks/forms.py b/bookmarks/forms.py new file mode 100644 index 0000000..3d3db88 --- /dev/null +++ b/bookmarks/forms.py @@ -0,0 +1,94 @@ +from django import forms + +from bookmarks.models import Bookmark, build_tag_string +from bookmarks.validators import BookmarkURLValidator +from bookmarks.type_defs import HttpRequest +from bookmarks.services.bookmarks import create_bookmark, update_bookmark + + +class BookmarkForm(forms.ModelForm): + # Use URLField for URL + url = forms.CharField(validators=[BookmarkURLValidator()]) + tag_string = forms.CharField(required=False) + # Do not require title and description as they may be empty + title = forms.CharField(max_length=512, required=False) + description = forms.CharField(required=False, widget=forms.Textarea()) + unread = forms.BooleanField(required=False) + shared = forms.BooleanField(required=False) + # Hidden field that determines whether to close window/tab after saving the bookmark + auto_close = forms.CharField(required=False) + + class Meta: + model = Bookmark + fields = [ + "url", + "tag_string", + "title", + "description", + "notes", + "unread", + "shared", + "auto_close", + ] + + def __init__(self, request: HttpRequest, instance: Bookmark = None): + self.request = request + + initial = None + if instance is None and request.method == "GET": + initial = { + "url": request.GET.get("url"), + "title": request.GET.get("title"), + "description": request.GET.get("description"), + "notes": request.GET.get("notes"), + "auto_close": "auto_close" in request.GET, + "unread": request.user_profile.default_mark_unread, + } + if instance is not None and request.method == "GET": + initial = {"tag_string": build_tag_string(instance.tag_names, " ")} + data = request.POST if request.method == "POST" else None + super().__init__(data, instance=instance, initial=initial) + + @property + def is_auto_close(self): + return self.data.get("auto_close", False) == "True" or self.initial.get( + "auto_close", False + ) + + @property + def has_notes(self): + return self.initial.get("notes", None) or ( + self.instance and self.instance.notes + ) + + def save(self, commit=False): + tag_string = convert_tag_string(self.data["tag_string"]) + bookmark = super().save(commit=False) + if self.instance.pk: + return update_bookmark(bookmark, tag_string, self.request.user) + else: + return create_bookmark(bookmark, tag_string, self.request.user) + + def clean_url(self): + # When creating a bookmark, the service logic prevents duplicate URLs by + # updating the existing bookmark instead, which is also communicated in + # the form's UI. When editing a bookmark, there is no assumption that + # it would update a different bookmark if the URL is a duplicate, so + # raise a validation error in that case. + url = self.cleaned_data["url"] + if self.instance.pk: + is_duplicate = ( + Bookmark.objects.filter(owner=self.instance.owner, url=url) + .exclude(pk=self.instance.pk) + .exists() + ) + if is_duplicate: + raise forms.ValidationError("A bookmark with this URL already exists.") + + return url + + +def convert_tag_string(tag_string: str): + # Tag strings coming from inputs are space-separated, however services.bookmarks functions expect comma-separated + # strings + return tag_string.replace(" ", ",") diff --git a/bookmarks/models.py b/bookmarks/models.py index 72b11d2..b11e5af 100644 --- a/bookmarks/models.py +++ b/bookmarks/models.py @@ -150,56 +150,6 @@ def bookmark_asset_deleted(sender, instance, **kwargs): logger.error(f"Failed to delete asset file: {filepath}", exc_info=error) -class BookmarkForm(forms.ModelForm): - # Use URLField for URL - url = forms.CharField(validators=[BookmarkURLValidator()]) - tag_string = forms.CharField(required=False) - # Do not require title and description as they may be empty - title = forms.CharField(max_length=512, required=False) - description = forms.CharField(required=False, widget=forms.Textarea()) - unread = forms.BooleanField(required=False) - shared = forms.BooleanField(required=False) - # Hidden field that determines whether to close window/tab after saving the bookmark - auto_close = forms.CharField(required=False) - - class Meta: - model = Bookmark - fields = [ - "url", - "tag_string", - "title", - "description", - "notes", - "unread", - "shared", - "auto_close", - ] - - @property - def has_notes(self): - return self.initial.get("notes", None) or ( - self.instance and self.instance.notes - ) - - def clean_url(self): - # When creating a bookmark, the service logic prevents duplicate URLs by - # updating the existing bookmark instead, which is also communicated in - # the form's UI. When editing a bookmark, there is no assumption that - # it would update a different bookmark if the URL is a duplicate, so - # raise a validation error in that case. - url = self.cleaned_data["url"] - if self.instance.pk: - is_duplicate = ( - Bookmark.objects.filter(owner=self.instance.owner, url=url) - .exclude(pk=self.instance.pk) - .exists() - ) - if is_duplicate: - raise forms.ValidationError("A bookmark with this URL already exists.") - - return url - - class BookmarkSearch: SORT_ADDED_ASC = "added_asc" SORT_ADDED_DESC = "added_desc" diff --git a/bookmarks/templates/bookmarks/edit.html b/bookmarks/templates/bookmarks/edit.html index de9b76b..4e1b766 100644 --- a/bookmarks/templates/bookmarks/edit.html +++ b/bookmarks/templates/bookmarks/edit.html @@ -1,5 +1,4 @@ {% extends 'bookmarks/layout.html' %} -{% load bookmarks %} {% block content %}
@@ -9,7 +8,7 @@
- {% bookmark_form form return_url bookmark_id %} + {% include 'bookmarks/form.html' %}
diff --git a/bookmarks/templates/bookmarks/form.html b/bookmarks/templates/bookmarks/form.html index f47674f..6245754 100644 --- a/bookmarks/templates/bookmarks/form.html +++ b/bookmarks/templates/bookmarks/form.html @@ -91,12 +91,12 @@ {% endif %}
- {% if auto_close %} + {% if form.is_auto_close %} {% else %} {% endif %} - Nevermind + Nevermind