Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.35 #14

Merged
merged 28 commits into from
Sep 24, 2024
Merged

1.35 #14

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0e488b7
Add documentation website (#833)
sissbruecker Sep 17, 2024
2aab281
fix community links
sissbruecker Sep 17, 2024
450980a
Add configuration options for pagination (#835)
sissbruecker Sep 18, 2024
ceceb56
Add go-linkding to community projects (#836)
piero-vic Sep 19, 2024
f3c1101
Improve docs
sissbruecker Sep 19, 2024
f79c244
Bump requests version to 3.23.3 (#839)
voltagex Sep 19, 2024
baa3d55
Bump path-to-regexp and astro in /docs (#840)
dependabot[bot] Sep 19, 2024
8544137
Use HTTPS repository link for devcontainer (#837)
voltagex Sep 19, 2024
3d8866c
Bump dependencies (#841)
sissbruecker Sep 19, 2024
6cf5fb3
remove deprecated API usage
sissbruecker Sep 19, 2024
b4108c9
bump python version in CI
sissbruecker Sep 19, 2024
afa57aa
Show placeholder if there is no preview image (#842)
sissbruecker Sep 20, 2024
fe7ddbe
Allow bookmarks to have empty title and description (#843)
sissbruecker Sep 22, 2024
f4e66c1
fix a broken link to options documentation (#844)
zbrox Sep 22, 2024
c5c5949
Do not overwrite provided title and description (#845)
sissbruecker Sep 22, 2024
ed57da3
Add clear buttons in bookmark form (#846)
sissbruecker Sep 23, 2024
95f489e
Format CSS with prettier
sissbruecker Sep 23, 2024
67f237c
Update docs link
sissbruecker Sep 23, 2024
f570859
Add basic fail2ban support (#847)
sissbruecker Sep 23, 2024
93e2832
Bump version
sissbruecker Sep 23, 2024
70bdf88
Update CHANGELOG.md
sissbruecker Sep 23, 2024
d400602
Fix preview image spacing
sissbruecker Sep 23, 2024
c3a2305
Return client error status code for invalid form submissions (#849)
sissbruecker Sep 23, 2024
23ad52f
Fix header.svg text (#850)
vladh Sep 23, 2024
7b405c0
Do not clear fields in POST requests (API behavior change) (#852)
sissbruecker Sep 24, 2024
d1f81fe
Prevent duplicates when editing (#853)
sissbruecker Sep 24, 2024
ba904ed
Fix header backdrop on iOS
sissbruecker Sep 24, 2024
efc6128
Merge branch 'environ' into master
krzysztofjeziorny Sep 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Python 3",
"image": "mcr.microsoft.com/devcontainers/python:0-3.10",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"features": {
"ghcr.io/devcontainers/features/node:1": {}
},
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"
- name: Set up Node
uses: actions/setup-node@v4
with:
Expand All @@ -37,7 +37,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"
- name: Set up Node
uses: actions/setup-node@v4
with:
Expand Down
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# Changelog

## (23/09/2024)

### What's Changed
* Add configuration options for pagination by @sissbruecker in https://github.com/sissbruecker/linkding/pull/835
* Show placeholder if there is no preview image by @sissbruecker in https://github.com/sissbruecker/linkding/pull/842
* Allow bookmarks to have empty title and description by @sissbruecker in https://github.com/sissbruecker/linkding/pull/843
* Add clear buttons in bookmark form by @sissbruecker in https://github.com/sissbruecker/linkding/pull/846
* Add basic fail2ban support by @sissbruecker in https://github.com/sissbruecker/linkding/pull/847
* Add documentation website by @sissbruecker in https://github.com/sissbruecker/linkding/pull/833
* Add go-linkding to community projects by @piero-vic in https://github.com/sissbruecker/linkding/pull/836
* Fix a broken link to options documentation by @zbrox in https://github.com/sissbruecker/linkding/pull/844
* Use HTTPS repository link for devcontainer by @voltagex in https://github.com/sissbruecker/linkding/pull/837
* Bump requests version to 3.23.3 by @voltagex in https://github.com/sissbruecker/linkding/pull/839
* Bump path-to-regexp and astro in /docs by @dependabot in https://github.com/sissbruecker/linkding/pull/840
* Bump dependencies by @sissbruecker in https://github.com/sissbruecker/linkding/pull/841

### New Contributors
* @piero-vic made their first contribution in https://github.com/sissbruecker/linkding/pull/836
* @voltagex made their first contribution in https://github.com/sissbruecker/linkding/pull/839
* @zbrox made their first contribution in https://github.com/sissbruecker/linkding/pull/844

**Full Changelog**: https://github.com/sissbruecker/linkding/compare/v1.34.0...v1.35.0

---

## v1.34.0 (16/09/2024)

### What's Changed
Expand Down
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ test:
format:
black bookmarks
black siteroot
npx prettier bookmarks/frontend --write
npx prettier bookmarks/frontend --write
npx prettier bookmarks/styles --write

install:
.venv/bin/pip install -r requirements.txt --upgrade
.venv/bin/pip install -r requirements.txt --upgrade
232 changes: 16 additions & 216 deletions README.md

Large diffs are not rendered by default.

File renamed without changes.
File renamed without changes
41 changes: 41 additions & 0 deletions assets/header.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 17 additions & 1 deletion assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
File renamed without changes
20 changes: 8 additions & 12 deletions bookmarks/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ def get_queryset(self):
return Bookmark.objects.all().filter(owner=user)

def get_serializer_context(self):
return {"request": self.request, "user": self.request.user}
disable_scraping = "disable_scraping" in self.request.GET
return {
"request": self.request,
"user": self.request.user,
"disable_scraping": disable_scraping,
}

@action(methods=["get"], detail=False)
def archived(self, request):
Expand Down Expand Up @@ -101,16 +106,7 @@ def check(self, request):
self.get_serializer(bookmark).data if bookmark else None
)

# Either return metadata from existing bookmark, or scrape from URL
if bookmark:
metadata = WebsiteMetadata(
url,
bookmark.website_title,
bookmark.website_description,
None,
)
else:
metadata = website_loader.load_website_metadata(url)
metadata = website_loader.load_website_metadata(url)

# Return tags that would be automatically applied to the bookmark
profile = request.user.profile
Expand All @@ -120,7 +116,7 @@ def check(self, request):
auto_tags = auto_tagging.get_tags(profile.auto_tagging_rules, url)
except Exception as e:
logger.error(
f"Failed to auto-tag bookmark. url={bookmark.url}",
f"Failed to auto-tag bookmark. url={url}",
exc_info=e,
)

Expand Down
88 changes: 56 additions & 32 deletions bookmarks/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
from rest_framework.serializers import ListSerializer

from bookmarks.models import Bookmark, Tag, build_tag_string, UserProfile
from bookmarks.services.bookmarks import create_bookmark, update_bookmark
from bookmarks.services.bookmarks import (
create_bookmark,
update_bookmark,
enhance_with_website_metadata,
)
from bookmarks.services.tags import get_or_create_tag


Expand All @@ -29,8 +33,6 @@ class Meta:
"title",
"description",
"notes",
"website_title",
"website_description",
"web_archive_snapshot_url",
"favicon_url",
"preview_image_url",
Expand All @@ -40,29 +42,29 @@ class Meta:
"tag_names",
"date_added",
"date_modified",
]
read_only_fields = [
"website_title",
"website_description",
]
read_only_fields = [
"web_archive_snapshot_url",
"favicon_url",
"preview_image_url",
"tag_names",
"date_added",
"date_modified",
"website_title",
"website_description",
]
list_serializer_class = BookmarkListSerializer

# Override optional char fields to provide default value
title = serializers.CharField(required=False, allow_blank=True, default="")
description = serializers.CharField(required=False, allow_blank=True, default="")
notes = serializers.CharField(required=False, allow_blank=True, default="")
is_archived = serializers.BooleanField(required=False, default=False)
unread = serializers.BooleanField(required=False, default=False)
shared = serializers.BooleanField(required=False, default=False)
# Override readonly tag_names property to allow passing a list of tag names to create/update
tag_names = TagListField(required=False, default=[])
# Custom tag_names field to allow passing a list of tag names to create/update
tag_names = TagListField(required=False)
# Custom fields to return URLs for favicon and preview image
favicon_url = serializers.SerializerMethodField()
preview_image_url = serializers.SerializerMethodField()
# Add dummy website title and description fields for backwards compatibility but keep them empty
website_title = serializers.SerializerMethodField()
website_description = serializers.SerializerMethodField()

def get_favicon_url(self, obj: Bookmark):
if not obj.favicon_file:
Expand All @@ -80,31 +82,53 @@ def get_preview_image_url(self, obj: Bookmark):
preview_image_url = request.build_absolute_uri(preview_image_file_path)
return preview_image_url

def get_website_title(self, obj: Bookmark):
return None

def get_website_description(self, obj: Bookmark):
return None

def create(self, validated_data):
bookmark = Bookmark()
bookmark.url = validated_data["url"]
bookmark.title = validated_data["title"]
bookmark.description = validated_data["description"]
bookmark.notes = validated_data["notes"]
bookmark.is_archived = validated_data["is_archived"]
bookmark.unread = validated_data["unread"]
bookmark.shared = validated_data["shared"]
tag_string = build_tag_string(validated_data["tag_names"])
return create_bookmark(bookmark, tag_string, self.context["user"])
tag_names = validated_data.pop("tag_names", [])
tag_string = build_tag_string(tag_names)
bookmark = Bookmark(**validated_data)

saved_bookmark = create_bookmark(bookmark, tag_string, self.context["user"])
# Unless scraping is explicitly disabled, enhance bookmark with website
# metadata to preserve backwards compatibility with clients that expect
# title and description to be populated automatically when left empty
if not self.context.get("disable_scraping", False):
enhance_with_website_metadata(saved_bookmark)
return saved_bookmark

def update(self, instance: Bookmark, validated_data):
# Update fields if they were provided in the payload
for key in ["url", "title", "description", "notes", "unread", "shared"]:
if key in validated_data:
setattr(instance, key, validated_data[key])
tag_names = validated_data.pop("tag_names", instance.tag_names)
tag_string = build_tag_string(tag_names)

# Use tag string from payload, or use bookmark's current tags as fallback
tag_string = build_tag_string(instance.tag_names)
if "tag_names" in validated_data:
tag_string = build_tag_string(validated_data["tag_names"])
for field_name, field in self.fields.items():
if not field.read_only and field_name in validated_data:
setattr(instance, field_name, validated_data[field_name])

return update_bookmark(instance, tag_string, self.context["user"])

def validate(self, attrs):
# When creating a bookmark, the service logic prevents duplicate URLs by
# updating the existing bookmark instead. 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.
if self.instance and "url" in attrs:
is_duplicate = (
Bookmark.objects.filter(owner=self.instance.owner, url=attrs["url"])
.exclude(pk=self.instance.pk)
.exists()
)
if is_duplicate:
raise serializers.ValidationError(
{"url": "A bookmark with this URL already exists."}
)

return attrs


class TagSerializer(serializers.ModelSerializer):
class Meta:
Expand Down
3 changes: 3 additions & 0 deletions bookmarks/e2e/e2e_test_bookmark_details_modal.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ def test_delete(self):

details_modal = self.open_details_modal(bookmark)

# Wait for confirm button to be initialized
self.page.wait_for_timeout(1000)

# Delete bookmark, verify return url
with self.page.expect_navigation(url=self.live_server_url + url):
details_modal.get_by_text("Delete...").click()
Expand Down
Loading
Loading