diff --git a/bookmarks/forms.py b/bookmarks/forms.py index c571d0f..244fbbf 100644 --- a/bookmarks/forms.py +++ b/bookmarks/forms.py @@ -50,6 +50,7 @@ class BookmarkForm(forms.ModelForm): "tag_string": request.GET.get("tags"), "auto_close": "auto_close" in request.GET, "unread": request.user_profile.default_mark_unread, + "shared": request.user_profile.default_mark_shared, } if instance is not None and request.method == "GET": initial = {"tag_string": build_tag_string(instance.tag_names, " ")} diff --git a/bookmarks/migrations/0048_userprofile_default_mark_shared.py b/bookmarks/migrations/0048_userprofile_default_mark_shared.py new file mode 100644 index 0000000..0b149a0 --- /dev/null +++ b/bookmarks/migrations/0048_userprofile_default_mark_shared.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.3 on 2025-08-22 17:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookmarks", "0047_populate_url_normalized_field"), + ] + + operations = [ + migrations.AddField( + model_name="userprofile", + name="default_mark_shared", + field=models.BooleanField(default=False), + ), + ] diff --git a/bookmarks/models.py b/bookmarks/models.py index 2e860d7..af6c3cd 100644 --- a/bookmarks/models.py +++ b/bookmarks/models.py @@ -479,6 +479,7 @@ class UserProfile(models.Model): search_preferences = models.JSONField(default=dict, null=False) enable_automatic_html_snapshots = models.BooleanField(default=True, null=False) default_mark_unread = models.BooleanField(default=False, null=False) + default_mark_shared = models.BooleanField(default=False, null=False) items_per_page = models.IntegerField( null=False, default=30, validators=[MinValueValidator(10)] ) @@ -520,6 +521,7 @@ class UserProfileForm(forms.ModelForm): "display_remove_bookmark_action", "permanent_notes", "default_mark_unread", + "default_mark_shared", "custom_css", "auto_tagging_rules", "items_per_page", diff --git a/bookmarks/templates/settings/general.html b/bookmarks/templates/settings/general.html index 16800bf..a1d0931 100644 --- a/bookmarks/templates/settings/general.html +++ b/bookmarks/templates/settings/general.html @@ -270,6 +270,17 @@ reddit.com/r/Music music reddit This can be overridden when creating each new bookmark. +
+ +
+ Sets the default state for the "Share" option when creating a new bookmark. + Setting this option will make all new bookmarks default to shared. + This can be overridden when creating each new bookmark. +
+
@@ -404,21 +415,25 @@ reddit.com/r/Music music reddit (function init() { const enableSharing = document.getElementById("{{ form.enable_sharing.id_for_label }}"); const enablePublicSharing = document.getElementById("{{ form.enable_public_sharing.id_for_label }}"); + const defaultMarkShared = document.getElementById("{{ form.default_mark_shared.id_for_label }}"); const bookmarkDescriptionDisplay = document.getElementById("{{ form.bookmark_description_display.id_for_label }}"); const bookmarkDescriptionMaxLines = document.getElementById("{{ form.bookmark_description_max_lines.id_for_label }}"); - // Automatically disable public bookmark sharing if bookmark sharing is disabled - function updatePublicSharing() { + // Automatically disable public bookmark sharing and default shared option if bookmark sharing is disabled + function updateSharingOptions() { if (enableSharing.checked) { enablePublicSharing.disabled = false; + defaultMarkShared.disabled = false; } else { enablePublicSharing.disabled = true; enablePublicSharing.checked = false; + defaultMarkShared.disabled = true; + defaultMarkShared.checked = false; } } - updatePublicSharing(); - enableSharing.addEventListener("change", updatePublicSharing); + updateSharingOptions(); + enableSharing.addEventListener("change", updateSharingOptions); // Automatically hide the bookmark description max lines input if the description display is set to inline function updateBookmarkDescriptionMaxLines() { diff --git a/bookmarks/tests/test_bookmark_new_view.py b/bookmarks/tests/test_bookmark_new_view.py index c4eaca3..a892197 100644 --- a/bookmarks/tests/test_bookmark_new_view.py +++ b/bookmarks/tests/test_bookmark_new_view.py @@ -281,3 +281,28 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin): '', html, ) + + def test_should_not_check_shared_by_default(self): + self.user.profile.enable_sharing = True + self.user.profile.save() + + response = self.client.get(reverse("linkding:bookmarks.new")) + html = response.content.decode() + + self.assertInHTML( + '', + html, + ) + + def test_should_check_shared_when_configured_in_profile(self): + self.user.profile.enable_sharing = True + self.user.profile.default_mark_shared = True + self.user.profile.save() + + response = self.client.get(reverse("linkding:bookmarks.new")) + html = response.content.decode() + + self.assertInHTML( + '', + html, + ) diff --git a/bookmarks/tests/test_settings_general_view.py b/bookmarks/tests/test_settings_general_view.py index ad250bb..c5036d5 100644 --- a/bookmarks/tests/test_settings_general_view.py +++ b/bookmarks/tests/test_settings_general_view.py @@ -115,6 +115,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin): "display_remove_bookmark_action": False, "permanent_notes": True, "default_mark_unread": True, + "default_mark_shared": True, "custom_css": "body { background-color: #000; }", "auto_tagging_rules": "example.com tag", "items_per_page": "10", @@ -188,6 +189,9 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin): self.assertEqual( self.user.profile.default_mark_unread, form_data["default_mark_unread"] ) + self.assertEqual( + self.user.profile.default_mark_shared, form_data["default_mark_shared"] + ) self.assertEqual(self.user.profile.custom_css, form_data["custom_css"]) self.assertEqual( self.user.profile.auto_tagging_rules, form_data["auto_tagging_rules"] diff --git a/bookmarks/tests_e2e/e2e_test_settings_general.py b/bookmarks/tests_e2e/e2e_test_settings_general.py index bf5a5d0..fafe28b 100644 --- a/bookmarks/tests_e2e/e2e_test_settings_general.py +++ b/bookmarks/tests_e2e/e2e_test_settings_general.py @@ -18,28 +18,43 @@ class SettingsGeneralE2ETestCase(LinkdingE2ETestCase): enable_public_sharing_label = page.get_by_text( "Enable public bookmark sharing" ) + default_mark_shared = page.get_by_label( + "Create bookmarks as shared by default" + ) + default_mark_shared_label = page.get_by_text( + "Create bookmarks as shared by default" + ) - # Public sharing is disabled by default + # Public sharing and default shared are disabled by default expect(enable_sharing).not_to_be_checked() expect(enable_public_sharing).not_to_be_checked() expect(enable_public_sharing).to_be_disabled() + expect(default_mark_shared).not_to_be_checked() + expect(default_mark_shared).to_be_disabled() # Enable sharing enable_sharing_label.click() expect(enable_sharing).to_be_checked() expect(enable_public_sharing).not_to_be_checked() expect(enable_public_sharing).to_be_enabled() + expect(default_mark_shared).not_to_be_checked() + expect(default_mark_shared).to_be_enabled() - # Enable public sharing + # Enable public sharing and default shared enable_public_sharing_label.click() + default_mark_shared_label.click() expect(enable_public_sharing).to_be_checked() expect(enable_public_sharing).to_be_enabled() + expect(default_mark_shared).to_be_checked() + expect(default_mark_shared).to_be_enabled() # Disable sharing enable_sharing_label.click() expect(enable_sharing).not_to_be_checked() expect(enable_public_sharing).not_to_be_checked() expect(enable_public_sharing).to_be_disabled() + expect(default_mark_shared).not_to_be_checked() + expect(default_mark_shared).to_be_disabled() def test_should_not_show_bookmark_description_max_lines_when_display_inline(self): profile = self.get_or_create_test_user().profile