mirror of
https://github.com/sissbruecker/linkding
synced 2024-11-24 20:33:04 +00:00
Allow saving search preferences (#540)
* Add indicator for modified filters * Rename shared filter values * Add update search preferences handler * Separate search and preferences forms * Properly initialize bookmark search from get or post * Add tests for applying search preferences * Implement saving search preferences * Remove bookmark search query alias * Use search preferences as default * Only show save button for authenticated users * Only show modified indicator if preferences are modified * Fix overriding search preferences * Add missing migration
This commit is contained in:
parent
4a2642f16c
commit
41f79e35a0
22 changed files with 1094 additions and 442 deletions
|
@ -34,7 +34,7 @@ class BookmarkViewSet(viewsets.GenericViewSet,
|
|||
user = self.request.user
|
||||
# For list action, use query set that applies search and tag projections
|
||||
if self.action == 'list':
|
||||
search = BookmarkSearch.from_request(self.request)
|
||||
search = BookmarkSearch.from_request(self.request.GET)
|
||||
return queries.query_bookmarks(user, user.profile, search)
|
||||
|
||||
# For single entity actions use default query set without projections
|
||||
|
@ -46,7 +46,7 @@ class BookmarkViewSet(viewsets.GenericViewSet,
|
|||
@action(methods=['get'], detail=False)
|
||||
def archived(self, request):
|
||||
user = request.user
|
||||
search = BookmarkSearch.from_request(request)
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
query_set = queries.query_archived_bookmarks(user, user.profile, search)
|
||||
page = self.paginate_queryset(query_set)
|
||||
serializer = self.get_serializer_class()
|
||||
|
@ -55,7 +55,7 @@ class BookmarkViewSet(viewsets.GenericViewSet,
|
|||
|
||||
@action(methods=['get'], detail=False)
|
||||
def shared(self, request):
|
||||
search = BookmarkSearch.from_request(request)
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
user = User.objects.filter(username=search.user).first()
|
||||
public_only = not request.user.is_authenticated
|
||||
query_set = queries.query_shared_bookmarks(user, request.user_profile, search, public_only)
|
||||
|
|
|
@ -17,7 +17,7 @@ class FeedContext:
|
|||
class BaseBookmarksFeed(Feed):
|
||||
def get_object(self, request, feed_key: str):
|
||||
feed_token = FeedToken.objects.get(key__exact=feed_key)
|
||||
search = BookmarkSearch(query=request.GET.get('q', ''))
|
||||
search = BookmarkSearch(q=request.GET.get('q', ''))
|
||||
query_set = queries.query_bookmarks(feed_token.user, feed_token.user.profile, search)
|
||||
return FeedContext(feed_token, query_set)
|
||||
|
||||
|
|
18
bookmarks/migrations/0025_userprofile_search_preferences.py
Normal file
18
bookmarks/migrations/0025_userprofile_search_preferences.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 4.1.9 on 2023-09-30 10:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bookmarks', '0024_userprofile_enable_public_sharing'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='search_preferences',
|
||||
field=models.JSONField(default=dict),
|
||||
),
|
||||
]
|
|
@ -5,10 +5,10 @@ from typing import List
|
|||
from django import forms
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.http import QueryDict
|
||||
|
||||
from bookmarks.utils import unique
|
||||
from bookmarks.validators import BookmarkURLValidator
|
||||
|
@ -130,15 +130,16 @@ class BookmarkSearch:
|
|||
SORT_TITLE_ASC = 'title_asc'
|
||||
SORT_TITLE_DESC = 'title_desc'
|
||||
|
||||
FILTER_SHARED_OFF = ''
|
||||
FILTER_SHARED_SHARED = 'shared'
|
||||
FILTER_SHARED_UNSHARED = 'unshared'
|
||||
FILTER_SHARED_OFF = 'off'
|
||||
FILTER_SHARED_SHARED = 'yes'
|
||||
FILTER_SHARED_UNSHARED = 'no'
|
||||
|
||||
FILTER_UNREAD_OFF = ''
|
||||
FILTER_UNREAD_OFF = 'off'
|
||||
FILTER_UNREAD_YES = 'yes'
|
||||
FILTER_UNREAD_NO = 'no'
|
||||
|
||||
params = ['q', 'user', 'sort', 'shared', 'unread']
|
||||
preferences = ['sort', 'shared', 'unread']
|
||||
defaults = {
|
||||
'q': '',
|
||||
'user': '',
|
||||
|
@ -148,43 +149,59 @@ class BookmarkSearch:
|
|||
}
|
||||
|
||||
def __init__(self,
|
||||
q: str = defaults['q'],
|
||||
query: str = defaults['q'], # alias for q
|
||||
user: str = defaults['user'],
|
||||
sort: str = defaults['sort'],
|
||||
shared: str = defaults['shared'],
|
||||
unread: str = defaults['unread']):
|
||||
self.q = q or query
|
||||
self.user = user
|
||||
self.sort = sort
|
||||
self.shared = shared
|
||||
self.unread = unread
|
||||
q: str = None,
|
||||
user: str = None,
|
||||
sort: str = None,
|
||||
shared: str = None,
|
||||
unread: str = None,
|
||||
preferences: dict = None):
|
||||
if not preferences:
|
||||
preferences = {}
|
||||
self.defaults = {**BookmarkSearch.defaults, **preferences}
|
||||
|
||||
@property
|
||||
def query(self):
|
||||
return self.q
|
||||
self.q = q or self.defaults['q']
|
||||
self.user = user or self.defaults['user']
|
||||
self.sort = sort or self.defaults['sort']
|
||||
self.shared = shared or self.defaults['shared']
|
||||
self.unread = unread or self.defaults['unread']
|
||||
|
||||
def is_modified(self, param):
|
||||
value = self.__dict__[param]
|
||||
return value and value != BookmarkSearch.defaults[param]
|
||||
return value != self.defaults[param]
|
||||
|
||||
@property
|
||||
def modified_params(self):
|
||||
return [field for field in self.params if self.is_modified(field)]
|
||||
|
||||
@property
|
||||
def modified_preferences(self):
|
||||
return [preference for preference in self.preferences if self.is_modified(preference)]
|
||||
|
||||
@property
|
||||
def has_modifications(self):
|
||||
return len(self.modified_params) > 0
|
||||
|
||||
@property
|
||||
def has_modified_preferences(self):
|
||||
return len(self.modified_preferences) > 0
|
||||
|
||||
@property
|
||||
def query_params(self):
|
||||
return {param: self.__dict__[param] for param in self.modified_params}
|
||||
|
||||
@property
|
||||
def preferences_dict(self):
|
||||
return {preference: self.__dict__[preference] for preference in self.preferences}
|
||||
|
||||
@staticmethod
|
||||
def from_request(request: WSGIRequest):
|
||||
def from_request(query_dict: QueryDict, preferences: dict = None):
|
||||
initial_values = {}
|
||||
for param in BookmarkSearch.params:
|
||||
value = request.GET.get(param)
|
||||
value = query_dict.get(param)
|
||||
if value:
|
||||
initial_values[param] = value
|
||||
|
||||
return BookmarkSearch(**initial_values)
|
||||
return BookmarkSearch(**initial_values, preferences=preferences)
|
||||
|
||||
|
||||
class BookmarkSearchForm(forms.Form):
|
||||
|
@ -214,6 +231,7 @@ class BookmarkSearchForm(forms.Form):
|
|||
def __init__(self, search: BookmarkSearch, editable_fields: List[str] = None, users: List[User] = None):
|
||||
super().__init__()
|
||||
editable_fields = editable_fields or []
|
||||
self.editable_fields = editable_fields
|
||||
|
||||
# set choices for user field if users are provided
|
||||
if users:
|
||||
|
@ -282,6 +300,7 @@ class UserProfile(models.Model):
|
|||
enable_favicons = models.BooleanField(default=False, null=False)
|
||||
display_url = models.BooleanField(default=False, null=False)
|
||||
permanent_notes = models.BooleanField(default=False, null=False)
|
||||
search_preferences = models.JSONField(default=dict, null=False)
|
||||
|
||||
|
||||
class UserProfileForm(forms.ModelForm):
|
||||
|
|
|
@ -37,7 +37,7 @@ def _base_bookmarks_query(user: Optional[User], profile: UserProfile, search: Bo
|
|||
query_set = query_set.filter(owner=user)
|
||||
|
||||
# Split query into search terms and tags
|
||||
query = parse_query_string(search.query)
|
||||
query = parse_query_string(search.q)
|
||||
|
||||
# Filter for search terms and tags
|
||||
for term in query['search_terms']:
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.bookmarks-page #search {
|
||||
.bookmarks-page .search-container {
|
||||
flex: 1 1 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
@import "../../node_modules/spectre.css/src/media";
|
||||
|
||||
// Components
|
||||
@import "../../node_modules/spectre.css/src/badges";
|
||||
@import "../../node_modules/spectre.css/src/dropdowns";
|
||||
@import "../../node_modules/spectre.css/src/empty";
|
||||
@import "../../node_modules/spectre.css/src/menus";
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
{% load widget_tweaks %}
|
||||
|
||||
<form id="search" action="" method="get" role="search">
|
||||
<div class="input-group">
|
||||
<div class="search-container">
|
||||
<form id="search" class="input-group" action="" method="get" role="search">
|
||||
<input type="search" class="form-input" name="q" placeholder="Search for words or #tags"
|
||||
value="{{ search.query }}">
|
||||
value="{{ search.q }}">
|
||||
<input type="submit" value="Search" class="btn input-group-btn">
|
||||
</div>
|
||||
{% for hidden_field in search_form.hidden_fields %}
|
||||
{{ hidden_field }}
|
||||
{% endfor %}
|
||||
</form>
|
||||
<div class="search-options dropdown dropdown-right">
|
||||
<button type="button" class="btn dropdown-toggle">
|
||||
<button type="button" class="btn dropdown-toggle{% if search.has_modified_preferences %} badge{% endif %}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" stroke-width="2"
|
||||
stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||
|
@ -23,40 +26,54 @@
|
|||
</svg>
|
||||
</button>
|
||||
<div class="menu text-sm" tabindex="0">
|
||||
<div class="form-group">
|
||||
<label for="{{ form.sort.id_for_label }}" class="form-label">Sort by</label>
|
||||
{{ form.sort|add_class:"form-select select-sm" }}
|
||||
</div>
|
||||
<div class="form-group radio-group">
|
||||
<div class="form-label">Shared filter</div>
|
||||
{% for radio in form.shared %}
|
||||
<label for="{{ radio.id_for_label }}" class="form-radio form-inline">
|
||||
{{ radio.tag }}
|
||||
<i class="form-icon"></i>
|
||||
{{ radio.choice_label }}
|
||||
</label>
|
||||
<form id="search_preferences" action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% if 'sort' in preferences_form.editable_fields %}
|
||||
<div class="form-group">
|
||||
<label for="{{ preferences_form.sort.id_for_label }}"
|
||||
class="form-label{% if 'sort' in search.modified_params %} text-bold{% endif %}">Sort by</label>
|
||||
{{ preferences_form.sort|add_class:"form-select select-sm" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'shared' in preferences_form.editable_fields %}
|
||||
<div class="form-group radio-group">
|
||||
<div class="form-label{% if 'shared' in search.modified_params %} text-bold{% endif %}">Shared filter</div>
|
||||
{% for radio in preferences_form.shared %}
|
||||
<label for="{{ radio.id_for_label }}" class="form-radio form-inline">
|
||||
{{ radio.tag }}
|
||||
<i class="form-icon"></i>
|
||||
{{ radio.choice_label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'unread' in preferences_form.editable_fields %}
|
||||
<div class="form-group radio-group">
|
||||
<div class="form-label{% if 'unread' in search.modified_params %} text-bold{% endif %}">Unread filter</div>
|
||||
{% for radio in preferences_form.unread %}
|
||||
<label for="{{ radio.id_for_label }}" class="form-radio form-inline">
|
||||
{{ radio.tag }}
|
||||
<i class="form-icon"></i>
|
||||
{{ radio.choice_label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn btn-sm btn-primary" name="apply">Apply</button>
|
||||
{% if request.user.is_authenticated %}
|
||||
<button type="submit" class="btn btn-sm" name="save">Save as default</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% for hidden_field in preferences_form.hidden_fields %}
|
||||
{{ hidden_field }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="form-group radio-group">
|
||||
<div class="form-label">Unread filter</div>
|
||||
{% for radio in form.unread %}
|
||||
<label for="{{ radio.id_for_label }}" class="form-radio form-inline">
|
||||
{{ radio.tag }}
|
||||
<i class="form-icon"></i>
|
||||
{{ radio.choice_label }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="submit" class="btn btn-sm btn-primary">Apply</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% for hidden_field in form.hidden_fields %}
|
||||
{{ hidden_field }}
|
||||
{% endfor %}
|
||||
</form>
|
||||
|
||||
{# Replace search input with auto-complete component #}
|
||||
<script type="application/javascript">
|
||||
|
@ -65,7 +82,7 @@
|
|||
const currentTags = currentTagsString.split(' ');
|
||||
const uniqueTags = [...new Set(currentTags)]
|
||||
const search = {
|
||||
q: '{{ search.query }}',
|
||||
q: '{{ search.q }}',
|
||||
user: '{{ search.user }}',
|
||||
shared: '{{ search.shared }}',
|
||||
unread: '{{ search.unread }}',
|
||||
|
@ -78,7 +95,7 @@
|
|||
props: {
|
||||
name: 'q',
|
||||
placeholder: 'Search for words or #tags',
|
||||
value: '{{ search.query|safe }}',
|
||||
value: '{{ search.q|safe }}',
|
||||
tags: uniqueTags,
|
||||
mode: '{{ mode }}',
|
||||
linkTarget: '{{ request.user_profile.bookmark_link_target }}',
|
||||
|
|
|
@ -22,11 +22,17 @@ def bookmark_form(context, form: BookmarkForm, cancel_url: str, bookmark_id: int
|
|||
def bookmark_search(context, search: BookmarkSearch, tags: [Tag], mode: str = ''):
|
||||
tag_names = [tag.name for tag in tags]
|
||||
tags_string = build_tag_string(tag_names, ' ')
|
||||
form = BookmarkSearchForm(search, editable_fields=['q', 'sort', 'shared', 'unread'])
|
||||
search_form = BookmarkSearchForm(search, editable_fields=['q'])
|
||||
|
||||
if mode == 'shared':
|
||||
preferences_form = BookmarkSearchForm(search, editable_fields=['sort'])
|
||||
else:
|
||||
preferences_form = BookmarkSearchForm(search, editable_fields=['sort', 'shared', 'unread'])
|
||||
return {
|
||||
'request': context['request'],
|
||||
'search': search,
|
||||
'form': form,
|
||||
'search_form': search_form,
|
||||
'preferences_form': preferences_form,
|
||||
'tags_string': tags_string,
|
||||
'mode': mode,
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ class BookmarkFactoryMixin:
|
|||
tags = []
|
||||
if with_tags:
|
||||
tag_name = f'{tag_prefix} {i}{suffix}'
|
||||
tags = [self.setup_tag(name=tag_name)]
|
||||
tags = [self.setup_tag(name=tag_name, user=user)]
|
||||
bookmark = self.setup_bookmark(url=url,
|
||||
title=title,
|
||||
is_archived=archived,
|
||||
|
@ -139,6 +139,12 @@ class BookmarkFactoryMixin:
|
|||
user.profile.save()
|
||||
return user
|
||||
|
||||
def get_tags_from_bookmarks(self, bookmarks: [Bookmark]):
|
||||
all_tags = []
|
||||
for bookmark in bookmarks:
|
||||
all_tags = all_tags + list(bookmark.tags.all())
|
||||
return all_tags
|
||||
|
||||
def get_random_string(self, length: int = 32):
|
||||
return get_random_string(length=length)
|
||||
|
||||
|
|
|
@ -440,21 +440,6 @@ class BookmarkActionViewTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.assertTrue(Bookmark.objects.get(id=bookmark2.id).is_archived)
|
||||
self.assertTrue(Bookmark.objects.get(id=bookmark3.id).is_archived)
|
||||
|
||||
def test_bulk_select_across_respects_query(self):
|
||||
self.setup_numbered_bookmarks(3, prefix='foo')
|
||||
self.setup_numbered_bookmarks(3, prefix='bar')
|
||||
|
||||
self.assertEqual(3, Bookmark.objects.filter(title__startswith='foo').count())
|
||||
|
||||
self.client.post(reverse('bookmarks:index.action') + '?q=foo', {
|
||||
'bulk_action': ['bulk_delete'],
|
||||
'bulk_execute': [''],
|
||||
'bulk_select_across': ['on'],
|
||||
})
|
||||
|
||||
self.assertEqual(0, Bookmark.objects.filter(title__startswith='foo').count())
|
||||
self.assertEqual(3, Bookmark.objects.filter(title__startswith='bar').count())
|
||||
|
||||
def test_bulk_select_across_ignores_page(self):
|
||||
self.setup_numbered_bookmarks(100)
|
||||
|
||||
|
@ -493,6 +478,21 @@ class BookmarkActionViewTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.assertIsNone(Bookmark.objects.filter(title='Bookmark 2').first())
|
||||
self.assertIsNone(Bookmark.objects.filter(title='Bookmark 3').first())
|
||||
|
||||
def test_index_action_bulk_select_across_respects_query(self):
|
||||
self.setup_numbered_bookmarks(3, prefix='foo')
|
||||
self.setup_numbered_bookmarks(3, prefix='bar')
|
||||
|
||||
self.assertEqual(3, Bookmark.objects.filter(title__startswith='foo').count())
|
||||
|
||||
self.client.post(reverse('bookmarks:index.action') + '?q=foo', {
|
||||
'bulk_action': ['bulk_delete'],
|
||||
'bulk_execute': [''],
|
||||
'bulk_select_across': ['on'],
|
||||
})
|
||||
|
||||
self.assertEqual(0, Bookmark.objects.filter(title__startswith='foo').count())
|
||||
self.assertEqual(3, Bookmark.objects.filter(title__startswith='bar').count())
|
||||
|
||||
def test_archived_action_bulk_select_across_only_affects_archived_bookmarks(self):
|
||||
self.setup_bulk_edit_scope_test_data()
|
||||
|
||||
|
@ -511,6 +511,21 @@ class BookmarkActionViewTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.assertIsNone(Bookmark.objects.filter(title='Archived Bookmark 2').first())
|
||||
self.assertIsNone(Bookmark.objects.filter(title='Archived Bookmark 3').first())
|
||||
|
||||
def test_archived_action_bulk_select_across_respects_query(self):
|
||||
self.setup_numbered_bookmarks(3, prefix='foo', archived=True)
|
||||
self.setup_numbered_bookmarks(3, prefix='bar', archived=True)
|
||||
|
||||
self.assertEqual(3, Bookmark.objects.filter(title__startswith='foo').count())
|
||||
|
||||
self.client.post(reverse('bookmarks:archived.action') + '?q=foo', {
|
||||
'bulk_action': ['bulk_delete'],
|
||||
'bulk_execute': [''],
|
||||
'bulk_select_across': ['on'],
|
||||
})
|
||||
|
||||
self.assertEqual(0, Bookmark.objects.filter(title__startswith='foo').count())
|
||||
self.assertEqual(3, Bookmark.objects.filter(title__startswith='bar').count())
|
||||
|
||||
def test_shared_action_bulk_select_across_not_supported(self):
|
||||
self.setup_bulk_edit_scope_test_data()
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.contrib.auth.models import User
|
|||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from bookmarks.models import Bookmark, Tag, UserProfile
|
||||
from bookmarks.models import Bookmark, BookmarkSearch, Tag, UserProfile
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin, HtmlTestMixin, collapse_whitespace
|
||||
|
||||
|
||||
|
@ -16,38 +16,51 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
|
|||
self.client.force_login(user)
|
||||
|
||||
def assertVisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
|
||||
html = response.content.decode()
|
||||
self.assertContains(response, '<li ld-bookmark-item>', count=len(bookmarks))
|
||||
soup = self.make_soup(response.content.decode())
|
||||
bookmark_list = soup.select_one(f'ul.bookmark-list[data-bookmarks-total="{len(bookmarks)}"]')
|
||||
self.assertIsNotNone(bookmark_list)
|
||||
|
||||
bookmark_items = bookmark_list.select('li[ld-bookmark-item]')
|
||||
self.assertEqual(len(bookmark_items), len(bookmarks))
|
||||
|
||||
for bookmark in bookmarks:
|
||||
self.assertInHTML(
|
||||
f'<a href="{bookmark.url}" target="{link_target}" rel="noopener">{bookmark.resolved_title}</a>',
|
||||
html
|
||||
)
|
||||
bookmark_item = bookmark_list.select_one(
|
||||
f'li[ld-bookmark-item] a[href="{bookmark.url}"][target="{link_target}"]')
|
||||
self.assertIsNotNone(bookmark_item)
|
||||
|
||||
def assertInvisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
|
||||
html = response.content.decode()
|
||||
soup = self.make_soup(response.content.decode())
|
||||
|
||||
for bookmark in bookmarks:
|
||||
self.assertInHTML(
|
||||
f'<a href="{bookmark.url}" target="{link_target}" rel="noopener">{bookmark.resolved_title}</a>',
|
||||
html,
|
||||
count=0
|
||||
)
|
||||
bookmark_item = soup.select_one(
|
||||
f'li[ld-bookmark-item] a[href="{bookmark.url}"][target="{link_target}"]')
|
||||
self.assertIsNone(bookmark_item)
|
||||
|
||||
def assertVisibleTags(self, response, tags: List[Tag]):
|
||||
self.assertContains(response, 'data-is-tag-item', count=len(tags))
|
||||
soup = self.make_soup(response.content.decode())
|
||||
tag_cloud = soup.select_one('div.tag-cloud')
|
||||
self.assertIsNotNone(tag_cloud)
|
||||
|
||||
tag_items = tag_cloud.select('a[data-is-tag-item]')
|
||||
self.assertEqual(len(tag_items), len(tags))
|
||||
|
||||
tag_item_names = [tag_item.text.strip() for tag_item in tag_items]
|
||||
|
||||
for tag in tags:
|
||||
self.assertContains(response, tag.name)
|
||||
self.assertTrue(tag.name in tag_item_names)
|
||||
|
||||
def assertInvisibleTags(self, response, tags: List[Tag]):
|
||||
soup = self.make_soup(response.content.decode())
|
||||
tag_items = soup.select('a[data-is-tag-item]')
|
||||
|
||||
tag_item_names = [tag_item.text.strip() for tag_item in tag_items]
|
||||
|
||||
for tag in tags:
|
||||
self.assertNotContains(response, tag.name)
|
||||
self.assertFalse(tag.name in tag_item_names)
|
||||
|
||||
def assertSelectedTags(self, response, tags: List[Tag]):
|
||||
soup = self.make_soup(response.content.decode())
|
||||
selected_tags = soup.select('p.selected-tags')[0]
|
||||
selected_tags = soup.select_one('p.selected-tags')
|
||||
self.assertIsNotNone(selected_tags)
|
||||
|
||||
tag_list = selected_tags.select('a')
|
||||
|
@ -73,67 +86,36 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
|
|||
|
||||
def test_should_list_archived_and_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True)
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, archived=True)
|
||||
invisible_bookmarks = [
|
||||
self.setup_bookmark(is_archived=False),
|
||||
self.setup_bookmark(is_archived=True, user=other_user),
|
||||
]
|
||||
|
||||
response = self.client.get(reverse('bookmarks:archived'))
|
||||
html = collapse_whitespace(response.content.decode())
|
||||
|
||||
# Should render list
|
||||
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, invisible_bookmarks)
|
||||
|
||||
def test_should_list_bookmarks_matching_query(self):
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True, title='searchvalue'),
|
||||
self.setup_bookmark(is_archived=True, title='searchvalue'),
|
||||
self.setup_bookmark(is_archived=True, title='searchvalue')
|
||||
]
|
||||
invisible_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True)
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, prefix='foo', archived=True)
|
||||
invisible_bookmarks = self.setup_numbered_bookmarks(3, prefix='bar', archived=True)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:archived') + '?q=searchvalue')
|
||||
response = self.client.get(reverse('bookmarks:archived') + '?q=foo')
|
||||
html = collapse_whitespace(response.content.decode())
|
||||
|
||||
# Should render list
|
||||
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, invisible_bookmarks)
|
||||
|
||||
def test_should_list_tags_for_archived_and_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
|
||||
visible_tags = [
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
]
|
||||
invisible_tags = [
|
||||
self.setup_tag(), # unused tag
|
||||
self.setup_tag(), # used in archived bookmark
|
||||
self.setup_tag(user=other_user), # belongs to other user
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, archived=True)
|
||||
unarchived_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, archived=False, tag_prefix='unarchived')
|
||||
other_user_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, archived=True, user=other_user,
|
||||
tag_prefix='otheruser')
|
||||
|
||||
# Assign tags to some bookmarks with duplicates
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[0]])
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[0]])
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[1]])
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[1]])
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[2]])
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[2]])
|
||||
|
||||
self.setup_bookmark(is_archived=False, tags=[invisible_tags[1]])
|
||||
self.setup_bookmark(is_archived=True, tags=[invisible_tags[2]], user=other_user)
|
||||
visible_tags = self.get_tags_from_bookmarks(visible_bookmarks)
|
||||
invisible_tags = self.get_tags_from_bookmarks(unarchived_bookmarks + other_user_bookmarks)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:archived'))
|
||||
|
||||
|
@ -141,29 +123,40 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
|
|||
self.assertInvisibleTags(response, invisible_tags)
|
||||
|
||||
def test_should_list_tags_for_bookmarks_matching_query(self):
|
||||
visible_tags = [
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
]
|
||||
invisible_tags = [
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, archived=True, prefix='foo',
|
||||
tag_prefix='foo')
|
||||
invisible_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, archived=True, prefix='bar',
|
||||
tag_prefix='bar')
|
||||
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[0]], title='searchvalue')
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[1]], title='searchvalue')
|
||||
self.setup_bookmark(is_archived=True, tags=[visible_tags[2]], title='searchvalue')
|
||||
self.setup_bookmark(is_archived=True, tags=[invisible_tags[0]])
|
||||
self.setup_bookmark(is_archived=True, tags=[invisible_tags[1]])
|
||||
self.setup_bookmark(is_archived=True, tags=[invisible_tags[2]])
|
||||
visible_tags = self.get_tags_from_bookmarks(visible_bookmarks)
|
||||
invisible_tags = self.get_tags_from_bookmarks(invisible_bookmarks)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:archived') + '?q=searchvalue')
|
||||
response = self.client.get(reverse('bookmarks:archived') + '?q=foo')
|
||||
|
||||
self.assertVisibleTags(response, visible_tags)
|
||||
self.assertInvisibleTags(response, invisible_tags)
|
||||
|
||||
def test_should_list_bookmarks_and_tags_for_search_preferences(self):
|
||||
user_profile = self.user.profile
|
||||
user_profile.search_preferences = {
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
user_profile.save()
|
||||
|
||||
unread_bookmarks = self.setup_numbered_bookmarks(3, archived=True, unread=True, with_tags=True, prefix='unread',
|
||||
tag_prefix='unread')
|
||||
read_bookmarks = self.setup_numbered_bookmarks(3, archived=True, unread=False, with_tags=True, prefix='read',
|
||||
tag_prefix='read')
|
||||
|
||||
unread_tags = self.get_tags_from_bookmarks(unread_bookmarks)
|
||||
read_tags = self.get_tags_from_bookmarks(read_bookmarks)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:archived'))
|
||||
self.assertVisibleBookmarks(response, unread_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, read_bookmarks)
|
||||
self.assertVisibleTags(response, unread_tags)
|
||||
self.assertInvisibleTags(response, read_tags)
|
||||
|
||||
def test_should_display_selected_tags_from_query(self):
|
||||
tags = [
|
||||
self.setup_tag(),
|
||||
|
@ -210,11 +203,7 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
|
|||
self.assertSelectedTags(response, [tags[0], tags[1]])
|
||||
|
||||
def test_should_open_bookmarks_in_new_page_by_default(self):
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True)
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, archived=True)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:archived'))
|
||||
|
||||
|
@ -225,11 +214,7 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
|
|||
user.profile.bookmark_link_target = UserProfile.BOOKMARK_LINK_TARGET_SELF
|
||||
user.profile.save()
|
||||
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(is_archived=True)
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, archived=True)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:archived'))
|
||||
|
||||
|
@ -328,6 +313,106 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
|
|||
</select>
|
||||
''', html)
|
||||
|
||||
def test_apply_search_preferences(self):
|
||||
# no params
|
||||
response = self.client.post(reverse('bookmarks:archived'))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:archived'))
|
||||
|
||||
# some params
|
||||
response = self.client.post(reverse('bookmarks:archived'), {
|
||||
'q': 'foo',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:archived') + '?q=foo&sort=title_asc')
|
||||
|
||||
# params with default value are removed
|
||||
response = self.client.post(reverse('bookmarks:archived'), {
|
||||
'q': 'foo',
|
||||
'user': '',
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:archived') + '?q=foo&unread=yes')
|
||||
|
||||
# page is removed
|
||||
response = self.client.post(reverse('bookmarks:archived'), {
|
||||
'q': 'foo',
|
||||
'page': '2',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:archived') + '?q=foo&sort=title_asc')
|
||||
|
||||
def test_save_search_preferences(self):
|
||||
user_profile = self.user.profile
|
||||
|
||||
# no params
|
||||
self.client.post(reverse('bookmarks:archived'), {
|
||||
'save': '',
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
# with param
|
||||
self.client.post(reverse('bookmarks:archived'), {
|
||||
'save': '',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
# add a param
|
||||
self.client.post(reverse('bookmarks:archived'), {
|
||||
'save': '',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
|
||||
# remove a param
|
||||
self.client.post(reverse('bookmarks:archived'), {
|
||||
'save': '',
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
|
||||
# ignores non-preferences
|
||||
self.client.post(reverse('bookmarks:archived'), {
|
||||
'save': '',
|
||||
'q': 'foo',
|
||||
'user': 'john',
|
||||
'page': '3',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
def test_url_encode_bookmark_actions_url(self):
|
||||
url = reverse('bookmarks:archived') + '?q=%23foo'
|
||||
response = self.client.get(url)
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.contrib.auth.models import User
|
|||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from bookmarks.models import Bookmark, Tag, UserProfile
|
||||
from bookmarks.models import Bookmark, BookmarkSearch, Tag, UserProfile
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin, HtmlTestMixin, collapse_whitespace
|
||||
|
||||
|
||||
|
@ -16,38 +16,51 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
self.client.force_login(user)
|
||||
|
||||
def assertVisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
|
||||
html = response.content.decode()
|
||||
self.assertContains(response, '<li ld-bookmark-item>', count=len(bookmarks))
|
||||
soup = self.make_soup(response.content.decode())
|
||||
bookmark_list = soup.select_one(f'ul.bookmark-list[data-bookmarks-total="{len(bookmarks)}"]')
|
||||
self.assertIsNotNone(bookmark_list)
|
||||
|
||||
bookmark_items = bookmark_list.select('li[ld-bookmark-item]')
|
||||
self.assertEqual(len(bookmark_items), len(bookmarks))
|
||||
|
||||
for bookmark in bookmarks:
|
||||
self.assertInHTML(
|
||||
f'<a href="{bookmark.url}" target="{link_target}" rel="noopener">{bookmark.resolved_title}</a>',
|
||||
html
|
||||
)
|
||||
bookmark_item = bookmark_list.select_one(
|
||||
f'li[ld-bookmark-item] a[href="{bookmark.url}"][target="{link_target}"]')
|
||||
self.assertIsNotNone(bookmark_item)
|
||||
|
||||
def assertInvisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
|
||||
html = response.content.decode()
|
||||
soup = self.make_soup(response.content.decode())
|
||||
|
||||
for bookmark in bookmarks:
|
||||
self.assertInHTML(
|
||||
f'<a href="{bookmark.url}" target="{link_target}" rel="noopener">{bookmark.resolved_title}</a>',
|
||||
html,
|
||||
count=0
|
||||
)
|
||||
bookmark_item = soup.select_one(
|
||||
f'li[ld-bookmark-item] a[href="{bookmark.url}"][target="{link_target}"]')
|
||||
self.assertIsNone(bookmark_item)
|
||||
|
||||
def assertVisibleTags(self, response, tags: List[Tag]):
|
||||
self.assertContains(response, 'data-is-tag-item', count=len(tags))
|
||||
soup = self.make_soup(response.content.decode())
|
||||
tag_cloud = soup.select_one('div.tag-cloud')
|
||||
self.assertIsNotNone(tag_cloud)
|
||||
|
||||
tag_items = tag_cloud.select('a[data-is-tag-item]')
|
||||
self.assertEqual(len(tag_items), len(tags))
|
||||
|
||||
tag_item_names = [tag_item.text.strip() for tag_item in tag_items]
|
||||
|
||||
for tag in tags:
|
||||
self.assertContains(response, tag.name)
|
||||
self.assertTrue(tag.name in tag_item_names)
|
||||
|
||||
def assertInvisibleTags(self, response, tags: List[Tag]):
|
||||
soup = self.make_soup(response.content.decode())
|
||||
tag_items = soup.select('a[data-is-tag-item]')
|
||||
|
||||
tag_item_names = [tag_item.text.strip() for tag_item in tag_items]
|
||||
|
||||
for tag in tags:
|
||||
self.assertNotContains(response, tag.name)
|
||||
self.assertFalse(tag.name in tag_item_names)
|
||||
|
||||
def assertSelectedTags(self, response, tags: List[Tag]):
|
||||
soup = self.make_soup(response.content.decode())
|
||||
selected_tags = soup.select('p.selected-tags')[0]
|
||||
selected_tags = soup.select_one('p.selected-tags')
|
||||
self.assertIsNotNone(selected_tags)
|
||||
|
||||
tag_list = selected_tags.select('a')
|
||||
|
@ -73,67 +86,34 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
|
||||
def test_should_list_unarchived_and_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark()
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3)
|
||||
invisible_bookmarks = [
|
||||
self.setup_bookmark(is_archived=True),
|
||||
self.setup_bookmark(user=other_user),
|
||||
]
|
||||
|
||||
response = self.client.get(reverse('bookmarks:index'))
|
||||
html = collapse_whitespace(response.content.decode())
|
||||
|
||||
# Should render list
|
||||
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, invisible_bookmarks)
|
||||
|
||||
def test_should_list_bookmarks_matching_query(self):
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(title='searchvalue'),
|
||||
self.setup_bookmark(title='searchvalue'),
|
||||
self.setup_bookmark(title='searchvalue')
|
||||
]
|
||||
invisible_bookmarks = [
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark()
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, prefix='foo')
|
||||
invisible_bookmarks = self.setup_numbered_bookmarks(3, prefix='bar')
|
||||
|
||||
response = self.client.get(reverse('bookmarks:index') + '?q=searchvalue')
|
||||
html = collapse_whitespace(response.content.decode())
|
||||
response = self.client.get(reverse('bookmarks:index') + '?q=foo')
|
||||
|
||||
# Should render list
|
||||
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, invisible_bookmarks)
|
||||
|
||||
def test_should_list_tags_for_unarchived_and_user_owned_bookmarks(self):
|
||||
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
|
||||
visible_tags = [
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
]
|
||||
invisible_tags = [
|
||||
self.setup_tag(), # unused tag
|
||||
self.setup_tag(), # used in archived bookmark
|
||||
self.setup_tag(user=other_user), # belongs to other user
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True)
|
||||
archived_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, archived=True, tag_prefix='archived')
|
||||
other_user_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, user=other_user, tag_prefix='otheruser')
|
||||
|
||||
# Assign tags to some bookmarks with duplicates
|
||||
self.setup_bookmark(tags=[visible_tags[0]])
|
||||
self.setup_bookmark(tags=[visible_tags[0]])
|
||||
self.setup_bookmark(tags=[visible_tags[1]])
|
||||
self.setup_bookmark(tags=[visible_tags[1]])
|
||||
self.setup_bookmark(tags=[visible_tags[2]])
|
||||
self.setup_bookmark(tags=[visible_tags[2]])
|
||||
|
||||
self.setup_bookmark(tags=[invisible_tags[1]], is_archived=True)
|
||||
self.setup_bookmark(tags=[invisible_tags[2]], user=other_user)
|
||||
visible_tags = self.get_tags_from_bookmarks(visible_bookmarks)
|
||||
invisible_tags = self.get_tags_from_bookmarks(archived_bookmarks + other_user_bookmarks)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:index'))
|
||||
|
||||
|
@ -141,29 +121,38 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
self.assertInvisibleTags(response, invisible_tags)
|
||||
|
||||
def test_should_list_tags_for_bookmarks_matching_query(self):
|
||||
visible_tags = [
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
]
|
||||
invisible_tags = [
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
self.setup_tag(),
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, prefix='foo', tag_prefix='foo')
|
||||
invisible_bookmarks = self.setup_numbered_bookmarks(3, with_tags=True, prefix='bar', tag_prefix='bar')
|
||||
|
||||
self.setup_bookmark(tags=[visible_tags[0]], title='searchvalue')
|
||||
self.setup_bookmark(tags=[visible_tags[1]], title='searchvalue')
|
||||
self.setup_bookmark(tags=[visible_tags[2]], title='searchvalue')
|
||||
self.setup_bookmark(tags=[invisible_tags[0]])
|
||||
self.setup_bookmark(tags=[invisible_tags[1]])
|
||||
self.setup_bookmark(tags=[invisible_tags[2]])
|
||||
visible_tags = self.get_tags_from_bookmarks(visible_bookmarks)
|
||||
invisible_tags = self.get_tags_from_bookmarks(invisible_bookmarks)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:index') + '?q=searchvalue')
|
||||
response = self.client.get(reverse('bookmarks:index') + '?q=foo')
|
||||
|
||||
self.assertVisibleTags(response, visible_tags)
|
||||
self.assertInvisibleTags(response, invisible_tags)
|
||||
|
||||
def test_should_list_bookmarks_and_tags_for_search_preferences(self):
|
||||
user_profile = self.user.profile
|
||||
user_profile.search_preferences = {
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
user_profile.save()
|
||||
|
||||
unread_bookmarks = self.setup_numbered_bookmarks(3, unread=True, with_tags=True, prefix='unread',
|
||||
tag_prefix='unread')
|
||||
read_bookmarks = self.setup_numbered_bookmarks(3, unread=False, with_tags=True, prefix='read',
|
||||
tag_prefix='read')
|
||||
|
||||
unread_tags = self.get_tags_from_bookmarks(unread_bookmarks)
|
||||
read_tags = self.get_tags_from_bookmarks(read_bookmarks)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:index'))
|
||||
self.assertVisibleBookmarks(response, unread_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, read_bookmarks)
|
||||
self.assertVisibleTags(response, unread_tags)
|
||||
self.assertInvisibleTags(response, read_tags)
|
||||
|
||||
def test_should_display_selected_tags_from_query(self):
|
||||
tags = [
|
||||
self.setup_tag(),
|
||||
|
@ -210,11 +199,7 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
self.assertSelectedTags(response, [tags[0], tags[1]])
|
||||
|
||||
def test_should_open_bookmarks_in_new_page_by_default(self):
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark()
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:index'))
|
||||
|
||||
|
@ -225,11 +210,7 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
user.profile.bookmark_link_target = UserProfile.BOOKMARK_LINK_TARGET_SELF
|
||||
user.profile.save()
|
||||
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark(),
|
||||
self.setup_bookmark()
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:index'))
|
||||
|
||||
|
@ -328,6 +309,106 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
</select>
|
||||
''', html)
|
||||
|
||||
def test_apply_search_preferences(self):
|
||||
# no params
|
||||
response = self.client.post(reverse('bookmarks:index'))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:index'))
|
||||
|
||||
# some params
|
||||
response = self.client.post(reverse('bookmarks:index'), {
|
||||
'q': 'foo',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:index') + '?q=foo&sort=title_asc')
|
||||
|
||||
# params with default value are removed
|
||||
response = self.client.post(reverse('bookmarks:index'), {
|
||||
'q': 'foo',
|
||||
'user': '',
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:index') + '?q=foo&unread=yes')
|
||||
|
||||
# page is removed
|
||||
response = self.client.post(reverse('bookmarks:index'), {
|
||||
'q': 'foo',
|
||||
'page': '2',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:index') + '?q=foo&sort=title_asc')
|
||||
|
||||
def test_save_search_preferences(self):
|
||||
user_profile = self.user.profile
|
||||
|
||||
# no params
|
||||
self.client.post(reverse('bookmarks:index'), {
|
||||
'save': '',
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
# with param
|
||||
self.client.post(reverse('bookmarks:index'), {
|
||||
'save': '',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
# add a param
|
||||
self.client.post(reverse('bookmarks:index'), {
|
||||
'save': '',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
|
||||
# remove a param
|
||||
self.client.post(reverse('bookmarks:index'), {
|
||||
'save': '',
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
|
||||
# ignores non-preferences
|
||||
self.client.post(reverse('bookmarks:index'), {
|
||||
'save': '',
|
||||
'q': 'foo',
|
||||
'user': 'john',
|
||||
'page': '3',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
def test_url_encode_bookmark_actions_url(self):
|
||||
url = reverse('bookmarks:index') + '?q=%23foo'
|
||||
response = self.client.get(url)
|
||||
|
|
|
@ -10,10 +10,10 @@ class BookmarkSearchFormTest(TestCase, BookmarkFactoryMixin):
|
|||
search = BookmarkSearch()
|
||||
form = BookmarkSearchForm(search)
|
||||
self.assertEqual(form['q'].initial, '')
|
||||
self.assertEqual(form['sort'].initial, BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertEqual(form['user'].initial, '')
|
||||
self.assertEqual(form['shared'].initial, '')
|
||||
self.assertEqual(form['unread'].initial, '')
|
||||
self.assertEqual(form['sort'].initial, BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertEqual(form['shared'].initial, BookmarkSearch.FILTER_SHARED_OFF)
|
||||
self.assertEqual(form['unread'].initial, BookmarkSearch.FILTER_UNREAD_OFF)
|
||||
|
||||
# with params
|
||||
search = BookmarkSearch(q='search query',
|
||||
|
@ -23,8 +23,8 @@ class BookmarkSearchFormTest(TestCase, BookmarkFactoryMixin):
|
|||
unread=BookmarkSearch.FILTER_UNREAD_YES)
|
||||
form = BookmarkSearchForm(search)
|
||||
self.assertEqual(form['q'].initial, 'search query')
|
||||
self.assertEqual(form['sort'].initial, BookmarkSearch.SORT_ADDED_ASC)
|
||||
self.assertEqual(form['user'].initial, 'user123')
|
||||
self.assertEqual(form['sort'].initial, BookmarkSearch.SORT_ADDED_ASC)
|
||||
self.assertEqual(form['shared'].initial, BookmarkSearch.FILTER_SHARED_SHARED)
|
||||
self.assertEqual(form['unread'].initial, BookmarkSearch.FILTER_UNREAD_YES)
|
||||
|
||||
|
|
|
@ -1,50 +1,70 @@
|
|||
from unittest.mock import Mock
|
||||
from bookmarks.models import BookmarkSearch
|
||||
from django.http import QueryDict
|
||||
from django.test import TestCase
|
||||
|
||||
from bookmarks.models import BookmarkSearch
|
||||
|
||||
|
||||
class BookmarkSearchModelTest(TestCase):
|
||||
def test_from_request(self):
|
||||
# no params
|
||||
mock_request = Mock()
|
||||
mock_request.GET = {}
|
||||
query_dict = QueryDict()
|
||||
|
||||
search = BookmarkSearch.from_request(mock_request)
|
||||
search = BookmarkSearch.from_request(query_dict)
|
||||
self.assertEqual(search.q, '')
|
||||
self.assertEqual(search.sort, BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertEqual(search.user, '')
|
||||
self.assertEqual(search.shared, '')
|
||||
self.assertEqual(search.unread, '')
|
||||
self.assertEqual(search.sort, BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertEqual(search.shared, BookmarkSearch.FILTER_SHARED_OFF)
|
||||
self.assertEqual(search.unread, BookmarkSearch.FILTER_UNREAD_OFF)
|
||||
|
||||
# some params
|
||||
mock_request.GET = {
|
||||
'q': 'search query',
|
||||
'user': 'user123',
|
||||
}
|
||||
query_dict = QueryDict('q=search query&user=user123')
|
||||
|
||||
bookmark_search = BookmarkSearch.from_request(mock_request)
|
||||
bookmark_search = BookmarkSearch.from_request(query_dict)
|
||||
self.assertEqual(bookmark_search.q, 'search query')
|
||||
self.assertEqual(bookmark_search.sort, BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertEqual(bookmark_search.user, 'user123')
|
||||
self.assertEqual(bookmark_search.shared, '')
|
||||
self.assertEqual(bookmark_search.unread, '')
|
||||
self.assertEqual(bookmark_search.sort, BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertEqual(search.shared, BookmarkSearch.FILTER_SHARED_OFF)
|
||||
self.assertEqual(search.unread, BookmarkSearch.FILTER_UNREAD_OFF)
|
||||
|
||||
# all params
|
||||
mock_request.GET = {
|
||||
'q': 'search query',
|
||||
'user': 'user123',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_SHARED,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
query_dict = QueryDict('q=search query&sort=title_asc&user=user123&shared=yes&unread=yes')
|
||||
|
||||
search = BookmarkSearch.from_request(mock_request)
|
||||
search = BookmarkSearch.from_request(query_dict)
|
||||
self.assertEqual(search.q, 'search query')
|
||||
self.assertEqual(search.user, 'user123')
|
||||
self.assertEqual(search.sort, BookmarkSearch.SORT_TITLE_ASC)
|
||||
self.assertEqual(search.shared, BookmarkSearch.FILTER_SHARED_SHARED)
|
||||
self.assertEqual(search.unread, BookmarkSearch.FILTER_UNREAD_YES)
|
||||
|
||||
# respects preferences
|
||||
preferences = {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
query_dict = QueryDict('q=search query')
|
||||
|
||||
search = BookmarkSearch.from_request(query_dict, preferences)
|
||||
self.assertEqual(search.q, 'search query')
|
||||
self.assertEqual(search.user, '')
|
||||
self.assertEqual(search.sort, BookmarkSearch.SORT_TITLE_ASC)
|
||||
self.assertEqual(search.shared, BookmarkSearch.FILTER_SHARED_OFF)
|
||||
self.assertEqual(search.unread, BookmarkSearch.FILTER_UNREAD_YES)
|
||||
|
||||
# query overrides preferences
|
||||
preferences = {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_SHARED,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
query_dict = QueryDict('sort=title_desc&shared=no&unread=off')
|
||||
|
||||
search = BookmarkSearch.from_request(query_dict, preferences)
|
||||
self.assertEqual(search.q, '')
|
||||
self.assertEqual(search.user, '')
|
||||
self.assertEqual(search.sort, BookmarkSearch.SORT_TITLE_DESC)
|
||||
self.assertEqual(search.shared, BookmarkSearch.FILTER_SHARED_UNSHARED)
|
||||
self.assertEqual(search.unread, BookmarkSearch.FILTER_UNREAD_OFF)
|
||||
|
||||
def test_modified_params(self):
|
||||
# no params
|
||||
bookmark_search = BookmarkSearch()
|
||||
|
@ -69,3 +89,74 @@ class BookmarkSearchModelTest(TestCase):
|
|||
unread=BookmarkSearch.FILTER_UNREAD_YES)
|
||||
modified_params = bookmark_search.modified_params
|
||||
self.assertCountEqual(modified_params, ['q', 'sort', 'user', 'shared', 'unread'])
|
||||
|
||||
# preferences are not modified params
|
||||
preferences = {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
bookmark_search = BookmarkSearch(preferences=preferences)
|
||||
modified_params = bookmark_search.modified_params
|
||||
self.assertEqual(len(modified_params), 0)
|
||||
|
||||
# param is not modified if it matches the preference
|
||||
preferences = {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
bookmark_search = BookmarkSearch(sort=BookmarkSearch.SORT_TITLE_ASC,
|
||||
unread=BookmarkSearch.FILTER_UNREAD_YES,
|
||||
preferences=preferences)
|
||||
modified_params = bookmark_search.modified_params
|
||||
self.assertEqual(len(modified_params), 0)
|
||||
|
||||
# overriding preferences is a modified param
|
||||
preferences = {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_SHARED,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
bookmark_search = BookmarkSearch(sort=BookmarkSearch.SORT_TITLE_DESC,
|
||||
shared=BookmarkSearch.FILTER_SHARED_UNSHARED,
|
||||
unread=BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
preferences=preferences)
|
||||
modified_params = bookmark_search.modified_params
|
||||
self.assertCountEqual(modified_params, ['sort', 'shared', 'unread'])
|
||||
|
||||
def test_has_modifications(self):
|
||||
# no params
|
||||
bookmark_search = BookmarkSearch()
|
||||
self.assertFalse(bookmark_search.has_modifications)
|
||||
|
||||
# params are default values
|
||||
bookmark_search = BookmarkSearch(q='', sort=BookmarkSearch.SORT_ADDED_DESC, user='', shared='')
|
||||
self.assertFalse(bookmark_search.has_modifications)
|
||||
|
||||
# modified params
|
||||
bookmark_search = BookmarkSearch(q='search query', sort=BookmarkSearch.SORT_ADDED_ASC)
|
||||
self.assertTrue(bookmark_search.has_modifications)
|
||||
|
||||
def test_preferences_dict(self):
|
||||
# no params
|
||||
bookmark_search = BookmarkSearch()
|
||||
self.assertEqual(bookmark_search.preferences_dict, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
# with params
|
||||
bookmark_search = BookmarkSearch(sort=BookmarkSearch.SORT_TITLE_DESC, unread=BookmarkSearch.FILTER_UNREAD_YES)
|
||||
self.assertEqual(bookmark_search.preferences_dict, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
|
||||
# only returns preferences
|
||||
bookmark_search = BookmarkSearch(q='search query', user='user123')
|
||||
self.assertEqual(bookmark_search.preferences_dict, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
|
|
@ -1,58 +1,226 @@
|
|||
from bs4 import BeautifulSoup
|
||||
from django.db.models import QuerySet
|
||||
from django.template import Template, RequestContext
|
||||
from django.test import TestCase, RequestFactory
|
||||
|
||||
from bookmarks.models import BookmarkSearch, Tag
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin, HtmlTestMixin
|
||||
|
||||
|
||||
class BookmarkSearchTagTest(TestCase, BookmarkFactoryMixin):
|
||||
def render_template(self, url: str, tags: QuerySet[Tag] = Tag.objects.all()):
|
||||
class BookmarkSearchTagTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
||||
def render_template(self, url: str, tags: QuerySet[Tag] = Tag.objects.all(), mode: str = ''):
|
||||
rf = RequestFactory()
|
||||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user_profile = self.get_or_create_test_user().profile
|
||||
search = BookmarkSearch.from_request(request)
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
context = RequestContext(request, {
|
||||
'request': request,
|
||||
'search': search,
|
||||
'tags': tags,
|
||||
'mode': mode,
|
||||
})
|
||||
template_to_render = Template(
|
||||
'{% load bookmarks %}'
|
||||
'{% bookmark_search search tags %}'
|
||||
'{% bookmark_search search tags mode %}'
|
||||
)
|
||||
return template_to_render.render(context)
|
||||
|
||||
def assertHiddenInput(self, html: str, name: str, value: str = None):
|
||||
needle = f'<input type="hidden" name="{name}"'
|
||||
def assertHiddenInput(self, form: BeautifulSoup, name: str, value: str = None):
|
||||
input = form.select_one(f'input[name="{name}"][type="hidden"]')
|
||||
self.assertIsNotNone(input)
|
||||
|
||||
if value is not None:
|
||||
needle += f' value="{value}"'
|
||||
self.assertEqual(input['value'], value)
|
||||
|
||||
self.assertIn(needle, html)
|
||||
def assertNoHiddenInput(self, form: BeautifulSoup, name: str):
|
||||
input = form.select_one(f'input[name="{name}"][type="hidden"]')
|
||||
self.assertIsNone(input)
|
||||
|
||||
def assertNoHiddenInput(self, html: str, name: str):
|
||||
needle = f'<input type="hidden" name="{name}"'
|
||||
def assertSearchInput(self, form: BeautifulSoup, name: str, value: str = None):
|
||||
input = form.select_one(f'input[name="{name}"][type="search"]')
|
||||
self.assertIsNotNone(input)
|
||||
|
||||
self.assertNotIn(needle, html)
|
||||
if value is not None:
|
||||
self.assertEqual(input['value'], value)
|
||||
|
||||
def test_hidden_inputs(self):
|
||||
def assertSelect(self, form: BeautifulSoup, name: str, value: str = None):
|
||||
select = form.select_one(f'select[name="{name}"]')
|
||||
self.assertIsNotNone(select)
|
||||
|
||||
if value is not None:
|
||||
options = select.select('option')
|
||||
for option in options:
|
||||
if option['value'] == value:
|
||||
self.assertTrue(option.has_attr('selected'))
|
||||
else:
|
||||
self.assertFalse(option.has_attr('selected'))
|
||||
|
||||
def assertRadioGroup(self, form: BeautifulSoup, name: str, value: str = None):
|
||||
radios = form.select(f'input[name="{name}"][type="radio"]')
|
||||
self.assertTrue(len(radios) > 0)
|
||||
|
||||
if value is not None:
|
||||
for radio in radios:
|
||||
if radio['value'] == value:
|
||||
self.assertTrue(radio.has_attr('checked'))
|
||||
else:
|
||||
self.assertFalse(radio.has_attr('checked'))
|
||||
|
||||
def assertNoRadioGroup(self, form: BeautifulSoup, name: str):
|
||||
radios = form.select(f'input[name="{name}"][type="radio"]')
|
||||
self.assertTrue(len(radios) == 0)
|
||||
|
||||
def assertUnmodifiedLabel(self, html: str, text: str, id: str = ''):
|
||||
id_attr = f'for="{id}"' if id else ''
|
||||
tag = 'label' if id else 'div'
|
||||
needle = f'<{tag} class="form-label" {id_attr}>{text}</{tag}>'
|
||||
|
||||
self.assertInHTML(needle, html)
|
||||
|
||||
def assertModifiedLabel(self, html: str, text: str, id: str = ''):
|
||||
id_attr = f'for="{id}"' if id else ''
|
||||
tag = 'label' if id else 'div'
|
||||
needle = f'<{tag} class="form-label text-bold" {id_attr}>{text}</{tag}>'
|
||||
|
||||
self.assertInHTML(needle, html)
|
||||
|
||||
def test_search_form_inputs(self):
|
||||
# Without params
|
||||
url = '/test'
|
||||
rendered_template = self.render_template(url)
|
||||
soup = self.make_soup(rendered_template)
|
||||
search_form = soup.select_one('form#search')
|
||||
|
||||
self.assertNoHiddenInput(rendered_template, 'user')
|
||||
self.assertNoHiddenInput(rendered_template, 'q')
|
||||
self.assertNoHiddenInput(rendered_template, 'sort')
|
||||
self.assertNoHiddenInput(rendered_template, 'shared')
|
||||
self.assertNoHiddenInput(rendered_template, 'unread')
|
||||
self.assertSearchInput(search_form, 'q')
|
||||
self.assertNoHiddenInput(search_form, 'user')
|
||||
self.assertNoHiddenInput(search_form, 'sort')
|
||||
self.assertNoHiddenInput(search_form, 'shared')
|
||||
self.assertNoHiddenInput(search_form, 'unread')
|
||||
|
||||
# With params
|
||||
url = '/test?q=foo&user=john&sort=title_asc&shared=shared&unread=yes'
|
||||
url = '/test?q=foo&user=john&sort=title_asc&shared=yes&unread=yes'
|
||||
rendered_template = self.render_template(url)
|
||||
soup = self.make_soup(rendered_template)
|
||||
search_form = soup.select_one('form#search')
|
||||
|
||||
self.assertSearchInput(search_form, 'q', 'foo')
|
||||
self.assertHiddenInput(search_form, 'user', 'john')
|
||||
self.assertHiddenInput(search_form, 'sort', BookmarkSearch.SORT_TITLE_ASC)
|
||||
self.assertHiddenInput(search_form, 'shared', BookmarkSearch.FILTER_SHARED_SHARED)
|
||||
self.assertHiddenInput(search_form, 'unread', BookmarkSearch.FILTER_UNREAD_YES)
|
||||
|
||||
def test_preferences_form_inputs(self):
|
||||
# Without params
|
||||
url = '/test'
|
||||
rendered_template = self.render_template(url)
|
||||
soup = self.make_soup(rendered_template)
|
||||
preferences_form = soup.select_one('form#search_preferences')
|
||||
|
||||
self.assertNoHiddenInput(preferences_form, 'q')
|
||||
self.assertNoHiddenInput(preferences_form, 'user')
|
||||
self.assertNoHiddenInput(preferences_form, 'sort')
|
||||
self.assertNoHiddenInput(preferences_form, 'shared')
|
||||
self.assertNoHiddenInput(preferences_form, 'unread')
|
||||
|
||||
self.assertSelect(preferences_form, 'sort', BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertRadioGroup(preferences_form, 'shared', BookmarkSearch.FILTER_SHARED_OFF)
|
||||
self.assertRadioGroup(preferences_form, 'unread', BookmarkSearch.FILTER_UNREAD_OFF)
|
||||
|
||||
# With params
|
||||
url = '/test?q=foo&user=john&sort=title_asc&shared=yes&unread=yes'
|
||||
rendered_template = self.render_template(url)
|
||||
soup = self.make_soup(rendered_template)
|
||||
preferences_form = soup.select_one('form#search_preferences')
|
||||
|
||||
self.assertHiddenInput(preferences_form, 'q', 'foo')
|
||||
self.assertHiddenInput(preferences_form, 'user', 'john')
|
||||
self.assertNoHiddenInput(preferences_form, 'sort')
|
||||
self.assertNoHiddenInput(preferences_form, 'shared')
|
||||
self.assertNoHiddenInput(preferences_form, 'unread')
|
||||
|
||||
self.assertSelect(preferences_form, 'sort', BookmarkSearch.SORT_TITLE_ASC)
|
||||
self.assertRadioGroup(preferences_form, 'shared', BookmarkSearch.FILTER_SHARED_SHARED)
|
||||
self.assertRadioGroup(preferences_form, 'unread', BookmarkSearch.FILTER_UNREAD_YES)
|
||||
|
||||
def test_preferences_form_inputs_shared_mode(self):
|
||||
# Without params
|
||||
url = '/test'
|
||||
rendered_template = self.render_template(url, mode='shared')
|
||||
soup = self.make_soup(rendered_template)
|
||||
preferences_form = soup.select_one('form#search_preferences')
|
||||
|
||||
self.assertNoHiddenInput(preferences_form, 'q')
|
||||
self.assertNoHiddenInput(preferences_form, 'user')
|
||||
self.assertNoHiddenInput(preferences_form, 'sort')
|
||||
self.assertNoHiddenInput(preferences_form, 'shared')
|
||||
self.assertNoHiddenInput(preferences_form, 'unread')
|
||||
|
||||
self.assertSelect(preferences_form, 'sort', BookmarkSearch.SORT_ADDED_DESC)
|
||||
self.assertNoRadioGroup(preferences_form, 'shared')
|
||||
self.assertNoRadioGroup(preferences_form, 'unread')
|
||||
|
||||
# With params
|
||||
url = '/test?q=foo&user=john&sort=title_asc'
|
||||
rendered_template = self.render_template(url, mode='shared')
|
||||
soup = self.make_soup(rendered_template)
|
||||
preferences_form = soup.select_one('form#search_preferences')
|
||||
|
||||
self.assertHiddenInput(preferences_form, 'q', 'foo')
|
||||
self.assertHiddenInput(preferences_form, 'user', 'john')
|
||||
self.assertNoHiddenInput(preferences_form, 'sort')
|
||||
self.assertNoHiddenInput(preferences_form, 'shared')
|
||||
self.assertNoHiddenInput(preferences_form, 'unread')
|
||||
|
||||
self.assertSelect(preferences_form, 'sort', BookmarkSearch.SORT_TITLE_ASC)
|
||||
self.assertNoRadioGroup(preferences_form, 'shared')
|
||||
self.assertNoRadioGroup(preferences_form, 'unread')
|
||||
|
||||
def test_modified_indicator(self):
|
||||
# Without modifications
|
||||
url = '/test'
|
||||
rendered_template = self.render_template(url)
|
||||
|
||||
self.assertHiddenInput(rendered_template, 'user', 'john')
|
||||
self.assertNoHiddenInput(rendered_template, 'q')
|
||||
self.assertNoHiddenInput(rendered_template, 'sort')
|
||||
self.assertNoHiddenInput(rendered_template, 'shared')
|
||||
self.assertNoHiddenInput(rendered_template, 'unread')
|
||||
self.assertIn('<button type="button" class="btn dropdown-toggle">', rendered_template)
|
||||
|
||||
# With modifications
|
||||
url = '/test?sort=title_asc'
|
||||
rendered_template = self.render_template(url)
|
||||
|
||||
self.assertIn('<button type="button" class="btn dropdown-toggle badge">', rendered_template)
|
||||
|
||||
# Ignores non-preferences modifications
|
||||
url = '/test?q=foo&user=john'
|
||||
rendered_template = self.render_template(url)
|
||||
|
||||
self.assertIn('<button type="button" class="btn dropdown-toggle">', rendered_template)
|
||||
|
||||
def test_modified_labels(self):
|
||||
# Without modifications
|
||||
url = '/test'
|
||||
rendered_template = self.render_template(url)
|
||||
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Sort by', 'id_sort')
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Shared filter')
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Unread filter')
|
||||
|
||||
# Modified sort
|
||||
url = '/test?sort=title_asc'
|
||||
rendered_template = self.render_template(url)
|
||||
self.assertModifiedLabel(rendered_template, 'Sort by', 'id_sort')
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Shared filter')
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Unread filter')
|
||||
|
||||
# Modified shared
|
||||
url = '/test?shared=yes'
|
||||
rendered_template = self.render_template(url)
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Sort by', 'id_sort')
|
||||
self.assertModifiedLabel(rendered_template, 'Shared filter')
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Unread filter')
|
||||
|
||||
# Modified unread
|
||||
url = '/test?unread=yes'
|
||||
rendered_template = self.render_template(url)
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Sort by', 'id_sort')
|
||||
self.assertUnmodifiedLabel(rendered_template, 'Shared filter')
|
||||
self.assertModifiedLabel(rendered_template, 'Unread filter')
|
||||
|
|
|
@ -5,8 +5,8 @@ from django.contrib.auth.models import User
|
|||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from bookmarks.models import Bookmark, Tag, UserProfile
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin, collapse_whitespace, HtmlTestMixin
|
||||
from bookmarks.models import Bookmark, BookmarkSearch, Tag, UserProfile
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin, HtmlTestMixin
|
||||
|
||||
|
||||
class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
||||
|
@ -22,27 +22,47 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
)
|
||||
|
||||
def assertVisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
|
||||
html = response.content.decode()
|
||||
self.assertContains(response, '<li ld-bookmark-item class="shared">', count=len(bookmarks))
|
||||
soup = self.make_soup(response.content.decode())
|
||||
bookmark_list = soup.select_one(f'ul.bookmark-list[data-bookmarks-total="{len(bookmarks)}"]')
|
||||
self.assertIsNotNone(bookmark_list)
|
||||
|
||||
bookmark_items = bookmark_list.select('li[ld-bookmark-item]')
|
||||
self.assertEqual(len(bookmark_items), len(bookmarks))
|
||||
|
||||
for bookmark in bookmarks:
|
||||
self.assertBookmarkCount(html, bookmark, 1, link_target)
|
||||
bookmark_item = bookmark_list.select_one(
|
||||
f'li[ld-bookmark-item] a[href="{bookmark.url}"][target="{link_target}"]')
|
||||
self.assertIsNotNone(bookmark_item)
|
||||
|
||||
def assertInvisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
|
||||
html = response.content.decode()
|
||||
soup = self.make_soup(response.content.decode())
|
||||
|
||||
for bookmark in bookmarks:
|
||||
self.assertBookmarkCount(html, bookmark, 0, link_target)
|
||||
bookmark_item = soup.select_one(
|
||||
f'li[ld-bookmark-item] a[href="{bookmark.url}"][target="{link_target}"]')
|
||||
self.assertIsNone(bookmark_item)
|
||||
|
||||
def assertVisibleTags(self, response, tags: [Tag]):
|
||||
self.assertContains(response, 'data-is-tag-item', count=len(tags))
|
||||
def assertVisibleTags(self, response, tags: List[Tag]):
|
||||
soup = self.make_soup(response.content.decode())
|
||||
tag_cloud = soup.select_one('div.tag-cloud')
|
||||
self.assertIsNotNone(tag_cloud)
|
||||
|
||||
tag_items = tag_cloud.select('a[data-is-tag-item]')
|
||||
self.assertEqual(len(tag_items), len(tags))
|
||||
|
||||
tag_item_names = [tag_item.text.strip() for tag_item in tag_items]
|
||||
|
||||
for tag in tags:
|
||||
self.assertContains(response, tag.name)
|
||||
self.assertTrue(tag.name in tag_item_names)
|
||||
|
||||
def assertInvisibleTags(self, response, tags: List[Tag]):
|
||||
soup = self.make_soup(response.content.decode())
|
||||
tag_items = soup.select('a[data-is-tag-item]')
|
||||
|
||||
tag_item_names = [tag_item.text.strip() for tag_item in tag_items]
|
||||
|
||||
def assertInvisibleTags(self, response, tags: [Tag]):
|
||||
for tag in tags:
|
||||
self.assertNotContains(response, tag.name)
|
||||
self.assertFalse(tag.name in tag_item_names)
|
||||
|
||||
def assertVisibleUserOptions(self, response, users: List[User]):
|
||||
html = response.content.decode()
|
||||
|
@ -86,10 +106,7 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
]
|
||||
|
||||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
html = collapse_whitespace(response.content.decode())
|
||||
|
||||
# Should render list
|
||||
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, invisible_bookmarks)
|
||||
|
||||
|
@ -116,22 +133,12 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
def test_should_list_bookmarks_matching_query(self):
|
||||
self.authenticate()
|
||||
user = self.setup_user(enable_sharing=True)
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(shared=True, title='searchvalue', user=user),
|
||||
self.setup_bookmark(shared=True, title='searchvalue', user=user),
|
||||
self.setup_bookmark(shared=True, title='searchvalue', user=user)
|
||||
]
|
||||
invisible_bookmarks = [
|
||||
self.setup_bookmark(shared=True, user=user),
|
||||
self.setup_bookmark(shared=True, user=user),
|
||||
self.setup_bookmark(shared=True, user=user)
|
||||
]
|
||||
|
||||
response = self.client.get(reverse('bookmarks:shared') + '?q=searchvalue')
|
||||
html = collapse_whitespace(response.content.decode())
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, shared=True, user=user, prefix='foo')
|
||||
invisible_bookmarks = self.setup_numbered_bookmarks(3, shared=True, user=user)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:shared') + '?q=foo')
|
||||
|
||||
# Should render list
|
||||
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, invisible_bookmarks)
|
||||
|
||||
|
@ -139,22 +146,11 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(shared=True, user=user1),
|
||||
self.setup_bookmark(shared=True, user=user1),
|
||||
self.setup_bookmark(shared=True, user=user1),
|
||||
]
|
||||
invisible_bookmarks = [
|
||||
self.setup_bookmark(shared=True, user=user2),
|
||||
self.setup_bookmark(shared=True, user=user2),
|
||||
self.setup_bookmark(shared=True, user=user2),
|
||||
]
|
||||
visible_bookmarks = self.setup_numbered_bookmarks(3, shared=True, user=user1, prefix='user1')
|
||||
invisible_bookmarks = self.setup_numbered_bookmarks(3, shared=True, user=user2, prefix='user2')
|
||||
|
||||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
html = collapse_whitespace(response.content.decode())
|
||||
|
||||
# Should render list
|
||||
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, invisible_bookmarks)
|
||||
|
||||
|
@ -297,6 +293,30 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
self.assertVisibleUserOptions(response, expected_visible_users)
|
||||
|
||||
def test_should_list_bookmarks_and_tags_for_search_preferences(self):
|
||||
self.authenticate()
|
||||
other_user = self.setup_user(enable_sharing=True)
|
||||
|
||||
user_profile = self.get_or_create_test_user().profile
|
||||
user_profile.search_preferences = {
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
}
|
||||
user_profile.save()
|
||||
|
||||
unread_bookmarks = self.setup_numbered_bookmarks(3, shared=True, unread=True, with_tags=True, prefix='unread',
|
||||
tag_prefix='unread', user=other_user)
|
||||
read_bookmarks = self.setup_numbered_bookmarks(3, shared=True, unread=False, with_tags=True, prefix='read',
|
||||
tag_prefix='read', user=other_user)
|
||||
|
||||
unread_tags = self.get_tags_from_bookmarks(unread_bookmarks)
|
||||
read_tags = self.get_tags_from_bookmarks(read_bookmarks)
|
||||
|
||||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
self.assertVisibleBookmarks(response, unread_bookmarks)
|
||||
self.assertInvisibleBookmarks(response, read_bookmarks)
|
||||
self.assertVisibleTags(response, unread_tags)
|
||||
self.assertInvisibleTags(response, read_tags)
|
||||
|
||||
def test_should_open_bookmarks_in_new_page_by_default(self):
|
||||
self.authenticate()
|
||||
user = self.get_or_create_test_user()
|
||||
|
@ -370,6 +390,107 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
response = self.client.get(base_url + url_params)
|
||||
self.assertEditLink(response, url)
|
||||
|
||||
def test_apply_search_preferences(self):
|
||||
# no params
|
||||
response = self.client.post(reverse('bookmarks:shared'))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:shared'))
|
||||
|
||||
# some params
|
||||
response = self.client.post(reverse('bookmarks:shared'), {
|
||||
'q': 'foo',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:shared') + '?q=foo&sort=title_asc')
|
||||
|
||||
# params with default value are removed
|
||||
response = self.client.post(reverse('bookmarks:shared'), {
|
||||
'q': 'foo',
|
||||
'user': '',
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:shared') + '?q=foo&unread=yes')
|
||||
|
||||
# page is removed
|
||||
response = self.client.post(reverse('bookmarks:shared'), {
|
||||
'q': 'foo',
|
||||
'page': '2',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, reverse('bookmarks:shared') + '?q=foo&sort=title_asc')
|
||||
|
||||
def test_save_search_preferences(self):
|
||||
self.authenticate()
|
||||
user_profile = self.user.profile
|
||||
|
||||
# no params
|
||||
self.client.post(reverse('bookmarks:shared'), {
|
||||
'save': '',
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
# with param
|
||||
self.client.post(reverse('bookmarks:shared'), {
|
||||
'save': '',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
# add a param
|
||||
self.client.post(reverse('bookmarks:shared'), {
|
||||
'save': '',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
|
||||
# remove a param
|
||||
self.client.post(reverse('bookmarks:shared'), {
|
||||
'save': '',
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_ADDED_DESC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_YES,
|
||||
})
|
||||
|
||||
# ignores non-preferences
|
||||
self.client.post(reverse('bookmarks:shared'), {
|
||||
'save': '',
|
||||
'q': 'foo',
|
||||
'user': 'john',
|
||||
'page': '3',
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
})
|
||||
user_profile.refresh_from_db()
|
||||
self.assertEqual(user_profile.search_preferences, {
|
||||
'sort': BookmarkSearch.SORT_TITLE_ASC,
|
||||
'shared': BookmarkSearch.FILTER_SHARED_OFF,
|
||||
'unread': BookmarkSearch.FILTER_UNREAD_OFF,
|
||||
})
|
||||
|
||||
def test_url_encode_bookmark_actions_url(self):
|
||||
url = reverse('bookmarks:shared') + '?q=%23foo'
|
||||
response = self.client.get(url)
|
||||
|
|
|
@ -99,12 +99,12 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
|||
self.assertBookmarkListEqual(response.data['results'], unshared_bookmarks + shared_bookmarks)
|
||||
|
||||
# Filter shared
|
||||
response = self.get(reverse('bookmarks:bookmark-list') + '?shared=shared',
|
||||
response = self.get(reverse('bookmarks:bookmark-list') + '?shared=yes',
|
||||
expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], shared_bookmarks)
|
||||
|
||||
# Filter unshared
|
||||
response = self.get(reverse('bookmarks:bookmark-list') + '?shared=unshared',
|
||||
response = self.get(reverse('bookmarks:bookmark-list') + '?shared=no',
|
||||
expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], unshared_bookmarks)
|
||||
|
||||
|
|
|
@ -146,12 +146,6 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(tags=[tag1, tag2, self.setup_tag()]),
|
||||
]
|
||||
|
||||
def get_tags_from_bookmarks(self, bookmarks: [Bookmark]):
|
||||
all_tags = []
|
||||
for bookmark in bookmarks:
|
||||
all_tags = all_tags + list(bookmark.tags.all())
|
||||
return all_tags
|
||||
|
||||
def assertQueryResult(self, query: QuerySet, item_lists: [[any]]):
|
||||
expected_items = []
|
||||
for item_list in item_lists:
|
||||
|
@ -164,7 +158,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmarks_should_return_all_for_empty_query(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q=''))
|
||||
self.assertQueryResult(query, [
|
||||
self.other_bookmarks,
|
||||
self.term1_bookmarks,
|
||||
|
@ -179,7 +173,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmarks_should_search_single_term(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='term1'))
|
||||
self.assertQueryResult(query, [
|
||||
self.term1_bookmarks,
|
||||
self.term1_term2_bookmarks,
|
||||
|
@ -189,35 +183,35 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmarks_should_search_multiple_terms(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term2 term1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='term2 term1'))
|
||||
|
||||
self.assertQueryResult(query, [self.term1_term2_bookmarks])
|
||||
|
||||
def test_query_bookmarks_should_search_single_tag(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='#tag1'))
|
||||
|
||||
self.assertQueryResult(query, [self.tag1_bookmarks, self.tag1_tag2_bookmarks, self.term1_tag1_bookmarks])
|
||||
|
||||
def test_query_bookmarks_should_search_multiple_tags(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag1 #tag2'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='#tag1 #tag2'))
|
||||
|
||||
self.assertQueryResult(query, [self.tag1_tag2_bookmarks])
|
||||
|
||||
def test_query_bookmarks_should_search_multiple_tags_ignoring_casing(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#Tag1 #TAG2'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='#Tag1 #TAG2'))
|
||||
|
||||
self.assertQueryResult(query, [self.tag1_tag2_bookmarks])
|
||||
|
||||
def test_query_bookmarks_should_search_terms_and_tags_combined(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 #tag1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='term1 #tag1'))
|
||||
|
||||
self.assertQueryResult(query, [self.term1_tag1_bookmarks])
|
||||
|
||||
|
@ -227,7 +221,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.profile.tag_search = UserProfile.TAG_SEARCH_STRICT
|
||||
self.profile.save()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='tag1'))
|
||||
self.assertQueryResult(query, [self.tag1_as_term_bookmarks])
|
||||
|
||||
def test_query_bookmarks_in_lax_mode_should_search_tags_as_terms(self):
|
||||
|
@ -236,7 +230,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.profile.tag_search = UserProfile.TAG_SEARCH_LAX
|
||||
self.profile.save()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='tag1'))
|
||||
self.assertQueryResult(query, [
|
||||
self.tag1_bookmarks,
|
||||
self.tag1_as_term_bookmarks,
|
||||
|
@ -244,17 +238,17 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.term1_tag1_bookmarks
|
||||
])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1 term1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='tag1 term1'))
|
||||
self.assertQueryResult(query, [
|
||||
self.term1_tag1_bookmarks,
|
||||
])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1 tag2'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='tag1 tag2'))
|
||||
self.assertQueryResult(query, [
|
||||
self.tag1_tag2_bookmarks,
|
||||
])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1 #tag2'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='tag1 #tag2'))
|
||||
self.assertQueryResult(query, [
|
||||
self.tag1_tag2_bookmarks,
|
||||
])
|
||||
|
@ -262,28 +256,28 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmarks_should_return_no_matches(self):
|
||||
self.setup_bookmark_search_data()
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term3'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='term3'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 term3'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='term1 term3'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 #tag2'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='term1 #tag2'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag3'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='#tag3'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
# Unused tag
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#unused_tag1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='#unused_tag1'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
# Unused tag combined with tag that is used
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag1 #unused_tag1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='#tag1 #unused_tag1'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
# Unused tag combined with term that is used
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 #unused_tag1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='term1 #unused_tag1'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
def test_query_bookmarks_should_not_return_archived_bookmarks(self):
|
||||
|
@ -293,7 +287,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True)
|
||||
self.setup_bookmark(is_archived=True)
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [[bookmark1, bookmark2]])
|
||||
|
||||
|
@ -304,7 +298,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark()
|
||||
self.setup_bookmark()
|
||||
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [[bookmark1, bookmark2]])
|
||||
|
||||
|
@ -319,7 +313,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(user=other_user)
|
||||
self.setup_bookmark(user=other_user)
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [owned_bookmarks])
|
||||
|
||||
|
@ -334,7 +328,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True, user=other_user)
|
||||
self.setup_bookmark(is_archived=True, user=other_user)
|
||||
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [owned_bookmarks])
|
||||
|
||||
|
@ -344,7 +338,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(tags=[tag])
|
||||
self.setup_bookmark(tags=[tag])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='!untagged'))
|
||||
self.assertCountEqual(list(query), [untagged_bookmark])
|
||||
|
||||
def test_query_bookmarks_untagged_should_be_combinable_with_search_terms(self):
|
||||
|
@ -353,7 +347,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(title='term2')
|
||||
self.setup_bookmark(tags=[tag])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='!untagged term1'))
|
||||
self.assertCountEqual(list(query), [untagged_bookmark])
|
||||
|
||||
def test_query_bookmarks_untagged_should_not_be_combinable_with_tags(self):
|
||||
|
@ -362,7 +356,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(tags=[tag])
|
||||
self.setup_bookmark(tags=[tag])
|
||||
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=f'!untagged #{tag.name}'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q=f'!untagged #{tag.name}'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
def test_query_archived_bookmarks_untagged_should_return_untagged_bookmarks_only(self):
|
||||
|
@ -371,7 +365,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged'))
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(q='!untagged'))
|
||||
self.assertCountEqual(list(query), [untagged_bookmark])
|
||||
|
||||
def test_query_archived_bookmarks_untagged_should_be_combinable_with_search_terms(self):
|
||||
|
@ -380,7 +374,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True, title='term2')
|
||||
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(q='!untagged term1'))
|
||||
self.assertCountEqual(list(query), [untagged_bookmark])
|
||||
|
||||
def test_query_archived_bookmarks_untagged_should_not_be_combinable_with_tags(self):
|
||||
|
@ -390,7 +384,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile,
|
||||
BookmarkSearch(query=f'!untagged #{tag.name}'))
|
||||
BookmarkSearch(q=f'!untagged #{tag.name}'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
def test_query_bookmarks_unread_should_return_unread_bookmarks_only(self):
|
||||
|
@ -398,7 +392,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
read_bookmarks = self.setup_numbered_bookmarks(5, unread=False)
|
||||
|
||||
# Legacy query filter
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='!unread'))
|
||||
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(q='!unread'))
|
||||
self.assertCountEqual(list(query), unread_bookmarks)
|
||||
|
||||
# Bookmark search filter - off
|
||||
|
@ -421,7 +415,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
read_bookmarks = self.setup_numbered_bookmarks(5, unread=False, archived=True)
|
||||
|
||||
# Legacy query filter
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query='!unread'))
|
||||
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(q='!unread'))
|
||||
self.assertCountEqual(list(query), unread_bookmarks)
|
||||
|
||||
# Bookmark search filter - off
|
||||
|
@ -461,7 +455,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_return_all_tags_for_empty_query(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.other_bookmarks),
|
||||
|
@ -476,7 +470,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_search_single_term(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='term1'))
|
||||
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.term1_bookmarks),
|
||||
|
@ -487,7 +481,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_search_multiple_terms(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term2 term1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='term2 term1'))
|
||||
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.term1_term2_bookmarks),
|
||||
|
@ -496,7 +490,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_search_single_tag(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='#tag1'))
|
||||
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.tag1_bookmarks),
|
||||
|
@ -507,7 +501,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_search_multiple_tags(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag1 #tag2'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='#tag1 #tag2'))
|
||||
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
|
||||
|
@ -516,7 +510,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_search_multiple_tags_ignoring_casing(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#Tag1 #TAG2'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='#Tag1 #TAG2'))
|
||||
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
|
||||
|
@ -525,7 +519,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_search_term_and_tag_combined(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 #tag1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='term1 #tag1'))
|
||||
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.term1_tag1_bookmarks),
|
||||
|
@ -537,7 +531,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.profile.tag_search = UserProfile.TAG_SEARCH_STRICT
|
||||
self.profile.save()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='tag1'))
|
||||
self.assertQueryResult(query, self.get_tags_from_bookmarks(self.tag1_as_term_bookmarks))
|
||||
|
||||
def test_query_bookmark_tags_in_lax_mode_should_search_tags_as_terms(self):
|
||||
|
@ -546,7 +540,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.profile.tag_search = UserProfile.TAG_SEARCH_LAX
|
||||
self.profile.save()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='tag1'))
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.tag1_bookmarks),
|
||||
self.get_tags_from_bookmarks(self.tag1_as_term_bookmarks),
|
||||
|
@ -554,17 +548,17 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.get_tags_from_bookmarks(self.term1_tag1_bookmarks)
|
||||
])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1 term1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='tag1 term1'))
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.term1_tag1_bookmarks),
|
||||
])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1 tag2'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='tag1 tag2'))
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
|
||||
])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1 #tag2'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='tag1 #tag2'))
|
||||
self.assertQueryResult(query, [
|
||||
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
|
||||
])
|
||||
|
@ -572,28 +566,28 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
def test_query_bookmark_tags_should_return_no_matches(self):
|
||||
self.setup_tag_search_data()
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term3'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='term3'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 term3'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='term1 term3'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 #tag2'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='term1 #tag2'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag3'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='#tag3'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
# Unused tag
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#unused_tag1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='#unused_tag1'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
# Unused tag combined with tag that is used
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag1 #unused_tag1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='#tag1 #unused_tag1'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
# Unused tag combined with term that is used
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 #unused_tag1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='term1 #unused_tag1'))
|
||||
self.assertQueryResult(query, [])
|
||||
|
||||
def test_query_bookmark_tags_should_return_tags_for_unarchived_bookmarks_only(self):
|
||||
|
@ -603,7 +597,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark()
|
||||
self.setup_bookmark(is_archived=True, tags=[tag2])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [[tag1]])
|
||||
|
||||
|
@ -613,7 +607,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(tags=[tag])
|
||||
self.setup_bookmark(tags=[tag])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [[tag]])
|
||||
|
||||
|
@ -624,7 +618,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark()
|
||||
self.setup_bookmark(is_archived=True, tags=[tag2])
|
||||
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [[tag2]])
|
||||
|
||||
|
@ -634,7 +628,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [[tag]])
|
||||
|
||||
|
@ -649,7 +643,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(user=other_user, tags=[self.setup_tag(user=other_user)])
|
||||
self.setup_bookmark(user=other_user, tags=[self.setup_tag(user=other_user)])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [self.get_tags_from_bookmarks(owned_bookmarks)])
|
||||
|
||||
|
@ -664,7 +658,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True, user=other_user, tags=[self.setup_tag(user=other_user)])
|
||||
self.setup_bookmark(is_archived=True, user=other_user, tags=[self.setup_tag(user=other_user)])
|
||||
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(q=''))
|
||||
|
||||
self.assertQueryResult(query, [self.get_tags_from_bookmarks(owned_bookmarks)])
|
||||
|
||||
|
@ -675,13 +669,13 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(title='term1', tags=[tag])
|
||||
self.setup_bookmark(tags=[tag])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='!untagged'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='!untagged term1'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=f'!untagged #{tag.name}'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q=f'!untagged #{tag.name}'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
def test_query_archived_bookmark_tags_untagged_should_never_return_any_tags(self):
|
||||
|
@ -691,14 +685,14 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(is_archived=True, title='term1', tags=[tag])
|
||||
self.setup_bookmark(is_archived=True, tags=[tag])
|
||||
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged'))
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(q='!untagged'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(q='!untagged term1'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
query = queries.query_archived_bookmark_tags(self.user, self.profile,
|
||||
BookmarkSearch(query=f'!untagged #{tag.name}'))
|
||||
BookmarkSearch(q=f'!untagged #{tag.name}'))
|
||||
self.assertCountEqual(list(query), [])
|
||||
|
||||
def test_query_bookmark_tags_filter_unread(self):
|
||||
|
@ -708,7 +702,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
read_tags = self.get_tags_from_bookmarks(read_bookmarks)
|
||||
|
||||
# Legacy query filter
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!unread'))
|
||||
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(q='!unread'))
|
||||
self.assertCountEqual(list(query), unread_tags)
|
||||
|
||||
# Bookmark search filter - off
|
||||
|
@ -769,14 +763,14 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(user=user4, shared=True, tags=[tag]),
|
||||
|
||||
# Should return shared bookmarks from all users
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query=''), False)
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(q=''), False)
|
||||
self.assertQueryResult(query_set, [shared_bookmarks])
|
||||
|
||||
# Should respect search query
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query='test title'), False)
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(q='test title'), False)
|
||||
self.assertQueryResult(query_set, [[shared_bookmarks[0]]])
|
||||
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query=f'#{tag.name}'), False)
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(q=f'#{tag.name}'), False)
|
||||
self.assertQueryResult(query_set, [[shared_bookmarks[2]]])
|
||||
|
||||
def test_query_publicly_shared_bookmarks(self):
|
||||
|
@ -786,7 +780,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
bookmark1 = self.setup_bookmark(user=user1, shared=True)
|
||||
self.setup_bookmark(user=user2, shared=True)
|
||||
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query=''), True)
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(q=''), True)
|
||||
self.assertQueryResult(query_set, [[bookmark1]])
|
||||
|
||||
def test_query_shared_bookmark_tags(self):
|
||||
|
@ -810,7 +804,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(user=user3, shared=False, tags=[self.setup_tag(user=user3)]),
|
||||
self.setup_bookmark(user=user4, shared=True, tags=[self.setup_tag(user=user4)]),
|
||||
|
||||
query_set = queries.query_shared_bookmark_tags(None, self.profile, BookmarkSearch(query=''), False)
|
||||
query_set = queries.query_shared_bookmark_tags(None, self.profile, BookmarkSearch(q=''), False)
|
||||
|
||||
self.assertQueryResult(query_set, [shared_tags])
|
||||
|
||||
|
@ -824,7 +818,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(user=user1, shared=True, tags=[tag1]),
|
||||
self.setup_bookmark(user=user2, shared=True, tags=[tag2]),
|
||||
|
||||
query_set = queries.query_shared_bookmark_tags(None, self.profile, BookmarkSearch(query=''), True)
|
||||
query_set = queries.query_shared_bookmark_tags(None, self.profile, BookmarkSearch(q=''), True)
|
||||
|
||||
self.assertQueryResult(query_set, [[tag1]])
|
||||
|
||||
|
@ -849,11 +843,11 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(user=users_without_shared_bookmarks[2], shared=True),
|
||||
|
||||
# Should return users with shared bookmarks
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(query=''), False)
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(q=''), False)
|
||||
self.assertQueryResult(query_set, [users_with_shared_bookmarks])
|
||||
|
||||
# Should respect search query
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(query='test title'), False)
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(q='test title'), False)
|
||||
self.assertQueryResult(query_set, [[users_with_shared_bookmarks[0]]])
|
||||
|
||||
def test_query_publicly_shared_bookmark_users(self):
|
||||
|
@ -863,7 +857,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
|||
self.setup_bookmark(user=user1, shared=True)
|
||||
self.setup_bookmark(user=user2, shared=True)
|
||||
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(query=''), True)
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(q=''), True)
|
||||
self.assertQueryResult(query_set, [[user1]])
|
||||
|
||||
def test_sorty_by_date_added_asc(self):
|
||||
|
|
|
@ -12,7 +12,7 @@ class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
|
|||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user_profile = self.get_or_create_test_user().profile
|
||||
search = BookmarkSearch.from_request(request)
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
context = RequestContext(request, {
|
||||
'request': request,
|
||||
'search': search,
|
||||
|
@ -82,11 +82,11 @@ class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
|
|||
self.assertNoHiddenInput(rendered_template, 'unread')
|
||||
|
||||
# With params
|
||||
url = '/test?q=foo&user=john&sort=title_asc&shared=shared&unread=yes'
|
||||
url = '/test?q=foo&user=john&sort=title_asc&shared=yes&unread=yes'
|
||||
rendered_template = self.render_template(url)
|
||||
|
||||
self.assertNoHiddenInput(rendered_template, 'user')
|
||||
self.assertHiddenInput(rendered_template, 'q', 'foo')
|
||||
self.assertHiddenInput(rendered_template, 'sort', 'title_asc')
|
||||
self.assertHiddenInput(rendered_template, 'shared', 'shared')
|
||||
self.assertHiddenInput(rendered_template, 'shared', 'yes')
|
||||
self.assertHiddenInput(rendered_template, 'unread', 'yes')
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import urllib.parse
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import QuerySet
|
||||
from django.http import HttpResponseRedirect, Http404, HttpResponseBadRequest
|
||||
from django.http import HttpResponseRedirect, Http404, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
|
||||
|
@ -17,6 +19,9 @@ _default_page_size = 30
|
|||
|
||||
@login_required
|
||||
def index(request):
|
||||
if request.method == 'POST':
|
||||
return search_action(request)
|
||||
|
||||
bookmark_list = contexts.ActiveBookmarkListContext(request)
|
||||
tag_cloud = contexts.ActiveTagCloudContext(request)
|
||||
return render(request, 'bookmarks/index.html', {
|
||||
|
@ -27,6 +32,9 @@ def index(request):
|
|||
|
||||
@login_required
|
||||
def archived(request):
|
||||
if request.method == 'POST':
|
||||
return search_action(request)
|
||||
|
||||
bookmark_list = contexts.ArchivedBookmarkListContext(request)
|
||||
tag_cloud = contexts.ArchivedTagCloudContext(request)
|
||||
return render(request, 'bookmarks/archive.html', {
|
||||
|
@ -36,11 +44,13 @@ def archived(request):
|
|||
|
||||
|
||||
def shared(request):
|
||||
search = BookmarkSearch.from_request(request)
|
||||
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, search, public_only)
|
||||
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,
|
||||
|
@ -48,6 +58,23 @@ def shared(request):
|
|||
})
|
||||
|
||||
|
||||
def search_action(request):
|
||||
if 'save' in request.POST:
|
||||
if not request.user.is_authenticated:
|
||||
return HttpResponseForbidden()
|
||||
search = BookmarkSearch.from_request(request.POST)
|
||||
request.user_profile.search_preferences = search.preferences_dict
|
||||
request.user_profile.save()
|
||||
|
||||
# redirect to base url including new query params
|
||||
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
|
||||
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
|
||||
|
@ -169,14 +196,14 @@ def mark_as_read(request, bookmark_id: int):
|
|||
|
||||
@login_required
|
||||
def index_action(request):
|
||||
search = BookmarkSearch.from_request(request)
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
query = queries.query_bookmarks(request.user, request.user_profile, search)
|
||||
return action(request, query)
|
||||
|
||||
|
||||
@login_required
|
||||
def archived_action(request):
|
||||
search = BookmarkSearch.from_request(request)
|
||||
search = BookmarkSearch.from_request(request.GET)
|
||||
query = queries.query_archived_bookmarks(request.user, request.user_profile, search)
|
||||
return action(request, query)
|
||||
|
||||
|
|
|
@ -54,11 +54,12 @@ class BookmarkItem:
|
|||
|
||||
class BookmarkListContext:
|
||||
def __init__(self, request: WSGIRequest) -> None:
|
||||
self.request = request
|
||||
self.search = BookmarkSearch.from_request(self.request)
|
||||
|
||||
user = request.user
|
||||
user_profile = request.user_profile
|
||||
|
||||
self.request = request
|
||||
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')
|
||||
paginator = Paginator(query_set, DEFAULT_PAGE_SIZE)
|
||||
|
@ -175,8 +176,10 @@ class TagGroup:
|
|||
|
||||
class TagCloudContext:
|
||||
def __init__(self, request: WSGIRequest) -> None:
|
||||
user_profile = request.user_profile
|
||||
|
||||
self.request = request
|
||||
self.search = BookmarkSearch.from_request(self.request)
|
||||
self.search = BookmarkSearch.from_request(self.request.GET, user_profile.search_preferences)
|
||||
|
||||
query_set = self.get_tag_query_set()
|
||||
tags = list(query_set)
|
||||
|
@ -196,7 +199,7 @@ class TagCloudContext:
|
|||
raise Exception(f'Must be implemented by subclass')
|
||||
|
||||
def get_selected_tags(self, tags: List[Tag]):
|
||||
parsed_query = queries.parse_query_string(self.search.query)
|
||||
parsed_query = queries.parse_query_string(self.search.q)
|
||||
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']
|
||||
|
|
Loading…
Reference in a new issue