From fb8f2d10984bcfa2585dc272b4c85d285b722792 Mon Sep 17 00:00:00 2001 From: Michael Manfre Date: Mon, 28 Nov 2022 23:41:36 -0500 Subject: Hashtags --- activities/views/admin/__init__.py | 0 activities/views/explore.py | 26 ++++++++++++++++++++++ activities/views/search.py | 43 ++++++++++++++++++++++++++++-------- activities/views/timelines.py | 45 ++++++++++++++++++++++++++++++++------ 4 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 activities/views/admin/__init__.py create mode 100644 activities/views/explore.py (limited to 'activities/views') diff --git a/activities/views/admin/__init__.py b/activities/views/admin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/activities/views/explore.py b/activities/views/explore.py new file mode 100644 index 0000000..ddb1e6c --- /dev/null +++ b/activities/views/explore.py @@ -0,0 +1,26 @@ +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/search.py b/activities/views/search.py index b175052..4719f64 100644 --- a/activities/views/search.py +++ b/activities/views/search.py @@ -1,6 +1,9 @@ +from typing import Set + from django import forms from django.views.generic import FormView +from activities.models import Hashtag from users.models import Domain, Identity @@ -9,13 +12,13 @@ class Search(FormView): template_name = "activities/search.html" class form_class(forms.Form): - query = forms.CharField(help_text="Search for a user by @username@domain") - - def form_valid(self, form): - query = form.cleaned_data["query"].lstrip("@").lower() - results = {"identities": set()} - # Search identities + query = forms.CharField( + help_text="Search for a user by @username@domain or hashtag by #tagname" + ) + def search_identities(self, query: str): + query = query.lstrip("@") + results: Set[Identity] = set() if "@" in query: username, domain = query.split("@", 1) @@ -35,13 +38,35 @@ class Search(FormView): ) identity = None if identity: - results["identities"].add(identity) + results.add(identity) else: for identity in Identity.objects.filter(username=query)[:20]: - results["identities"].add(identity) + results.add(identity) for identity in Identity.objects.filter(username__startswith=query)[:20]: - results["identities"].add(identity) + results.add(identity) + return results + + def search_hashtags(self, query: str): + results: Set[Hashtag] = set() + + if "@" in query: + return results + + query = query.lstrip("#") + for hashtag in Hashtag.objects.public().hashtag_or_alias(query)[:10]: + results.add(hashtag) + for hashtag in Hashtag.objects.public().filter(hashtag__startswith=query)[:10]: + results.add(hashtag) + return results + + def form_valid(self, form): + query = form.cleaned_data["query"].lower() + results = { + "identities": self.search_identities(query), + "hashtags": self.search_hashtags(query), + } + # Render results context = self.get_context_data(form=form) context["results"] = results diff --git a/activities/views/timelines.py b/activities/views/timelines.py index 4f2a515..ffe329c 100644 --- a/activities/views/timelines.py +++ b/activities/views/timelines.py @@ -1,10 +1,10 @@ from django import forms -from django.shortcuts import redirect +from django.shortcuts import get_object_or_404, redirect from django.template.defaultfilters import linebreaks_filter from django.utils.decorators import method_decorator from django.views.generic import FormView, ListView -from activities.models import Post, PostInteraction, TimelineEvent +from activities.models import Hashtag, Post, PostInteraction, TimelineEvent from core.models import Config from users.decorators import identity_required @@ -61,6 +61,41 @@ class Home(FormView): return redirect(".") +class Tag(ListView): + + template_name = "activities/tag.html" + extra_context = { + "current_page": "tag", + "allows_refresh": True, + } + paginate_by = 50 + + def get(self, request, hashtag, *args, **kwargs): + tag = hashtag.lower().lstrip("#") + if hashtag != tag: + # SEO sanitize + return redirect(f"/tags/{tag}/", permanent=True) + self.hashtag = get_object_or_404(Hashtag.objects.public(), hashtag=tag) + return super().get(request, *args, **kwargs) + + def get_queryset(self): + return ( + Post.objects.local_public() + .tagged_with(self.hashtag) + .select_related("author") + .prefetch_related("attachments") + .order_by("-created")[:50] + ) + + 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 + ) + return context + + class Local(ListView): template_name = "activities/local.html" @@ -72,11 +107,7 @@ class Local(ListView): def get_queryset(self): return ( - Post.objects.filter( - visibility=Post.Visibilities.public, - author__local=True, - in_reply_to__isnull=True, - ) + Post.objects.local_public() .select_related("author") .prefetch_related("attachments") .order_by("-created")[:50] -- cgit v1.2.3