From 2dfdb0b8594d6602672cf45e4bec6e35255edbbf Mon Sep 17 00:00:00 2001 From: Cy Date: Sat, 30 May 2020 23:07:38 +0000 Subject: [PATCH 01/27] Support feature_set= other than mainline for Mastodon Pleroma will send records that cause brutaldon to make pleroma-specific responses, which the mastodon python module wigs out on claiming it doesn't support that "feature set" so allow for a feature set to be specified... --- brutaldon/views.py | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/brutaldon/views.py b/brutaldon/views.py index 5249078..a561e13 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -71,7 +71,7 @@ def get_session(domain): return s -def get_usercontext(request): +def get_usercontext(request, feature_set="mainline"): if is_logged_in(request): try: client = Client.objects.get(api_base_id=request.session["active_instance"]) @@ -83,13 +83,14 @@ def get_usercontext(request): Account.MultipleObjectsReturned, ): raise NotLoggedInException() - mastodon = Mastodon( + mastodon = get_mastodon()Mastodon( client_id=client.client_id, client_secret=client.client_secret, access_token=user.access_token, api_base_url=client.api_base_id, session=get_session(client.api_base_id), ratelimit_method="throw", + feature_set=feature_set ) return user, mastodon else: @@ -808,7 +809,23 @@ def settings(request): {"form": form, "account": account, "preferences": account.preferences}, ) +def status_post(account, request, mastodon, **kw): + try: + mastodon.status_post(**kw) + except MastodonIllegalArgumentError as e: + if not 'is only available with feature set' in e.args[0]: + raise + feature_set = e.args[0].rsplit(" ",1)[-1] + account, mastodon = get_usercontext(request, + feature_set=feature_set) + + return status_post(account, request, mastodon, **kw) + except TypeError: + kw.pop("content_type") + return status_post(account, request, mastodon, **kw) + return account, mastodon + @never_cache @br_login_required def toot(request, mention=None): @@ -864,26 +881,19 @@ def toot(request, mention=None): ), ) ) + if form.cleaned_data["visibility"] == "": form.cleaned_data["visibility"] = request.session[ "active_user" ].source.privacy try: - try: - mastodon.status_post( - status=form.cleaned_data["status"], - visibility=form.cleaned_data["visibility"], - spoiler_text=form.cleaned_data["spoiler_text"], - media_ids=media_objects, - content_type="text/markdown", - ) - except TypeError: - mastodon.status_post( - status=form.cleaned_data["status"], - visibility=form.cleaned_data["visibility"], - spoiler_text=form.cleaned_data["spoiler_text"], - media_ids=media_objects, - ) + status_post( + account, mastodon, + status=form.cleaned_data["status"], + visibility=form.cleaned_data["visibility"], + spoiler_text=form.cleaned_data["spoiler_text"], + media_ids=media_objects, + content_type="text/markdown") except MastodonAPIError as error: form.add_error( "", @@ -903,6 +913,8 @@ def toot(request, mention=None): "preferences": account.preferences, }, ) + else: + return result return redirect(home) else: return render( From 12d7b4cb7d6aef2c3dc511a76e9bcef8f668a502 Mon Sep 17 00:00:00 2001 From: Cy Date: Sat, 30 May 2020 23:06:28 +0000 Subject: [PATCH 02/27] Handle feature_set errors automatically Recreate the mastodon object if there's an error complaining about a missing feature set. Only happens for status_post I think. Could be further generalized... --- brutaldon/views.py | 50 ++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/brutaldon/views.py b/brutaldon/views.py index a561e13..4f2ba49 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -16,6 +16,7 @@ from brutaldon.forms import ( from brutaldon.models import Client, Account, Preference, Theme from mastodon import ( Mastodon, + MastodonIllegalArgumentError, AttribAccessDict, MastodonError, MastodonAPIError, @@ -83,14 +84,14 @@ def get_usercontext(request, feature_set="mainline"): Account.MultipleObjectsReturned, ): raise NotLoggedInException() - mastodon = get_mastodon()Mastodon( + mastodon = Mastodon( client_id=client.client_id, client_secret=client.client_secret, access_token=user.access_token, api_base_url=client.api_base_id, session=get_session(client.api_base_id), ratelimit_method="throw", - feature_set=feature_set + feature_set=feature_set ) return user, mastodon else: @@ -810,22 +811,27 @@ def settings(request): ) def status_post(account, request, mastodon, **kw): - try: - mastodon.status_post(**kw) - except MastodonIllegalArgumentError as e: - if not 'is only available with feature set' in e.args[0]: - raise - feature_set = e.args[0].rsplit(" ",1)[-1] + while True: + try: + mastodon.status_post(**kw) + except MastodonIllegalArgumentError as e: + if not 'is only available with feature set' in e.args[0]: + raise + feature_set = e.args[0].rsplit(" ",1)[-1] - account, mastodon = get_usercontext(request, - feature_set=feature_set) - - return status_post(account, request, mastodon, **kw) - except TypeError: - kw.pop("content_type") - return status_post(account, request, mastodon, **kw) + account, mastodon = get_usercontext(request, + feature_set=feature_set) + + continue + except TypeError: + # not sure why, but the old code retried status_post without a + # content_type keyword, if there was a TypeError + kw.pop("content_type") + continue + else: + break return account, mastodon - + @never_cache @br_login_required def toot(request, mention=None): @@ -881,15 +887,15 @@ def toot(request, mention=None): ), ) ) - + if form.cleaned_data["visibility"] == "": form.cleaned_data["visibility"] = request.session[ "active_user" ].source.privacy try: - status_post( - account, mastodon, - status=form.cleaned_data["status"], + status_post( + account, request, mastodon, + status=form.cleaned_data["status"], visibility=form.cleaned_data["visibility"], spoiler_text=form.cleaned_data["spoiler_text"], media_ids=media_objects, @@ -913,8 +919,8 @@ def toot(request, mention=None): "preferences": account.preferences, }, ) - else: - return result + else: + return result return redirect(home) else: return render( From c0caab49193bb24d675ca2ceb8b703b8170ee9fe Mon Sep 17 00:00:00 2001 From: Cy Date: Sun, 31 May 2020 01:04:43 +0000 Subject: [PATCH 03/27] Missed a few status_post calls --- brutaldon/views.py | 54 ++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/brutaldon/views.py b/brutaldon/views.py index 4f2ba49..2caa7b6 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -16,7 +16,7 @@ from brutaldon.forms import ( from brutaldon.models import Client, Account, Preference, Theme from mastodon import ( Mastodon, - MastodonIllegalArgumentError, + MastodonIllegalArgumentError, AttribAccessDict, MastodonError, MastodonAPIError, @@ -995,23 +995,15 @@ def redraft(request, id): "active_user" ].source.privacy try: - try: - mastodon.status_post( - status=form.cleaned_data["status"], - visibility=form.cleaned_data["visibility"], - spoiler_text=form.cleaned_data["spoiler_text"], - media_ids=media_objects, - in_reply_to_id=toot.in_reply_to_id, - content_type="text/markdown", - ) - except TypeError: - mastodon.status_post( - status=form.cleaned_data["status"], - visibility=form.cleaned_data["visibility"], - spoiler_text=form.cleaned_data["spoiler_text"], - media_ids=media_objects, - in_reply_to_id=toot.in_reply_to_id, - ) + status_post( + account, request, mastodon, + status=form.cleaned_data["status"], + visibility=form.cleaned_data["visibility"], + spoiler_text=form.cleaned_data["spoiler_text"], + media_ids=media_objects, + in_reply_to_id=toot.in_reply_to_id, + content_type="text/markdown", + ) mastodon.status_delete(id) except MastodonAPIError as error: form.add_error( @@ -1125,23 +1117,15 @@ def reply(request, id): ) ) try: - try: - mastodon.status_post( - status=form.cleaned_data["status"], - visibility=form.cleaned_data["visibility"], - spoiler_text=form.cleaned_data["spoiler_text"], - media_ids=media_objects, - in_reply_to_id=id, - content_type="text/markdown", - ) - except TypeError: - mastodon.status_post( - status=form.cleaned_data["status"], - visibility=form.cleaned_data["visibility"], - spoiler_text=form.cleaned_data["spoiler_text"], - media_ids=media_objects, - in_reply_to_id=id, - ) + status_post( + account, request, mastodon, + status=form.cleaned_data["status"], + visibility=form.cleaned_data["visibility"], + spoiler_text=form.cleaned_data["spoiler_text"], + media_ids=media_objects, + in_reply_to_id=id, + content_type="text/markdown", + ) except MastodonAPIError as error: form.add_error( "", From 9415defedea12f5b91862a51e5ca870f5594eac9 Mon Sep 17 00:00:00 2001 From: Cy Date: Sun, 31 May 2020 02:22:47 +0000 Subject: [PATCH 04/27] whoops, left an old mistake in the code --- brutaldon/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/brutaldon/views.py b/brutaldon/views.py index 2caa7b6..ef76ebf 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -919,8 +919,6 @@ def toot(request, mention=None): "preferences": account.preferences, }, ) - else: - return result return redirect(home) else: return render( From 8eea5b05b1175e45e400d88247d3ff8e40e7a2c1 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:35:00 +0000 Subject: [PATCH 05/27] Viewing threads as a tree, not flattened I couldn't tell who was replying to whom, so I thought I'd give a shot at implementing a tree of threads, instead of a flattened list, with only the root distinguishable from the rest. --- brutaldon/threadtree.py | 54 +++++++++++++++++++++++++++++++++++++++++ brutaldon/views.py | 6 ++++- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 brutaldon/threadtree.py diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py new file mode 100644 index 0000000..32aee85 --- /dev/null +++ b/brutaldon/threadtree.py @@ -0,0 +1,54 @@ +def maketree(descendants): + lookup = {(descendant.id, descendant) for descendant in descendants} + replies = {} + roots = set() + for descendant in descendants: + if not descendant.in_reply_to_id: + roots.add(descendant.id) + if descendant.in_reply_to_id in replies: + reps = replies[descendant.in_reply_to_id] + reps.add(descendant.id) + else: + reps = set() + replies[descendant.in_reply_to_id] = set([descendant.id]) + seen = set() + def onelevel(reps): + for rep in reps: + if rep in seen: continue + seen.add(rep) + subreps = replies.get(rep) + if subreps: + yield lookup[rep], onelevel(subreps) + else: + yield lookup[rep], () + for root in roots: + seen.add(root) + reps = replies.get(root) + if reps: + yield lookup[root], onelevel(reps) + else: + yield lookup[root], () +# returns (status, gen[(status, gen[(status, ...), (status, ())]), ...]) + +# django can't do recursion well so we'll turn the tree +# ((A, (B, C))) +# into +# (in, in, A, in, B, C, out, out, out) +class OPERATION: pass +IN = OPERATION() +OUT = OPERATION() +class POST(OPERATION): + post = None + def __init__(self, post): + self.post = post + +def unmaketree(tree): + for post, children in tree: + yield POST(post) + if children: + yield IN + yield from unmaketree(children) + yield OUT + +def threadtree(descendants): + return unmaketree(maketree(descendants)) diff --git a/brutaldon/views.py b/brutaldon/views.py index ef76ebf..e4d7ee0 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -687,6 +687,10 @@ def thread(request, id): notifications = _notes_count(account, mastodon) filters = get_filters(mastodon, context="thread") + import pprint + pprint.pprint(context) + raise SystemExit(23) + # Apply filters descendants = [ x for x in context.descendants if not toot_matches_filters(x, filters) @@ -699,7 +703,7 @@ def thread(request, id): "context": context, "toot": toot, "root": root, - "descendants": descendants, + "descendants": unmaketree(maketree(descendants)), "own_acct": request.session["active_user"], "notifications": notifications, "preferences": account.preferences, From 11546907a68a5e7ebf1020f560a019c288bb5c4b Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:41:13 +0000 Subject: [PATCH 06/27] Cleaning up, adding tokens Doing some token based temporary flattening for django --- brutaldon/threadtree.py | 2 +- brutaldon/views.py | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 32aee85..3c1fdd8 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -50,5 +50,5 @@ def unmaketree(tree): yield from unmaketree(children) yield OUT -def threadtree(descendants): +def build(descendants): return unmaketree(maketree(descendants)) diff --git a/brutaldon/views.py b/brutaldon/views.py index e4d7ee0..114fde9 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -671,6 +671,7 @@ def note(request, next=None, prev=None): }, ) +import threadtree @br_login_required def thread(request, id): @@ -687,10 +688,6 @@ def thread(request, id): notifications = _notes_count(account, mastodon) filters = get_filters(mastodon, context="thread") - import pprint - pprint.pprint(context) - raise SystemExit(23) - # Apply filters descendants = [ x for x in context.descendants if not toot_matches_filters(x, filters) @@ -703,10 +700,12 @@ def thread(request, id): "context": context, "toot": toot, "root": root, - "descendants": unmaketree(maketree(descendants)), + "posts": threadtree.build(descendants)), "own_acct": request.session["active_user"], "notifications": notifications, "preferences": account.preferences, + "IN": threadtree.IN, + "OUT": threadtree.OUT, }, ) From 4e7395babe3b93bd0bb705de28f4eae617883465 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:42:31 +0000 Subject: [PATCH 07/27] Debugging a lookup error It was saying stuff was unhashable, but I thought I was just hashing by post ID. --- brutaldon/threadtree.py | 7 ++++++- brutaldon/views.py | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 3c1fdd8..1567f93 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -1,5 +1,10 @@ def maketree(descendants): - lookup = {(descendant.id, descendant) for descendant in descendants} + try: + lookup = {(descendant.id, descendant) for descendant in descendants} + except: + from pprint import pprint + pprint(lookup) + raise replies = {} roots = set() for descendant in descendants: diff --git a/brutaldon/views.py b/brutaldon/views.py index 114fde9..f8f55db 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -671,7 +671,7 @@ def note(request, next=None, prev=None): }, ) -import threadtree +from . import threadtree @br_login_required def thread(request, id): @@ -700,7 +700,7 @@ def thread(request, id): "context": context, "toot": toot, "root": root, - "posts": threadtree.build(descendants)), + "posts": threadtree.build(descendants), "own_acct": request.session["active_user"], "notifications": notifications, "preferences": account.preferences, From b221e6a7585eece094cf6357e2fa6ea16d66804e Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:44:39 +0000 Subject: [PATCH 08/27] Still trying to figure out what my data structure is Python's dynamic typing doesn't make this easy... --- brutaldon/threadtree.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 1567f93..327e375 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -1,13 +1,17 @@ +from pprint import pprint + def maketree(descendants): try: - lookup = {(descendant.id, descendant) for descendant in descendants} + lookup = [(descendant.id, descendant) for descendant in descendants] + print(descendants[0][0]) + lookup = dict(descendants) except: - from pprint import pprint pprint(lookup) raise replies = {} roots = set() for descendant in descendants: + pprint(descendant) if not descendant.in_reply_to_id: roots.add(descendant.id) if descendant.in_reply_to_id in replies: From 88d6c6f3ce1b84f6dc59805610e1886d407334ff Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:46:32 +0000 Subject: [PATCH 09/27] OK no hashable errors anymore I think I got it working. --- brutaldon/threadtree.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 327e375..a429e48 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -1,13 +1,7 @@ from pprint import pprint def maketree(descendants): - try: - lookup = [(descendant.id, descendant) for descendant in descendants] - print(descendants[0][0]) - lookup = dict(descendants) - except: - pprint(lookup) - raise + lookup = dict((descendant.id, descendant) for descendant in descendants) replies = {} roots = set() for descendant in descendants: From 4ad353801780e1daef0fcbe97862fa00fe6697e8 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:48:51 +0000 Subject: [PATCH 10/27] Adding an outer IN/OUT If we have multiple roots ever, we need the whole thing in a big
    --- brutaldon/threadtree.py | 5 +++-- brutaldon/views.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index a429e48..de3669c 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -5,7 +5,6 @@ def maketree(descendants): replies = {} roots = set() for descendant in descendants: - pprint(descendant) if not descendant.in_reply_to_id: roots.add(descendant.id) if descendant.in_reply_to_id in replies: @@ -54,4 +53,6 @@ def unmaketree(tree): yield OUT def build(descendants): - return unmaketree(maketree(descendants)) + yield IN + yield from unmaketree(maketree(descendants)) + yield OUT diff --git a/brutaldon/views.py b/brutaldon/views.py index f8f55db..ca5e389 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -700,7 +700,7 @@ def thread(request, id): "context": context, "toot": toot, "root": root, - "posts": threadtree.build(descendants), + "posts": tuple(threadtree.build(descendants)), "own_acct": request.session["active_user"], "notifications": notifications, "preferences": account.preferences, From be1db47fe1e475ced084f3bf647771ae13ea0fa3 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:50:17 +0000 Subject: [PATCH 11/27] Trying to figure out why only the root post is coming through Is nothing in reply to the root post? Nothing at all? --- brutaldon/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/brutaldon/views.py b/brutaldon/views.py index ca5e389..49a8b55 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -692,7 +692,10 @@ def thread(request, id): descendants = [ x for x in context.descendants if not toot_matches_filters(x, filters) ] - + posts = tuple(threadtree.build(descendants)) + from pprint import pprint + pprint(posts) + raise SystemExit(0) return render( request, "main/thread.html", @@ -700,7 +703,7 @@ def thread(request, id): "context": context, "toot": toot, "root": root, - "posts": tuple(threadtree.build(descendants)), + "posts": posts, "own_acct": request.session["active_user"], "notifications": notifications, "preferences": account.preferences, From a7e3c10fd08c2cc2113334dba8a3bec9dafb2dcd Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:51:32 +0000 Subject: [PATCH 12/27] Nothing at all? More debugging... --- brutaldon/threadtree.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index de3669c..1f157a5 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -53,6 +53,8 @@ def unmaketree(tree): yield OUT def build(descendants): + derp = tuple(maketree(descendants)) + pprint(("derp?", derp)) yield IN - yield from unmaketree(maketree(descendants)) + yield from unmaketree(derp) yield OUT From 09e5573b24f63c0f670d4ce498237f384ca47199 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:53:23 +0000 Subject: [PATCH 13/27] Monitor tree building progress Trying to find why only the one post comes out with no replies --- brutaldon/threadtree.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 1f157a5..c2eedf7 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -7,11 +7,14 @@ def maketree(descendants): for descendant in descendants: if not descendant.in_reply_to_id: roots.add(descendant.id) - if descendant.in_reply_to_id in replies: + print("ROOT", descendant.id, descendant.account.acct) + elif descendant.in_reply_to_id in replies: reps = replies[descendant.in_reply_to_id] reps.add(descendant.id) + print("REPLY", descendant.id, descendant.in_reply_to_id) else: reps = set() + print("NEWREPLY", descendant.id, descendant.in_reply_to_id) replies[descendant.in_reply_to_id] = set([descendant.id]) seen = set() def onelevel(reps): From 7c692d4c49cbceb6ba7ae4c37bba2128082bfe25 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:56:38 +0000 Subject: [PATCH 14/27] Still trying... --- brutaldon/threadtree.py | 10 +++++++--- brutaldon/views.py | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index c2eedf7..bedc94b 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -7,14 +7,18 @@ def maketree(descendants): for descendant in descendants: if not descendant.in_reply_to_id: roots.add(descendant.id) - print("ROOT", descendant.id, descendant.account.acct) + print("ROOT", descendant.id, descendant.account.id, descendant.account.acct) elif descendant.in_reply_to_id in replies: reps = replies[descendant.in_reply_to_id] reps.add(descendant.id) - print("REPLY", descendant.id, descendant.in_reply_to_id) + print("REPLY", descendant.id, + descendant.in_reply_to_id, + descendant.in_reply_to_id in lookup) else: reps = set() - print("NEWREPLY", descendant.id, descendant.in_reply_to_id) + print("NEWREPLY", descendant.id, + descendant.in_reply_to_id, + descendant.in_reply_to_id in lookup) replies[descendant.in_reply_to_id] = set([descendant.id]) seen = set() def onelevel(reps): diff --git a/brutaldon/views.py b/brutaldon/views.py index 49a8b55..056807b 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -688,10 +688,10 @@ def thread(request, id): notifications = _notes_count(account, mastodon) filters = get_filters(mastodon, context="thread") - # Apply filters - descendants = [ - x for x in context.descendants if not toot_matches_filters(x, filters) - ] + # # Apply filters + # descendants = [ + # x for x in context.descendants if not toot_matches_filters(x, filters) + # ] posts = tuple(threadtree.build(descendants)) from pprint import pprint pprint(posts) From d08d32c11cc712313f4c565193ee40d807399e11 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 01:59:07 +0000 Subject: [PATCH 15/27] Maybe the root is getting filtered out? I can't imagine how, but...# --- brutaldon/threadtree.py | 1 + brutaldon/views.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index bedc94b..eb12ab0 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -13,6 +13,7 @@ def maketree(descendants): reps.add(descendant.id) print("REPLY", descendant.id, descendant.in_reply_to_id, + descendant.in_reply_to_account_id, descendant.in_reply_to_id in lookup) else: reps = set() diff --git a/brutaldon/views.py b/brutaldon/views.py index 056807b..1decaec 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -692,7 +692,7 @@ def thread(request, id): # descendants = [ # x for x in context.descendants if not toot_matches_filters(x, filters) # ] - posts = tuple(threadtree.build(descendants)) + posts = tuple(threadtree.build(context.descendants)) from pprint import pprint pprint(posts) raise SystemExit(0) From be49ed879ed8665b83e9c8988a16155524157366 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:01:25 +0000 Subject: [PATCH 16/27] Yet more debugging Trying to find how to thread stuff is harder than I thought it would be. Where's the root? --- brutaldon/threadtree.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index eb12ab0..ae8e6e3 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -4,23 +4,22 @@ def maketree(descendants): lookup = dict((descendant.id, descendant) for descendant in descendants) replies = {} roots = set() + def getreps(id): + if id in replies: + reps = replies[id] + else: + reps = set() + replies[id] = reps + return reps for descendant in descendants: if not descendant.in_reply_to_id: roots.add(descendant.id) print("ROOT", descendant.id, descendant.account.id, descendant.account.acct) - elif descendant.in_reply_to_id in replies: - reps = replies[descendant.in_reply_to_id] - reps.add(descendant.id) - print("REPLY", descendant.id, - descendant.in_reply_to_id, - descendant.in_reply_to_account_id, - descendant.in_reply_to_id in lookup) else: - reps = set() - print("NEWREPLY", descendant.id, - descendant.in_reply_to_id, - descendant.in_reply_to_id in lookup) - replies[descendant.in_reply_to_id] = set([descendant.id]) + reps = getreps(descendant.in_reply_to_id) + reps.add(descendant.id) + reps = getreps(descendant.in_reply_to_account_id) + reps.add(descendant.id) seen = set() def onelevel(reps): for rep in reps: From 4699ce9e1991e694c4fe3fb1ec4da8a108c8b29a Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:03:54 +0000 Subject: [PATCH 17/27] Sorting to make it easier to read when debugging --- brutaldon/threadtree.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index ae8e6e3..e58ac4f 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -20,9 +20,12 @@ def maketree(descendants): reps.add(descendant.id) reps = getreps(descendant.in_reply_to_account_id) reps.add(descendant.id) + print("REPLY", descendant.id, + descendant.in_reply_to_id, + descendant.in_reply_to_account_id) seen = set() def onelevel(reps): - for rep in reps: + for rep in sorted(reps): if rep in seen: continue seen.add(rep) subreps = replies.get(rep) @@ -30,7 +33,7 @@ def maketree(descendants): yield lookup[rep], onelevel(subreps) else: yield lookup[rep], () - for root in roots: + for root in sorted(roots): seen.add(root) reps = replies.get(root) if reps: From 7a5ffbd9d11929e2144abccdd9137eda01b047d9 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:08:03 +0000 Subject: [PATCH 18/27] Removing redundant code The top level roots acts like any other level, I noticed. --- brutaldon/threadtree.py | 9 ++------- brutaldon/views.py | 3 --- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index e58ac4f..2ff3d4c 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -33,13 +33,8 @@ def maketree(descendants): yield lookup[rep], onelevel(subreps) else: yield lookup[rep], () - for root in sorted(roots): - seen.add(root) - reps = replies.get(root) - if reps: - yield lookup[root], onelevel(reps) - else: - yield lookup[root], () + return onelevel(roots) + # returns (status, gen[(status, gen[(status, ...), (status, ())]), ...]) # django can't do recursion well so we'll turn the tree diff --git a/brutaldon/views.py b/brutaldon/views.py index 1decaec..362d08c 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -693,9 +693,6 @@ def thread(request, id): # x for x in context.descendants if not toot_matches_filters(x, filters) # ] posts = tuple(threadtree.build(context.descendants)) - from pprint import pprint - pprint(posts) - raise SystemExit(0) return render( request, "main/thread.html", From 2d514ba7ca7ffc83808dd312fe5fb2d0866d25ac Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:09:53 +0000 Subject: [PATCH 19/27] Leftovers? Trying to add the leftover toots that don't reply to anything at the end. --- brutaldon/threadtree.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 2ff3d4c..f0a2bef 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -33,7 +33,8 @@ def maketree(descendants): yield lookup[rep], onelevel(subreps) else: yield lookup[rep], () - return onelevel(roots) + leftovers = set(lookup.keys()) - seen + return onelevel(roots), (lookup[leftover] for leftover in leftovers) # returns (status, gen[(status, gen[(status, ...), (status, ())]), ...]) @@ -58,8 +59,13 @@ def unmaketree(tree): yield OUT def build(descendants): - derp = tuple(maketree(descendants)) + herp, derp = maketree(descendants) + derp = tuple(derp) pprint(("derp?", derp)) yield IN - yield from unmaketree(derp) + yield from unmaketree(herp) + yield OUT + yield IN + for post in derp: + yield POST(derp) yield OUT From 356742febf2827dfead217197dcf0c1172f58cbb Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:11:47 +0000 Subject: [PATCH 20/27] Leftovers isn't lazy enough 1) initialize seen to empty 2) get all posts not in seen 3) add posts to seen because the generator was iterated over lazily 4) wonder why it looks like there weren't any posts in seen yeah... leftovers has to be lazy too. --- brutaldon/threadtree.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index f0a2bef..96b09fc 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -33,8 +33,10 @@ def maketree(descendants): yield lookup[rep], onelevel(subreps) else: yield lookup[rep], () - leftovers = set(lookup.keys()) - seen - return onelevel(roots), (lookup[leftover] for leftover in leftovers) + def leftovers(): + for leftover in set(lookup.keys()) - seen: + yield lookup[leftover] + return onelevel(roots), leftovers # returns (status, gen[(status, gen[(status, ...), (status, ())]), ...]) @@ -60,12 +62,13 @@ def unmaketree(tree): def build(descendants): herp, derp = maketree(descendants) - derp = tuple(derp) - pprint(("derp?", derp)) yield IN yield from unmaketree(herp) yield OUT yield IN + derp = tuple(derp()) + pprint("derp", derp) for post in derp: - yield POST(derp) + pprint(("derp?", post)) + yield POST(post) yield OUT From aa503003e7c3139f1611aa122ad26657bbcc4b6c Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:14:16 +0000 Subject: [PATCH 21/27] auto 0 20 244 --- brutaldon/threadtree.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 96b09fc..7ac010b 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -44,10 +44,10 @@ def maketree(descendants): # ((A, (B, C))) # into # (in, in, A, in, B, C, out, out, out) -class OPERATION: pass -IN = OPERATION() -OUT = OPERATION() -class POST(OPERATION): + +IN = 0 +OUT = 1 +class POST: post = None def __init__(self, post): self.post = post @@ -67,7 +67,7 @@ def build(descendants): yield OUT yield IN derp = tuple(derp()) - pprint("derp", derp) + pprint(("derp", derp)) for post in derp: pprint(("derp?", post)) yield POST(post) From 1a3cc90c85db37e975bbcbad46eb3a7e13ca03ee Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:31:53 +0000 Subject: [PATCH 22/27] Pulling any missing posts by ID We have the post ID, so why would Pleroma not send us the post? Request any missing posts it hasn't sent us, to try and get a thread that doesn't lose all its replies. --- brutaldon/threadtree.py | 24 +++++++++++++----------- brutaldon/views.py | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 7ac010b..f4da6db 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -1,9 +1,13 @@ from pprint import pprint -def maketree(descendants): +def maketree(mastodon, descendants): lookup = dict((descendant.id, descendant) for descendant in descendants) replies = {} roots = set() + def lookup_or_fetch(id): + if not id in lookup: + lookup[id] = mastodon.status(id) + return lookup[id] def getreps(id): if id in replies: reps = replies[id] @@ -30,12 +34,12 @@ def maketree(descendants): seen.add(rep) subreps = replies.get(rep) if subreps: - yield lookup[rep], onelevel(subreps) + yield lookup_or_fetch(rep), onelevel(subreps) else: - yield lookup[rep], () + yield lookup_or_fetch(rep), () def leftovers(): for leftover in set(lookup.keys()) - seen: - yield lookup[leftover] + yield lookup_or_fetch(leftover) return onelevel(roots), leftovers # returns (status, gen[(status, gen[(status, ...), (status, ())]), ...]) @@ -60,15 +64,13 @@ def unmaketree(tree): yield from unmaketree(children) yield OUT -def build(descendants): - herp, derp = maketree(descendants) +def build(mastodon, descendants): + tree, leftover = maketree(mastodon, descendants) yield IN - yield from unmaketree(herp) + yield from unmaketree(tree) yield OUT yield IN - derp = tuple(derp()) - pprint(("derp", derp)) - for post in derp: - pprint(("derp?", post)) + leftover = tuple(leftover()) + for post in leftover: yield POST(post) yield OUT diff --git a/brutaldon/views.py b/brutaldon/views.py index 362d08c..758ffdd 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -692,7 +692,7 @@ def thread(request, id): # descendants = [ # x for x in context.descendants if not toot_matches_filters(x, filters) # ] - posts = tuple(threadtree.build(context.descendants)) + posts = tuple(threadtree.build(mastodon, context.descendants)) return render( request, "main/thread.html", From e424765fc42bad1d4c88097e573b941d979ba011 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:34:15 +0000 Subject: [PATCH 23/27] Consistent naming Right, I forgot I was in the middle of changing the name post to toot. Thus explaining why op.post had an empty result, since op.toot was what I changed. --- brutaldon/threadtree.py | 16 ++++++++-------- brutaldon/views.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index f4da6db..fe49144 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -51,14 +51,14 @@ def maketree(mastodon, descendants): IN = 0 OUT = 1 -class POST: - post = None - def __init__(self, post): - self.post = post +class TOOT: + toot = None + def __init__(self, toot): + self.toot = toot def unmaketree(tree): - for post, children in tree: - yield POST(post) + for toot, children in tree: + yield TOOT(toot) if children: yield IN yield from unmaketree(children) @@ -71,6 +71,6 @@ def build(mastodon, descendants): yield OUT yield IN leftover = tuple(leftover()) - for post in leftover: - yield POST(post) + for toot in leftover: + yield TOOT(toot) yield OUT diff --git a/brutaldon/views.py b/brutaldon/views.py index 758ffdd..c25b7e2 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -692,7 +692,7 @@ def thread(request, id): # descendants = [ # x for x in context.descendants if not toot_matches_filters(x, filters) # ] - posts = tuple(threadtree.build(mastodon, context.descendants)) + toots = tuple(threadtree.build(mastodon, context.descendants)) return render( request, "main/thread.html", @@ -700,7 +700,7 @@ def thread(request, id): "context": context, "toot": toot, "root": root, - "posts": posts, + "toots": toots, "own_acct": request.session["active_user"], "notifications": notifications, "preferences": account.preferences, From 5095718192d276a520e5651f949f1605c87e78b1 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:38:17 +0000 Subject: [PATCH 24/27] The root post is not included in its descendants Oh for Pete's sake I'm an idiot. The descendants array isn't going to contain the root post at all, because it's totally separate. That's the missing post everything was trying to reply to! --- brutaldon/threadtree.py | 9 +++++---- brutaldon/views.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index fe49144..a9cc416 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -1,9 +1,10 @@ from pprint import pprint -def maketree(mastodon, descendants): +def maketree(mastodon, root, descendants): lookup = dict((descendant.id, descendant) for descendant in descendants) + lookup[root.id] = root replies = {} - roots = set() + roots = set([root.id]) def lookup_or_fetch(id): if not id in lookup: lookup[id] = mastodon.status(id) @@ -64,8 +65,8 @@ def unmaketree(tree): yield from unmaketree(children) yield OUT -def build(mastodon, descendants): - tree, leftover = maketree(mastodon, descendants) +def build(mastodon, root, descendants): + tree, leftover = maketree(mastodon, root, descendants) yield IN yield from unmaketree(tree) yield OUT diff --git a/brutaldon/views.py b/brutaldon/views.py index c25b7e2..765f29e 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -692,7 +692,7 @@ def thread(request, id): # descendants = [ # x for x in context.descendants if not toot_matches_filters(x, filters) # ] - toots = tuple(threadtree.build(mastodon, context.descendants)) + toots = tuple(threadtree.build(mastodon, root, context.descendants)) return render( request, "main/thread.html", From 593343ec037e2ac5b6ed60f3e5200d98fecb9cb1 Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:44:44 +0000 Subject: [PATCH 25/27] Why is the root post displaying twice? I thought the root post only displayed once. Maybe it needs to be removed? --- brutaldon/threadtree.py | 1 + 1 file changed, 1 insertion(+) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index a9cc416..165b9d7 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -29,6 +29,7 @@ def maketree(mastodon, root, descendants): descendant.in_reply_to_id, descendant.in_reply_to_account_id) seen = set() + seen.add(root.id) def onelevel(reps): for rep in sorted(reps): if rep in seen: continue From 91c3b8215208e50eb51b04f7107f21762dd8f66d Mon Sep 17 00:00:00 2001 From: autocommit Date: Mon, 1 Jun 2020 02:45:41 +0000 Subject: [PATCH 26/27] The template prints out the root by itself Right, the template is where the duplication of the root is, since now the root is just the first "descendant" in the tree. --- brutaldon/threadtree.py | 1 - brutaldon/views.py | 1 - 2 files changed, 2 deletions(-) diff --git a/brutaldon/threadtree.py b/brutaldon/threadtree.py index 165b9d7..a9cc416 100644 --- a/brutaldon/threadtree.py +++ b/brutaldon/threadtree.py @@ -29,7 +29,6 @@ def maketree(mastodon, root, descendants): descendant.in_reply_to_id, descendant.in_reply_to_account_id) seen = set() - seen.add(root.id) def onelevel(reps): for rep in sorted(reps): if rep in seen: continue diff --git a/brutaldon/views.py b/brutaldon/views.py index 765f29e..ea6e41f 100644 --- a/brutaldon/views.py +++ b/brutaldon/views.py @@ -699,7 +699,6 @@ def thread(request, id): { "context": context, "toot": toot, - "root": root, "toots": toots, "own_acct": request.session["active_user"], "notifications": notifications, From a6346a405321803e19ce067d33812ff0b8490908 Mon Sep 17 00:00:00 2001 From: Cy Date: Mon, 1 Jun 2020 02:58:24 +0000 Subject: [PATCH 27/27] Changing the template, prettifying a bit Now that everything is a
  • can set the margin-top value to make a gap, instead of making a visible "invisible" hr. And with the template thread.html fixed, it seems to be working, showing everything as a tree, instead of a flat list. --- brutaldon/static/css/brutaldon-dark.css | 7 +++++++ brutaldon/templates/main/thread.html | 22 ++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/brutaldon/static/css/brutaldon-dark.css b/brutaldon/static/css/brutaldon-dark.css index a1aee64..61be09f 100644 --- a/brutaldon/static/css/brutaldon-dark.css +++ b/brutaldon/static/css/brutaldon-dark.css @@ -255,3 +255,10 @@ div.poll { { margin-top: 0; } + +li { + margin-top: 0.1vh; +} +ul { + padding-left: 2vw; +} diff --git a/brutaldon/templates/main/thread.html b/brutaldon/templates/main/thread.html index 7c05fe4..dceb97e 100644 --- a/brutaldon/templates/main/thread.html +++ b/brutaldon/templates/main/thread.html @@ -18,14 +18,20 @@ mastodon.status_context()

    Thread

    - {% include "main/toot_partial.html" with toot=root %} - {% for descendant in descendants %} - {% if descendant == toot %} - {% include "main/toot_partial.html" with toot=toot active=True %} - {% else %} - {% include "main/toot_partial.html" with toot=descendant %} - {% endif %} - + {% for op in toots %} + {% if op == IN %} +
      + {% elif op == OUT %} +
    + {% else %} +
  • + {% if op.toot == toot %} + {% include "main/toot_partial.html" with toot=op.toot active=True %} + {% else %} + {% include "main/toot_partial.html" with toot=op.toot %} + {% endif %} +
  • + {% endif %} {% endfor %} {% if not preferences.no_javascript %}