diff --git a/bookmarks/admin.py b/bookmarks/admin.py index f4ff566..a9be988 100644 --- a/bookmarks/admin.py +++ b/bookmarks/admin.py @@ -21,9 +21,9 @@ class LinkdingAdminSite(AdminSite): class AdminBookmark(admin.ModelAdmin): list_display = ('resolved_title', 'url', 'is_archived', 'owner', 'date_added') search_fields = ('title', 'description', 'website_title', 'website_description', 'url', 'tags__name') - list_filter = ('owner__username', 'is_archived', 'tags',) + list_filter = ('owner__username', 'is_archived', 'unread', 'tags',) ordering = ('-date_added',) - actions = ['archive_selected_bookmarks', 'unarchive_selected_bookmarks'] + actions = ['archive_selected_bookmarks', 'unarchive_selected_bookmarks', 'mark_as_read', 'mark_as_unread'] def archive_selected_bookmarks(self, request, queryset: QuerySet): for bookmark in queryset: @@ -45,6 +45,24 @@ class AdminBookmark(admin.ModelAdmin): bookmarks_count, ) % bookmarks_count, messages.SUCCESS) + def mark_as_read(self, request, queryset: QuerySet): + bookmarks_count = queryset.count() + queryset.update(unread=False) + self.message_user(request, ngettext( + '%d bookmark marked as read.', + '%d bookmarks marked as read.', + bookmarks_count, + ) % bookmarks_count, messages.SUCCESS) + + def mark_as_unread(self, request, queryset: QuerySet): + bookmarks_count = queryset.count() + queryset.update(unread=True) + self.message_user(request, ngettext( + '%d bookmark marked as unread.', + '%d bookmarks marked as unread.', + bookmarks_count, + ) % bookmarks_count, messages.SUCCESS) + class AdminTag(admin.ModelAdmin): list_display = ('name', 'bookmarks_count', 'owner', 'date_added') diff --git a/bookmarks/api/serializers.py b/bookmarks/api/serializers.py index 2f49501..4e2be52 100644 --- a/bookmarks/api/serializers.py +++ b/bookmarks/api/serializers.py @@ -20,6 +20,7 @@ class BookmarkSerializer(serializers.ModelSerializer): 'website_title', 'website_description', 'is_archived', + 'unread', 'tag_names', 'date_added', 'date_modified' @@ -35,6 +36,7 @@ class BookmarkSerializer(serializers.ModelSerializer): title = serializers.CharField(required=False, allow_blank=True, default='') description = serializers.CharField(required=False, allow_blank=True, default='') is_archived = serializers.BooleanField(required=False, default=False) + unread = 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=[]) @@ -44,12 +46,13 @@ class BookmarkSerializer(serializers.ModelSerializer): bookmark.title = validated_data['title'] bookmark.description = validated_data['description'] bookmark.is_archived = validated_data['is_archived'] + bookmark.unread = validated_data['unread'] tag_string = build_tag_string(validated_data['tag_names']) return create_bookmark(bookmark, tag_string, self.context['user']) def update(self, instance: Bookmark, validated_data): # Update fields if they were provided in the payload - for key in ['url', 'title', 'description']: + for key in ['url', 'title', 'description', 'unread']: if key in validated_data: setattr(instance, key, validated_data[key]) diff --git a/bookmarks/migrations/0014_alter_bookmark_unread.py b/bookmarks/migrations/0014_alter_bookmark_unread.py new file mode 100644 index 0000000..885b1b5 --- /dev/null +++ b/bookmarks/migrations/0014_alter_bookmark_unread.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.13 on 2022-07-23 12:30 + +from django.db import migrations, models + + +def forwards(apps, schema_editor): + Bookmark = apps.get_model('bookmarks', 'Bookmark') + Bookmark.objects.update(unread=False) + + +def reverse(apps, schema_editor): + pass + + +class Migration(migrations.Migration): + dependencies = [ + ('bookmarks', '0013_web_archive_optin_toast'), + ] + + operations = [ + migrations.AlterField( + model_name='bookmark', + name='unread', + field=models.BooleanField(default=False), + ), + migrations.RunPython(forwards, reverse), + ] diff --git a/bookmarks/models.py b/bookmarks/models.py index fe64b8b..7269845 100644 --- a/bookmarks/models.py +++ b/bookmarks/models.py @@ -50,7 +50,7 @@ class Bookmark(models.Model): website_title = models.CharField(max_length=512, blank=True, null=True) website_description = models.TextField(blank=True, null=True) web_archive_snapshot_url = models.CharField(max_length=2048, blank=True) - unread = models.BooleanField(default=True) + unread = models.BooleanField(default=False) is_archived = models.BooleanField(default=False) date_added = models.DateTimeField() date_modified = models.DateTimeField() @@ -97,12 +97,13 @@ class BookmarkForm(forms.ModelForm): required=False) description = forms.CharField(required=False, widget=forms.Textarea()) + unread = forms.BooleanField(required=False) # Hidden field that determines whether to close window/tab after saving the bookmark auto_close = forms.CharField(required=False) class Meta: model = Bookmark - fields = ['url', 'tag_string', 'title', 'description', 'auto_close'] + fields = ['url', 'tag_string', 'title', 'description', 'unread', 'auto_close'] class UserProfile(models.Model): diff --git a/bookmarks/queries.py b/bookmarks/queries.py index 016bb59..eaaa888 100644 --- a/bookmarks/queries.py +++ b/bookmarks/queries.py @@ -60,6 +60,11 @@ def _base_bookmarks_query(user: User, query_string: str) -> QuerySet: query_set = query_set.filter( tags=None ) + # Unread bookmarks + if query['unread']: + query_set = query_set.filter( + unread=True + ) # Sort by date added query_set = query_set.order_by('-date_added') @@ -102,9 +107,11 @@ def _parse_query_string(query_string): # Special search commands untagged = '!untagged' in keywords + unread = '!unread' in keywords return { 'search_terms': search_terms, 'tag_names': tag_names, 'untagged': untagged, + 'unread': unread, } diff --git a/bookmarks/services/importer.py b/bookmarks/services/importer.py index eb59367..fd9c315 100644 --- a/bookmarks/services/importer.py +++ b/bookmarks/services/importer.py @@ -192,7 +192,7 @@ def _copy_bookmark_data(netscape_bookmark: NetscapeBookmark, bookmark: Bookmark) else: bookmark.date_added = timezone.now() bookmark.date_modified = bookmark.date_added - bookmark.unread = False + bookmark.unread = netscape_bookmark.to_read if netscape_bookmark.title: bookmark.title = netscape_bookmark.title if netscape_bookmark.description: diff --git a/bookmarks/services/parser.py b/bookmarks/services/parser.py index 539152e..7d27e7a 100644 --- a/bookmarks/services/parser.py +++ b/bookmarks/services/parser.py @@ -10,6 +10,7 @@ class NetscapeBookmark: description: str date_added: str tag_string: str + to_read: bool class BookmarkParser(HTMLParser): @@ -24,6 +25,7 @@ class BookmarkParser(HTMLParser): self.tags = '' self.title = '' self.description = '' + self.toread = '' def handle_starttag(self, tag: str, attrs: list): name = 'handle_start_' + tag.lower() @@ -56,6 +58,7 @@ class BookmarkParser(HTMLParser): description='', date_added=self.add_date, tag_string=self.tags, + to_read=self.toread == '1' ) def handle_a_data(self, data): @@ -75,6 +78,7 @@ class BookmarkParser(HTMLParser): self.tags = '' self.title = '' self.description = '' + self.toread = '' def parse(html: str) -> List[NetscapeBookmark]: diff --git a/bookmarks/templates/bookmarks/archive.html b/bookmarks/templates/bookmarks/archive.html index 8e6e280..0c0c5cd 100644 --- a/bookmarks/templates/bookmarks/archive.html +++ b/bookmarks/templates/bookmarks/archive.html @@ -33,10 +33,8 @@ {# Tag list #}
-
+

