Add option for showing bookmark favicons (#390)

* Implement favicon loader

* Implement load favicon task

* Show favicons in bookmark list

* Add missing migration

* Load missing favicons on import

* Automatically refresh favicons

* Add enable favicon setting

* Update uwsgi config to host favicons

* Improve settings wording

* Fix favicon loader test setup

* Document LD_FAVICON_PROVIDER setting

* Add refresh favicons button
This commit is contained in:
Sascha Ißbrücker
2023-01-21 16:36:10 +01:00
committed by GitHub
parent 4cb39fae99
commit 814401be2e
22 changed files with 786 additions and 47 deletions

View File

@@ -1,12 +1,13 @@
import random
from django.test import TestCase
from django.urls import reverse
from unittest.mock import patch, Mock
import requests
from django.test import TestCase, override_settings
from django.urls import reverse
from requests import RequestException
from bookmarks.models import UserProfile
from bookmarks.services import tasks
from bookmarks.tests.helpers import BookmarkFactoryMixin
from bookmarks.views.settings import app_version, get_version_info
@@ -17,6 +18,20 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
user = self.get_or_create_test_user()
self.client.force_login(user)
def create_profile_form_data(self, overrides=None):
if not overrides:
overrides = {}
form_data = {
'theme': UserProfile.THEME_AUTO,
'bookmark_date_display': UserProfile.BOOKMARK_DATE_DISPLAY_RELATIVE,
'bookmark_link_target': UserProfile.BOOKMARK_LINK_TARGET_BLANK,
'web_archive_integration': UserProfile.WEB_ARCHIVE_INTEGRATION_DISABLED,
'enable_sharing': False,
'enable_favicons': False,
}
return {**form_data, **overrides}
def test_should_render_successfully(self):
response = self.client.get(reverse('bookmarks:settings.general'))
@@ -28,15 +43,18 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
self.assertRedirects(response, reverse('login') + '?next=' + reverse('bookmarks:settings.general'))
def test_should_save_profile(self):
def test_update_profile(self):
form_data = {
'update_profile': '',
'theme': UserProfile.THEME_DARK,
'bookmark_date_display': UserProfile.BOOKMARK_DATE_DISPLAY_HIDDEN,
'bookmark_link_target': UserProfile.BOOKMARK_LINK_TARGET_SELF,
'web_archive_integration': UserProfile.WEB_ARCHIVE_INTEGRATION_ENABLED,
'enable_sharing': True,
'enable_favicons': True,
}
response = self.client.post(reverse('bookmarks:settings.general'), form_data)
html = response.content.decode()
self.user.profile.refresh_from_db()
@@ -46,6 +64,118 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
self.assertEqual(self.user.profile.bookmark_link_target, form_data['bookmark_link_target'])
self.assertEqual(self.user.profile.web_archive_integration, form_data['web_archive_integration'])
self.assertEqual(self.user.profile.enable_sharing, form_data['enable_sharing'])
self.assertEqual(self.user.profile.enable_favicons, form_data['enable_favicons'])
self.assertInHTML('''
<p class="form-input-hint">Profile updated</p>
''', html)
def test_update_profile_should_not_be_called_without_respective_form_action(self):
form_data = {
'theme': UserProfile.THEME_DARK,
}
response = self.client.post(reverse('bookmarks:settings.general'), form_data)
html = response.content.decode()
self.user.profile.refresh_from_db()
self.assertEqual(response.status_code, 200)
self.assertEqual(self.user.profile.theme, UserProfile.THEME_AUTO)
self.assertInHTML('''
<p class="form-input-hint">Profile updated</p>
''', html, count=0)
def test_enable_favicons_should_schedule_icon_update(self):
with patch.object(tasks, 'schedule_bookmarks_without_favicons') as mock_schedule_bookmarks_without_favicons:
# Enabling favicons schedules update
form_data = self.create_profile_form_data({
'update_profile': '',
'enable_favicons': True,
})
self.client.post(reverse('bookmarks:settings.general'), form_data)
mock_schedule_bookmarks_without_favicons.assert_called_once_with(self.user)
# No update scheduled if favicons are already enabled
mock_schedule_bookmarks_without_favicons.reset_mock()
self.client.post(reverse('bookmarks:settings.general'), form_data)
mock_schedule_bookmarks_without_favicons.assert_not_called()
# No update scheduled when disabling favicons
form_data = self.create_profile_form_data({
'enable_favicons': False,
})
self.client.post(reverse('bookmarks:settings.general'), form_data)
mock_schedule_bookmarks_without_favicons.assert_not_called()
def test_refresh_favicons(self):
with patch.object(tasks, 'schedule_refresh_favicons') as mock_schedule_refresh_favicons:
form_data = {
'refresh_favicons': '',
}
response = self.client.post(reverse('bookmarks:settings.general'), form_data)
html = response.content.decode()
mock_schedule_refresh_favicons.assert_called_once()
self.assertInHTML('''
<p class="form-input-hint">
Scheduled favicon update. This may take a while...
</p>
''', html)
def test_refresh_favicons_should_not_be_called_without_respective_form_action(self):
with patch.object(tasks, 'schedule_refresh_favicons') as mock_schedule_refresh_favicons:
form_data = {
}
response = self.client.post(reverse('bookmarks:settings.general'), form_data)
html = response.content.decode()
mock_schedule_refresh_favicons.assert_not_called()
self.assertInHTML('''
<p class="form-input-hint">
Scheduled favicon update. This may take a while...
</p>
''', html, count=0)
def test_refresh_favicons_should_be_visible_when_favicons_enabled_in_profile(self):
profile = self.get_or_create_test_user().profile
profile.enable_favicons = True
profile.save()
response = self.client.get(reverse('bookmarks:settings.general'))
html = response.content.decode()
self.assertInHTML('''
<button class="btn mt-2" name="refresh_favicons">Refresh Favicons</button>
''', html, count=1)
def test_refresh_favicons_should_not_be_visible_when_favicons_disabled_in_profile(self):
profile = self.get_or_create_test_user().profile
profile.enable_favicons = False
profile.save()
response = self.client.get(reverse('bookmarks:settings.general'))
html = response.content.decode()
self.assertInHTML('''
<button class="btn mt-2" name="refresh_favicons">Refresh Favicons</button>
''', html, count=0)
@override_settings(LD_ENABLE_REFRESH_FAVICONS=False)
def test_refresh_favicons_should_not_be_visible_when_disabled(self):
profile = self.get_or_create_test_user().profile
profile.enable_favicons = True
profile.save()
response = self.client.get(reverse('bookmarks:settings.general'))
html = response.content.decode()
self.assertInHTML('''
<button class="btn mt-2" name="refresh_favicons">Refresh Favicons</button>
''', html, count=0)
def test_about_shows_version_info(self):
response = self.client.get(reverse('bookmarks:settings.general'))