From 0225c6e8ba2d38442f4792980918afd26732f412 Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Thu, 27 Apr 2023 19:09:16 -0600 Subject: [PATCH] Continue to refactor --- activities/services/post.py | 8 +- activities/views/compose.py | 95 +----------------- activities/views/explore.py | 26 ----- activities/views/hashtags.py | 38 ------- activities/views/posts.py | 28 +----- activities/views/search.py | 2 +- activities/views/timelines.py | 77 ++------------ core/decorators.py | 10 -- core/views.py | 2 +- static/img/apps/elk.svg | 42 ++++++++ static/img/apps/ivory.webp | Bin 0 -> 12544 bytes static/img/apps/tusky.png | Bin 0 -> 14698 bytes takahe/urls.py | 37 ++----- templates/activities/_bookmark.html | 9 -- templates/activities/_hashtag_follow.html | 9 -- templates/activities/_image_upload.html | 15 --- templates/activities/_image_uploaded.html | 19 ---- templates/activities/_post.html | 15 +-- templates/activities/compose.html | 25 +---- templates/activities/federated.html | 3 - templates/activities/local.html | 25 ----- templates/activities/notifications.html | 79 +++++++-------- templates/activities/post.html | 16 +-- templates/activities/tag.html | 41 ++++---- templates/admin/_menu.html | 61 +++++++++++ templates/admin/base.html | 13 +++ templates/admin/settings.html | 20 ++++ templates/settings/_menu.html | 11 ++ templates/settings/follows.html | 46 +++++++++ templates/settings/import_export.html | 4 +- templates/settings/profile.html | 1 - users/shortcuts.py | 11 ++ users/views/admin/reports.py | 4 +- users/views/base.py | 24 +++++ users/views/identity.py | 27 ----- users/views/report.py | 76 -------------- users/views/settings/__init__.py | 1 + .../views => users/views/settings}/follows.py | 19 ++-- users/views/settings/import_export.py | 28 +++--- 39 files changed, 364 insertions(+), 603 deletions(-) delete mode 100644 activities/views/explore.py delete mode 100644 activities/views/hashtags.py create mode 100755 static/img/apps/elk.svg create mode 100755 static/img/apps/ivory.webp create mode 100755 static/img/apps/tusky.png delete mode 100644 templates/activities/_bookmark.html delete mode 100644 templates/activities/_hashtag_follow.html delete mode 100644 templates/activities/_image_upload.html delete mode 100644 templates/activities/_image_uploaded.html delete mode 100644 templates/activities/federated.html delete mode 100644 templates/activities/local.html create mode 100644 templates/admin/_menu.html create mode 100644 templates/admin/base.html create mode 100644 templates/admin/settings.html create mode 100644 templates/settings/follows.html create mode 100644 users/views/base.py delete mode 100644 users/views/report.py rename {activities/views => users/views/settings}/follows.py (86%) diff --git a/activities/services/post.py b/activities/services/post.py index f225fdd..f7e0b31 100644 --- a/activities/services/post.py +++ b/activities/services/post.py @@ -72,7 +72,12 @@ class PostService: def unboost_as(self, identity: Identity): self.uninteract_as(identity, PostInteraction.Types.boost) - def context(self, identity: Identity | None) -> tuple[list[Post], list[Post]]: + def context( + self, + identity: Identity | None, + num_ancestors: int = 10, + num_descendants: int = 50, + ) -> tuple[list[Post], list[Post]]: """ Returns ancestor/descendant information. @@ -82,7 +87,6 @@ class PostService: If identity is provided, includes mentions/followers-only posts they can see. Otherwise, shows unlisted and above only. """ - num_ancestors = 10 num_descendants = 50 # Retrieve ancestors via parent walk ancestors: list[Post] = [] diff --git a/activities/views/compose.py b/activities/views/compose.py index e1f640c..0b81e82 100644 --- a/activities/views/compose.py +++ b/activities/views/compose.py @@ -16,7 +16,7 @@ from activities.models import ( from core.files import blurhash_image, resize_image from core.html import FediverseHtmlParser from core.models import Config -from users.shortcuts import by_handle_or_404 +from users.shortcuts import by_handle_for_user_or_404 from django.contrib.auth.decorators import login_required @@ -167,10 +167,10 @@ class Compose(FormView): ) # Add their own timeline event for immediate visibility TimelineEvent.add_post(self.identity, post) - return redirect("/") + return redirect(self.identity.urls.view) def dispatch(self, request, handle=None, post_id=None, *args, **kwargs): - self.identity = by_handle_or_404(self.request, handle, local=True, fetch=False) + self.identity = by_handle_for_user_or_404(self.request, handle) self.post_obj = None if handle and post_id: self.post_obj = get_object_or_404(self.identity.posts, pk=post_id) @@ -190,94 +190,7 @@ class Compose(FormView): context = super().get_context_data(**kwargs) context["reply_to"] = self.reply_to context["identity"] = self.identity + context["section"] = "compose" if self.post_obj: context["post"] = self.post_obj return context - - -@method_decorator(login_required, name="dispatch") -class ImageUpload(FormView): - """ - Handles image upload - returns a new input type hidden to embed in - the main form that references an orphaned PostAttachment - """ - - template_name = "activities/_image_upload.html" - - class form_class(forms.Form): - image = forms.ImageField( - widget=forms.FileInput( - attrs={ - "_": f""" - on change - if me.files[0].size > {settings.SETUP.MEDIA_MAX_IMAGE_FILESIZE_MB * 1024 ** 2} - add [@disabled=] to #upload - - remove - make called errorlist - make
  • called error - set size_in_mb to (me.files[0].size / 1024 / 1024).toFixed(2) - put 'File must be {settings.SETUP.MEDIA_MAX_IMAGE_FILESIZE_MB}MB or less (actual: ' + size_in_mb + 'MB)' into error - put error into errorlist - put errorlist before me - else - remove @disabled from #upload - remove - end - end - """ - } - ) - ) - description = forms.CharField(required=False) - - def clean_image(self): - value = self.cleaned_data["image"] - max_mb = settings.SETUP.MEDIA_MAX_IMAGE_FILESIZE_MB - max_bytes = max_mb * 1024 * 1024 - if value.size > max_bytes: - # Erase the file from our data to stop trying to show it again - self.files = {} - raise forms.ValidationError( - f"File must be {max_mb}MB or less (actual: {value.size / 1024 ** 2:.2f})" - ) - return value - - def form_invalid(self, form): - return super().form_invalid(form) - - def form_valid(self, form): - # Make a PostAttachment - main_file = resize_image( - form.cleaned_data["image"], - size=(2000, 2000), - cover=False, - ) - thumbnail_file = resize_image( - form.cleaned_data["image"], - size=(400, 225), - cover=True, - ) - attachment = PostAttachment.objects.create( - blurhash=blurhash_image(thumbnail_file), - mimetype="image/webp", - width=main_file.image.width, - height=main_file.image.height, - name=form.cleaned_data.get("description"), - state=PostAttachmentStates.fetched, - author=self.identity, - ) - - attachment.file.save( - main_file.name, - main_file, - ) - attachment.thumbnail.save( - thumbnail_file.name, - thumbnail_file, - ) - attachment.save() - # Return the response, with a hidden input plus a note - return render( - self.request, "activities/_image_uploaded.html", {"attachment": attachment} - ) diff --git a/activities/views/explore.py b/activities/views/explore.py deleted file mode 100644 index ddb1e6c..0000000 --- a/activities/views/explore.py +++ /dev/null @@ -1,26 +0,0 @@ -from django.views.generic import ListView - -from activities.models import Hashtag - - -class ExploreTag(ListView): - - template_name = "activities/explore_tag.html" - extra_context = { - "current_page": "explore", - "allows_refresh": True, - } - paginate_by = 20 - - def get_queryset(self): - return ( - Hashtag.objects.public() - .filter( - stats__total__gt=0, - ) - .order_by("-stats__total") - )[:20] - - -class Explore(ExploreTag): - pass diff --git a/activities/views/hashtags.py b/activities/views/hashtags.py deleted file mode 100644 index bc939ab..0000000 --- a/activities/views/hashtags.py +++ /dev/null @@ -1,38 +0,0 @@ -from django.http import HttpRequest -from django.shortcuts import get_object_or_404, redirect, render -from django.utils.decorators import method_decorator -from django.views.generic import View - -from activities.models.hashtag import Hashtag -from django.contrib.auth.decorators import login_required - - -@method_decorator(login_required, name="dispatch") -class HashtagFollow(View): - """ - Follows/unfollows a hashtag with the current identity - """ - - undo = False - - def post(self, request: HttpRequest, hashtag): - hashtag = get_object_or_404( - Hashtag, - pk=hashtag, - ) - follow = None - if self.undo: - request.identity.hashtag_follows.filter(hashtag=hashtag).delete() - else: - follow = request.identity.hashtag_follows.get_or_create(hashtag=hashtag) - # Return either a redirect or a HTMX snippet - if request.htmx: - return render( - request, - "activities/_hashtag_follow.html", - { - "hashtag": hashtag, - "follow": follow, - }, - ) - return redirect(hashtag.urls.view) diff --git a/activities/views/posts.py b/activities/views/posts.py index 1f34341..bfac8eb 100644 --- a/activities/views/posts.py +++ b/activities/views/posts.py @@ -47,7 +47,9 @@ class Individual(TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - ancestors, descendants = PostService(self.post_obj).context(None) + ancestors, descendants = PostService(self.post_obj).context( + identity=None, num_ancestors=2 + ) context.update( { @@ -69,27 +71,3 @@ class Individual(TemplateView): canonicalise(self.post_obj.to_ap(), include_security=True), content_type="application/activity+json", ) - - -@method_decorator(login_required, name="dispatch") -class Delete(TemplateView): - """ - Deletes a post - """ - - template_name = "activities/post_delete.html" - - def dispatch(self, request, handle, post_id): - # Make sure the request identity owns the post! - if handle != request.identity.handle: - raise PermissionDenied("Post author is not requestor") - self.identity = by_handle_or_404(self.request, handle, local=False) - self.post_obj = get_object_or_404(self.identity.posts, pk=post_id) - return super().dispatch(request) - - def get_context_data(self): - return {"post": self.post_obj} - - def post(self, request): - PostService(self.post_obj).delete() - return redirect("/") diff --git a/activities/views/search.py b/activities/views/search.py index 4c709e0..afff395 100644 --- a/activities/views/search.py +++ b/activities/views/search.py @@ -15,7 +15,7 @@ class Search(FormView): ) def form_valid(self, form): - searcher = SearchService(form.cleaned_data["query"], self.request.identity) + searcher = SearchService(form.cleaned_data["query"], identity=None) # Render results context = self.get_context_data(form=form) context["results"] = searcher.search_all() diff --git a/activities/views/timelines.py b/activities/views/timelines.py index 6404d8b..4f8dad4 100644 --- a/activities/views/timelines.py +++ b/activities/views/timelines.py @@ -1,3 +1,5 @@ +from typing import Any +from django.http import Http404 from django.core.paginator import Paginator from django.shortcuts import get_object_or_404, redirect from django.utils.decorators import method_decorator @@ -8,6 +10,7 @@ from activities.services import TimelineService from core.decorators import cache_page from django.contrib.auth.decorators import login_required from users.models import Bookmark, HashtagFollow, Identity +from users.views.base import IdentityViewMixin @method_decorator(login_required, name="dispatch") @@ -46,74 +49,15 @@ class Tag(ListView): return super().get(request, *args, **kwargs) def get_queryset(self): - return TimelineService(self.request.identity).hashtag(self.hashtag) + return TimelineService(None).hashtag(self.hashtag) def get_context_data(self): context = super().get_context_data() context["hashtag"] = self.hashtag - context["interactions"] = PostInteraction.get_post_interactions( - context["page_obj"], self.request.identity - ) - context["bookmarks"] = Bookmark.for_identity( - self.request.identity, context["page_obj"] - ) - context["follow"] = HashtagFollow.maybe_get( - self.request.identity, - self.hashtag, - ) return context -@method_decorator( - cache_page("cache_timeout_page_timeline", public_only=True), name="dispatch" -) -class Local(ListView): - template_name = "activities/local.html" - extra_context = { - "current_page": "local", - "allows_refresh": True, - } - paginate_by = 25 - - def get_queryset(self): - return TimelineService(self.request.identity).local() - - def get_context_data(self): - context = super().get_context_data() - context["interactions"] = PostInteraction.get_post_interactions( - context["page_obj"], self.request.identity - ) - context["bookmarks"] = Bookmark.for_identity( - self.request.identity, context["page_obj"] - ) - return context - - -@method_decorator(login_required, name="dispatch") -class Federated(ListView): - template_name = "activities/federated.html" - extra_context = { - "current_page": "federated", - "allows_refresh": True, - } - paginate_by = 25 - - def get_queryset(self): - return TimelineService(self.request.identity).federated() - - def get_context_data(self): - context = super().get_context_data() - context["interactions"] = PostInteraction.get_post_interactions( - context["page_obj"], self.request.identity - ) - context["bookmarks"] = Bookmark.for_identity( - self.request.identity, context["page_obj"] - ) - return context - - -@method_decorator(login_required, name="dispatch") -class Notifications(ListView): +class Notifications(IdentityViewMixin, ListView): template_name = "activities/notifications.html" extra_context = { "current_page": "notifications", @@ -125,7 +69,6 @@ class Notifications(ListView): "boosted": TimelineEvent.Types.boosted, "mentioned": TimelineEvent.Types.mentioned, "liked": TimelineEvent.Types.liked, - "identity_created": TimelineEvent.Types.identity_created, } def get_queryset(self): @@ -143,7 +86,7 @@ class Notifications(ListView): for type_name, type in self.notification_types.items(): if notification_options.get(type_name, True): types.append(type) - return TimelineService(self.request.identity).notifications(types) + return TimelineService(self.identity).notifications(types) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -164,12 +107,6 @@ class Notifications(ListView): events.append(event) # Retrieve what kinds of things to show context["events"] = events + context["identity"] = self.identity context["notification_options"] = self.request.session["notification_options"] - context["interactions"] = PostInteraction.get_event_interactions( - context["page_obj"], - self.request.identity, - ) - context["bookmarks"] = Bookmark.for_identity( - self.request.identity, context["page_obj"], "subject_post_id" - ) return context diff --git a/core/decorators.py b/core/decorators.py index dc8d4d2..dd4fc2f 100644 --- a/core/decorators.py +++ b/core/decorators.py @@ -20,16 +20,6 @@ def vary_by_ap_json(request, *args, **kwargs) -> str: return "not_ap" -def vary_by_identity(request, *args, **kwargs) -> str: - """ - Return a cache usable string token that is different based upon the - request.identity - """ - if request.identity: - return f"ident{request.identity.pk}" - return "identNone" - - def cache_page( timeout: int | str = "cache_timeout_page_default", *, diff --git a/core/views.py b/core/views.py index fb43c6e..7fae532 100644 --- a/core/views.py +++ b/core/views.py @@ -30,7 +30,7 @@ class About(TemplateView): template_name = "about.html" def get_context_data(self): - service = TimelineService(self.request.identity) + service = TimelineService(None) return { "current_page": "about", "content": mark_safe( diff --git a/static/img/apps/elk.svg b/static/img/apps/elk.svg new file mode 100755 index 0000000..aea8c9d --- /dev/null +++ b/static/img/apps/elk.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + diff --git a/static/img/apps/ivory.webp b/static/img/apps/ivory.webp new file mode 100755 index 0000000000000000000000000000000000000000..6f37fcacc31eddccf961efffd0b9b236f3e64b86 GIT binary patch literal 12544 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 literal 0 HcmV?d00001 diff --git a/takahe/urls.py b/takahe/urls.py index 354dff4..32607a7 100644 --- a/takahe/urls.py +++ b/takahe/urls.py @@ -5,9 +5,6 @@ from django.urls import include, path, re_path from activities.views import ( compose, debug, - explore, - follows, - hashtags, posts, search, timelines, @@ -22,28 +19,21 @@ from users.views import ( announcements, auth, identity, - report, settings, ) +from users.views.settings import follows urlpatterns = [ path("", core.homepage), path("robots.txt", core.RobotsTxt.as_view()), # Activity views - path("notifications/", timelines.Notifications.as_view(), name="notifications"), - path("local/", timelines.Local.as_view(), name="local"), - path("federated/", timelines.Federated.as_view(), name="federated"), + path( + "@/notifications/", + timelines.Notifications.as_view(), + name="notifications", + ), path("search/", search.Search.as_view(), name="search"), path("tags//", timelines.Tag.as_view(), name="tag"), - path("tags//follow/", hashtags.HashtagFollow.as_view()), - path("tags//unfollow/", hashtags.HashtagFollow.as_view(undo=True)), - path("explore/", explore.Explore.as_view(), name="explore"), - path("explore/tags/", explore.ExploreTag.as_view(), name="explore-tag"), - path( - "follows/", - follows.Follows.as_view(), - name="follows", - ), # Settings views path( "settings/", @@ -70,6 +60,11 @@ urlpatterns = [ settings.InterfacePage.as_view(), name="settings_interface", ), + path( + "@/settings/follows/", + settings.FollowsPage.as_view(), + name="settings_follows", + ), path( "@/settings/import_export/", settings.ImportExportPage.as_view(), @@ -240,22 +235,12 @@ urlpatterns = [ path("@/", identity.ViewIdentity.as_view()), path("@/inbox/", activitypub.Inbox.as_view()), path("@/outbox/", activitypub.Outbox.as_view()), - path("@/action/", identity.ActionIdentity.as_view()), path("@/rss/", identity.IdentityFeed()), - path("@/report/", report.SubmitReport.as_view()), path("@/following/", identity.IdentityFollows.as_view(inbound=False)), path("@/followers/", identity.IdentityFollows.as_view(inbound=True)), # Posts path("@/compose/", compose.Compose.as_view(), name="compose"), - path( - "@/compose/image_upload/", - compose.ImageUpload.as_view(), - name="compose_image_upload", - ), path("@/posts//", posts.Individual.as_view()), - path("@/posts//delete/", posts.Delete.as_view()), - path("@/posts//report/", report.SubmitReport.as_view()), - path("@/posts//edit/", compose.Compose.as_view()), # Authentication path("auth/login/", auth.Login.as_view(), name="login"), path("auth/logout/", auth.Logout.as_view(), name="logout"), diff --git a/templates/activities/_bookmark.html b/templates/activities/_bookmark.html deleted file mode 100644 index ab9731d..0000000 --- a/templates/activities/_bookmark.html +++ /dev/null @@ -1,9 +0,0 @@ -{% if post.pk in bookmarks %} - - - -{% else %} - - - -{% endif %} diff --git a/templates/activities/_hashtag_follow.html b/templates/activities/_hashtag_follow.html deleted file mode 100644 index cdf00c5..0000000 --- a/templates/activities/_hashtag_follow.html +++ /dev/null @@ -1,9 +0,0 @@ -{% if follow %} - -{% else %} - -{% endif %} diff --git a/templates/activities/_image_upload.html b/templates/activities/_image_upload.html deleted file mode 100644 index dec9160..0000000 --- a/templates/activities/_image_upload.html +++ /dev/null @@ -1,15 +0,0 @@ -
    - {% csrf_token %} - {% include "forms/_field.html" with field=form.image %} - {% include "forms/_field.html" with field=form.description %} -
    - - -
    -
    diff --git a/templates/activities/_image_uploaded.html b/templates/activities/_image_uploaded.html deleted file mode 100644 index e2424ce..0000000 --- a/templates/activities/_image_uploaded.html +++ /dev/null @@ -1,19 +0,0 @@ -
    - - -

    - {{ attachment.name|default:"(no description)" }} -

    -
    - -
    -
    -{% if request.htmx %} - -{% endif %} diff --git a/templates/activities/_post.html b/templates/activities/_post.html index fd10fa4..9fc52b3 100644 --- a/templates/activities/_post.html +++ b/templates/activities/_post.html @@ -76,15 +76,15 @@
    - + - + - + @@ -96,14 +96,7 @@ Report - {% if post.author == request.identity %} - - Edit - - - Delete - - {% elif not post.local and post.url %} + {% if not post.local and post.url %} See Original diff --git a/templates/activities/compose.html b/templates/activities/compose.html index ff0b3ec..b7b4cdf 100644 --- a/templates/activities/compose.html +++ b/templates/activities/compose.html @@ -1,41 +1,26 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} {% block title %}Compose{% endblock %} -{% block content %} +{% block settings_content %}
    {% csrf_token %}
    - Content + Compose {% if reply_to %} {% include "activities/_mini_post.html" with post=reply_to %} {% endif %} +

    For more advanced posting options, like editing and image uploads, please use an app.

    {{ form.reply_to }} {{ form.id }} {% include "forms/_field.html" with field=form.text %} {% include "forms/_field.html" with field=form.content_warning %} {% include "forms/_field.html" with field=form.visibility %}
    -
    - Images - {% if post %} - {% for attachment in post.attachments.all %} - {% include "activities/_image_uploaded.html" %} - {% endfor %} - {% endif %} - {% if not post or post.attachments.count < 4 %} - - {% endif %} -
    {{ config.post_length }} - +
    {% endblock %} diff --git a/templates/activities/federated.html b/templates/activities/federated.html deleted file mode 100644 index 9e61b6b..0000000 --- a/templates/activities/federated.html +++ /dev/null @@ -1,3 +0,0 @@ -{% extends "activities/local.html" %} - -{% block title %}Federated Timeline{% endblock %} diff --git a/templates/activities/local.html b/templates/activities/local.html deleted file mode 100644 index 5a9b6a4..0000000 --- a/templates/activities/local.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Local Timeline{% endblock %} - -{% block content %} - {% if page_obj.number == 1 %} - {% include "_announcements.html" %} - {% endif %} - - {% for post in page_obj %} - {% include "activities/_post.html" with feedindex=forloop.counter %} - {% empty %} - No posts yet. - {% endfor %} - - -{% endblock %} diff --git a/templates/activities/notifications.html b/templates/activities/notifications.html index d4116dd..96ffd9a 100644 --- a/templates/activities/notifications.html +++ b/templates/activities/notifications.html @@ -1,55 +1,50 @@ -{% extends "base.html" %} +{% extends "settings/base.html" %} {% block title %}Notifications{% endblock %} -{% block content %} +{% block settings_content %} {% if page_obj.number == 1 %} {% include "_announcements.html" %} {% endif %} -
    - {% if notification_options.followed %} - Followers - {% else %} - Followers - {% endif %} - {% if notification_options.boosted %} - Boosts - {% else %} - Boosts - {% endif %} - {% if notification_options.liked %} - Likes - {% else %} - Likes - {% endif %} - {% if notification_options.mentioned %} - Mentions - {% else %} - Mentions - {% endif %} - {% if request.user.admin %} - {% if notification_options.identity_created %} - New Identities +
    - {% for event in events %} - {% include "activities/_event.html" %} - {% empty %} - No notifications yet. - {% endfor %} + {% for event in events %} + {% include "activities/_event.html" %} + {% empty %} + No notifications yet. + {% endfor %} - + {% endblock %} diff --git a/templates/activities/post.html b/templates/activities/post.html index cb7e60e..5fb8554 100644 --- a/templates/activities/post.html +++ b/templates/activities/post.html @@ -7,11 +7,13 @@ {% endblock %} {% block content %} - {% for ancestor in ancestors reversed %} - {% include "activities/_post.html" with post=ancestor reply=True link_original=False %} - {% endfor %} - {% include "activities/_post.html" %} - {% for descendant in descendants %} - {% include "activities/_post.html" with post=descendant reply=True link_original=False %} - {% endfor %} + {% endblock %} diff --git a/templates/activities/tag.html b/templates/activities/tag.html index e0e35bf..b084cb3 100644 --- a/templates/activities/tag.html +++ b/templates/activities/tag.html @@ -3,27 +3,26 @@ {% block title %}#{{ hashtag.display_name }} Timeline{% endblock %} {% block content %} -
    -