Squashed commit of the following:

commit 0a80206abb8fae7785a59aab88043b2b1974756b
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Tue Nov 5 19:22:00 2019 -0500

    Fix oxford comma in bundled notifications, remove unused dependency

commit e96bd22bdce996734aaaf1d5625e08add3c8fcf7
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Tue Nov 5 19:19:42 2019 -0500

    Now template works with bundled or un-bundled notifications

commit 6f46bef7fdd0defe2f02e09e28558de882ce4456
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Tue Nov 5 19:02:51 2019 -0500

    Bundled toots work; now fix unbundled case

commit 07d9de49f943d019d04a5a5203081e57dc0741d8
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Tue Nov 5 14:09:14 2019 -0500

    Notifications are now sorted by groups, but not collapsed

commit f62666929f12cf0c7db4c68a1468f7e138318a5c
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Tue Nov 5 13:58:41 2019 -0500

    Fix saving of bundle_notifications setting

commit 335d5f985c968bb84e4b459dabf77d1d7ecad646
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Mon Nov 4 18:57:54 2019 -0500

    Forgot to include migration for bundle notifications preference

commit 0e8232591c4f1bb972e9694433c546c9f66b5419
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Mon Nov 4 18:57:35 2019 -0500

    Bundle notifications setting front-end

commit 6e945f1ceb2ff19470e164a946a6a48de4142812
Author: Jason McBrayer <jmcbray@carcosa.net>
Date:   Mon Nov 4 18:54:49 2019 -0500

    Backend code to group notifications
This commit is contained in:
Jason McBrayer 2019-11-05 19:23:58 -05:00
parent 61f8d19879
commit cf13ad3790
8 changed files with 174 additions and 69 deletions

View File

@ -27,4 +27,3 @@ inscriptis = "*"
lxml = "*"
[dev-packages]

View File

@ -38,6 +38,7 @@ class PreferencesForm(forms.ModelForm):
"click_to_load",
"lightbox",
"filter_notifications",
"bundle_notifications",
"poll_frequency",
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.7 on 2019-11-04 23:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('brutaldon', '0022_auto_20190506_0938'),
]
operations = [
migrations.AddField(
model_name='preference',
name='bundle_notifications',
field=models.BooleanField(default=False, help_text='Collapse together boosts or likes of the same toot in the notifications page.'),
),
]

View File

@ -65,6 +65,12 @@ class Preference(models.Model):
default=False,
help_text=_("""Exclude boosts and favs from your notifications."""),
)
bundle_notifications = models.BooleanField(
default=False,
help_text=_(
"""Collapse together boosts or likes of the same toot in the notifications page."""
),
)
class Account(models.Model):

View File

@ -0,0 +1,5 @@
{% if not forloop.first %}
{% if forloop.last %}, and
{% else %},
{% endif %}
{% endif %}

View File

