mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-13 21:49:26 +02:00
Add black code formatter
This commit is contained in:
@@ -2,15 +2,32 @@ import urllib.parse
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import QuerySet
|
||||
from django.http import HttpResponseRedirect, Http404, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.http import (
|
||||
HttpResponseRedirect,
|
||||
Http404,
|
||||
HttpResponseBadRequest,
|
||||
HttpResponseForbidden,
|
||||
)
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
|
||||
from bookmarks import queries
|
||||
from bookmarks.models import Bookmark, BookmarkForm, BookmarkSearch, build_tag_string
|
||||
from bookmarks.services.bookmarks import create_bookmark, update_bookmark, archive_bookmark, archive_bookmarks, \
|
||||
unarchive_bookmark, unarchive_bookmarks, delete_bookmarks, tag_bookmarks, untag_bookmarks, mark_bookmarks_as_read, \
|
||||
mark_bookmarks_as_unread, share_bookmarks, unshare_bookmarks
|
||||
from bookmarks.services.bookmarks import (
|
||||
create_bookmark,
|
||||
update_bookmark,
|
||||
archive_bookmark,
|
||||
archive_bookmarks,
|
||||
unarchive_bookmark,
|
||||
unarchive_bookmarks,
|
||||
delete_bookmarks,
|
||||
tag_bookmarks,
|
||||
untag_bookmarks,
|
||||
mark_bookmarks_as_read,
|
||||
mark_bookmarks_as_unread,
|
||||
share_bookmarks,
|
||||
unshare_bookmarks,
|
||||
)
|
||||
from bookmarks.utils import get_safe_return_url
|
||||
from bookmarks.views.partials import contexts
|
||||
|
||||
@@ -19,47 +36,57 @@ _default_page_size = 30
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
return search_action(request)
|
||||
|
||||
bookmark_list = contexts.ActiveBookmarkListContext(request)
|
||||
tag_cloud = contexts.ActiveTagCloudContext(request)
|
||||
return render(request, 'bookmarks/index.html', {
|
||||
'bookmark_list': bookmark_list,
|
||||
'tag_cloud': tag_cloud,
|
||||
})
|
||||
return render(
|
||||
request,
|
||||
"bookmarks/index.html",
|
||||
{
|
||||
"bookmark_list": bookmark_list,
|
||||
"tag_cloud": tag_cloud,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def archived(request):
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
return search_action(request)
|
||||
|
||||
bookmark_list = contexts.ArchivedBookmarkListContext(request)
|
||||
tag_cloud = contexts.ArchivedTagCloudContext(request)
|
||||
return render(request, 'bookmarks/archive.html', {
|
||||
'bookmark_list': bookmark_list,
|
||||
'tag_cloud': tag_cloud,
|
||||
})
|
||||
return render(
|
||||
request,
|
||||
"bookmarks/archive.html",
|
||||
{
|
||||
"bookmark_list": bookmark_list,
|
||||
"tag_cloud": tag_cloud,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def shared(request):
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
return search_action(request)
|
||||
|
||||
bookmark_list = contexts.SharedBookmarkListContext(request)
|
||||
tag_cloud = contexts.SharedTagCloudContext(request)
|
||||
public_only = not request.user.is_authenticated
|
||||
users = queries.query_shared_bookmark_users(request.user_profile, bookmark_list.search, public_only)
|
||||
return render(request, 'bookmarks/shared.html', {
|
||||
'bookmark_list': bookmark_list,
|
||||
'tag_cloud': tag_cloud,
|
||||
'users': users
|
||||
})
|
||||
users = queries.query_shared_bookmark_users(
|
||||
request.user_profile, bookmark_list.search, public_only
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
"bookmarks/shared.html",
|
||||
{"bookmark_list": bookmark_list, "tag_cloud": tag_cloud, "users": users},
|
||||
)
|
||||
|
||||
|
||||
def search_action(request):
|
||||
if 'save' in request.POST:
|
||||
if "save" in request.POST:
|
||||
if not request.user.is_authenticated:
|
||||
return HttpResponseForbidden()
|
||||
search = BookmarkSearch.from_request(request.POST)
|
||||
@@ -67,56 +94,58 @@ def search_action(request):
|
||||
request.user_profile.save()
|
||||
|
||||
# redirect to base url including new query params
|
||||
search = BookmarkSearch.from_request(request.POST, request.user_profile.search_preferences)
|
||||
search = BookmarkSearch.from_request(
|
||||
request.POST, request.user_profile.search_preferences
|
||||
)
|
||||
base_url = request.path
|
||||
query_params = search.query_params
|
||||
query_string = urllib.parse.urlencode(query_params)
|
||||
url = base_url if not query_string else base_url + '?' + query_string
|
||||
url = base_url if not query_string else base_url + "?" + query_string
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
def convert_tag_string(tag_string: str):
|
||||
# Tag strings coming from inputs are space-separated, however services.bookmarks functions expect comma-separated
|
||||
# strings
|
||||
return tag_string.replace(' ', ',')
|
||||
return tag_string.replace(" ", ",")
|
||||
|
||||
|
||||
@login_required
|
||||
def new(request):
|
||||
initial_url = request.GET.get('url')
|
||||
initial_title = request.GET.get('title')
|
||||
initial_description = request.GET.get('description')
|
||||
initial_auto_close = 'auto_close' in request.GET
|
||||
initial_url = request.GET.get("url")
|
||||
initial_title = request.GET.get("title")
|
||||
initial_description = request.GET.get("description")
|
||||
initial_auto_close = "auto_close" in request.GET
|
||||
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
form = BookmarkForm(request.POST)
|
||||
auto_close = form.data['auto_close']
|
||||
auto_close = form.data["auto_close"]
|
||||
if form.is_valid():
|
||||
current_user = request.user
|
||||
tag_string = convert_tag_string(form.data['tag_string'])
|
||||
tag_string = convert_tag_string(form.data["tag_string"])
|
||||
create_bookmark(form.save(commit=False), tag_string, current_user)
|
||||
if auto_close:
|
||||
return HttpResponseRedirect(reverse('bookmarks:close'))
|
||||
return HttpResponseRedirect(reverse("bookmarks:close"))
|
||||
else:
|
||||
return HttpResponseRedirect(reverse('bookmarks:index'))
|
||||
return HttpResponseRedirect(reverse("bookmarks:index"))
|
||||
else:
|
||||
form = BookmarkForm()
|
||||
if initial_url:
|
||||
form.initial['url'] = initial_url
|
||||
form.initial["url"] = initial_url
|
||||
if initial_title:
|
||||
form.initial['title'] = initial_title
|
||||
form.initial["title"] = initial_title
|
||||
if initial_description:
|
||||
form.initial['description'] = initial_description
|
||||
form.initial["description"] = initial_description
|
||||
if initial_auto_close:
|
||||
form.initial['auto_close'] = 'true'
|
||||
form.initial["auto_close"] = "true"
|
||||
|
||||
context = {
|
||||
'form': form,
|
||||
'auto_close': initial_auto_close,
|
||||
'return_url': reverse('bookmarks:index')
|
||||
"form": form,
|
||||
"auto_close": initial_auto_close,
|
||||
"return_url": reverse("bookmarks:index"),
|
||||
}
|
||||
|
||||
return render(request, 'bookmarks/new.html', context)
|
||||
return render(request, "bookmarks/new.html", context)
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -124,34 +153,32 @@ def edit(request, bookmark_id: int):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
raise Http404('Bookmark does not exist')
|
||||
return_url = get_safe_return_url(request.GET.get('return_url'), reverse('bookmarks:index'))
|
||||
raise Http404("Bookmark does not exist")
|
||||
return_url = get_safe_return_url(
|
||||
request.GET.get("return_url"), reverse("bookmarks:index")
|
||||
)
|
||||
|
||||
if request.method == 'POST':
|
||||
if request.method == "POST":
|
||||
form = BookmarkForm(request.POST, instance=bookmark)
|
||||
if form.is_valid():
|
||||
tag_string = convert_tag_string(form.data['tag_string'])
|
||||
tag_string = convert_tag_string(form.data["tag_string"])
|
||||
update_bookmark(form.save(commit=False), tag_string, request.user)
|
||||
return HttpResponseRedirect(return_url)
|
||||
else:
|
||||
form = BookmarkForm(instance=bookmark)
|
||||
|
||||
form.initial['tag_string'] = build_tag_string(bookmark.tag_names, ' ')
|
||||
form.initial["tag_string"] = build_tag_string(bookmark.tag_names, " ")
|
||||
|
||||
context = {
|
||||
'form': form,
|
||||
'bookmark_id': bookmark_id,
|
||||
'return_url': return_url
|
||||
}
|
||||
context = {"form": form, "bookmark_id": bookmark_id, "return_url": return_url}
|
||||
|
||||
return render(request, 'bookmarks/edit.html', context)
|
||||
return render(request, "bookmarks/edit.html", context)
|
||||
|
||||
|
||||
def remove(request, bookmark_id: int):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
raise Http404('Bookmark does not exist')
|
||||
raise Http404("Bookmark does not exist")
|
||||
|
||||
bookmark.delete()
|
||||
|
||||
@@ -160,7 +187,7 @@ def archive(request, bookmark_id: int):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
raise Http404('Bookmark does not exist')
|
||||
raise Http404("Bookmark does not exist")
|
||||
|
||||
archive_bookmark(bookmark)
|
||||
|
||||
@@ -169,7 +196,7 @@ def unarchive(request, bookmark_id: int):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
raise Http404('Bookmark does not exist')
|
||||
raise Http404("Bookmark does not exist")
|
||||
|
||||
unarchive_bookmark(bookmark)
|
||||
|
||||
@@ -178,7 +205,7 @@ def unshare(request, bookmark_id: int):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
raise Http404('Bookmark does not exist')
|
||||
raise Http404("Bookmark does not exist")
|
||||
|
||||
bookmark.shared = False
|
||||
bookmark.save()
|
||||
@@ -188,7 +215,7 @@ def mark_as_read(request, bookmark_id: int):
|
||||
try:
|
||||
bookmark = Bookmark.objects.get(pk=bookmark_id, owner=request.user)
|
||||
except Bookmark.DoesNotExist:
|
||||
raise Http404('Bookmark does not exist')
|
||||
raise Http404("Bookmark does not exist")
|
||||
|
||||
bookmark.unread = False
|
||||
bookmark.save()
|
||||
@@ -215,57 +242,59 @@ def shared_action(request):
|
||||
|
||||
def action(request, query: QuerySet[Bookmark] = None):
|
||||
# Single bookmark actions
|
||||
if 'archive' in request.POST:
|
||||
archive(request, request.POST['archive'])
|
||||
if 'unarchive' in request.POST:
|
||||
unarchive(request, request.POST['unarchive'])
|
||||
if 'remove' in request.POST:
|
||||
remove(request, request.POST['remove'])
|
||||
if 'mark_as_read' in request.POST:
|
||||
mark_as_read(request, request.POST['mark_as_read'])
|
||||
if 'unshare' in request.POST:
|
||||
unshare(request, request.POST['unshare'])
|
||||
if "archive" in request.POST:
|
||||
archive(request, request.POST["archive"])
|
||||
if "unarchive" in request.POST:
|
||||
unarchive(request, request.POST["unarchive"])
|
||||
if "remove" in request.POST:
|
||||
remove(request, request.POST["remove"])
|
||||
if "mark_as_read" in request.POST:
|
||||
mark_as_read(request, request.POST["mark_as_read"])
|
||||
if "unshare" in request.POST:
|
||||
unshare(request, request.POST["unshare"])
|
||||
|
||||
# Bulk actions
|
||||
if 'bulk_execute' in request.POST:
|
||||
if "bulk_execute" in request.POST:
|
||||
if query is None:
|
||||
return HttpResponseBadRequest('View does not support bulk actions')
|
||||
return HttpResponseBadRequest("View does not support bulk actions")
|
||||
|
||||
bulk_action = request.POST['bulk_action']
|
||||
bulk_action = request.POST["bulk_action"]
|
||||
|
||||
# Determine set of bookmarks
|
||||
if request.POST.get('bulk_select_across') == 'on':
|
||||
if request.POST.get("bulk_select_across") == "on":
|
||||
# Query full list of bookmarks across all pages
|
||||
bookmark_ids = query.only('id').values_list('id', flat=True)
|
||||
bookmark_ids = query.only("id").values_list("id", flat=True)
|
||||
else:
|
||||
# Use only selected bookmarks
|
||||
bookmark_ids = request.POST.getlist('bookmark_id')
|
||||
bookmark_ids = request.POST.getlist("bookmark_id")
|
||||
|
||||
if 'bulk_archive' == bulk_action:
|
||||
if "bulk_archive" == bulk_action:
|
||||
archive_bookmarks(bookmark_ids, request.user)
|
||||
if 'bulk_unarchive' == bulk_action:
|
||||
if "bulk_unarchive" == bulk_action:
|
||||
unarchive_bookmarks(bookmark_ids, request.user)
|
||||
if 'bulk_delete' == bulk_action:
|
||||
if "bulk_delete" == bulk_action:
|
||||
delete_bookmarks(bookmark_ids, request.user)
|
||||
if 'bulk_tag' == bulk_action:
|
||||
tag_string = convert_tag_string(request.POST['bulk_tag_string'])
|
||||
if "bulk_tag" == bulk_action:
|
||||
tag_string = convert_tag_string(request.POST["bulk_tag_string"])
|
||||
tag_bookmarks(bookmark_ids, tag_string, request.user)
|
||||
if 'bulk_untag' == bulk_action:
|
||||
tag_string = convert_tag_string(request.POST['bulk_tag_string'])
|
||||
if "bulk_untag" == bulk_action:
|
||||
tag_string = convert_tag_string(request.POST["bulk_tag_string"])
|
||||
untag_bookmarks(bookmark_ids, tag_string, request.user)
|
||||
if 'bulk_read' == bulk_action:
|
||||
if "bulk_read" == bulk_action:
|
||||
mark_bookmarks_as_read(bookmark_ids, request.user)
|
||||
if 'bulk_unread' == bulk_action:
|
||||
if "bulk_unread" == bulk_action:
|
||||
mark_bookmarks_as_unread(bookmark_ids, request.user)
|
||||
if 'bulk_share' == bulk_action:
|
||||
if "bulk_share" == bulk_action:
|
||||
share_bookmarks(bookmark_ids, request.user)
|
||||
if 'bulk_unshare' == bulk_action:
|
||||
if "bulk_unshare" == bulk_action:
|
||||
unshare_bookmarks(bookmark_ids, request.user)
|
||||
|
||||
return_url = get_safe_return_url(request.GET.get('return_url'), reverse('bookmarks:index'))
|
||||
return_url = get_safe_return_url(
|
||||
request.GET.get("return_url"), reverse("bookmarks:index")
|
||||
)
|
||||
return HttpResponseRedirect(return_url)
|
||||
|
||||
|
||||
@login_required
|
||||
def close(request):
|
||||
return render(request, 'bookmarks/close.html')
|
||||
return render(request, "bookmarks/close.html")
|
||||
|
@@ -6,15 +6,12 @@ from bookmarks.views.settings import app_version
|
||||
|
||||
def health(request):
|
||||
code = 200
|
||||
response = {
|
||||
'version': app_version,
|
||||
'status': 'healthy'
|
||||
}
|
||||
response = {"version": app_version, "status": "healthy"}
|
||||
|
||||
try:
|
||||
connections['default'].ensure_connection()
|
||||
connections["default"].ensure_connection()
|
||||
except Exception:
|
||||
response['status'] = 'unhealthy'
|
||||
response["status"] = "unhealthy"
|
||||
code = 500
|
||||
|
||||
return JsonResponse(response, status=code)
|
||||
|
@@ -7,7 +7,7 @@ def manifest(request):
|
||||
"short_name": "linkding",
|
||||
"start_url": "bookmarks",
|
||||
"display": "standalone",
|
||||
"scope": "/" + settings.LD_CONTEXT_PATH
|
||||
"scope": "/" + settings.LD_CONTEXT_PATH,
|
||||
}
|
||||
|
||||
return JsonResponse(response, status=200)
|
||||
|
@@ -8,51 +8,51 @@ from bookmarks.views.partials import contexts
|
||||
def active_bookmark_list(request):
|
||||
bookmark_list_context = contexts.ActiveBookmarkListContext(request)
|
||||
|
||||
return render(request, 'bookmarks/bookmark_list.html', {
|
||||
'bookmark_list': bookmark_list_context
|
||||
})
|
||||
return render(
|
||||
request,
|
||||
"bookmarks/bookmark_list.html",
|
||||
{"bookmark_list": bookmark_list_context},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def active_tag_cloud(request):
|
||||
tag_cloud_context = contexts.ActiveTagCloudContext(request)
|
||||
|
||||
return render(request, 'bookmarks/tag_cloud.html', {
|
||||
'tag_cloud': tag_cloud_context
|
||||
})
|
||||
return render(request, "bookmarks/tag_cloud.html", {"tag_cloud": tag_cloud_context})
|
||||
|
||||
|
||||
@login_required
|
||||
def archived_bookmark_list(request):
|
||||
bookmark_list_context = contexts.ArchivedBookmarkListContext(request)
|
||||
|
||||
return render(request, 'bookmarks/bookmark_list.html', {
|
||||
'bookmark_list': bookmark_list_context
|
||||
})
|
||||
return render(
|
||||
request,
|
||||
"bookmarks/bookmark_list.html",
|
||||
{"bookmark_list": bookmark_list_context},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def archived_tag_cloud(request):
|
||||
tag_cloud_context = contexts.ArchivedTagCloudContext(request)
|
||||
|
||||
return render(request, 'bookmarks/tag_cloud.html', {
|
||||
'tag_cloud': tag_cloud_context
|
||||
})
|
||||
return render(request, "bookmarks/tag_cloud.html", {"tag_cloud": tag_cloud_context})
|
||||
|
||||
|
||||
@login_required
|
||||
def shared_bookmark_list(request):
|
||||
bookmark_list_context = contexts.SharedBookmarkListContext(request)
|
||||
|
||||
return render(request, 'bookmarks/bookmark_list.html', {
|
||||
'bookmark_list': bookmark_list_context
|
||||
})
|
||||
return render(
|
||||
request,
|
||||
"bookmarks/bookmark_list.html",
|
||||
{"bookmark_list": bookmark_list_context},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def shared_tag_cloud(request):
|
||||
tag_cloud_context = contexts.SharedTagCloudContext(request)
|
||||
|
||||
return render(request, 'bookmarks/tag_cloud.html', {
|
||||
'tag_cloud': tag_cloud_context
|
||||
})
|
||||
return render(request, "bookmarks/tag_cloud.html", {"tag_cloud": tag_cloud_context})
|
||||
|
@@ -8,7 +8,14 @@ from django.urls import reverse
|
||||
|
||||
from bookmarks import queries
|
||||
from bookmarks import utils
|
||||
from bookmarks.models import Bookmark, BookmarkSearch, BookmarkSearchForm, User, UserProfile, Tag
|
||||
from bookmarks.models import (
|
||||
Bookmark,
|
||||
BookmarkSearch,
|
||||
BookmarkSearchForm,
|
||||
User,
|
||||
UserProfile,
|
||||
Tag,
|
||||
)
|
||||
|
||||
DEFAULT_PAGE_SIZE = 30
|
||||
|
||||
@@ -34,22 +41,26 @@ class BookmarkItem:
|
||||
|
||||
css_classes = []
|
||||
if bookmark.unread:
|
||||
css_classes.append('unread')
|
||||
css_classes.append("unread")
|
||||
if bookmark.shared:
|
||||
css_classes.append('shared')
|
||||
css_classes.append("shared")
|
||||
|
||||
self.css_classes = ' '.join(css_classes)
|
||||
self.css_classes = " ".join(css_classes)
|
||||
|
||||
if profile.bookmark_date_display == UserProfile.BOOKMARK_DATE_DISPLAY_RELATIVE:
|
||||
self.display_date = utils.humanize_relative_date(bookmark.date_added)
|
||||
elif profile.bookmark_date_display == UserProfile.BOOKMARK_DATE_DISPLAY_ABSOLUTE:
|
||||
elif (
|
||||
profile.bookmark_date_display == UserProfile.BOOKMARK_DATE_DISPLAY_ABSOLUTE
|
||||
):
|
||||
self.display_date = utils.humanize_absolute_date(bookmark.date_added)
|
||||
|
||||
self.show_notes_button = bookmark.notes and not profile.permanent_notes
|
||||
self.show_mark_as_read = is_editable and bookmark.unread
|
||||
self.show_unshare = is_editable and bookmark.shared and profile.enable_sharing
|
||||
|
||||
self.has_extra_actions = self.show_notes_button or self.show_mark_as_read or self.show_unshare
|
||||
self.has_extra_actions = (
|
||||
self.show_notes_button or self.show_mark_as_read or self.show_unshare
|
||||
)
|
||||
|
||||
|
||||
class BookmarkListContext:
|
||||
@@ -58,22 +69,30 @@ class BookmarkListContext:
|
||||
user_profile = request.user_profile
|
||||
|
||||
self.request = request
|
||||
self.search = BookmarkSearch.from_request(self.request.GET, user_profile.search_preferences)
|
||||
self.search = BookmarkSearch.from_request(
|
||||
self.request.GET, user_profile.search_preferences
|
||||
)
|
||||
|
||||
query_set = self.get_bookmark_query_set()
|
||||
page_number = request.GET.get('page')
|
||||
page_number = request.GET.get("page")
|
||||
paginator = Paginator(query_set, DEFAULT_PAGE_SIZE)
|
||||
bookmarks_page = paginator.get_page(page_number)
|
||||
# Prefetch related objects, this avoids n+1 queries when accessing fields in templates
|
||||
models.prefetch_related_objects(bookmarks_page.object_list, 'owner', 'tags')
|
||||
models.prefetch_related_objects(bookmarks_page.object_list, "owner", "tags")
|
||||
|
||||
self.items = [BookmarkItem(bookmark, user, user_profile) for bookmark in bookmarks_page]
|
||||
self.items = [
|
||||
BookmarkItem(bookmark, user, user_profile) for bookmark in bookmarks_page
|
||||
]
|
||||
|
||||
self.is_empty = paginator.count == 0
|
||||
self.bookmarks_page = bookmarks_page
|
||||
self.bookmarks_total = paginator.count
|
||||
self.return_url = self.generate_return_url(self.search, self.get_base_url(), page_number)
|
||||
self.action_url = self.generate_action_url(self.search, self.get_base_action_url(), self.return_url)
|
||||
self.return_url = self.generate_return_url(
|
||||
self.search, self.get_base_url(), page_number
|
||||
)
|
||||
self.action_url = self.generate_action_url(
|
||||
self.search, self.get_base_action_url(), self.return_url
|
||||
)
|
||||
self.link_target = user_profile.bookmark_link_target
|
||||
self.date_display = user_profile.bookmark_date_display
|
||||
self.show_url = user_profile.display_url
|
||||
@@ -84,69 +103,74 @@ class BookmarkListContext:
|
||||
def generate_return_url(search: BookmarkSearch, base_url: str, page: int = None):
|
||||
query_params = search.query_params
|
||||
if page is not None:
|
||||
query_params['page'] = page
|
||||
query_params["page"] = page
|
||||
query_string = urllib.parse.urlencode(query_params)
|
||||
|
||||
return base_url if query_string == '' else base_url + '?' + query_string
|
||||
return base_url if query_string == "" else base_url + "?" + query_string
|
||||
|
||||
@staticmethod
|
||||
def generate_action_url(search: BookmarkSearch, base_action_url: str, return_url: str):
|
||||
def generate_action_url(
|
||||
search: BookmarkSearch, base_action_url: str, return_url: str
|
||||
):
|
||||
query_params = search.query_params
|
||||
query_params['return_url'] = return_url
|
||||
query_params["return_url"] = return_url
|
||||
query_string = urllib.parse.urlencode(query_params)
|
||||
|
||||
return base_action_url if query_string == '' else base_action_url + '?' + query_string
|
||||
return (
|
||||
base_action_url
|
||||
if query_string == ""
|
||||
else base_action_url + "?" + query_string
|
||||
)
|
||||
|
||||
def get_base_url(self):
|
||||
raise Exception(f'Must be implemented by subclass')
|
||||
raise Exception(f"Must be implemented by subclass")
|
||||
|
||||
def get_base_action_url(self):
|
||||
raise Exception(f'Must be implemented by subclass')
|
||||
raise Exception(f"Must be implemented by subclass")
|
||||
|
||||
def get_bookmark_query_set(self):
|
||||
raise Exception(f'Must be implemented by subclass')
|
||||
raise Exception(f"Must be implemented by subclass")
|
||||
|
||||
|
||||
class ActiveBookmarkListContext(BookmarkListContext):
|
||||
def get_base_url(self):
|
||||
return reverse('bookmarks:index')
|
||||
return reverse("bookmarks:index")
|
||||
|
||||
def get_base_action_url(self):
|
||||
return reverse('bookmarks:index.action')
|
||||
return reverse("bookmarks:index.action")
|
||||
|
||||
def get_bookmark_query_set(self):
|
||||
return queries.query_bookmarks(self.request.user,
|
||||
self.request.user_profile,
|
||||
self.search)
|
||||
return queries.query_bookmarks(
|
||||
self.request.user, self.request.user_profile, self.search
|
||||
)
|
||||
|
||||
|
||||
class ArchivedBookmarkListContext(BookmarkListContext):
|
||||
def get_base_url(self):
|
||||
return reverse('bookmarks:archived')
|
||||
return reverse("bookmarks:archived")
|
||||
|
||||
def get_base_action_url(self):
|
||||
return reverse('bookmarks:archived.action')
|
||||
return reverse("bookmarks:archived.action")
|
||||
|
||||
def get_bookmark_query_set(self):
|
||||
return queries.query_archived_bookmarks(self.request.user,
|
||||
self.request.user_profile,
|
||||
self.search)
|
||||
return queries.query_archived_bookmarks(
|
||||
self.request.user, self.request.user_profile, self.search
|
||||
)
|
||||
|
||||
|
||||
class SharedBookmarkListContext(BookmarkListContext):
|
||||
def get_base_url(self):
|
||||
return reverse('bookmarks:shared')
|
||||
return reverse("bookmarks:shared")
|
||||
|
||||
def get_base_action_url(self):
|
||||
return reverse('bookmarks:shared.action')
|
||||
return reverse("bookmarks:shared.action")
|
||||
|
||||
def get_bookmark_query_set(self):
|
||||
user = User.objects.filter(username=self.search.user).first()
|
||||
public_only = not self.request.user.is_authenticated
|
||||
return queries.query_shared_bookmarks(user,
|
||||
self.request.user_profile,
|
||||
self.search,
|
||||
public_only)
|
||||
return queries.query_shared_bookmarks(
|
||||
user, self.request.user_profile, self.search, public_only
|
||||
)
|
||||
|
||||
|
||||
class TagGroup:
|
||||
@@ -179,13 +203,17 @@ class TagCloudContext:
|
||||
user_profile = request.user_profile
|
||||
|
||||
self.request = request
|
||||
self.search = BookmarkSearch.from_request(self.request.GET, user_profile.search_preferences)
|
||||
self.search = BookmarkSearch.from_request(
|
||||
self.request.GET, user_profile.search_preferences
|
||||
)
|
||||
|
||||
query_set = self.get_tag_query_set()
|
||||
tags = list(query_set)
|
||||
selected_tags = self.get_selected_tags(tags)
|
||||
unique_tags = utils.unique(tags, key=lambda x: str.lower(x.name))
|
||||
unique_selected_tags = utils.unique(selected_tags, key=lambda x: str.lower(x.name))
|
||||
unique_selected_tags = utils.unique(
|
||||
selected_tags, key=lambda x: str.lower(x.name)
|
||||
)
|
||||
has_selected_tags = len(unique_selected_tags) > 0
|
||||
unselected_tags = set(unique_tags).symmetric_difference(unique_selected_tags)
|
||||
groups = TagGroup.create_tag_groups(unselected_tags)
|
||||
@@ -196,13 +224,13 @@ class TagCloudContext:
|
||||
self.has_selected_tags = has_selected_tags
|
||||
|
||||
def get_tag_query_set(self):
|
||||
raise Exception(f'Must be implemented by subclass')
|
||||
raise Exception(f"Must be implemented by subclass")
|
||||
|
||||
def get_selected_tags(self, tags: List[Tag]):
|
||||
parsed_query = queries.parse_query_string(self.search.q)
|
||||
tag_names = parsed_query['tag_names']
|
||||
tag_names = parsed_query["tag_names"]
|
||||
if self.request.user_profile.tag_search == UserProfile.TAG_SEARCH_LAX:
|
||||
tag_names = tag_names + parsed_query['search_terms']
|
||||
tag_names = tag_names + parsed_query["search_terms"]
|
||||
tag_names = [tag_name.lower() for tag_name in tag_names]
|
||||
|
||||
return [tag for tag in tags if tag.name.lower() in tag_names]
|
||||
@@ -210,23 +238,22 @@ class TagCloudContext:
|
||||
|
||||
class ActiveTagCloudContext(TagCloudContext):
|
||||
def get_tag_query_set(self):
|
||||
return queries.query_bookmark_tags(self.request.user,
|
||||
self.request.user_profile,
|
||||
self.search)
|
||||
return queries.query_bookmark_tags(
|
||||
self.request.user, self.request.user_profile, self.search
|
||||
)
|
||||
|
||||
|
||||
class ArchivedTagCloudContext(TagCloudContext):
|
||||
def get_tag_query_set(self):
|
||||
return queries.query_archived_bookmark_tags(self.request.user,
|
||||
self.request.user_profile,
|
||||
self.search)
|
||||
return queries.query_archived_bookmark_tags(
|
||||
self.request.user, self.request.user_profile, self.search
|
||||
)
|
||||
|
||||
|
||||
class SharedTagCloudContext(TagCloudContext):
|
||||
def get_tag_query_set(self):
|
||||
user = User.objects.filter(username=self.search.user).first()
|
||||
public_only = not self.request.user.is_authenticated
|
||||
return queries.query_shared_bookmark_tags(user,
|
||||
self.request.user_profile,
|
||||
self.search,
|
||||
public_only)
|
||||
return queries.query_shared_bookmark_tags(
|
||||
user, self.request.user_profile, self.search, public_only
|
||||
)
|
||||
|
@@ -26,30 +26,40 @@ def general(request):
|
||||
enable_refresh_favicons = django_settings.LD_ENABLE_REFRESH_FAVICONS
|
||||
update_profile_success_message = None
|
||||
refresh_favicons_success_message = None
|
||||
import_success_message = _find_message_with_tag(messages.get_messages(request), 'bookmark_import_success')
|
||||
import_errors_message = _find_message_with_tag(messages.get_messages(request), 'bookmark_import_errors')
|
||||
import_success_message = _find_message_with_tag(
|
||||
messages.get_messages(request), "bookmark_import_success"
|
||||
)
|
||||
import_errors_message = _find_message_with_tag(
|
||||
messages.get_messages(request), "bookmark_import_errors"
|
||||
)
|
||||
version_info = get_version_info(get_ttl_hash())
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'update_profile' in request.POST:
|
||||
if request.method == "POST":
|
||||
if "update_profile" in request.POST:
|
||||
profile_form = update_profile(request)
|
||||
update_profile_success_message = 'Profile updated'
|
||||
if 'refresh_favicons' in request.POST:
|
||||
update_profile_success_message = "Profile updated"
|
||||
if "refresh_favicons" in request.POST:
|
||||
tasks.schedule_refresh_favicons(request.user)
|
||||
refresh_favicons_success_message = 'Scheduled favicon update. This may take a while...'
|
||||
refresh_favicons_success_message = (
|
||||
"Scheduled favicon update. This may take a while..."
|
||||
)
|
||||
|
||||
if not profile_form:
|
||||
profile_form = UserProfileForm(instance=request.user_profile)
|
||||
|
||||
return render(request, 'settings/general.html', {
|
||||
'form': profile_form,
|
||||
'enable_refresh_favicons': enable_refresh_favicons,
|
||||
'update_profile_success_message': update_profile_success_message,
|
||||
'refresh_favicons_success_message': refresh_favicons_success_message,
|
||||
'import_success_message': import_success_message,
|
||||
'import_errors_message': import_errors_message,
|
||||
'version_info': version_info,
|
||||
})
|
||||
return render(
|
||||
request,
|
||||
"settings/general.html",
|
||||
{
|
||||
"form": profile_form,
|
||||
"enable_refresh_favicons": enable_refresh_favicons,
|
||||
"update_profile_success_message": update_profile_success_message,
|
||||
"refresh_favicons_success_message": refresh_favicons_success_message,
|
||||
"import_success_message": import_success_message,
|
||||
"import_errors_message": import_errors_message,
|
||||
"version_info": version_info,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def update_profile(request):
|
||||
@@ -69,21 +79,23 @@ def update_profile(request):
|
||||
def get_version_info(ttl_hash=None):
|
||||
latest_version = None
|
||||
try:
|
||||
latest_version_url = 'https://api.github.com/repos/sissbruecker/linkding/releases/latest'
|
||||
latest_version_url = (
|
||||
"https://api.github.com/repos/sissbruecker/linkding/releases/latest"
|
||||
)
|
||||
response = requests.get(latest_version_url, timeout=5)
|
||||
json = response.json()
|
||||
if response.status_code == 200 and 'name' in json:
|
||||
latest_version = json['name'][1:]
|
||||
if response.status_code == 200 and "name" in json:
|
||||
latest_version = json["name"][1:]
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
|
||||
latest_version_info = ''
|
||||
latest_version_info = ""
|
||||
if latest_version == app_version:
|
||||
latest_version_info = ' (latest)'
|
||||
latest_version_info = " (latest)"
|
||||
elif latest_version is not None:
|
||||
latest_version_info = f' (latest: {latest_version})'
|
||||
latest_version_info = f" (latest: {latest_version})"
|
||||
|
||||
return f'{app_version}{latest_version_info}'
|
||||
return f"{app_version}{latest_version_info}"
|
||||
|
||||
|
||||
def get_ttl_hash(seconds=3600):
|
||||
@@ -93,42 +105,61 @@ def get_ttl_hash(seconds=3600):
|
||||
|
||||
@login_required
|
||||
def integrations(request):
|
||||
application_url = request.build_absolute_uri(reverse('bookmarks:new'))
|
||||
application_url = request.build_absolute_uri(reverse("bookmarks:new"))
|
||||
api_token = Token.objects.get_or_create(user=request.user)[0]
|
||||
feed_token = FeedToken.objects.get_or_create(user=request.user)[0]
|
||||
all_feed_url = request.build_absolute_uri(reverse('bookmarks:feeds.all', args=[feed_token.key]))
|
||||
unread_feed_url = request.build_absolute_uri(reverse('bookmarks:feeds.unread', args=[feed_token.key]))
|
||||
return render(request, 'settings/integrations.html', {
|
||||
'application_url': application_url,
|
||||
'api_token': api_token.key,
|
||||
'all_feed_url': all_feed_url,
|
||||
'unread_feed_url': unread_feed_url,
|
||||
})
|
||||
all_feed_url = request.build_absolute_uri(
|
||||
reverse("bookmarks:feeds.all", args=[feed_token.key])
|
||||
)
|
||||
unread_feed_url = request.build_absolute_uri(
|
||||
reverse("bookmarks:feeds.unread", args=[feed_token.key])
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
"settings/integrations.html",
|
||||
{
|
||||
"application_url": application_url,
|
||||
"api_token": api_token.key,
|
||||
"all_feed_url": all_feed_url,
|
||||
"unread_feed_url": unread_feed_url,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def bookmark_import(request):
|
||||
import_file = request.FILES.get('import_file')
|
||||
import_options = importer.ImportOptions(map_private_flag=request.POST.get('map_private_flag') == 'on')
|
||||
import_file = request.FILES.get("import_file")
|
||||
import_options = importer.ImportOptions(
|
||||
map_private_flag=request.POST.get("map_private_flag") == "on"
|
||||
)
|
||||
|
||||
if import_file is None:
|
||||
messages.error(request, 'Please select a file to import.', 'bookmark_import_errors')
|
||||
return HttpResponseRedirect(reverse('bookmarks:settings.general'))
|
||||
messages.error(
|
||||
request, "Please select a file to import.", "bookmark_import_errors"
|
||||
)
|
||||
return HttpResponseRedirect(reverse("bookmarks:settings.general"))
|
||||
|
||||
try:
|
||||
content = import_file.read().decode()
|
||||
result = importer.import_netscape_html(content, request.user, import_options)
|
||||
success_msg = str(result.success) + ' bookmarks were successfully imported.'
|
||||
messages.success(request, success_msg, 'bookmark_import_success')
|
||||
success_msg = str(result.success) + " bookmarks were successfully imported."
|
||||
messages.success(request, success_msg, "bookmark_import_success")
|
||||
if result.failed > 0:
|
||||
err_msg = str(result.failed) + ' bookmarks could not be imported. Please check the logs for more details.'
|
||||
messages.error(request, err_msg, 'bookmark_import_errors')
|
||||
err_msg = (
|
||||
str(result.failed)
|
||||
+ " bookmarks could not be imported. Please check the logs for more details."
|
||||
)
|
||||
messages.error(request, err_msg, "bookmark_import_errors")
|
||||
except:
|
||||
logging.exception('Unexpected error during bookmark import')
|
||||
messages.error(request, 'An error occurred during bookmark import.', 'bookmark_import_errors')
|
||||
logging.exception("Unexpected error during bookmark import")
|
||||
messages.error(
|
||||
request,
|
||||
"An error occurred during bookmark import.",
|
||||
"bookmark_import_errors",
|
||||
)
|
||||
pass
|
||||
|
||||
return HttpResponseRedirect(reverse('bookmarks:settings.general'))
|
||||
return HttpResponseRedirect(reverse("bookmarks:settings.general"))
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -137,18 +168,20 @@ def bookmark_export(request):
|
||||
try:
|
||||
bookmarks = Bookmark.objects.filter(owner=request.user)
|
||||
# Prefetch tags to prevent n+1 queries
|
||||
prefetch_related_objects(bookmarks, 'tags')
|
||||
prefetch_related_objects(bookmarks, "tags")
|
||||
file_content = exporter.export_netscape_html(bookmarks)
|
||||
|
||||
response = HttpResponse(content_type='text/plain; charset=UTF-8')
|
||||
response['Content-Disposition'] = 'attachment; filename="bookmarks.html"'
|
||||
response = HttpResponse(content_type="text/plain; charset=UTF-8")
|
||||
response["Content-Disposition"] = 'attachment; filename="bookmarks.html"'
|
||||
response.write(file_content)
|
||||
|
||||
return response
|
||||
except:
|
||||
return render(request, 'settings/general.html', {
|
||||
'export_error': 'An error occurred during bookmark export.'
|
||||
})
|
||||
return render(
|
||||
request,
|
||||
"settings/general.html",
|
||||
{"export_error": "An error occurred during bookmark export."},
|
||||
)
|
||||
|
||||
|
||||
def _find_message_with_tag(messages, tag):
|
||||
|
@@ -8,13 +8,15 @@ from bookmarks.utils import get_safe_return_url
|
||||
|
||||
@login_required
|
||||
def acknowledge(request):
|
||||
toast_id = request.POST['toast']
|
||||
toast_id = request.POST["toast"]
|
||||
try:
|
||||
toast = Toast.objects.get(pk=toast_id, owner=request.user)
|
||||
except Toast.DoesNotExist:
|
||||
raise Http404('Toast does not exist')
|
||||
raise Http404("Toast does not exist")
|
||||
toast.acknowledged = True
|
||||
toast.save()
|
||||
|
||||
return_url = get_safe_return_url(request.GET.get('return_url'), reverse('bookmarks:index'))
|
||||
return_url = get_safe_return_url(
|
||||
request.GET.get("return_url"), reverse("bookmarks:index")
|
||||
)
|
||||
return HttpResponseRedirect(return_url)
|
||||
|
Reference in New Issue
Block a user