mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-07 18:58:30 +02:00
Improve about section (#265)
* Improve about section * Add changelog link Co-authored-by: Sascha Ißbrücker <sascha.issbruecker@gmail.com>
This commit is contained in:
@@ -11,4 +11,8 @@
|
|||||||
.input-group > input[type=submit] {
|
.input-group > input[type=submit] {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section.about table {
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -98,13 +98,29 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{# About section #}
|
{# About section #}
|
||||||
<section class="content-area">
|
<section class="content-area about">
|
||||||
<h2>About</h2>
|
<h2>About</h2>
|
||||||
<p>Version: {{ app_version }}</p>
|
<table class="table">
|
||||||
<p>
|
<tbody>
|
||||||
Code: <a href="https://github.com/sissbruecker/linkding/"
|
<tr>
|
||||||
target="_blank">GitHub</a>
|
<td>Version</td>
|
||||||
</p>
|
<td>{{ version_info }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3" style="vertical-align: top">Links</td>
|
||||||
|
<td><a href="https://github.com/sissbruecker/linkding/"
|
||||||
|
target="_blank">GitHub</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><a href="https://github.com/sissbruecker/linkding#documentation"
|
||||||
|
target="_blank">Documentation</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><a href="https://github.com/sissbruecker/linkding/blob/master/CHANGELOG.md"
|
||||||
|
target="_blank">Changelog</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -1,8 +1,14 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from unittest.mock import patch, Mock
|
||||||
|
import requests
|
||||||
|
from requests import RequestException
|
||||||
|
|
||||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
|
||||||
from bookmarks.models import UserProfile
|
from bookmarks.models import UserProfile
|
||||||
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
from bookmarks.views.settings import app_version, get_version_info
|
||||||
|
|
||||||
|
|
||||||
class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
@@ -38,3 +44,31 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
|||||||
self.assertEqual(self.user.profile.bookmark_date_display, form_data['bookmark_date_display'])
|
self.assertEqual(self.user.profile.bookmark_date_display, form_data['bookmark_date_display'])
|
||||||
self.assertEqual(self.user.profile.bookmark_link_target, form_data['bookmark_link_target'])
|
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.web_archive_integration, form_data['web_archive_integration'])
|
||||||
|
|
||||||
|
def test_about_shows_version_info(self):
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.general'))
|
||||||
|
html = response.content.decode()
|
||||||
|
|
||||||
|
self.assertInHTML(f'''
|
||||||
|
<tr>
|
||||||
|
<td>Version</td>
|
||||||
|
<td>{get_version_info(random.random())}</td>
|
||||||
|
</tr>
|
||||||
|
''', html)
|
||||||
|
|
||||||
|
def test_get_version_info_just_displays_latest_when_versions_are_equal(self):
|
||||||
|
latest_version_response_mock = Mock(status_code=201, json=lambda: {'name': f'v{app_version}'})
|
||||||
|
with patch.object(requests, 'get', return_value=latest_version_response_mock):
|
||||||
|
version_info = get_version_info(random.random())
|
||||||
|
self.assertEqual(version_info, f'{app_version} (latest)')
|
||||||
|
|
||||||
|
def test_get_version_info_shows_latest_version_when_versions_are_not_equal(self):
|
||||||
|
latest_version_response_mock = Mock(status_code=201, json=lambda: {'name': f'v123.0.1'})
|
||||||
|
with patch.object(requests, 'get', return_value=latest_version_response_mock):
|
||||||
|
version_info = get_version_info(random.random())
|
||||||
|
self.assertEqual(version_info, f'{app_version} (latest: 123.0.1)')
|
||||||
|
|
||||||
|
def test_get_version_info_silently_ignores_request_errors(self):
|
||||||
|
with patch.object(requests, 'get', side_effect=RequestException()):
|
||||||
|
version_info = get_version_info(random.random())
|
||||||
|
self.assertEqual(version_info, f'{app_version}')
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
import requests
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import HttpResponseRedirect, HttpResponse
|
from django.http import HttpResponseRedirect, HttpResponse
|
||||||
@@ -21,6 +24,7 @@ except Exception as exc:
|
|||||||
logging.exception(exc)
|
logging.exception(exc)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def general(request):
|
def general(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@@ -32,14 +36,41 @@ def general(request):
|
|||||||
|
|
||||||
import_success_message = _find_message_with_tag(messages.get_messages(request), 'bookmark_import_success')
|
import_success_message = _find_message_with_tag(messages.get_messages(request), 'bookmark_import_success')
|
||||||
import_errors_message = _find_message_with_tag(messages.get_messages(request), 'bookmark_import_errors')
|
import_errors_message = _find_message_with_tag(messages.get_messages(request), 'bookmark_import_errors')
|
||||||
|
version_info = get_version_info(get_ttl_hash())
|
||||||
return render(request, 'settings/general.html', {
|
return render(request, 'settings/general.html', {
|
||||||
'form': form,
|
'form': form,
|
||||||
'import_success_message': import_success_message,
|
'import_success_message': import_success_message,
|
||||||
'import_errors_message': import_errors_message,
|
'import_errors_message': import_errors_message,
|
||||||
'app_version': app_version
|
'version_info': version_info,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
# Cache API call response, for one hour when using get_ttl_hash with default params
|
||||||
|
@lru_cache(maxsize=1)
|
||||||
|
def get_version_info(ttl_hash=None):
|
||||||
|
latest_version = None
|
||||||
|
try:
|
||||||
|
latest_version_url = 'https://api.github.com/repos/sissbruecker/linkding/releases/latest'
|
||||||
|
response = requests.get(latest_version_url, timeout=5)
|
||||||
|
json = response.json()
|
||||||
|
latest_version = json['name'][1:]
|
||||||
|
except requests.exceptions.RequestException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
latest_version_info = ''
|
||||||
|
if latest_version == app_version:
|
||||||
|
latest_version_info = ' (latest)'
|
||||||
|
elif latest_version is not None:
|
||||||
|
latest_version_info = f' (latest: {latest_version})'
|
||||||
|
|
||||||
|
return f'{app_version}{latest_version_info}'
|
||||||
|
|
||||||
|
|
||||||
|
def get_ttl_hash(seconds=3600):
|
||||||
|
"""Return the same value within `seconds` time period"""
|
||||||
|
return round(time.time() / seconds)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def integrations(request):
|
def integrations(request):
|
||||||
application_url = request.build_absolute_uri("/bookmarks/new")
|
application_url = request.build_absolute_uri("/bookmarks/new")
|
||||||
|
Reference in New Issue
Block a user