Tags

-
- Show Untagged
{% tag_cloud tags %}
diff --git a/bookmarks/templates/bookmarks/bookmark_list.html b/bookmarks/templates/bookmarks/bookmark_list.html index 7777e38..4554b93 100644 --- a/bookmarks/templates/bookmarks/bookmark_list.html +++ b/bookmarks/templates/bookmarks/bookmark_list.html @@ -9,7 +9,7 @@
- {{ bookmark.resolved_title }} + {{ bookmark.resolved_title }}
{% if bookmark.tag_names %} @@ -65,6 +65,11 @@ {% endif %} + {% if bookmark.unread %} + | + + {% endif %}
{% endfor %} diff --git a/bookmarks/templates/bookmarks/form.html b/bookmarks/templates/bookmarks/form.html index 8d8a596..bddbeb6 100644 --- a/bookmarks/templates/bookmarks/form.html +++ b/bookmarks/templates/bookmarks/form.html @@ -49,7 +49,7 @@
- {{ form.description|add_class:"form-input"|attr:"rows:4" }} + {{ form.description|add_class:"form-input"|attr:"rows:2" }} @@ -65,6 +65,16 @@
{{ form.description.errors }}
+
+ +
+ Unread bookmarks can be filtered for, and marked as read after you had a chance to look at them. +
+

{% if auto_close %} diff --git a/bookmarks/templates/bookmarks/index.html b/bookmarks/templates/bookmarks/index.html index 5f7e268..80ddde4 100644 --- a/bookmarks/templates/bookmarks/index.html +++ b/bookmarks/templates/bookmarks/index.html @@ -33,10 +33,8 @@ {# Tag list #}
-
+ {% tag_cloud tags %}
diff --git a/bookmarks/templates/bookmarks/nav_menu.html b/bookmarks/templates/bookmarks/nav_menu.html index aa606c0..a2af266 100644 --- a/bookmarks/templates/bookmarks/nav_menu.html +++ b/bookmarks/templates/bookmarks/nav_menu.html @@ -1,7 +1,28 @@ {# Basic menu list #}
Add bookmark - Archive + Settings Logout
@@ -21,7 +42,16 @@