mirror of
https://gitlab.com/SIGBUS/nyaa.git
synced 2024-12-22 15:00:01 +00:00
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:
parent
5bfd7d8695
commit
c655463078
|
@ -3,6 +3,7 @@ import re
|
||||||
import shlex
|
import shlex
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from urllib.parse import quote, urlencode
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask_sqlalchemy import Pagination
|
from flask_sqlalchemy import Pagination
|
||||||
|
@ -60,17 +61,18 @@ def _get_index_name(column):
|
||||||
return table_indexes.get(column.name)
|
return table_indexes.get(column.name)
|
||||||
|
|
||||||
|
|
||||||
def _generate_query_string(term, category, filter, user):
|
def _generate_query_string(term, category, filter, user_names):
|
||||||
params = {}
|
params = []
|
||||||
if term:
|
if term:
|
||||||
params['q'] = str(term)
|
params.append(('q', str(term)))
|
||||||
if category:
|
if category:
|
||||||
params['c'] = str(category)
|
params.append(('c', str(category)))
|
||||||
if filter:
|
if filter:
|
||||||
params['f'] = str(filter)
|
params.append(('f', str(filter)))
|
||||||
if user:
|
for name in user_names:
|
||||||
params['u'] = str(user)
|
params.append(('u', name))
|
||||||
return params
|
|
||||||
|
return urlencode(params, quote_via=quote)
|
||||||
|
|
||||||
|
|
||||||
# For preprocessing ES search terms in _parse_es_search_terms
|
# For preprocessing ES search terms in _parse_es_search_terms
|
||||||
|
@ -181,7 +183,7 @@ def _parse_es_search_terms(search, search_terms):
|
||||||
return search
|
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,
|
category='0_0', quality_filter='0', page=1,
|
||||||
rss=False, admin=False, logged_in_user=None,
|
rss=False, admin=False, logged_in_user=None,
|
||||||
per_page=75, max_search_results=1000):
|
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:
|
if not main_category:
|
||||||
flask.abort(400)
|
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
|
same_user = False
|
||||||
if logged_in_user:
|
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
|
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)
|
s = _parse_es_search_terms(s, term)
|
||||||
|
|
||||||
# User view (/user/username)
|
# User view (/user/username)
|
||||||
if user:
|
if user_ids:
|
||||||
s = s.filter('term', uploader_id=user)
|
s = s.filter('terms', uploader_id=user_ids)
|
||||||
|
|
||||||
if not admin:
|
if not admin:
|
||||||
# Hide all DELETED torrents if regular user
|
# Hide all DELETED torrents if regular user
|
||||||
|
@ -370,7 +364,7 @@ class QueryPairCaller(object):
|
||||||
return wrapper
|
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,
|
quality_filter='0', page=1, rss=False, admin=False,
|
||||||
logged_in_user=None, per_page=75):
|
logged_in_user=None, per_page=75):
|
||||||
if page > 4294967295:
|
if page > 4294967295:
|
||||||
|
@ -380,7 +374,7 @@ def search_db(term='', user=None, sort='id', order='desc', category='0_0',
|
||||||
|
|
||||||
same_user = False
|
same_user = False
|
||||||
if logged_in_user:
|
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.
|
# Logged in users should always be able to view their full listing.
|
||||||
if same_user or admin:
|
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:
|
if filter_tuple is sentinel:
|
||||||
flask.abort(400)
|
flask.abort(400)
|
||||||
|
|
||||||
if user:
|
|
||||||
user = models.User.by_id(user)
|
|
||||||
if not user:
|
|
||||||
flask.abort(404)
|
|
||||||
user = user.id
|
|
||||||
|
|
||||||
main_category = None
|
main_category = None
|
||||||
sub_category = None
|
sub_category = None
|
||||||
main_cat_id = 0
|
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)
|
qpc = QueryPairCaller(query, count_query)
|
||||||
|
|
||||||
# User view (/user/username)
|
# User view (/user/username)
|
||||||
if user:
|
if user_ids:
|
||||||
qpc.filter(models.Torrent.uploader_id == user)
|
qpc.filter(models.Torrent.uploader_id.in_(user_ids))
|
||||||
|
|
||||||
if not admin:
|
if not admin:
|
||||||
# Hide all DELETED torrents if regular user
|
# 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,
|
quality_filter='0', page=1, rss=False, admin=False,
|
||||||
logged_in_user=None, per_page=75):
|
logged_in_user=None, per_page=75):
|
||||||
if page > 4294967295:
|
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:
|
if filter_lambda is sentinel:
|
||||||
flask.abort(400)
|
flask.abort(400)
|
||||||
|
|
||||||
if user:
|
|
||||||
user = models.User.by_id(user)
|
|
||||||
if not user:
|
|
||||||
flask.abort(404)
|
|
||||||
user = user.id
|
|
||||||
|
|
||||||
main_cat_id = 0
|
main_cat_id = 0
|
||||||
sub_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
|
same_user = False
|
||||||
if logged_in_user:
|
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:
|
if term:
|
||||||
query = bakery(lambda session: session.query(models.TorrentNameSearch))
|
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 = {}
|
baked_params = {}
|
||||||
|
|
||||||
# User view (/user/username)
|
# User view (/user/username)
|
||||||
if user:
|
if user_ids:
|
||||||
qpc += lambda q: q.filter(models.Torrent.uploader_id == bp('user'))
|
qpc += lambda q: q.filter(models.Torrent.uploader_id.in_(bp('user_ids', expanding=True)))
|
||||||
baked_params['user'] = user
|
baked_params['user_ids'] = user_ids
|
||||||
|
|
||||||
if not admin:
|
if not admin:
|
||||||
# Hide all DELETED torrents if regular user
|
# Hide all DELETED torrents if regular user
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<link rel="shortcut icon" type="image/png" href="{{ url_for('static', filename='favicon.png') }}">
|
<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="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="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:site_name" content="{{ config.SITE_NAME }}">
|
||||||
<meta property="og:title" content="{{ self.title() }}">
|
<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>
|
<li {% if request.path == url_for('site.trusted') %}class="active"{% endif %}><a href="{{ url_for('site.trusted') }}">Trusted</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</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' %}
|
{% if config.SITE_FLAVOR == 'nyaa' %}
|
||||||
<li><a href="//{{ config.EXTERNAL_URLS['fap'] }}">Fap</a></li>
|
<li><a href="//{{ config.EXTERNAL_URLS['fap'] }}">Fap</a></li>
|
||||||
{% elif config.SITE_FLAVOR == 'sukebei' %}
|
{% elif config.SITE_FLAVOR == 'sukebei' %}
|
||||||
|
|
|
@ -76,7 +76,7 @@ def home(rss):
|
||||||
category = chain_get(req_args, 'c', 'cats')
|
category = chain_get(req_args, 'c', 'cats')
|
||||||
quality_filter = chain_get(req_args, 'f', 'filter')
|
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')
|
page_number = chain_get(req_args, 'p', 'page', 'offset')
|
||||||
try:
|
try:
|
||||||
page_number = max(1, int(page_number))
|
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)
|
results_per_page = app.config.get('RESULTS_PER_PAGE', DEFAULT_PER_PAGE)
|
||||||
|
|
||||||
user_id = None
|
user_ids = []
|
||||||
if user_name:
|
if user_names:
|
||||||
user = models.User.by_username(user_name)
|
for name in user_names:
|
||||||
if not user:
|
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)
|
flask.abort(404)
|
||||||
user_id = user.id
|
user_ids = tuple(user_ids)
|
||||||
|
|
||||||
special_results = {
|
special_results = {
|
||||||
'first_word_user': None,
|
'first_word_user': None,
|
||||||
|
@ -101,7 +105,7 @@ def home(rss):
|
||||||
'infohash_torrent': None
|
'infohash_torrent': None
|
||||||
}
|
}
|
||||||
# Add advanced features to searches (but not RSS or user searches)
|
# 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
|
# Check if the first word of the search is an existing user
|
||||||
user_word_match = re.match(r'^([a-zA-Z0-9_-]+) *(.*|$)', search_term)
|
user_word_match = re.match(r'^([a-zA-Z0-9_-]+) *(.*|$)', search_term)
|
||||||
if user_word_match:
|
if user_word_match:
|
||||||
|
@ -122,7 +126,7 @@ def home(rss):
|
||||||
special_results['infohash_torrent'] = matched_torrent
|
special_results['infohash_torrent'] = matched_torrent
|
||||||
|
|
||||||
query_args = {
|
query_args = {
|
||||||
'user': user_id,
|
'user_ids': user_ids,
|
||||||
'sort': sort_key or 'id',
|
'sort': sort_key or 'id',
|
||||||
'order': sort_order or 'desc',
|
'order': sort_order or 'desc',
|
||||||
'category': category or '0_0',
|
'category': category or '0_0',
|
||||||
|
@ -166,7 +170,7 @@ def home(rss):
|
||||||
use_elastic=True, magnet_links=use_magnet_links)
|
use_elastic=True, magnet_links=use_magnet_links)
|
||||||
else:
|
else:
|
||||||
rss_query_string = _generate_query_string(
|
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'])
|
max_results = min(max_search_results, query_results['hits']['total'])
|
||||||
# change p= argument to whatever you change page_parameter to or pagination breaks
|
# change p= argument to whatever you change page_parameter to or pagination breaks
|
||||||
pagination = Pagination(p=query_args['page'], per_page=results_per_page,
|
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)
|
return render_rss('Home', query, use_elastic=False, magnet_links=use_magnet_links)
|
||||||
else:
|
else:
|
||||||
rss_query_string = _generate_query_string(
|
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
|
# 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)
|
# if we're browsing without a search term (which means we default to DB)
|
||||||
# or if ES is disabled
|
# or if ES is disabled
|
||||||
|
|
|
@ -130,7 +130,7 @@ def view_user(user_name):
|
||||||
|
|
||||||
query_args = {
|
query_args = {
|
||||||
'term': search_term or '',
|
'term': search_term or '',
|
||||||
'user': user.id,
|
'user_ids': (user.id,), # Tuple!
|
||||||
'sort': sort_key or 'id',
|
'sort': sort_key or 'id',
|
||||||
'order': sort_order or 'desc',
|
'order': sort_order or 'desc',
|
||||||
'category': category or '0_0',
|
'category': category or '0_0',
|
||||||
|
@ -146,7 +146,7 @@ def view_user(user_name):
|
||||||
query_args['admin'] = True
|
query_args['admin'] = True
|
||||||
|
|
||||||
# Use elastic search for term searching
|
# 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')
|
use_elastic = app.config.get('USE_ELASTIC_SEARCH')
|
||||||
if use_elastic and search_term:
|
if use_elastic and search_term:
|
||||||
query_args['term'] = search_term
|
query_args['term'] = search_term
|
||||||
|
|
Loading…
Reference in a new issue