mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-07 18:58:30 +02:00
Fix some type hints
This commit is contained in:
@@ -19,6 +19,7 @@ from bookmarks.api.serializers import (
|
||||
)
|
||||
from bookmarks.models import Bookmark, BookmarkAsset, BookmarkSearch, Tag, User
|
||||
from bookmarks.services import assets, bookmarks, auto_tagging, website_loader
|
||||
from bookmarks.type_defs import HttpRequest
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -31,6 +32,7 @@ class BookmarkViewSet(
|
||||
mixins.UpdateModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
):
|
||||
request: HttpRequest
|
||||
serializer_class = BookmarkSerializer
|
||||
|
||||
def get_permissions(self):
|
||||
@@ -73,27 +75,27 @@ class BookmarkViewSet(
|
||||
}
|
||||
|
||||
@action(methods=["get"], detail=False)
|
||||
def archived(self, request):
|
||||
def archived(self, request: HttpRequest):
|
||||
return self.list(request)
|
||||
|
||||
@action(methods=["get"], detail=False)
|
||||
def shared(self, request):
|
||||
def shared(self, request: HttpRequest):
|
||||
return self.list(request)
|
||||
|
||||
@action(methods=["post"], detail=True)
|
||||
def archive(self, request, pk):
|
||||
def archive(self, request: HttpRequest, pk):
|
||||
bookmark = self.get_object()
|
||||
bookmarks.archive_bookmark(bookmark)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@action(methods=["post"], detail=True)
|
||||
def unarchive(self, request, pk):
|
||||
def unarchive(self, request: HttpRequest, pk):
|
||||
bookmark = self.get_object()
|
||||
bookmarks.unarchive_bookmark(bookmark)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
@action(methods=["get"], detail=False)
|
||||
def check(self, request):
|
||||
def check(self, request: HttpRequest):
|
||||
url = request.GET.get("url")
|
||||
bookmark = Bookmark.objects.filter(owner=request.user, url=url).first()
|
||||
existing_bookmark_data = (
|
||||
@@ -124,13 +126,13 @@ class BookmarkViewSet(
|
||||
)
|
||||
|
||||
@action(methods=["post"], detail=False)
|
||||
def singlefile(self, request):
|
||||
def singlefile(self, request: HttpRequest):
|
||||
if settings.LD_DISABLE_ASSET_UPLOAD:
|
||||
return Response(
|
||||
{"error": "Asset upload is disabled."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
url = request.data.get("url")
|
||||
url = request.POST.get("url")
|
||||
file = request.FILES.get("file")
|
||||
|
||||
if not url or not file:
|
||||
@@ -162,6 +164,7 @@ class BookmarkAssetViewSet(
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.DestroyModelMixin,
|
||||
):
|
||||
request: HttpRequest
|
||||
serializer_class = BookmarkAssetSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -177,7 +180,7 @@ class BookmarkAssetViewSet(
|
||||
return {"user": self.request.user}
|
||||
|
||||
@action(detail=True, methods=["get"], url_path="download")
|
||||
def download(self, request, bookmark_id, pk):
|
||||
def download(self, request: HttpRequest, bookmark_id, pk):
|
||||
asset = self.get_object()
|
||||
try:
|
||||
file_path = os.path.join(settings.LD_ASSET_FOLDER, asset.file)
|
||||
@@ -205,7 +208,7 @@ class BookmarkAssetViewSet(
|
||||
return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
@action(methods=["post"], detail=False)
|
||||
def upload(self, request, bookmark_id):
|
||||
def upload(self, request: HttpRequest, bookmark_id):
|
||||
if settings.LD_DISABLE_ASSET_UPLOAD:
|
||||
return Response(
|
||||
{"error": "Asset upload is disabled."},
|
||||
@@ -242,6 +245,7 @@ class TagViewSet(
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
):
|
||||
request: HttpRequest
|
||||
serializer_class = TagSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
@@ -254,7 +258,7 @@ class TagViewSet(
|
||||
|
||||
class UserViewSet(viewsets.GenericViewSet):
|
||||
@action(methods=["get"], detail=False)
|
||||
def profile(self, request):
|
||||
def profile(self, request: HttpRequest):
|
||||
return Response(UserProfileSerializer(request.user.profile).data)
|
||||
|
||||
|
||||
|
@@ -22,6 +22,11 @@ class BookmarkListSerializer(ListSerializer):
|
||||
return super().to_representation(data)
|
||||
|
||||
|
||||
class EmtpyField(serializers.ReadOnlyField):
|
||||
def to_representation(self, value):
|
||||
return None
|
||||
|
||||
|
||||
class BookmarkSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Bookmark
|
||||
@@ -62,8 +67,8 @@ class BookmarkSerializer(serializers.ModelSerializer):
|
||||
preview_image_url = serializers.SerializerMethodField()
|
||||
web_archive_snapshot_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()
|
||||
website_title = EmtpyField()
|
||||
website_description = EmtpyField()
|
||||
|
||||
def get_favicon_url(self, obj: Bookmark):
|
||||
if not obj.favicon_file:
|
||||
@@ -87,12 +92,6 @@ class BookmarkSerializer(serializers.ModelSerializer):
|
||||
|
||||
return generate_fallback_webarchive_url(obj.url, obj.date_added)
|
||||
|
||||
def get_website_title(self, obj: Bookmark):
|
||||
return None
|
||||
|
||||
def get_website_description(self, obj: Bookmark):
|
||||
return None
|
||||
|
||||
def create(self, validated_data):
|
||||
tag_names = validated_data.pop("tag_names", [])
|
||||
tag_string = build_tag_string(tag_names)
|
||||
@@ -185,9 +184,5 @@ class UserProfileSerializer(serializers.ModelSerializer):
|
||||
"search_preferences",
|
||||
"version",
|
||||
]
|
||||
read_only_fields = ["version"]
|
||||
|
||||
version = serializers.SerializerMethodField()
|
||||
|
||||
def get_version(self, obj: UserProfile):
|
||||
return app_version
|
||||
version = serializers.ReadOnlyField(default=app_version)
|
||||
|
@@ -1,6 +1,5 @@
|
||||
from bookmarks import queries
|
||||
from bookmarks.models import BookmarkSearch, Toast
|
||||
from bookmarks import utils
|
||||
from bookmarks.models import Toast
|
||||
|
||||
|
||||
def toasts(request):
|
||||
|
@@ -6,7 +6,6 @@ from typing import List
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.db import models
|
||||
@@ -23,7 +22,7 @@ logger = logging.getLogger(__name__)
|
||||
class Tag(models.Model):
|
||||
name = models.CharField(max_length=64)
|
||||
date_added = models.DateTimeField()
|
||||
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||
owner = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -70,7 +69,7 @@ class Bookmark(models.Model):
|
||||
date_added = models.DateTimeField()
|
||||
date_modified = models.DateTimeField()
|
||||
date_accessed = models.DateTimeField(blank=True, null=True)
|
||||
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||
owner = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
tags = models.ManyToManyField(Tag)
|
||||
|
||||
@property
|
||||
@@ -387,9 +386,7 @@ class UserProfile(models.Model):
|
||||
(TAG_GROUPING_ALPHABETICAL, "Alphabetical"),
|
||||
(TAG_GROUPING_DISABLED, "Disabled"),
|
||||
]
|
||||
user = models.OneToOneField(
|
||||
get_user_model(), related_name="profile", on_delete=models.CASCADE
|
||||
)
|
||||
user = models.OneToOneField(User, related_name="profile", on_delete=models.CASCADE)
|
||||
theme = models.CharField(
|
||||
max_length=10, choices=THEME_CHOICES, blank=False, default=THEME_AUTO
|
||||
)
|
||||
@@ -497,13 +494,13 @@ class UserProfileForm(forms.ModelForm):
|
||||
]
|
||||
|
||||
|
||||
@receiver(post_save, sender=get_user_model())
|
||||
@receiver(post_save, sender=User)
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
UserProfile.objects.create(user=instance)
|
||||
|
||||
|
||||
@receiver(post_save, sender=get_user_model())
|
||||
@receiver(post_save, sender=User)
|
||||
def save_user_profile(sender, instance, **kwargs):
|
||||
instance.profile.save()
|
||||
|
||||
@@ -512,7 +509,7 @@ class Toast(models.Model):
|
||||
key = models.CharField(max_length=50)
|
||||
message = models.TextField()
|
||||
acknowledged = models.BooleanField(default=False)
|
||||
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||
owner = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class FeedToken(models.Model):
|
||||
@@ -522,7 +519,7 @@ class FeedToken(models.Model):
|
||||
|
||||
key = models.CharField(max_length=40, primary_key=True)
|
||||
user = models.OneToOneField(
|
||||
get_user_model(),
|
||||
User,
|
||||
related_name="feed_token",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
@@ -556,7 +553,7 @@ class GlobalSettings(models.Model):
|
||||
default=LANDING_PAGE_LOGIN,
|
||||
)
|
||||
guest_profile_user = models.ForeignKey(
|
||||
get_user_model(), on_delete=models.SET_NULL, null=True, blank=True
|
||||
User, on_delete=models.SET_NULL, null=True, blank=True
|
||||
)
|
||||
enable_link_prefetch = models.BooleanField(default=False, null=False)
|
||||
|
||||
|
@@ -1,10 +1,9 @@
|
||||
import logging
|
||||
from typing import Union
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils import timezone
|
||||
|
||||
from bookmarks.models import Bookmark, parse_tag_string
|
||||
from bookmarks.models import Bookmark, User, parse_tag_string
|
||||
from bookmarks.services import auto_tagging
|
||||
from bookmarks.services import tasks
|
||||
from bookmarks.services import website_loader
|
||||
|
@@ -4,7 +4,6 @@ from typing import List
|
||||
|
||||
import waybackpy
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
from huey import crontab
|
||||
@@ -157,7 +156,7 @@ def schedule_bookmarks_without_favicons(user: User):
|
||||
|
||||
@task()
|
||||
def _schedule_bookmarks_without_favicons_task(user_id: int):
|
||||
user = get_user_model().objects.get(id=user_id)
|
||||
user = User.objects.get(id=user_id)
|
||||
bookmarks = Bookmark.objects.filter(favicon_file__exact="", owner=user)
|
||||
|
||||
# TODO: Implement bulk task creation
|
||||
@@ -173,7 +172,7 @@ def schedule_refresh_favicons(user: User):
|
||||
|
||||
@task()
|
||||
def _schedule_refresh_favicons_task(user_id: int):
|
||||
user = get_user_model().objects.get(id=user_id)
|
||||
user = User.objects.get(id=user_id)
|
||||
bookmarks = Bookmark.objects.filter(owner=user)
|
||||
|
||||
# TODO: Implement bulk task creation
|
||||
@@ -212,7 +211,7 @@ def schedule_bookmarks_without_previews(user: User):
|
||||
|
||||
@task()
|
||||
def _schedule_bookmarks_without_previews_task(user_id: int):
|
||||
user = get_user_model().objects.get(id=user_id)
|
||||
user = User.objects.get(id=user_id)
|
||||
bookmarks = Bookmark.objects.filter(
|
||||
Q(preview_image_file__exact=""),
|
||||
owner=user,
|
||||
|
@@ -10,7 +10,6 @@ from unittest import TestCase
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import override_settings
|
||||
from django.utils import timezone
|
||||
from django.utils.crypto import get_random_string
|
||||
@@ -18,7 +17,7 @@ from rest_framework import status
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from bookmarks.models import Bookmark, BookmarkAsset, Tag
|
||||
from bookmarks.models import Bookmark, BookmarkAsset, Tag, User
|
||||
|
||||
|
||||
class BookmarkFactoryMixin:
|
||||
|
@@ -138,8 +138,7 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
html = response.content.decode()
|
||||
|
||||
self.assertInHTML(
|
||||
'<input type="hidden" name="auto_close" value="true" '
|
||||
'id="id_auto_close">',
|
||||
'<input type="hidden" name="auto_close" value="True" id="id_auto_close">',
|
||||
html,
|
||||
)
|
||||
|
||||
@@ -148,7 +147,8 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
html = response.content.decode()
|
||||
|
||||
self.assertInHTML(
|
||||
'<input type="hidden" name="auto_close" id="id_auto_close">', html
|
||||
'<input type="hidden" name="auto_close" id="id_auto_close">',
|
||||
html,
|
||||
)
|
||||
|
||||
def test_should_redirect_to_index_view(self):
|
||||
@@ -264,7 +264,6 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
html = response.content.decode()
|
||||
|
||||
self.assertInHTML(
|
||||
'<input type="checkbox" name="unread" value="true" '
|
||||
'id="id_unread" checked="">',
|
||||
'<input type="checkbox" name="unread" id="id_unread" checked="">',
|
||||
html,
|
||||
)
|
||||
|
@@ -1,12 +1,10 @@
|
||||
import datetime
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
from bookmarks.models import BookmarkForm, Bookmark
|
||||
|
||||
User = get_user_model()
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
|
||||
ENABLED_URL_VALIDATION_TEST_CASES = [
|
||||
("thisisnotavalidurl", False),
|
||||
@@ -29,12 +27,10 @@ DISABLED_URL_VALIDATION_TEST_CASES = [
|
||||
]
|
||||
|
||||
|
||||
class BookmarkValidationTestCase(TestCase):
|
||||
class BookmarkValidationTestCase(TestCase, BookmarkFactoryMixin):
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.user = User.objects.create_user(
|
||||
"testuser", "test@example.com", "password123"
|
||||
)
|
||||
self.get_or_create_test_user()
|
||||
|
||||
def test_bookmark_model_should_not_allow_missing_url(self):
|
||||
bookmark = Bookmark(
|
||||
|
@@ -1,6 +1,5 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
@@ -25,8 +24,6 @@ from bookmarks.services.bookmarks import (
|
||||
)
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
|
||||
@@ -270,9 +267,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertTrue(Bookmark.objects.get(id=bookmark3.id).is_archived)
|
||||
|
||||
def test_archive_bookmarks_should_only_archive_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark()
|
||||
bookmark2 = self.setup_bookmark()
|
||||
inaccessible_bookmark = self.setup_bookmark(user=other_user)
|
||||
@@ -327,9 +322,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertFalse(Bookmark.objects.get(id=bookmark3.id).is_archived)
|
||||
|
||||
def test_unarchive_bookmarks_should_only_unarchive_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark(is_archived=True)
|
||||
bookmark2 = self.setup_bookmark(is_archived=True)
|
||||
inaccessible_bookmark = self.setup_bookmark(is_archived=True, user=other_user)
|
||||
@@ -382,9 +375,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertIsNone(Bookmark.objects.filter(id=bookmark3.id).first())
|
||||
|
||||
def test_delete_bookmarks_should_only_delete_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark()
|
||||
bookmark2 = self.setup_bookmark()
|
||||
inaccessible_bookmark = self.setup_bookmark(user=other_user)
|
||||
@@ -508,9 +499,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertCountEqual(bookmark3.tags.all(), [tag1, tag2])
|
||||
|
||||
def test_tag_bookmarks_should_only_tag_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark()
|
||||
bookmark2 = self.setup_bookmark()
|
||||
inaccessible_bookmark = self.setup_bookmark(user=other_user)
|
||||
@@ -591,9 +580,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertCountEqual(bookmark3.tags.all(), [])
|
||||
|
||||
def test_untag_bookmarks_should_only_tag_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
tag1 = self.setup_tag()
|
||||
tag2 = self.setup_tag()
|
||||
bookmark1 = self.setup_bookmark(tags=[tag1, tag2])
|
||||
@@ -658,9 +645,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertFalse(Bookmark.objects.get(id=bookmark3.id).unread)
|
||||
|
||||
def test_mark_bookmarks_as_read_should_only_update_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark(unread=True)
|
||||
bookmark2 = self.setup_bookmark(unread=True)
|
||||
inaccessible_bookmark = self.setup_bookmark(unread=True, user=other_user)
|
||||
@@ -715,9 +700,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertTrue(Bookmark.objects.get(id=bookmark3.id).unread)
|
||||
|
||||
def test_mark_bookmarks_as_unread_should_only_update_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark(unread=False)
|
||||
bookmark2 = self.setup_bookmark(unread=False)
|
||||
inaccessible_bookmark = self.setup_bookmark(unread=False, user=other_user)
|
||||
@@ -770,9 +753,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertTrue(Bookmark.objects.get(id=bookmark3.id).shared)
|
||||
|
||||
def test_share_bookmarks_should_only_update_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark(shared=False)
|
||||
bookmark2 = self.setup_bookmark(shared=False)
|
||||
inaccessible_bookmark = self.setup_bookmark(shared=False, user=other_user)
|
||||
@@ -825,9 +806,7 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertFalse(Bookmark.objects.get(id=bookmark3.id).shared)
|
||||
|
||||
def test_unshare_bookmarks_should_only_update_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
bookmark1 = self.setup_bookmark(shared=True)
|
||||
bookmark2 = self.setup_bookmark(shared=True)
|
||||
inaccessible_bookmark = self.setup_bookmark(shared=True, user=other_user)
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import operator
|
||||
import datetime
|
||||
import operator
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db.models import QuerySet
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
@@ -11,8 +10,6 @@ from bookmarks.models import BookmarkSearch, UserProfile
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin, random_sentence
|
||||
from bookmarks.utils import unique
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
def setUp(self):
|
||||
@@ -372,9 +369,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertQueryResult(query, [[bookmark1, bookmark2]])
|
||||
|
||||
def test_query_bookmarks_should_only_return_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
owned_bookmarks = [
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark(),
|
||||
@@ -389,9 +384,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertQueryResult(query, [owned_bookmarks])
|
||||
|
||||
def test_query_archived_bookmarks_should_only_return_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
owned_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True),
|
||||
@@ -828,9 +821,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertQueryResult(query, [[tag]])
|
||||
|
||||
def test_query_bookmark_tags_should_only_return_user_owned_tags(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
owned_bookmarks = [
|
||||
self.setup_bookmark(tags=[self.setup_tag()]),
|
||||
self.setup_bookmark(tags=[self.setup_tag()]),
|
||||
@@ -847,9 +838,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertQueryResult(query, [self.get_tags_from_bookmarks(owned_bookmarks)])
|
||||
|
||||
def test_query_archived_bookmark_tags_should_only_return_user_owned_tags(self):
|
||||
other_user = User.objects.create_user(
|
||||
"otheruser", "otheruser@example.com", "password123"
|
||||
)
|
||||
other_user = self.setup_user()
|
||||
owned_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True, tags=[self.setup_tag()]),
|
||||
self.setup_bookmark(is_archived=True, tags=[self.setup_tag()]),
|
||||
|
@@ -1,21 +1,17 @@
|
||||
import datetime
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from bookmarks.models import Tag
|
||||
from bookmarks.services.tags import get_or_create_tag, get_or_create_tags
|
||||
|
||||
User = get_user_model()
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
|
||||
|
||||
class TagServiceTestCase(TestCase):
|
||||
class TagServiceTestCase(TestCase, BookmarkFactoryMixin):
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.user = User.objects.create_user(
|
||||
"testuser", "test@example.com", "password123"
|
||||
)
|
||||
self.get_or_create_test_user()
|
||||
|
||||
def test_get_or_create_tag_should_create_new_tag(self):
|
||||
get_or_create_tag("Book", self.user)
|
||||
|
14
bookmarks/type_defs.py
Normal file
14
bookmarks/type_defs.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
Stuff in here is only used for type hints
|
||||
"""
|
||||
|
||||
from django import http
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
|
||||
from bookmarks.models import GlobalSettings, UserProfile, User
|
||||
|
||||
|
||||
class HttpRequest(http.HttpRequest):
|
||||
global_settings: GlobalSettings
|
||||
user_profile: UserProfile
|
||||
user: User | AnonymousUser
|
@@ -36,12 +36,13 @@ from bookmarks.services.bookmarks import (
|
||||
share_bookmarks,
|
||||
unshare_bookmarks,
|
||||
)
|
||||
from bookmarks.type_defs import HttpRequest
|
||||
from bookmarks.utils import get_safe_return_url
|
||||
from bookmarks.views import contexts, partials, turbo
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
def index(request: HttpRequest):
|
||||
if request.method == "POST":
|
||||
return search_action(request)
|
||||
|
||||
@@ -63,7 +64,7 @@ def index(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def archived(request):
|
||||
def archived(request: HttpRequest):
|
||||
if request.method == "POST":
|
||||
return search_action(request)
|
||||
|
||||
@@ -84,7 +85,7 @@ def archived(request):
|
||||
)
|
||||
|
||||
|
||||
def shared(request):
|
||||
def shared(request: HttpRequest):
|
||||
if request.method == "POST":
|
||||
return search_action(request)
|
||||
|
||||
@@ -110,7 +111,7 @@ def shared(request):
|
||||
)
|
||||
|
||||
|
||||
def render_bookmarks_view(request, template_name, context):
|
||||
def render_bookmarks_view(request: HttpRequest, template_name, context):
|
||||
if turbo.is_frame(request, "details-modal"):
|
||||
return render(
|
||||
request,
|
||||
@@ -125,7 +126,7 @@ def render_bookmarks_view(request, template_name, context):
|
||||
)
|
||||
|
||||
|
||||
def search_action(request):
|
||||
def search_action(request: HttpRequest):
|
||||
if "save" in request.POST:
|
||||
if not request.user.is_authenticated:
|
||||
return HttpResponseForbidden()
|
||||
@@ -151,13 +152,8 @@ def convert_tag_string(tag_string: str):
|
||||
|
||||
|
||||
@login_required
|
||||
def new(request):
|
||||
initial_url = request.GET.get("url")
|
||||
initial_title = request.GET.get("title")
|
||||
initial_description = request.GET.get("description")
|
||||
initial_notes = request.GET.get("notes")
|
||||
initial_auto_close = "auto_close" in request.GET
|
||||
initial_mark_unread = request.user.profile.default_mark_unread
|
||||
def new(request: HttpRequest):
|
||||
initial_auto_close = True if "auto_close" in request.GET else None
|
||||
|
||||
if request.method == "POST":
|
||||
form = BookmarkForm(request.POST)
|
||||
@@ -171,19 +167,16 @@ def new(request):
|
||||
else:
|
||||
return HttpResponseRedirect(reverse("linkding:bookmarks.index"))
|
||||
else:
|
||||
form = BookmarkForm()
|
||||
if initial_url:
|
||||
form.initial["url"] = initial_url
|
||||
if initial_title:
|
||||
form.initial["title"] = initial_title
|
||||
if initial_description:
|
||||
form.initial["description"] = initial_description
|
||||
if initial_notes:
|
||||
form.initial["notes"] = initial_notes
|
||||
if initial_auto_close:
|
||||
form.initial["auto_close"] = "true"
|
||||
if initial_mark_unread:
|
||||
form.initial["unread"] = "true"
|
||||
form = BookmarkForm(
|
||||
initial={
|
||||
"url": request.GET.get("url"),
|
||||
"title": request.GET.get("title"),
|
||||
"description": request.GET.get("description"),
|
||||
"notes": request.GET.get("notes"),
|
||||
"auto_close": initial_auto_close,
|
||||
"unread": request.user_profile.default_mark_unread,
|
||||
}
|
||||
)
|
||||
|
||||
status = 422 if request.method == "POST" and not form.is_valid() else 200
|
||||
context = {
|
||||
@@ -196,7 +189,7 @@ def new(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def edit(request, bookmark_id: int):
|
||||
def edit(request: HttpRequest, bookmark_id: int):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -214,7 +207,7 @@ def edit(request, bookmark_id: int):
|
||||
else:
|
||||
form = BookmarkForm(instance=bookmark)
|
||||
|
||||
form.initial["tag_string"] = build_tag_string(bookmark.tag_names, " ")
|
||||
form.fields["tag_string"].initial = build_tag_string(bookmark.tag_names, " ")
|
||||
|
||||
status = 422 if request.method == "POST" and not form.is_valid() else 200
|
||||
context = {"form": form, "bookmark_id": bookmark_id, "return_url": return_url}
|
||||
@@ -222,7 +215,7 @@ def edit(request, bookmark_id: int):
|
||||
return render(request, "bookmarks/edit.html", context, status=status)
|
||||
|
||||
|
||||
def remove(request, bookmark_id: int):
|
||||
def remove(request: HttpRequest, bookmark_id: int | str):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -231,7 +224,7 @@ def remove(request, bookmark_id: int):
|
||||
bookmark.delete()
|
||||
|
||||
|
||||
def archive(request, bookmark_id: int):
|
||||
def archive(request: HttpRequest, bookmark_id: int | str):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -240,7 +233,7 @@ def archive(request, bookmark_id: int):
|
||||
archive_bookmark(bookmark)
|
||||
|
||||
|
||||
def unarchive(request, bookmark_id: int):
|
||||
def unarchive(request: HttpRequest, bookmark_id: int | str):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -249,7 +242,7 @@ def unarchive(request, bookmark_id: int):
|
||||
unarchive_bookmark(bookmark)
|
||||
|
||||
|
||||
def unshare(request, bookmark_id: int):
|
||||
def unshare(request: HttpRequest, bookmark_id: int | str):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -259,7 +252,7 @@ def unshare(request, bookmark_id: int):
|
||||
bookmark.save()
|
||||
|
||||
|
||||
def mark_as_read(request, bookmark_id: int):
|
||||
def mark_as_read(request: HttpRequest, bookmark_id: int | str):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -269,7 +262,7 @@ def mark_as_read(request, bookmark_id: int):
|
||||
bookmark.save()
|
||||
|
||||
|
||||
def create_html_snapshot(request, bookmark_id: int):
|
||||
def create_html_snapshot(request: HttpRequest, bookmark_id: int | str):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -278,7 +271,7 @@ def create_html_snapshot(request, bookmark_id: int):
|
||||
tasks.create_html_snapshot(bookmark)
|
||||
|
||||
|
||||
def upload_asset(request, bookmark_id: int):
|
||||
def upload_asset(request: HttpRequest, bookmark_id: int | str):
|
||||
if settings.LD_DISABLE_ASSET_UPLOAD:
|
||||
return HttpResponseForbidden("Asset upload is disabled")
|
||||
|
||||
@@ -294,7 +287,7 @@ def upload_asset(request, bookmark_id: int):
|
||||
asset_actions.upload_asset(bookmark, file)
|
||||
|
||||
|
||||
def remove_asset(request, asset_id: int):
|
||||
def remove_asset(request: HttpRequest, asset_id: int | str):
|
||||
try:
|
||||
asset = BookmarkAsset.objects.get(pk=asset_id, bookmark__owner=request.user)
|
||||
except BookmarkAsset.DoesNotExist:
|
||||
@@ -303,7 +296,7 @@ def remove_asset(request, asset_id: int):
|
||||
asset.delete()
|
||||
|
||||
|
||||
def update_state(request, bookmark_id: int):
|
||||
def update_state(request: HttpRequest, bookmark_id: int | str):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
@@ -316,7 +309,7 @@ def update_state(request, bookmark_id: int):
|
||||
|
||||
|
||||
@login_required
|
||||
def index_action(request):
|
||||
def index_action(request: HttpRequest):
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
query = queries.query_bookmarks(request.user, request.user_profile, search)
|
||||
|
||||
@@ -331,7 +324,7 @@ def index_action(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def archived_action(request):
|
||||
def archived_action(request: HttpRequest):
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
query = queries.query_archived_bookmarks(request.user, request.user_profile, search)
|
||||
|
||||
@@ -346,7 +339,7 @@ def archived_action(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def shared_action(request):
|
||||
def shared_action(request: HttpRequest):
|
||||
if "bulk_execute" in request.POST:
|
||||
return HttpResponseBadRequest("View does not support bulk actions")
|
||||
|
||||
@@ -360,7 +353,7 @@ def shared_action(request):
|
||||
return utils.redirect_with_query(request, reverse("linkding:bookmarks.shared"))
|
||||
|
||||
|
||||
def handle_action(request, query: QuerySet[Bookmark] = None):
|
||||
def handle_action(request: HttpRequest, query: QuerySet[Bookmark] = None):
|
||||
# Single bookmark actions
|
||||
if "archive" in request.POST:
|
||||
return archive(request, request.POST["archive"])
|
||||
@@ -421,5 +414,5 @@ def handle_action(request, query: QuerySet[Bookmark] = None):
|
||||
|
||||
|
||||
@login_required
|
||||
def close(request):
|
||||
def close(request: HttpRequest):
|
||||
return render(request, "bookmarks/close.html")
|
||||
|
@@ -3,7 +3,6 @@ import urllib.parse
|
||||
from typing import Set, List
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.core.paginator import Paginator
|
||||
from django.db import models
|
||||
from django.http import Http404
|
||||
@@ -20,6 +19,7 @@ from bookmarks.models import (
|
||||
Tag,
|
||||
)
|
||||
from bookmarks.services.wayback import generate_fallback_webarchive_url
|
||||
from bookmarks.type_defs import HttpRequest
|
||||
|
||||
CJK_RE = re.compile(r"[\u4e00-\u9fff]+")
|
||||
|
||||
@@ -28,7 +28,7 @@ class RequestContext:
|
||||
index_view = "linkding:bookmarks.index"
|
||||
action_view = "linkding:bookmarks.index.action"
|
||||
|
||||
def __init__(self, request: WSGIRequest):
|
||||
def __init__(self, request: HttpRequest):
|
||||
self.request = request
|
||||
self.index_url = reverse(self.index_view)
|
||||
self.action_url = reverse(self.action_view)
|
||||
@@ -168,7 +168,7 @@ class BookmarkItem:
|
||||
class BookmarkListContext:
|
||||
request_context = RequestContext
|
||||
|
||||
def __init__(self, request: WSGIRequest) -> None:
|
||||
def __init__(self, request: HttpRequest) -> None:
|
||||
request_context = self.request_context(request)
|
||||
user = request.user
|
||||
user_profile = request.user_profile
|
||||
@@ -305,7 +305,7 @@ class TagGroup:
|
||||
class TagCloudContext:
|
||||
request_context = RequestContext
|
||||
|
||||
def __init__(self, request: WSGIRequest) -> None:
|
||||
def __init__(self, request: HttpRequest) -> None:
|
||||
request_context = self.request_context(request)
|
||||
user_profile = request.user_profile
|
||||
|
||||
@@ -381,7 +381,7 @@ class BookmarkAssetItem:
|
||||
class BookmarkDetailsContext:
|
||||
request_context = RequestContext
|
||||
|
||||
def __init__(self, request: WSGIRequest, bookmark: Bookmark):
|
||||
def __init__(self, request: HttpRequest, bookmark: Bookmark):
|
||||
request_context = self.request_context(request)
|
||||
|
||||
user = request.user
|
||||
@@ -437,7 +437,7 @@ class SharedBookmarkDetailsContext(BookmarkDetailsContext):
|
||||
|
||||
|
||||
def get_details_context(
|
||||
request: WSGIRequest, context_type
|
||||
request: HttpRequest, context_type
|
||||
) -> BookmarkDetailsContext | None:
|
||||
bookmark_id = request.GET.get("details")
|
||||
if not bookmark_id:
|
||||
|
@@ -22,13 +22,14 @@ from bookmarks.models import (
|
||||
)
|
||||
from bookmarks.services import exporter, tasks
|
||||
from bookmarks.services import importer
|
||||
from bookmarks.type_defs import HttpRequest
|
||||
from bookmarks.utils import app_version
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@login_required
|
||||
def general(request, status=200, context_overrides=None):
|
||||
def general(request: HttpRequest, status=200, context_overrides=None):
|
||||
enable_refresh_favicons = django_settings.LD_ENABLE_REFRESH_FAVICONS
|
||||
has_snapshot_support = django_settings.LD_ENABLE_SNAPSHOTS
|
||||
success_message = _find_message_with_tag(
|
||||
@@ -65,7 +66,7 @@ def general(request, status=200, context_overrides=None):
|
||||
|
||||
|
||||
@login_required
|
||||
def update(request):
|
||||
def update(request: HttpRequest):
|
||||
if request.method == "POST":
|
||||
if "update_profile" in request.POST:
|
||||
return update_profile(request)
|
||||
@@ -97,7 +98,7 @@ def update(request):
|
||||
return HttpResponseRedirect(reverse("linkding:settings.general"))
|
||||
|
||||
|
||||
def update_profile(request):
|
||||
def update_profile(request: HttpRequest):
|
||||
user = request.user
|
||||
profile = user.profile
|
||||
favicons_were_enabled = profile.enable_favicons
|
||||
@@ -195,7 +196,7 @@ def integrations(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def bookmark_import(request):
|
||||
def bookmark_import(request: HttpRequest):
|
||||
import_file = request.FILES.get("import_file")
|
||||
import_options = importer.ImportOptions(
|
||||
map_private_flag=request.POST.get("map_private_flag") == "on"
|
||||
@@ -230,13 +231,13 @@ def bookmark_import(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def bookmark_export(request):
|
||||
def bookmark_export(request: HttpRequest):
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
bookmarks = Bookmark.objects.filter(owner=request.user)
|
||||
# Prefetch tags to prevent n+1 queries
|
||||
prefetch_related_objects(bookmarks, "tags")
|
||||
file_content = exporter.export_netscape_html(bookmarks)
|
||||
file_content = exporter.export_netscape_html(list(bookmarks))
|
||||
|
||||
response = HttpResponse(content_type="text/plain; charset=UTF-8")
|
||||
response["Content-Disposition"] = 'attachment; filename="bookmarks.html"'
|
||||
|
Reference in New Issue
Block a user