mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-08 03:08:29 +02:00
Add REST endpoint for uploading snapshots from the Singlefile extension (#996)
* Extract asset logic * Allow disabling HTML snapshot when creating bookmark * Add endpoint for uploading singlefile snapshots * Add URL parameter to disable HTML snapshots * Allow using asset list in base Docker image * Expose app version through profile
This commit is contained in:
@@ -13,13 +13,7 @@ from bookmarks.api.serializers import (
|
||||
UserProfileSerializer,
|
||||
)
|
||||
from bookmarks.models import Bookmark, BookmarkSearch, Tag, User
|
||||
from bookmarks.services import auto_tagging
|
||||
from bookmarks.services.bookmarks import (
|
||||
archive_bookmark,
|
||||
unarchive_bookmark,
|
||||
website_loader,
|
||||
)
|
||||
from bookmarks.services.website_loader import WebsiteMetadata
|
||||
from bookmarks.services import assets, bookmarks, auto_tagging, website_loader
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -57,10 +51,12 @@ class BookmarkViewSet(
|
||||
|
||||
def get_serializer_context(self):
|
||||
disable_scraping = "disable_scraping" in self.request.GET
|
||||
disable_html_snapshot = "disable_html_snapshot" in self.request.GET
|
||||
return {
|
||||
"request": self.request,
|
||||
"user": self.request.user,
|
||||
"disable_scraping": disable_scraping,
|
||||
"disable_html_snapshot": disable_html_snapshot,
|
||||
}
|
||||
|
||||
@action(methods=["get"], detail=False)
|
||||
@@ -89,13 +85,13 @@ class BookmarkViewSet(
|
||||
@action(methods=["post"], detail=True)
|
||||
def archive(self, request, pk):
|
||||
bookmark = self.get_object()
|
||||
archive_bookmark(bookmark)
|
||||
bookmarks.archive_bookmark(bookmark)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@action(methods=["post"], detail=True)
|
||||
def unarchive(self, request, pk):
|
||||
bookmark = self.get_object()
|
||||
unarchive_bookmark(bookmark)
|
||||
bookmarks.unarchive_bookmark(bookmark)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@action(methods=["get"], detail=False)
|
||||
@@ -129,6 +125,33 @@ class BookmarkViewSet(
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
@action(methods=["post"], detail=False)
|
||||
def singlefile(self, request):
|
||||
url = request.data.get("url")
|
||||
file = request.FILES.get("file")
|
||||
|
||||
if not url or not file:
|
||||
return Response(
|
||||
{"error": "Both 'url' and 'file' parameters are required."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
bookmark = Bookmark.objects.filter(owner=request.user, url=url).first()
|
||||
|
||||
if not bookmark:
|
||||
bookmark = Bookmark(url=url)
|
||||
bookmark = bookmarks.create_bookmark(
|
||||
bookmark, "", request.user, disable_html_snapshot=True
|
||||
)
|
||||
bookmarks.enhance_with_website_metadata(bookmark)
|
||||
|
||||
assets.upload_snapshot(bookmark, file.read())
|
||||
|
||||
return Response(
|
||||
{"message": "Snapshot uploaded successfully."},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
class TagViewSet(
|
||||
viewsets.GenericViewSet,
|
||||
|
@@ -4,13 +4,10 @@ from rest_framework import serializers
|
||||
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,
|
||||
enhance_with_website_metadata,
|
||||
)
|
||||
from bookmarks.services import bookmarks
|
||||
from bookmarks.services.tags import get_or_create_tag
|
||||
from bookmarks.services.wayback import generate_fallback_webarchive_url
|
||||
from bookmarks.utils import app_version
|
||||
|
||||
|
||||
class TagListField(serializers.ListField):
|
||||
@@ -101,12 +98,20 @@ class BookmarkSerializer(serializers.ModelSerializer):
|
||||
tag_string = build_tag_string(tag_names)
|
||||
bookmark = Bookmark(**validated_data)
|
||||
|
||||
saved_bookmark = create_bookmark(bookmark, tag_string, self.context["user"])
|
||||
disable_scraping = self.context.get("disable_scraping", False)
|
||||
disable_html_snapshot = self.context.get("disable_html_snapshot", False)
|
||||
|
||||
saved_bookmark = bookmarks.create_bookmark(
|
||||
bookmark,
|
||||
tag_string,
|
||||
self.context["user"],
|
||||
disable_html_snapshot=disable_html_snapshot,
|
||||
)
|
||||
# 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)
|
||||
if not disable_scraping:
|
||||
bookmarks.enhance_with_website_metadata(saved_bookmark)
|
||||
return saved_bookmark
|
||||
|
||||
def update(self, instance: Bookmark, validated_data):
|
||||
@@ -117,7 +122,7 @@ class BookmarkSerializer(serializers.ModelSerializer):
|
||||
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"])
|
||||
return bookmarks.update_bookmark(instance, tag_string, self.context["user"])
|
||||
|
||||
def validate(self, attrs):
|
||||
# When creating a bookmark, the service logic prevents duplicate URLs by
|
||||
@@ -163,4 +168,11 @@ class UserProfileSerializer(serializers.ModelSerializer):
|
||||
"display_url",
|
||||
"permanent_notes",
|
||||
"search_preferences",
|
||||
"version",
|
||||
]
|
||||
read_only_fields = ["version"]
|
||||
|
||||
version = serializers.SerializerMethodField()
|
||||
|
||||
def get_version(self, obj: UserProfile):
|
||||
return app_version
|
||||
|
Reference in New Issue
Block a user