diff --git a/API.md b/API.md index a3bbfbf..b72f353 100644 --- a/API.md +++ b/API.md @@ -49,7 +49,7 @@ Example response: "website_description": "Website description", "tag_names": [ "tag1", - "tag2" + "tag2" ], "date_added": "2020-09-26T09:46:23.006313Z", "date_modified": "2020-09-26T16:01:14.275335Z" @@ -59,6 +59,16 @@ Example response: } ``` +**Archived** + +``` +GET /api/bookmarks/archived/ +``` + +List archived bookmarks. + +Parameters and response are the same as for the regular list endpoint. + **Retrieve** ``` diff --git a/bookmarks/api/routes.py b/bookmarks/api/routes.py index 696ddaa..f75a859 100644 --- a/bookmarks/api/routes.py +++ b/bookmarks/api/routes.py @@ -1,4 +1,6 @@ -from rest_framework import viewsets, mixins +from rest_framework import viewsets, mixins, status +from rest_framework.decorators import action +from rest_framework.response import Response from rest_framework.routers import DefaultRouter from bookmarks import queries @@ -27,6 +29,16 @@ class BookmarkViewSet(viewsets.GenericViewSet, def get_serializer_context(self): return {'user': self.request.user} + @action(methods=['get'], detail=False) + def archived(self, request): + user = request.user + query_string = request.GET.get('q') + query_set = queries.query_archived_bookmarks(user, query_string) + page = self.paginate_queryset(query_set) + serializer = self.get_serializer_class() + data = serializer(page, many=True).data + return self.get_paginated_response(data) + class TagViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, diff --git a/bookmarks/components/SearchAutoComplete.svelte b/bookmarks/components/SearchAutoComplete.svelte index 130c7c9..5d1b5e3 100644 --- a/bookmarks/components/SearchAutoComplete.svelte +++ b/bookmarks/components/SearchAutoComplete.svelte @@ -8,6 +8,7 @@ export let placeholder; export let value; export let tags; + export let mode = 'default'; export let apiClient; let isFocus = false; @@ -111,7 +112,9 @@ let bookmarks = [] if (value && value.length >= 3) { - const fetchedBookmarks = await apiClient.getBookmarks(value, {limit: 5, offset: 0}) + const fetchedBookmarks = mode === 'archive' + ? await apiClient.getArchivedBookmarks(value, {limit: 5, offset: 0}) + : await apiClient.getBookmarks(value, {limit: 5, offset: 0}) bookmarks = fetchedBookmarks.map(bookmark => { const fullLabel = bookmark.title || bookmark.website_title || bookmark.url const label = clampText(fullLabel, 60) diff --git a/bookmarks/components/api.js b/bookmarks/components/api.js index 89f314c..292c892 100644 --- a/bookmarks/components/api.js +++ b/bookmarks/components/api.js @@ -11,4 +11,13 @@ export class ApiClient { .then(response => response.json()) .then(data => data.results) } + + getArchivedBookmarks(query, options = {limit: 100, offset: 0}) { + const encodedQuery = encodeURIComponent(query) + const url = `${this.baseUrl}bookmarks/archived?q=${encodedQuery}&limit=${options.limit}&offset=${options.offset}` + + return fetch(url) + .then(response => response.json()) + .then(data => data.results) + } } \ No newline at end of file diff --git a/bookmarks/migrations/0006_bookmark_is_archived.py b/bookmarks/migrations/0006_bookmark_is_archived.py new file mode 100644 index 0000000..21190e9 --- /dev/null +++ b/bookmarks/migrations/0006_bookmark_is_archived.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.13 on 2021-02-14 09:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('bookmarks', '0005_auto_20210103_1212'), + ] + + operations = [ + migrations.AddField( + model_name='bookmark', + name='is_archived', + field=models.BooleanField(default=False), + ), + ] diff --git a/bookmarks/models.py b/bookmarks/models.py index 407b11a..fd9905b 100644 --- a/bookmarks/models.py +++ b/bookmarks/models.py @@ -39,6 +39,7 @@ class Bookmark(models.Model): website_title = models.CharField(max_length=512, blank=True, null=True) website_description = models.TextField(blank=True, null=True) unread = models.BooleanField(default=True) + is_archived = models.BooleanField(default=False) date_added = models.DateTimeField() date_modified = models.DateTimeField() date_accessed = models.DateTimeField(blank=True, null=True) diff --git a/bookmarks/queries.py b/bookmarks/queries.py index bcce913..b36842b 100644 --- a/bookmarks/queries.py +++ b/bookmarks/queries.py @@ -1,5 +1,5 @@ from django.contrib.auth.models import User -from django.db.models import Q, Count, Aggregate, CharField, Value, BooleanField +from django.db.models import Q, Count, Aggregate, CharField, Value, BooleanField, QuerySet from bookmarks.models import Bookmark, Tag from bookmarks.utils import unique @@ -17,7 +17,17 @@ class Concat(Aggregate): **extra) -def query_bookmarks(user: User, query_string: str): +def query_bookmarks(user: User, query_string: str) -> QuerySet: + return _base_bookmarks_query(user, query_string) \ + .filter(is_archived=False) + + +def query_archived_bookmarks(user: User, query_string: str) -> QuerySet: + return _base_bookmarks_query(user, query_string) \ + .filter(is_archived=True) + + +def _base_bookmarks_query(user: User, query_string: str) -> QuerySet: # Add aggregated tag info to bookmark instances query_set = Bookmark.objects \ .annotate(tag_count=Count('tags'), @@ -51,7 +61,19 @@ def query_bookmarks(user: User, query_string: str): return query_set -def query_tags(user: User, query_string: str): +def query_bookmark_tags(user: User, query_string: str) -> QuerySet: + return _base_bookmark_tags_query(user, query_string) \ + .filter(bookmark__is_archived=False) \ + .distinct() + + +def query_archived_bookmark_tags(user: User, query_string: str) -> QuerySet: + return _base_bookmark_tags_query(user, query_string) \ + .filter(bookmark__is_archived=True) \ + .distinct() + + +def _base_bookmark_tags_query(user: User, query_string: str) -> QuerySet: query_set = Tag.objects # Filter for user diff --git a/bookmarks/services/bookmarks.py b/bookmarks/services/bookmarks.py index 72e7d19..2769fe0 100644 --- a/bookmarks/services/bookmarks.py +++ b/bookmarks/services/bookmarks.py @@ -39,6 +39,20 @@ def update_bookmark(bookmark: Bookmark, tag_string, current_user: User): return bookmark +def archive_bookmark(bookmark: Bookmark): + bookmark.is_archived = True + bookmark.date_modified = timezone.now() + bookmark.save() + return bookmark + + +def unarchive_bookmark(bookmark: Bookmark): + bookmark.is_archived = False + bookmark.date_modified = timezone.now() + bookmark.save() + return bookmark + + def _merge_bookmark_data(from_bookmark: Bookmark, to_bookmark: Bookmark): to_bookmark.title = from_bookmark.title to_bookmark.description = from_bookmark.description diff --git a/bookmarks/templates/bookmarks/archive.html b/bookmarks/templates/bookmarks/archive.html new file mode 100644 index 0000000..7ebfb1e --- /dev/null +++ b/bookmarks/templates/bookmarks/archive.html @@ -0,0 +1,34 @@ +{% extends "bookmarks/layout.html" %} +{% load static %} +{% load shared %} +{% load bookmarks %} + +{% block content %} +
+ + {# Bookmark list #} +
+
+

Archived bookmarks

+
+ {% bookmark_search query tags mode='archive' %} +
+ + {% if empty %} + {% include 'bookmarks/empty_bookmarks.html' %} + {% else %} + {% bookmark_list bookmarks return_url %} + {% endif %} +
+ + {# Tag list #} +
+
+

Tags

+
+ {% tag_cloud tags %} +
+
+ + +{% endblock %} diff --git a/bookmarks/templates/bookmarks/bookmark_list.html b/bookmarks/templates/bookmarks/bookmark_list.html index 81b7b94..606f757 100644 --- a/bookmarks/templates/bookmarks/bookmark_list.html +++ b/bookmarks/templates/bookmarks/bookmark_list.html @@ -24,6 +24,13 @@
Edit + {% if bookmark.is_archived %} + Unarchive + {% else %} + Archive + {% endif %} Remove diff --git a/bookmarks/templates/bookmarks/bookmarklet.html b/bookmarks/templates/bookmarks/bookmarklet.html deleted file mode 100644 index 91eaf64..0000000 --- a/bookmarks/templates/bookmarks/bookmarklet.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "bookmarks/layout.html" %} - -{% block content %} -
-
-
-

Bookmarklet

-
-

The bookmarklet is a quick way to add new bookmarks without opening the linkding application - first. Here's how it works:

-
    -
  • Drag the bookmarklet below into your browsers bookmark bar / toolbar
  • -
  • Open the website that you want to bookmark
  • -
  • Click the bookmarklet in your browsers toolbar
  • -
  • linkding opens in a new window or tab and allows you to add a bookmark for the site
  • -
  • After saving the bookmark the linkding window closes and you are back on your website
  • -
-

Drag the following bookmarklet to your browsers toolbar:

- 📎 Add bookmark -
-
-{% endblock %} - diff --git a/bookmarks/templates/bookmarks/empty_bookmarks.html b/bookmarks/templates/bookmarks/empty_bookmarks.html index d97a88f..aed6895 100644 --- a/bookmarks/templates/bookmarks/empty_bookmarks.html +++ b/bookmarks/templates/bookmarks/empty_bookmarks.html @@ -1,8 +1,8 @@

You have no bookmarks yet

- You can get started by adding bookmarks, importing your existing bookmarks or configuring the bookmarklet. + You can get started by adding bookmarks, + importing your existing bookmarks or configuring the + bookmarklet.

diff --git a/bookmarks/templates/bookmarks/index.html b/bookmarks/templates/bookmarks/index.html index 8c0ff03..3f33294 100644 --- a/bookmarks/templates/bookmarks/index.html +++ b/bookmarks/templates/bookmarks/index.html @@ -11,17 +11,7 @@

Bookmarks

- + {% bookmark_search query tags %}
{% if empty %} @@ -40,24 +30,5 @@
- {# Replace search input with auto-complete component #} - {% endblock %} diff --git a/bookmarks/templates/bookmarks/nav_menu.html b/bookmarks/templates/bookmarks/nav_menu.html index 4cb5a28..2cb5528 100644 --- a/bookmarks/templates/bookmarks/nav_menu.html +++ b/bookmarks/templates/bookmarks/nav_menu.html @@ -1,7 +1,7 @@ {# Basic menu list #}
Add bookmark - Bookmarklet + Archive Settings Logout
@@ -17,7 +17,7 @@