search: Allow specifying multiple usernames...

...by repeating &u=user in the GET parameters.
No UX for this yet.
Reworks the RSS URL generator to fit with duplicated keys.
This commit is contained in:
TheAMM 2019-10-31 22:56:47 +02:00
parent 5bfd7d8695
commit c655463078
4 changed files with 41 additions and 55 deletions

View File

@ -3,6 +3,7 @@ import re
import shlex
import threading
import time
from urllib.parse import quote, urlencode
import flask
from flask_sqlalchemy import Pagination
@ -60,17 +61,18 @@ def _get_index_name(column):
return table_indexes.get(column.name)
def _generate_query_string(term, category, filter, user):
params = {}
def _generate_query_string(term, category, filter, user_names):
params = []
if term:
params['q'] = str(term)
params.append(('q', str(term)))
if category:
params['c'] = str(category)
params.append(('c', str(category)))
if filter:
params['f'] = str(filter)
if user:
params['u'] = str(user)
return params
params.append(('f', str(filter)))
for name in user_names:
params.append(('u', name))
return urlencode(params, quote_via=quote)
# For preprocessing ES search terms in _parse_es_search_terms
@ -181,7 +183,7 @@ def _parse_es_search_terms(search, search_terms):
return search
def search_elastic(term='', user=None, sort='id', order='desc',
def search_elastic(term='', user_ids=None, sort='id', order='desc',
category='0_0', quality_filter='0', page=1,
rss=False, admin=False, logged_in_user=None,
per_page=75, max_search_results=1000):
@ -261,17 +263,9 @@ def search_elastic(term='', user=None, sort='id', order='desc',
if not main_category:
flask.abort(400)
# This might be useless since we validate users
# before coming into this method, but just to be safe...
if user:
user = models.User.by_id(user)
if not user:
flask.abort(404)
user = user.id
same_user = False
if logged_in_user:
same_user = user == logged_in_user.id
same_user = len(user_ids) == 1 and logged_in_user.id in user_ids
s = Search(using=es_client, index=app.config.get('ES_INDEX_NAME')) # todo, sukebei prefix
@ -281,8 +275,8 @@ def search_elastic(term='', user=None, sort='id', order='desc',
s = _parse_es_search_terms(s, term)
# User view (/user/username)
if user:
s = s.filter('term', uploader_id=user)
if user_ids:
s = s.filter('terms', uploader_id=user_ids)
if not admin:
# Hide all DELETED torrents if regular user
@ -370,7 +364,7 @@ class QueryPairCaller(object):
return wrapper
def search_db(term='', user=None, sort='id', order='desc', category='0_0',
def search_db(term='', user_ids=None, sort='id', order='desc', category='0_0',
quality_filter='0', page=1, rss=False, admin=False,
logged_in_user=None, per_page=75):
if page > 4294967295:
@ -380,7 +374,7 @@ def search_db(term='', user=None, sort='id', order='desc', category='0_0',
same_user = False
if logged_in_user:
same_user = logged_in_user.id == user
same_user = len(user_ids) == 1 and logged_in_user.id in user_ids
# Logged in users should always be able to view their full listing.
if same_user or admin:
@ -426,12 +420,6 @@ def search_db(term='', user=None, sort='id', order='desc', category='0_0',
if filter_tuple is sentinel:
flask.abort(400)
if user:
user = models.User.by_id(user)
if not user:
flask.abort(404)
user = user.id
main_category = None
sub_category = None
main_cat_id = 0
@ -469,8 +457,8 @@ def search_db(term='', user=None, sort='id', order='desc', category='0_0',
qpc = QueryPairCaller(query, count_query)
# User view (/user/username)
if user:
qpc.filter(models.Torrent.uploader_id == user)
if user_ids:
qpc.filter(models.Torrent.uploader_id.in_(user_ids))
if not admin:
# Hide all DELETED torrents if regular user
@ -610,7 +598,7 @@ BAKED_FILTER_LAMBDAS = {
}
def search_db_baked(term='', user=None, sort='id', order='desc', category='0_0',
def search_db_baked(term='', user_ids=None, sort='id', order='desc', category='0_0',
quality_filter='0', page=1, rss=False, admin=False,
logged_in_user=None, per_page=75):
if page > 4294967295:
@ -631,12 +619,6 @@ def search_db_baked(term='', user=None, sort='id', order='desc', category='0_0',
if filter_lambda is sentinel:
flask.abort(400)
if user:
user = models.User.by_id(user)
if not user:
flask.abort(404)
user = user.id
main_cat_id = 0
sub_cat_id = 0
@ -664,7 +646,7 @@ def search_db_baked(term='', user=None, sort='id', order='desc', category='0_0',
same_user = False
if logged_in_user:
same_user = logged_in_user.id == user
same_user = len(user_ids) == 1 and logged_in_user.id in user_ids
if term:
query = bakery(lambda session: session.query(models.TorrentNameSearch))
@ -685,9 +667,9 @@ def search_db_baked(term='', user=None, sort='id', order='desc', category='0_0',
baked_params = {}
# User view (/user/username)
if user:
qpc += lambda q: q.filter(models.Torrent.uploader_id == bp('user'))
baked_params['user'] = user
if user_ids:
qpc += lambda q: q.filter(models.Torrent.uploader_id.in_(bp('user_ids', expanding=True)))
baked_params['user_ids'] = user_ids
if not admin:
# Hide all DELETED torrents if regular user

View File

@ -9,7 +9,7 @@
<link rel="shortcut icon" type="image/png" href="{{ url_for('static', filename='favicon.png') }}">
<link rel="icon" type="image/png" href="{{ url_for('static', filename='favicon.png') }}">
<link rel="mask-icon" href="{{ url_for('static', filename='pinned-tab.svg') }}" color="#3582F7">
<link rel="alternate" type="application/rss+xml" href="{% if rss_filter %}{{ url_for('main.home', page='rss', _external=True, **rss_filter) }}{% else %}{{ url_for('main.home', page='rss', _external=True) }}{% endif %}" />
<link rel="alternate" type="application/rss+xml" href="{% if rss_filter %}{{ url_for('main.home', page='rss', _external=True) + '&' + rss_filter }}{% else %}{{ url_for('main.home', page='rss', _external=True) }}{% endif %}" />
<meta property="og:site_name" content="{{ config.SITE_NAME }}">
<meta property="og:title" content="{{ self.title() }}">
@ -93,7 +93,7 @@
<li {% if request.path == url_for('site.trusted') %}class="active"{% endif %}><a href="{{ url_for('site.trusted') }}">Trusted</a></li>
</ul>
</li>
<li><a href="{% if rss_filter %}{{ url_for('main.home', page='rss', **rss_filter) }}{% else %}{{ url_for('main.home', page='rss') }}{% endif %}">RSS</a></li>
<li><a href="{% if rss_filter %}{{ url_for('main.home', page='rss') + '&' + rss_filter }}{% else %}{{ url_for('main.home', page='rss') }}{% endif %}">RSS</a></li>
{% if config.SITE_FLAVOR == 'nyaa' %}
<li><a href="//{{ config.EXTERNAL_URLS['fap'] }}">Fap</a></li>
{% elif config.SITE_FLAVOR == 'sukebei' %}

View File

@ -76,7 +76,7 @@ def home(rss):
category = chain_get(req_args, 'c', 'cats')
quality_filter = chain_get(req_args, 'f', 'filter')
user_name = chain_get(req_args, 'u', 'user')
user_names = set(req_args.getlist('u') + req_args.getlist('user'))
page_number = chain_get(req_args, 'p', 'page', 'offset')
try:
page_number = max(1, int(page_number))
@ -88,12 +88,16 @@ def home(rss):
results_per_page = app.config.get('RESULTS_PER_PAGE', DEFAULT_PER_PAGE)
user_id = None
if user_name:
user = models.User.by_username(user_name)
if not user:
user_ids = []
if user_names:
for name in user_names:
user = models.User.by_username(name)
if user:
user_ids.append(user.id)
# If we have usernames to look up but find none, 404
if not user_ids:
flask.abort(404)
user_id = user.id
user_ids = tuple(user_ids)
special_results = {
'first_word_user': None,
@ -101,7 +105,7 @@ def home(rss):
'infohash_torrent': None
}
# Add advanced features to searches (but not RSS or user searches)
if search_term and not render_as_rss and not user_id:
if search_term and not render_as_rss and not user_ids:
# Check if the first word of the search is an existing user
user_word_match = re.match(r'^([a-zA-Z0-9_-]+) *(.*|$)', search_term)
if user_word_match:
@ -122,7 +126,7 @@ def home(rss):
special_results['infohash_torrent'] = matched_torrent
query_args = {
'user': user_id,
'user_ids': user_ids,
'sort': sort_key or 'id',
'order': sort_order or 'desc',
'category': category or '0_0',
@ -166,7 +170,7 @@ def home(rss):
use_elastic=True, magnet_links=use_magnet_links)
else:
rss_query_string = _generate_query_string(
search_term, category, quality_filter, user_name)
search_term, category, quality_filter, user_names)
max_results = min(max_search_results, query_results['hits']['total'])
# change p= argument to whatever you change page_parameter to or pagination breaks
pagination = Pagination(p=query_args['page'], per_page=results_per_page,
@ -195,7 +199,7 @@ def home(rss):
return render_rss('Home', query, use_elastic=False, magnet_links=use_magnet_links)
else:
rss_query_string = _generate_query_string(
search_term, category, quality_filter, user_name)
search_term, category, quality_filter, user_names)
# Use elastic is always false here because we only hit this section
# if we're browsing without a search term (which means we default to DB)
# or if ES is disabled

View File

@ -130,7 +130,7 @@ def view_user(user_name):
query_args = {
'term': search_term or '',
'user': user.id,
'user_ids': (user.id,), # Tuple!
'sort': sort_key or 'id',
'order': sort_order or 'desc',
'category': category or '0_0',
@ -146,7 +146,7 @@ def view_user(user_name):
query_args['admin'] = True
# Use elastic search for term searching
rss_query_string = _generate_query_string(search_term, category, quality_filter, user_name)
rss_query_string = _generate_query_string(search_term, category, quality_filter, [user_name])
use_elastic = app.config.get('USE_ELASTIC_SEARCH')
if use_elastic and search_term:
query_args['term'] = search_term