From 469883a6746133b1d74c8ae6f87da6dcf6d042a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 10:01:36 +0200 Subject: [PATCH 1/5] --- (#740) updated-dependencies: - dependency-name: requests dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 39f477f5..c14b38a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -61,7 +61,7 @@ python-dateutil==2.8.2 # via -r requirements.in pytz==2023.3.post1 # via djangorestframework -requests==2.31.0 +requests==2.32.0 # via # -r requirements.in # mozilla-django-oidc From 44b49a4cfed275d417e598ff6196f17d225d20f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Sun, 16 Jun 2024 10:04:38 +0200 Subject: [PATCH 2/5] Preview auto tags in bookmark form (#737) --- bookmarks/api/routes.py | 13 +++++++++++- bookmarks/e2e/e2e_test_bookmark_form.py | 22 +++++++++++++++++++ bookmarks/styles/bookmark-form.scss | 9 ++++---- bookmarks/templates/bookmarks/form.html | 18 +++++++++++++--- bookmarks/tests/test_bookmarks_api.py | 28 +++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 9 deletions(-) diff --git a/bookmarks/api/routes.py b/bookmarks/api/routes.py index 41f73219..5249c512 100644 --- a/bookmarks/api/routes.py +++ b/bookmarks/api/routes.py @@ -11,6 +11,7 @@ UserProfileSerializer, ) from bookmarks.models import Bookmark, BookmarkSearch, Tag, User +from bookmarks.services import auto_tagging from bookmarks.services.bookmarks import ( archive_bookmark, unarchive_bookmark, @@ -107,8 +108,18 @@ def check(self, request): else: metadata = website_loader.load_website_metadata(url) + # Return tags that would be automatically applied to the bookmark + profile = request.user.profile + auto_tags = [] + if profile.auto_tagging_rules: + auto_tags = auto_tagging.get_tags(profile.auto_tagging_rules, url) + return Response( - {"bookmark": existing_bookmark_data, "metadata": metadata.to_dict()}, + { + "bookmark": existing_bookmark_data, + "metadata": metadata.to_dict(), + "auto_tags": auto_tags, + }, status=status.HTTP_200_OK, ) diff --git a/bookmarks/e2e/e2e_test_bookmark_form.py b/bookmarks/e2e/e2e_test_bookmark_form.py index c4da421e..8c031d5d 100644 --- a/bookmarks/e2e/e2e_test_bookmark_form.py +++ b/bookmarks/e2e/e2e_test_bookmark_form.py @@ -85,3 +85,25 @@ def test_enter_url_of_existing_bookmark_should_show_notes(self): page.get_by_label("URL").fill(bookmark.url) expect(details).to_have_attribute("open", value="") + + def test_create_should_preview_auto_tags(self): + profile = self.get_or_create_test_user().profile + profile.auto_tagging_rules = "github.com dev github" + profile.save() + + with sync_playwright() as p: + # Open page with URL that should have auto tags + browser = self.setup_browser(p) + page = browser.new_page() + url = self.live_server_url + reverse("bookmarks:new") + url += f"?url=https%3A%2F%2Fgithub.com%2Fsissbruecker%2Flinkding" + page.goto(url) + + auto_tags_hint = page.locator(".form-input-hint.auto-tags") + expect(auto_tags_hint).to_be_visible() + expect(auto_tags_hint).to_have_text("Auto tags: dev github") + + # Change to URL without auto tags + page.get_by_label("URL").fill("https://example.com") + + expect(auto_tags_hint).to_be_hidden() diff --git a/bookmarks/styles/bookmark-form.scss b/bookmarks/styles/bookmark-form.scss index e80af60e..1b31754b 100644 --- a/bookmarks/styles/bookmark-form.scss +++ b/bookmarks/styles/bookmark-form.scss @@ -36,12 +36,11 @@ .form-input-hint.bookmark-exists { display: none; color: $warning-color; + } - a { - color: $warning-color; - text-decoration: underline; - font-weight: bold; - } + .form-input-hint.auto-tags { + display: none; + color: $success-color; } details.notes textarea { diff --git a/bookmarks/templates/bookmarks/form.html b/bookmarks/templates/bookmarks/form.html index 2dd05f80..d9beb61c 100644 --- a/bookmarks/templates/bookmarks/form.html +++ b/bookmarks/templates/bookmarks/form.html @@ -23,10 +23,10 @@ {{ form.tag_string|add_class:"form-input"|attr:"ld-tag-autocomplete"|attr:"autocomplete:off"|attr:"autocapitalize:off" }}
- Enter any number of tags separated by space and without the hash (#). If a tag does not - exist it will be - automatically created. + Enter any number of tags separated by space and without the hash (#). + If a tag does not exist it will be automatically created.
+
{{ form.tag_string.errors }}
@@ -197,6 +197,18 @@ } else { bookmarkExistsHint.style['display'] = 'none'; } + + // Preview auto tags + const autoTags = data.auto_tags; + const autoTagsHint = document.querySelector('.form-input-hint.auto-tags'); + + if (autoTags.length > 0) { + autoTags.sort(); + autoTagsHint.style['display'] = 'block'; + autoTagsHint.innerHTML = `Auto tags: ${autoTags.join(" ")}`; + } else { + autoTagsHint.style['display'] = 'none'; + } }); } diff --git a/bookmarks/tests/test_bookmarks_api.py b/bookmarks/tests/test_bookmarks_api.py index 4c58d2c1..58448df6 100644 --- a/bookmarks/tests/test_bookmarks_api.py +++ b/bookmarks/tests/test_bookmarks_api.py @@ -742,6 +742,34 @@ def test_check_returns_existing_metadata_if_url_is_bookmarked(self): self.assertEqual(bookmark.website_description, metadata["description"]) self.assertIsNone(metadata["preview_image"]) + def test_check_returns_no_auto_tags_if_none_configured(self): + self.authenticate() + + url = reverse("bookmarks:bookmark-check") + check_url = urllib.parse.quote_plus("https://example.com") + response = self.get( + f"{url}?url={check_url}", expected_status_code=status.HTTP_200_OK + ) + auto_tags = response.data["auto_tags"] + + self.assertCountEqual(auto_tags, []) + + def test_check_returns_matching_auto_tags(self): + self.authenticate() + + profile = self.get_or_create_test_user().profile + profile.auto_tagging_rules = "example.com tag1 tag2" + profile.save() + + url = reverse("bookmarks:bookmark-check") + check_url = urllib.parse.quote_plus("https://example.com") + response = self.get( + f"{url}?url={check_url}", expected_status_code=status.HTTP_200_OK + ) + auto_tags = response.data["auto_tags"] + + self.assertCountEqual(auto_tags, ["tag1", "tag2"]) + def test_can_only_access_own_bookmarks(self): self.authenticate() self.setup_bookmark() From fe40139838e75a162e5066c232f50a3f8e95402b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Sun, 16 Jun 2024 10:37:02 +0200 Subject: [PATCH 3/5] Make backup include preview images --- bookmarks/management/commands/full_backup.py | 13 +++++++++++++ docs/backup.md | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/bookmarks/management/commands/full_backup.py b/bookmarks/management/commands/full_backup.py index 49241564..642c89e1 100644 --- a/bookmarks/management/commands/full_backup.py +++ b/bookmarks/management/commands/full_backup.py @@ -48,6 +48,19 @@ def handle(self, *args, **options): file_path = os.path.join(root, file) zip_file.write(file_path, os.path.join("favicons", file)) + # Backup the previews folder + if not os.path.exists(os.path.join("data", "previews")): + self.stdout.write( + self.style.WARNING("No previews folder found. Skipping...") + ) + else: + self.stdout.write("Backup bookmark previews...") + previews_folder = os.path.join("data", "previews") + for root, _, files in os.walk(previews_folder): + for file in files: + file_path = os.path.join(root, file) + zip_file.write(file_path, os.path.join("previews", file)) + self.stdout.write(self.style.SUCCESS(f"Backup created at {backup_file}")) def backup_database(self, backup_db_file): diff --git a/docs/backup.md b/docs/backup.md index e76e2308..05f32dd3 100644 --- a/docs/backup.md +++ b/docs/backup.md @@ -8,12 +8,13 @@ The data folder contains the following contents that are relevant for backups: - `db.sqlite3` - the SQLite database - `assets` - folder that contains HTML snapshots of bookmarks - `favicons` - folder that contains downloaded favicons +- `previews` - folder that contains downloaded preview images The following sections explain how to back up the individual contents. ## Full backup -linkding provides a CLI command to create a full backup of the data folder. This creates a zip file that contains backups of the database, assets, and favicons. +linkding provides a CLI command to create a full backup of the data folder. This creates a zip file that contains backups of the database, assets, favicons, and preview images. > [!NOTE] > This method assumes that you are using the default SQLite database. @@ -90,7 +91,7 @@ This is the least technical option to back up bookmarks, but has several limitat - It only exports your own bookmarks, not those of other users. - It does not export URLs of snapshots on the Internet Archive Wayback machine. - It does not export HTML snapshots of bookmarks. Even if you backup and restore the assets folder, the bookmarks will not be linked to the snapshots anymore. -- It does not export favicons. +- It does not export favicons or preview images. Only use this method if you are fine with the above limitations. From 695b0dc300772add2069d7857b99b989da2305b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Sun, 16 Jun 2024 11:45:06 +0200 Subject: [PATCH 4/5] Bump version --- package.json | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fd1e8319..f1ca89a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "linkding", - "version": "1.30.0", + "version": "1.31.0", "description": "", "main": "index.js", "scripts": { diff --git a/version.txt b/version.txt index 034552a8..34aae156 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.30.0 +1.31.0 From b28352fb28f0e892d4d93b2e5d787739a4118885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Sun, 16 Jun 2024 22:45:01 +0200 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11fc7a4f..399505ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## v1.31.0 (16/06/2024) + +### What's Changed +* Add support for bookmark thumbnails by @vslinko in https://github.com/sissbruecker/linkding/pull/721 +* Automatically add tags to bookmarks based on URL pattern by @vslinko in https://github.com/sissbruecker/linkding/pull/736 +* Load bookmark thumbnails after import by @vslinko in https://github.com/sissbruecker/linkding/pull/724 +* Load missing thumbnails after enabling the feature by @sissbruecker in https://github.com/sissbruecker/linkding/pull/725 +* Thumbnails lazy loading by @vslinko in https://github.com/sissbruecker/linkding/pull/734 +* Add option for disabling tag grouping by @vslinko in https://github.com/sissbruecker/linkding/pull/735 +* Preview auto tags in bookmark form by @sissbruecker in https://github.com/sissbruecker/linkding/pull/737 +* Hide tooltip on mobile by @vslinko in https://github.com/sissbruecker/linkding/pull/733 +* Bump requests from 2.31.0 to 2.32.0 by @dependabot in https://github.com/sissbruecker/linkding/pull/740 + +### New Contributors +* @vslinko made their first contribution in https://github.com/sissbruecker/linkding/pull/721 + +**Full Changelog**: https://github.com/sissbruecker/linkding/compare/v1.30.0...v1.31.0 + +--- + ## v1.30.0 (20/04/2024) ### What's Changed