hide search category

This commit is contained in:
Your Name 2023-07-12 01:11:15 -04:00 committed by Henri Dickson
parent 3de032367a
commit a5d73e864e
12 changed files with 149 additions and 67 deletions

View file

@ -45,7 +45,10 @@ def search_item(
if not query:
return 400, {"message": "Invalid query"}
items, num_pages, count, _ = query_index(
query, page=page, category=category, prepare_external=False
query,
page=page,
categories=[category] if category else None,
prepare_external=False,
)
return 200, {"data": items, "pages": num_pages, "count": count}

View file

@ -18,7 +18,7 @@ _logger = logging.getLogger(__name__)
class DbIndexer:
@classmethod
def search(cls, q, page=1, category=None, tag=None, sort=None):
def search(cls, q, page=1, categories=None, tag=None, sort=None):
result = lambda: None
result.items = Item.objects.filter(title__contains=q)[:10]
result.num_pages = 1
@ -47,14 +47,14 @@ else:
Indexer = DbIndexer
def query_index(keywords, category=None, tag=None, page=1, prepare_external=True):
def query_index(keywords, categories=None, tag=None, page=1, prepare_external=True):
if (
page < 1
or page > 99
or (not tag and isinstance(keywords, str) and len(keywords) < 2)
):
return [], 0, 0, []
result = Indexer.search(keywords, page=page, category=category, tag=tag)
result = Indexer.search(keywords, page=page, categories=categories, tag=tag)
keys = set()
items = []
duplicated_items = []
@ -92,7 +92,7 @@ def query_index(keywords, category=None, tag=None, page=1, prepare_external=True
if prepare_external:
# store site url to avoid dups in external search
cache_key = f"search_{category}_{keywords}"
cache_key = f"search_{','.join(categories or [])}_{keywords}"
urls = list(set(cache.get(cache_key, []) + urls))
cache.set(cache_key, urls, timeout=300)

View file

@ -311,13 +311,10 @@ class Indexer:
logger.warn(f"delete item error: \n{e}")
@classmethod
def search(cls, q, page=1, category=None, tag=None, sort=None):
def search(cls, q, page=1, categories=None, tag=None, sort=None):
f = []
if category:
if category == "movietv":
f.append("category:= [movie,tv]")
else:
f.append("category:= " + category)
if categories:
f.append(f"category:= [{','.join(categories)}]")
if tag:
f.append(f"tags:= '{tag}'")
filters = " && ".join(f)

View file

@ -5,7 +5,7 @@ from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseRedirect
from catalog.common.models import SiteName
from catalog.common.models import ItemCategory, SiteName
from catalog.common.sites import AbstractSite, SiteManager
from ..models import *
from django.conf import settings
@ -82,10 +82,27 @@ def fetch(request, url, is_refetch: bool = False, site: AbstractSite | None = No
)
def visible_categories(request):
vc = request.session.get("p_categories", None)
if vc is None:
vc = [
x
for x in item_categories()
if x.value not in request.user.preference.hidden_categories
]
request.session["p_categories"] = vc
return vc
def search(request):
category = request.GET.get("c", default="all").strip().lower()
if category == "all":
if category == "all" or not category:
category = None
categories = visible_categories(request)
elif category == "movietv":
categories = [ItemCategory.Movie, ItemCategory.TV]
else:
categories = [ItemCategory(category)]
keywords = request.GET.get("q", default="").strip()
tag = request.GET.get("tag", default="").strip()
p = request.GET.get("page", default="1")
@ -105,7 +122,7 @@ def search(request):
if site:
return fetch(request, keywords, False, site)
items, num_pages, _, dup_items = query_index(keywords, category, tag, p)
items, num_pages, _, dup_items = query_index(keywords, categories, tag, p)
return render(
request,
"search_results.html",

View file

@ -4,6 +4,7 @@
{% load humanize %}
{% load admin_url %}
{% load mastodon %}
{% load duration %}
{% load oauth_token %}
{% load truncate %}
{% load highlight %}
@ -26,46 +27,59 @@
<hgroup>
<h5>“{{ request.GET.q }}” {% trans '的搜索结果' %}</h5>
<div>
{% visible_categories as cats %}
{% if request.GET.c and request.GET.c != 'all' %}
<a href="?q={{ request.GET.q }}&c=all">全部</a>
<a href="?q={{ request.GET.q }}&amp;c=all">全部</a>
{% else %}
全部
{% endif %}
|
{% if request.GET.c != 'book' %}
<a href="?q={{ request.GET.q }}&c=book">书籍</a>
{% else %}
书籍
{% if 'book' in cats %}
|
{% if request.GET.c != 'book' %}
<a href="?q={{ request.GET.q }}&amp;c=book">书籍</a>
{% else %}
书籍
{% endif %}
{% endif %}
|
{% if request.GET.c != 'movietv' %}
<a href="?q={{ request.GET.q }}&c=movietv">影视</a>
{% else %}
影视
{% if 'movie' in cats or 'tv' in cats %}
|
{% if request.GET.c != 'movietv' %}
<a href="?q={{ request.GET.q }}&amp;c=movietv">影视</a>
{% else %}
影视
{% endif %}
{% endif %}
|
{% if request.GET.c != 'podcast' %}
<a href="?q={{ request.GET.q }}&c=podcast">播客</a>
{% else %}
播客
{% if 'podcast' in cats %}
|
{% if request.GET.c != 'podcast' %}
<a href="?q={{ request.GET.q }}&amp;c=podcast">播客</a>
{% else %}
播客
{% endif %}
{% endif %}
|
{% if request.GET.c != 'music' %}
<a href="?q={{ request.GET.q }}&c=music">音乐</a>
{% else %}
音乐
{% if 'music' in cats %}
|
{% if request.GET.c != 'music' %}
<a href="?q={{ request.GET.q }}&amp;c=music">音乐</a>
{% else %}
音乐
{% endif %}
{% endif %}
|
{% if request.GET.c != 'game' %}
<a href="?q={{ request.GET.q }}&c=game">游戏</a>
{% else %}
游戏
{% if 'game' in cats %}
|
{% if request.GET.c != 'game' %}
<a href="?q={{ request.GET.q }}&amp;c=game">游戏</a>
{% else %}
游戏
{% endif %}
{% endif %}
|
{% if request.GET.c != 'performance' %}
<a href="?q={{ request.GET.q }}&c=performance">演出</a>
{% else %}
演出
{% if 'performance' in cats %}
|
{% if request.GET.c != 'performance' %}
<a href="?q={{ request.GET.q }}&amp;c=performance">演出</a>
{% else %}
演出
{% endif %}
{% endif %}
</div>
</hgroup>
@ -116,24 +130,24 @@
</div>
<div class="pagination">
{% if pagination.has_prev %}
<a href="?page=1&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
<a href="?page=1&amp;{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link pagination__nav-link">&laquo;</a>
<a href="?page={{ pagination.previous_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
<a href="?page={{ pagination.previous_page }}&amp;{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link pagination__nav-link--right-margin pagination__nav-link">&lsaquo;</a>
{% endif %}
{% for page in pagination.page_range %}
{% if page == pagination.current_page %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
<a href="?page={{ page }}&amp;{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__page-link pagination__page-link--current">{{ page }}</a>
{% else %}
<a href="?page={{ page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
<a href="?page={{ page }}&amp;{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__page-link">{{ page }}</a>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<a href="?page={{ pagination.next_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
<a href="?page={{ pagination.next_page }}&amp;{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link pagination__nav-link--left-margin">&rsaquo;</a>
<a href="?page={{ pagination.last_page }}&{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
<a href="?page={{ pagination.last_page }}&amp;{% if request.GET.q %}q={{ request.GET.q }}{% elif request.GET.tag %}tag={{ request.GET.tag }}{% endif %}{% if request.GET.c %}&c={{ request.GET.c }}{% endif %}"
class="pagination__nav-link">&raquo;</a>
{% endif %}
</div>

View file

@ -1,4 +1,5 @@
{% load admin_url %}
{% load duration %}
{% load static %}
{% load i18n %}
<header class="container-fluid">
@ -18,19 +19,32 @@
class="search"
value="{{ request.GET.q|default:'' }}" />
<select name="c">
{% visible_categories as cats %}
<option value="all">全部</option>
<option {% if request.GET.c and request.GET.c == 'book' or '/book/' in request.path %}selected{% endif %}
value="book">书籍</option>
<option {% if request.GET.c and request.GET.c == 'movietv' or '/movie/' in request.path or '/tv/' in request.path %}selected{% endif %}
value="movietv">影视</option>
<option {% if request.GET.c and request.GET.c == 'podcast' or '/podcast/' in request.path %}selected{% endif %}
value="podcast">播客</option>
<option {% if request.GET.c and request.GET.c == 'music' or '/album/' in request.path %}selected{% endif %}
value="music">音乐</option>
<option {% if request.GET.c and request.GET.c == 'game' or '/game/' in request.path %}selected{% endif %}
value="game">游戏</option>
<option {% if request.GET.c and request.GET.c == 'performance' or '/performance/' in request.path %}selected{% endif %}
value="performance">演出</option>
{% if 'book' in cats %}
<option {% if request.GET.c == 'book' or '/book/' in request.path %}selected{% endif %}
value="book">书籍</option>
{% endif %}
{% if 'movie' in cats or 'tv' in cats %}
<option {% if request.GET.c and request.GET.c == 'movietv' or '/movie/' in request.path or '/tv/' in request.path %}selected{% endif %}
value="movietv">影视</option>
{% endif %}
{% if 'podcast' in cats %}
<option {% if request.GET.c and request.GET.c == 'podcast' or '/podcast/' in request.path %}selected{% endif %}
value="podcast">播客</option>
{% endif %}
{% if 'music' in cats %}
<option {% if request.GET.c and request.GET.c == 'music' or '/album/' in request.path %}selected{% endif %}
value="music">音乐</option>
{% endif %}
{% if 'game' in cats %}
<option {% if request.GET.c and request.GET.c == 'game' or '/game/' in request.path %}selected{% endif %}
value="game">游戏</option>
{% endif %}
{% if 'performance' in cats %}
<option {% if request.GET.c == 'performance' or '/performance/' in request.path %}selected{% endif %}
value="performance">演出</option>
{% endif %}
</select>
<input type="submit" value="&#xf002;" class="fa-solid" />
</form>

View file

@ -2,10 +2,22 @@ from django import template
from django.template.defaultfilters import stringfilter
from django.utils.text import Truncator
from django.utils.safestring import mark_safe
from catalog.common.models import ItemCategory, item_categories
from catalog.search.views import visible_categories as _visible_categories
register = template.Library()
@register.simple_tag(takes_context=True)
def visible_categories(context):
return _visible_categories(context["request"])
@register.simple_tag
def all_categories():
return item_categories()
@register.filter(is_safe=True)
@stringfilter
def duration_format(value, unit):

View file

@ -88,7 +88,7 @@ classDiagram
Add a new site
--------------
> **Site official API** should be the prioritised way to get data when adding a new site.
- If official API is available for the site, it should be the preferred way to get data.
- add a new value to `IdType` and `SiteName` in `catalog/common/models.py`
- add a new file in `catalog/sites/`, a new class inherits `AbstractSite`, with:
* `SITE_NAME`

View file

@ -457,9 +457,16 @@ def swap_login(request, token, site, refresh_token):
return redirect(reverse("users:data"))
def clear_preference_cache(request):
for key in list(request.session.keys()):
if key.startswith("p_"):
del request.session[key]
def auth_login(request, user):
"""Decorates django ``login()``. Attach token to session."""
auth.login(request, user, backend="mastodon.auth.OAuth2Backend")
clear_preference_cache(request)
if (
user.mastodon_last_refresh < timezone.now() - timedelta(hours=1)
or user.mastodon_account == {}

View file

@ -29,6 +29,7 @@ def preferences(request):
preference.default_no_share = bool(request.POST.get("default_no_share"))
preference.no_anonymous_view = bool(request.POST.get("no_anonymous_view"))
preference.classic_homepage = int(request.POST.get("classic_homepage"))
preference.hidden_categories = request.POST.getlist("hidden_categories")
preference.mastodon_publish_public = bool(
request.POST.get("mastodon_publish_public")
)
@ -45,8 +46,10 @@ def preferences(request):
"mastodon_publish_public",
"mastodon_append_tag",
"show_last_edit",
"hidden_categories",
]
)
clear_preference_cache(request)
return render(request, "users/preferences.html")

View file

@ -20,7 +20,7 @@ from django.templatetags.static import static
import hashlib
from loguru import logger
RESERVED_USERNAMES = [
_RESERVED_USERNAMES = [
"connect",
"oauth2_login",
"__",
@ -40,7 +40,7 @@ class UsernameValidator(validators.RegexValidator):
flags = re.ASCII
def __call__(self, value):
if value and value.lower() in RESERVED_USERNAMES:
if value and value.lower() in _RESERVED_USERNAMES:
raise ValidationError(self.message, code=self.code)
return super().__call__(value)
@ -52,6 +52,7 @@ def report_image_path(instance, filename):
class User(AbstractUser):
preference: "Preference"
username_validator = UsernameValidator()
username = models.CharField(
_("username"),
@ -457,7 +458,7 @@ class User(AbstractUser):
or target.mastodon_site in self.mastodon_domain_blocks
)
if target.is_authenticated
else self.preference.no_anonymous_view # type: ignore
else self.preference.no_anonymous_view
)
def is_blocked_by(self, target):
@ -556,6 +557,7 @@ class Preference(models.Model):
mastodon_append_tag = models.CharField(max_length=2048, default="")
show_last_edit = models.PositiveSmallIntegerField(default=0)
no_anonymous_view = models.PositiveSmallIntegerField(default=0)
hidden_categories = models.JSONField(default=list)
def __str__(self):
return str(self.user)

View file

@ -4,6 +4,7 @@
{% load mastodon %}
{% load oauth_token %}
{% load truncate %}
{% load duration %}
{% load thumb %}
<!DOCTYPE html>
<html lang="zh" class="classic-page">
@ -108,6 +109,18 @@
placeholder="例如 #我的书影音"
value="{{ request.user.preference.mastodon_append_tag }}">
</fieldset>
<fieldset>
<legend>{% trans '搜索时不显示以下类型:' %}</legend>
<select name="hidden_categories" size="3" multiple>
{% all_categories as categories %}
{% for c in categories %}
<option value="{{ c.value }}"
{% if c in request.user.preference.hidden_categories %}selected{% endif %}>
{{ c.label }}
</option>
{% endfor %}
</select>
</fieldset>
<input type="submit" value="{% trans '保存' %}">
</form>
</details>