From 394666357fd2e21a1b99c1b3df1e42c8a6aa4ee8 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 18 Jan 2021 16:32:02 -0800 Subject: [PATCH 1/9] Poll for notifications --- bookwyrm/static/js/shared.js | 21 +++++++++++++++++++++ bookwyrm/templates/layout.html | 6 +++--- bookwyrm/urls.py | 5 +++-- bookwyrm/views/__init__.py | 1 + bookwyrm/views/updates.py | 17 +++++++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 bookwyrm/views/updates.py diff --git a/bookwyrm/static/js/shared.js b/bookwyrm/static/js/shared.js index 55a5c1b20..8bac038bc 100644 --- a/bookwyrm/static/js/shared.js +++ b/bookwyrm/static/js/shared.js @@ -31,8 +31,29 @@ window.onload = function() { // hidden submit button in a form document.querySelectorAll('.hidden-form input') .forEach(t => t.onchange = revealForm); + + // polling + document.querySelectorAll('[data-poll]') + .forEach(t => setInterval(function () { polling(t) }, 10000)); }; + +function polling(el) { + // poll the endpoint + fetch('/api/updates/' + el.getAttribute('data-poll'), { + method : "GET", + }).then(response => response.json()) + .then(data => updateCountElement(el, data)); +} +function updateCountElement(el, data) { + const count = data[el.getAttribute('data-poll')]; + if (count) { + removeClass(el, 'hidden'); + el.innerHTML = count; + } +} + + function revealForm(e) { var hidden = e.currentTarget.closest('.hidden-form').getElementsByClassName('hidden')[0]; if (hidden) { diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 30c8bf7a4..f3e378614 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -113,9 +113,9 @@ Notifications - {% if request.user|notification_count %} - {{ request.user | notification_count }} - {% endif %} + + {{ request.user | notification_count }} + diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index f014d44d8..ab134b1c5 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -31,14 +31,15 @@ urlpatterns = [ re_path(r'^inbox/?$', incoming.shared_inbox), re_path(r'%s/inbox/?$' % local_user_path, incoming.inbox), re_path(r'%s/outbox/?$' % local_user_path, views.Outbox.as_view()), - - # .well-known endpoints re_path(r'^.well-known/webfinger/?$', wellknown.webfinger), re_path(r'^.well-known/nodeinfo/?$', wellknown.nodeinfo_pointer), re_path(r'^nodeinfo/2\.0/?$', wellknown.nodeinfo), re_path(r'^api/v1/instance/?$', wellknown.instance_info), re_path(r'^api/v1/instance/peers/?$', wellknown.peers), + # polling updates + re_path('^api/updates/notifications/?$', views.Updates.as_view()), + # authentication re_path(r'^login/?$', views.Login.as_view()), re_path(r'^register/?$', views.Register.as_view()), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index e1ffeda42..d37851aa4 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -23,4 +23,5 @@ from .shelf import Shelf from .shelf import user_shelves_page, create_shelf, delete_shelf from .shelf import shelve, unshelve from .status import Status, Replies, CreateStatus, DeleteStatus +from .updates import Updates from .user import User, EditUser, Followers, Following diff --git a/bookwyrm/views/updates.py b/bookwyrm/views/updates.py new file mode 100644 index 000000000..233e51917 --- /dev/null +++ b/bookwyrm/views/updates.py @@ -0,0 +1,17 @@ +''' endpoints for getting updates about activity ''' +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse +from django.utils.decorators import method_decorator +from django.views import View + +# pylint: disable= no-self-use +@method_decorator(login_required, name='dispatch') +class Updates(View): + ''' so the app can poll ''' + def get(self, request): + ''' any notifications waiting? ''' + return JsonResponse({ + 'notifications': request.user.notification_set.filter( + read=False + ).count(), + }) From 128dc3be44b457ed2ba6f4fb1b6f240b5419c669 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 18 Jan 2021 16:52:51 -0800 Subject: [PATCH 2/9] Remove a div --- bookwyrm/templates/layout.html | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index f3e378614..ddbafbb42 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -106,17 +106,15 @@ {% else %} From 3fce67a60dba013d1fff0072e75c7caf2321ac1d Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 19 Jan 2021 14:25:04 -0800 Subject: [PATCH 3/9] Only update on change --- bookwyrm/static/js/shared.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/js/shared.js b/bookwyrm/static/js/shared.js index 8bac038bc..fa3f6eb4b 100644 --- a/bookwyrm/static/js/shared.js +++ b/bookwyrm/static/js/shared.js @@ -34,7 +34,7 @@ window.onload = function() { // polling document.querySelectorAll('[data-poll]') - .forEach(t => setInterval(function () { polling(t) }, 10000)); + .forEach(t => setInterval(function () { polling(t); }, 10000)); }; @@ -46,8 +46,9 @@ function polling(el) { .then(data => updateCountElement(el, data)); } function updateCountElement(el, data) { + const currentCount = el.innerHTML; const count = data[el.getAttribute('data-poll')]; - if (count) { + if (count && count != currentCount) { removeClass(el, 'hidden'); el.innerHTML = count; } From 94a41498cfae8d4f342bfbfa6cd0a33fa40afbd7 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 19 Jan 2021 14:32:08 -0800 Subject: [PATCH 4/9] Remove counts when notifications are deleted --- bookwyrm/static/js/shared.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/js/shared.js b/bookwyrm/static/js/shared.js index fa3f6eb4b..3a56431e6 100644 --- a/bookwyrm/static/js/shared.js +++ b/bookwyrm/static/js/shared.js @@ -48,8 +48,8 @@ function polling(el) { function updateCountElement(el, data) { const currentCount = el.innerHTML; const count = data[el.getAttribute('data-poll')]; - if (count && count != currentCount) { - removeClass(el, 'hidden'); + if (count != currentCount) { + addRemoveClass(el, 'hidden', count < 1); el.innerHTML = count; } } From 1778e8dd468ff2c28d36b7797408a81915c9af37 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 19 Jan 2021 14:59:46 -0800 Subject: [PATCH 5/9] Uses timeout instead of interval --- bookwyrm/static/js/shared.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/bookwyrm/static/js/shared.js b/bookwyrm/static/js/shared.js index 3a56431e6..e8ff9c469 100644 --- a/bookwyrm/static/js/shared.js +++ b/bookwyrm/static/js/shared.js @@ -34,23 +34,25 @@ window.onload = function() { // polling document.querySelectorAll('[data-poll]') - .forEach(t => setInterval(function () { polling(t); }, 10000)); + .forEach(el => polling(el)); }; - function polling(el) { - // poll the endpoint - fetch('/api/updates/' + el.getAttribute('data-poll'), { - method : "GET", - }).then(response => response.json()) - .then(data => updateCountElement(el, data)); + let delay = 10000 + (Math.random() * 1000); + setTimeout(function() { + fetch('/api/updates/' + el.getAttribute('data-poll')) + .then(response => response.json()) + .then(data => updateCountElement(el, data)); + polling(el); + }, delay, el); } + function updateCountElement(el, data) { - const currentCount = el.innerHTML; + const currentCount = el.innerText; const count = data[el.getAttribute('data-poll')]; if (count != currentCount) { addRemoveClass(el, 'hidden', count < 1); - el.innerHTML = count; + el.innerText = count; } } From 2411b4fe79ab57563f0fdb282a46b82b5c40b2c3 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 19 Jan 2021 16:16:22 -0800 Subject: [PATCH 6/9] puts @'mentions directly in compose box --- bookwyrm/static/js/shared.js | 4 +++- bookwyrm/templates/snippets/create_status_form.html | 3 ++- bookwyrm/templatetags/bookwyrm_tags.py | 4 ++-- bookwyrm/views/status.py | 2 -- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bookwyrm/static/js/shared.js b/bookwyrm/static/js/shared.js index e8ff9c469..a0c21bec6 100644 --- a/bookwyrm/static/js/shared.js +++ b/bookwyrm/static/js/shared.js @@ -112,7 +112,9 @@ function toggleAction(e) { // set focus, if appropriate var focus = el.getAttribute('data-focus-target'); if (focus) { - document.getElementById(focus).focus(); + var focusEl = document.getElementById(focus); + focusEl.focus(); + setTimeout(function(){ focusEl.selectionStart = focusEl.selectionEnd = 10000; }, 0); } } diff --git a/bookwyrm/templates/snippets/create_status_form.html b/bookwyrm/templates/snippets/create_status_form.html index 3dfc19d99..0c2ebbee3 100644 --- a/bookwyrm/templates/snippets/create_status_form.html +++ b/bookwyrm/templates/snippets/create_status_form.html @@ -1,3 +1,4 @@ +{% load bookwyrm_tags %}
{% csrf_token %} @@ -34,7 +35,7 @@ {% else %} {% include 'snippets/content_warning_field.html' with parent_status=status %} - + {% endif %} {% if type == 'quotation' %} diff --git a/bookwyrm/templatetags/bookwyrm_tags.py b/bookwyrm/templatetags/bookwyrm_tags.py index c58f5c476..08bbcafed 100644 --- a/bookwyrm/templatetags/bookwyrm_tags.py +++ b/bookwyrm/templatetags/bookwyrm_tags.py @@ -142,10 +142,10 @@ def get_markdown(content): @register.filter(name='mentions') def get_mentions(status, user): - ''' anyone tagged or replied to in this status ''' + ''' people to @ in a reply: the parent and all mentions ''' mentions = set([status.user] + list(status.mention_users.all())) return ' '.join( - '@' + get_user_identifier(m) for m in mentions if not m == user) + '@' + get_user_identifier(m) for m in mentions if not m == user) + ' ' @register.filter(name='status_preview_name') def get_status_preview_name(obj): diff --git a/bookwyrm/views/status.py b/bookwyrm/views/status.py index a624c806d..834cf5837 100644 --- a/bookwyrm/views/status.py +++ b/bookwyrm/views/status.py @@ -86,8 +86,6 @@ class CreateStatus(View): # add reply parent to mentions and notify if status.reply_parent: status.mention_users.add(status.reply_parent.user) - for mention_user in status.reply_parent.mention_users.all(): - status.mention_users.add(mention_user) if status.reply_parent.user.local: create_notification( From 9f2ca73a58afc4778217cd599a2f681753a350ac Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 19 Jan 2021 16:48:06 -0800 Subject: [PATCH 7/9] Tests terminal space in mentions string --- bookwyrm/tests/test_templatetags.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/tests/test_templatetags.py b/bookwyrm/tests/test_templatetags.py index 2cc61eab3..d315144f6 100644 --- a/bookwyrm/tests/test_templatetags.py +++ b/bookwyrm/tests/test_templatetags.py @@ -228,7 +228,7 @@ class TemplateTags(TestCase): status = models.Status.objects.create( content='hi', user=self.remote_user) result = bookwyrm_tags.get_mentions(status, self.user) - self.assertEqual(result, '@rat@example.com') + self.assertEqual(result, '@rat@example.com ') def test_get_status_preview_name(self): From fe42c6d85358963d9a9de78723e1efbe449e875e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 20 Jan 2021 07:16:25 -0800 Subject: [PATCH 8/9] Remove login decorator from about page --- bookwyrm/views/landing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bookwyrm/views/landing.py b/bookwyrm/views/landing.py index 8305e0063..ec6cb3a9b 100644 --- a/bookwyrm/views/landing.py +++ b/bookwyrm/views/landing.py @@ -13,7 +13,6 @@ from .helpers import get_activity_feed # pylint: disable= no-self-use -@method_decorator(login_required, name='dispatch') class About(View): ''' create invites ''' def get(self, request): From b6b6a8a3f844ef72965a1bcd003f444921667031 Mon Sep 17 00:00:00 2001 From: Chad Nelson Date: Wed, 20 Jan 2021 17:17:30 -0500 Subject: [PATCH 9/9] Add docker-compose up to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2dfedebba..52e5c4cf5 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ You'll have to install the Docker and docker-compose. When you're ready, run: docker-compose build docker-compose run --rm web python manage.py migrate docker-compose run --rm web python manage.py initdb +docker-compose up ``` Once the build is complete, you can access the instance at `localhost:1333`