@ -3,7 +3,7 @@
{% load taglinks %}
{% block title %}
Brutaldon ({{ own_acct.username }}) - Notifications timelime
Brutaldon ({{ own_acct.username }}) - Notifications timelime
{% endblock %}
{% comment %}
@ -21,73 +21,99 @@ mastodon.notifications()[0]
{% block content %}
<h1 class="title">Your notifications timeline</h1>
{% for note in notes %}
{% if note.type == 'mention' %}
<p>
<strong>{{ note.account.display_name }}</strong>
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
mentioned you.
</p>
<br>
{% include "main/toot_partial.html" with toot=note.status reblog=False %}
<hr class="is-hidden">
{% elif note.type == 'reblog' %}
<p>
{{ note.account.display_name }}
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
boosted your toot.
(<span>
<small>{{ note.created_at |humane_time }}</small>
</span>)
</p>
{% include "main/toot_partial.html" with toot=note.status reblog=True reblog_by=note.account.acct reblog_icon=note.account.avatar_static %}
<hr class="is-hidden">
{% elif note.type == 'favourite' %}
<p>
{{ note.account.display_name }}
(<a href="{{ note.account.url | localuser}}">{{ note.account.acct }}</a>)
favorited your toot.
(<span>
<small>{{ note.created_at |humane_time }}</small>
</span>)
</p>
{% include "main/toot_partial.html" with toot=note.status %}
<hr class="is-hidden">
{% elif note.type == 'follow' %}
<article class="media">
<figure class="media-left">
<p class="image is-64x64">
<img src="{{ note.account.avatar_static }}" alt="">
</p>
</figure>
<div class="media-content" >
<div class="content">
<strong>{{ note.account.display_name }}</strong>
(<a href="{{ note.account.url |localuser }}">{{ note.account.acct }}</a>)
followed you.
(<a href="{{ note.url }}">
<small>{{ note.created_at |humane_time }}</small>
</a>)
</div>
</div>
</article>
<hr class="is-hidden">
{% elif note.type == 'poll' %}
<p>A poll you created or voted in has ended.</p>
{% include "main/toot_partial.html" with toot=note.status %}
<hr class="is-hidden">
{% endif %}
{% endfor %}
<h1 class="title">Your notifications timeline</h1>
{% for group in groups %}
{% if bundle_notifications and group.0.type in bundleable %}
{% if group.0.type == 'favourite' %}
<p>
{% for account in group.accounts %}
{% include "comma.html" %}{{ account.display_name }}
(<a href="{{ account.url | localuser}}">{{ account.acct }}</a>)
{% endfor %}
favorited your toot.
</p>
{% include "main/toot_partial.html" with toot=group.0.status %}
<hr class="is-hidden">
{% elif group.0.type == 'reblog' %}
<p>
{% for account in group.accounts %}
{% include "comma.html" %}{{ account.display_name }}
(<a href="{{ account.url | localuser }}">{{ account.acct }}</a>)
{% endfor %}
boosted your toot.
</p>
{% include "main/toot_partial.html" with toot=group.0.status reblog=True reblog_by=group.0.account.acct reblog_icon=group.0.account.avatar_static %}
<hr class="is-hidden">
{% endif %}
{% else %}
{% for note in group %}
{% if note.type == 'mention' %}
<p>
<strong>{{ note.account.display_name }}</strong>
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
mentioned you.
</p>
<br>
{% include "main/toot_partial.html" with toot=note.status reblog=False %}
<hr class="is-hidden">
{% elif note.type == 'reblog' %}
<p>
{{ note.account.display_name }}
(<a href="{{ note.account.url | localuser }}">{{ note.account.acct }}</a>)
boosted your toot.
(<span>
<small>{{ note.created_at |humane_time }}</small>
</span>)
</p>
{% include "main/toot_partial.html" with toot=note.status reblog=True reblog_by=note.account.acct reblog_icon=note.account.avatar_static %}
<hr class="is-hidden">
{% elif note.type == 'favourite' %}
<p>
{{ note.account.display_name }}
(<a href="{{ note.account.url | localuser}}">{{ note.account.acct }}</a>)
favorited your toot.
(<span>
<small>{{ note.created_at |humane_time }}</small>
</span>)
</p>
{% include "main/toot_partial.html" with toot=note.status %}
<hr class="is-hidden">
{% elif note.type == 'follow' %}
<article class="media">
<figure class="media-left">
<p class="image is-64x64">
<img src="{{ note.account.avatar_static }}" alt="">
</p>
</figure>
<div class="media-content" >
<div class="content">
<strong>{{ note.account.display_name }}</strong>
(<a href="{{ note.account.url |localuser }}">{{ note.account.acct }}</a>)
followed you.
(<a href="{{ note.url }}">
<small>{{ note.created_at |humane_time }}</small>
</a>)
</div>
</div>
</article>
<hr class="is-hidden">
{% elif note.type == 'poll' %}
<p>A poll you created or voted in has ended.</p>
{% include "main/toot_partial.html" with toot=note.status %}
<hr class="is-hidden">
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
{% if prev %}
<a class="pagination-next" href="{% url 'note_prev' prev.min_id %}">Newer</a>
{% endif %}
{% if next %}
<a class="pagination-previous" href="{% url 'note_next' next.max_id %}">Older</a>
{% endif %}
</nav>
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
{% if prev %}
<a class="pagination-next" href="{% url 'note_prev' prev.min_id %}">Newer</a>
{% endif %}
{% if next %}
<a class="pagination-previous" href="{% url 'note_next' next.max_id %}">Older</a>
{% endif %}
</nav>
{% endblock %}

View File

@ -125,6 +125,23 @@
</div>
</div>
<div class="columns">
<div class="column is-quarter">
<label class="label checkbox" for="id_bundle_notifications">
{% render_field form.bundle_notifications class+="checkbox" %}
{{ form.bundle_notifications.label }}
</label>
</div>
<div class="column is-quarter">
<p class="notification is-info preferences-help">
{{ form.bundle_notifications.help_text }}
</p>
</div>
<div class="column is-half">
</div>
</div>
<div class="columns">
<div class="column is-quarter">
<label class="label" for="id_poll_frequency">

View File

@ -24,6 +24,7 @@ from mastodon import (
)
from urllib import parse
from pdb import set_trace
from itertools import groupby
from inscriptis import get_text
from time import sleep
from requests import Session
@ -32,7 +33,19 @@ import re
class NotLoggedInException(Exception):
pass
class LabeledList(list):
"""A subclass of list that can accept additional attributes"""
def __new__(self, *args, **kwargs):
return super(LabeledList, self).__new__(self, args, kwargs)
def __init(self, *args, **kwargs):
if len(args) == 1 and hasattr(args[0], '__iter__'):
list.__init__(self, args[0])
else:
list.__init__(self, args)
self.__dict__.update(kwargs)
def __call(self, **kwargs):
self.__dict__.update(kwargs)
return self
global sessons_cache
sessions_cache = {}
@ -612,17 +625,34 @@ def note(request, next=None, prev=None):
next = notes[-1]._pagination_next
except (IndexError, AttributeError, KeyError):
next = None
# Now group notes into lists based on type and status
groups = []
if account.preferences.bundle_notifications:
def bundle_key(note):
return str(note.status.id) + note.type
sorted_notes = sorted(notes, key=bundle_key, reverse=True)
for _, group in groupby(sorted_notes, bundle_key):
group = LabeledList(group)
group.accounts = [x.account for x in group]
groups.append(group)
else:
groups.append(notes)
return render(
request,
"main/notifications.html",
{
"notes": notes,
"groups": groups,
"timeline": "Notifications",
"timeline_name": "Notifications",
"own_acct": request.session["active_user"],
"preferences": account.preferences,
"prev": prev,
"next": next,
"bundleable": ["favourite", "reblog"],
"bundle_notifications": account.preferences.bundle_notifications,
},
)
@ -735,6 +765,9 @@ def settings(request):
account.preferences.filter_notifications = form.cleaned_data[
"filter_notifications"
]
account.preferences.bundle_notifications = form.cleaned_data[
"bundle_notifications"
]
account.preferences.poll_frequency = form.cleaned_data["poll_frequency"]
request.session["timezone"] = account.preferences.timezone
account.preferences.save()